Browse Source

feat: 文件推送未完成

sunxiao 8 months ago
parent
commit
af9b8fb8de
5 changed files with 461 additions and 24 deletions
  1. 14 0
      deploy/config.js
  2. 123 0
      deploy/index.js
  3. 1 1
      index.html
  4. 316 20
      package-lock.json
  5. 7 3
      package.json

+ 14 - 0
deploy/config.js

@@ -0,0 +1,14 @@
+export const config = [
+  {
+    id: 0,
+    nodeEnv: "test",
+    name: "测试环境",
+    domain: "",
+    host: "10.0.0.28",
+    port: "22",
+    username: "root",
+    password: "hsmysql",
+    path: "/usr/share/nginx/html",//部署路径
+    removepath: "/usr/share/nginx/html", //删除路径
+  },
+];

+ 123 - 0
deploy/index.js

@@ -0,0 +1,123 @@
+import Client from 'ssh2-sftp-client';
+import chalk from 'chalk';
+import shelljs from 'shelljs';
+import fs from 'fs';
+import path from 'path';
+
+import { config } from './config.js';
+
+const rawArgv = process.argv.slice(2);
+
+const filterStage = rawArgv.includes("--prod") ? "prod" : "test";
+
+// 打包
+const compileDist = async () => {
+  if (shell.exec(`npm run build:${filterStage}`).code === 0) {
+    console.log(chalk.green("打包成功"));
+  }
+}
+
+// 获取配置
+const getConfig = () => {
+  const [ result ] = config.filter(({ nodeEnv }) => nodeEnv === filterStage);
+  return result;
+}
+
+// 部署
+const connectShell = async (params) => {
+  const sftp = new Client();
+  sftp.connect({
+    host: item.host,
+    port: item.port,
+    username: item.username,
+    password: item.password,
+  }).then(() => {
+
+  })
+
+  // 判断需要上传的服务器
+  config
+    .filter((item) => item.nodeEnv == filterStage)
+    .map((item, index) => {
+      const sftp = new Client();
+      sftp
+        .connect({
+          host: item.host,
+          port: item.port,
+          username: item.username,
+          password: item.password,
+        })
+        // 备份
+        .then(() => {
+          if (index > 0) {
+            return "ok";
+          }
+          console.log(
+            chalk.red(`${item.host}--`) + chalk.blue(`---执行下拉文件备份---`)
+          );
+          console.log(chalk.blue(`---创建备份文件夹中···---`));
+          let newFile = `/${item.host}/${dayjs().format(
+            "YYYY-MM-DD"
+          )}/dist-${dayjs().format("HH_mm_ss")}`;
+          // 创建本地文件夹
+          fs.mkdir(
+            path.resolve(__dirname, `../distbak${newFile}`),
+            { recursive: true },
+            (err) => {
+              if (err) throw err;
+              console.log(chalk.green("---创建备份文件夹成功---"));
+            }
+          );
+          //执行服务器下拉操作
+          return sftp.downloadDir(
+            item.path, //服务器路径
+            path.resolve(__dirname, `../distbak${newFile}`) //写入的本地路径地址
+          );
+        })
+        // 删除
+        .then(() => {
+          if (index === 0) {
+            console.log(
+              chalk.red(`${item.host}--`) + chalk.blue(`---备份完成---`)
+            );
+          }
+          console.log(
+            chalk.yellow(`${item.host}--`) +
+            chalk.red(`---执行删除文件中···---`)
+          );
+          // 删除路径 递归删除
+          return sftp.rmdir(item.path, true);
+        })
+        // 上传
+        .then(() => {
+          console.log(
+            chalk.red(`${item.host}--`) + chalk.green(`执行删除文件成功---`)
+          );
+          console.log(
+            chalk.hex("#DEADED").bold(`---${item.host}执行上传文件中···---`)
+          );
+          return sftp.uploadDir(path.resolve(__dirname, "../dist"), item.path);
+        })
+        // 上传成功 关闭链接
+        .then(() => {
+          console.log(
+            chalk.yellow(`${item.host}--`) + chalk.green(`上传完成,部署成功---`)
+          );
+          sftp.end();
+        })
+        // 上传失败
+        .catch((err) => {
+          console.error(
+            err,
+            chalk.red(`${item.host}--`) + chalk.red(`上传失败`)
+          );
+          sftp.end();
+        });
+    });
+}
+
+async function runStart() {
+  await compileDist();
+  await connectShell();
+}
+// runStart();

+ 1 - 1
index.html

@@ -5,7 +5,7 @@
   <meta charset="UTF-8">
   <link rel="icon" href="/favicon.ico">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
-  <link rel="stylesheet" href="https://static.fuxicarbon.com/bigModel/js/katex.min.css">
+  <!-- <link rel="stylesheet" href="https://static.fuxicarbon.com/bigModel/js/katex.min.css"> -->
   <script src="https://static.fuxicarbon.com/bigModel/js/katex.min.js"></script>
   <title>LibraAI人工智能运营体</title>
 </head>

+ 316 - 20
package-lock.json

@@ -35,9 +35,12 @@
         "@vitejs/plugin-vue-jsx": "^3.1.0",
         "@vue/tsconfig": "^0.5.1",
         "autoprefixer": "^10.4.19",
+        "chalk": "^5.3.0",
         "dayjs": "^1.11.11",
         "npm-run-all2": "^6.1.2",
         "postcss": "^8.4.38",
+        "shelljs": "^0.8.5",
+        "ssh2-sftp-client": "^10.0.3",
         "tailwindcss": "^3.4.4",
         "typescript": "~5.4.0",
         "vite": "^5.2.8",
@@ -1997,6 +2000,15 @@
         "ascii2mathml": "bin/index.js"
       }
     },
+    "node_modules/asn1": {
+      "version": "0.2.6",
+      "resolved": "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz",
+      "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
     "node_modules/assign-symbols": {
       "version": "1.0.0",
       "resolved": "https://registry.npmmirror.com/assign-symbols/-/assign-symbols-1.0.0.tgz",
@@ -2114,6 +2126,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
+      "dev": true,
+      "dependencies": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
     "node_modules/big.js": {
       "version": "5.2.2",
       "resolved": "https://registry.npmmirror.com/big.js/-/big.js-5.2.2.tgz",
@@ -2198,6 +2219,22 @@
         "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
       }
     },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "node_modules/buildcheck": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmmirror.com/buildcheck/-/buildcheck-0.0.6.tgz",
+      "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/bundle-name": {
       "version": "4.1.0",
       "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz",
@@ -2294,28 +2331,15 @@
       ]
     },
     "node_modules/chalk": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmmirror.com/chalk/-/chalk-1.1.3.tgz",
-      "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
-      "dev": true,
-      "dependencies": {
-        "ansi-styles": "^2.2.1",
-        "escape-string-regexp": "^1.0.2",
-        "has-ansi": "^2.0.0",
-        "strip-ansi": "^3.0.0",
-        "supports-color": "^2.0.0"
-      },
-      "engines": {
-        "node": ">=0.10.0"
-      }
-    },
-    "node_modules/chalk/node_modules/supports-color": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-2.0.0.tgz",
-      "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+      "version": "5.3.0",
+      "resolved": "https://registry.npmmirror.com/chalk/-/chalk-5.3.0.tgz",
+      "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
       "dev": true,
       "engines": {
-        "node": ">=0.8.0"
+        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
       }
     },
     "node_modules/chokidar": {
@@ -2456,6 +2480,27 @@
       "integrity": "sha512-7CEBgcMjVmitjYo5q8JTJVra6X5mQ20uTThdK+0kR7UEaDrAWEQcRiBtWJzga4eRpP6afNwwLsX2SET2JhVB1Q==",
       "dev": true
     },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+      "dev": true
+    },
+    "node_modules/concat-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-2.0.0.tgz",
+      "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==",
+      "dev": true,
+      "engines": [
+        "node >= 6.0"
+      ],
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.0.2",
+        "typedarray": "^0.0.6"
+      }
+    },
     "node_modules/convert-source-map": {
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz",
@@ -2484,6 +2529,21 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/cpu-features": {
+      "version": "0.0.10",
+      "resolved": "https://registry.npmmirror.com/cpu-features/-/cpu-features-0.0.10.tgz",
+      "integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "dependencies": {
+        "buildcheck": "~0.0.6",
+        "nan": "^2.19.0"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
     "node_modules/cross-spawn": {
       "version": "7.0.3",
       "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -3006,6 +3066,12 @@
         "url": "https://github.com/fb55/entities?sponsor=1"
       }
     },
+    "node_modules/err-code": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/err-code/-/err-code-2.0.3.tgz",
+      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+      "dev": true
+    },
     "node_modules/error-stack-parser-es": {
       "version": "0.1.4",
       "resolved": "https://registry.npmmirror.com/error-stack-parser-es/-/error-stack-parser-es-0.1.4.tgz",
@@ -3488,6 +3554,12 @@
         "node": ">=12"
       }
     },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true
+    },
     "node_modules/fsevents": {
       "version": "2.3.3",
       "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
@@ -3917,6 +3989,17 @@
       "resolved": "https://registry.npmmirror.com/immutable/-/immutable-4.3.6.tgz",
       "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ=="
     },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+      "dev": true,
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
     "node_modules/inherits": {
       "version": "2.0.4",
       "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
@@ -3937,6 +4020,15 @@
         "node": ">= 0.4"
       }
     },
+    "node_modules/interpret": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmmirror.com/interpret/-/interpret-1.4.0.tgz",
+      "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/is-accessor-descriptor": {
       "version": "1.0.1",
       "resolved": "https://registry.npmmirror.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz",
@@ -4906,6 +4998,13 @@
         "vue": "^3.0.0"
       }
     },
+    "node_modules/nan": {
+      "version": "2.20.0",
+      "resolved": "https://registry.npmmirror.com/nan/-/nan-2.20.0.tgz",
+      "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
+      "dev": true,
+      "optional": true
+    },
     "node_modules/nanoid": {
       "version": "3.3.7",
       "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz",
@@ -5234,6 +5333,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
     "node_modules/onetime": {
       "version": "6.0.0",
       "resolved": "https://registry.npmmirror.com/onetime/-/onetime-6.0.0.tgz",
@@ -5282,6 +5390,15 @@
       "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
       "dev": true
     },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/path-key": {
       "version": "3.1.1",
       "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz",
@@ -5653,6 +5770,19 @@
         "posthtml-render": "^1.0.6"
       }
     },
+    "node_modules/promise-retry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz",
+      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+      "dev": true,
+      "dependencies": {
+        "err-code": "^2.0.2",
+        "retry": "^0.12.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/proxy-from-env": {
       "version": "1.1.0",
       "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
@@ -5746,6 +5876,18 @@
         "node": ">=8.10.0"
       }
     },
+    "node_modules/rechoir": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmmirror.com/rechoir/-/rechoir-0.6.2.tgz",
+      "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
+      "dev": true,
+      "dependencies": {
+        "resolve": "^1.1.6"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
     "node_modules/regenerator-runtime": {
       "version": "0.14.1",
       "resolved": "https://registry.npmmirror.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
@@ -5858,6 +6000,15 @@
         "node": ">=0.12"
       }
     },
+    "node_modules/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
     "node_modules/reusify": {
       "version": "1.0.4",
       "resolved": "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz",
@@ -6014,6 +6165,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
     "node_modules/sass": {
       "version": "1.77.1",
       "resolved": "https://registry.npmmirror.com/sass/-/sass-1.77.1.tgz",
@@ -6160,6 +6317,66 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/shelljs": {
+      "version": "0.8.5",
+      "resolved": "https://registry.npmmirror.com/shelljs/-/shelljs-0.8.5.tgz",
+      "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.0.0",
+        "interpret": "^1.0.0",
+        "rechoir": "^0.6.2"
+      },
+      "bin": {
+        "shjs": "bin/shjs"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/shelljs/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/shelljs/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Glob versions prior to v9 are no longer supported",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/shelljs/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/side-channel": {
       "version": "1.0.6",
       "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.6.tgz",
@@ -6372,6 +6589,42 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/ssh2": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmmirror.com/ssh2/-/ssh2-1.15.0.tgz",
+      "integrity": "sha512-C0PHgX4h6lBxYx7hcXwu3QWdh4tg6tZZsTfXcdvc5caW/EMxaB4H9dWsl7qk+F7LAW762hp8VbXOX7x4xUYvEw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "dependencies": {
+        "asn1": "^0.2.6",
+        "bcrypt-pbkdf": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=10.16.0"
+      },
+      "optionalDependencies": {
+        "cpu-features": "~0.0.9",
+        "nan": "^2.18.0"
+      }
+    },
+    "node_modules/ssh2-sftp-client": {
+      "version": "10.0.3",
+      "resolved": "https://registry.npmmirror.com/ssh2-sftp-client/-/ssh2-sftp-client-10.0.3.tgz",
+      "integrity": "sha512-Wlhasz/OCgrlqC8IlBZhF19Uw/X/dHI8ug4sFQybPE+0sDztvgvDf7Om6o7LbRLe68E7XkFZf3qMnqAvqn1vkQ==",
+      "dev": true,
+      "dependencies": {
+        "concat-stream": "^2.0.0",
+        "promise-retry": "^2.0.1",
+        "ssh2": "^1.15.0"
+      },
+      "engines": {
+        "node": ">=16.20.2"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://square.link/u/4g7sPflL"
+      }
+    },
     "node_modules/stable": {
       "version": "0.1.8",
       "resolved": "https://registry.npmmirror.com/stable/-/stable-0.1.8.tgz",
@@ -6673,6 +6926,31 @@
         "traverse": "^0.6.6"
       }
     },
+    "node_modules/svg-baker/node_modules/chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmmirror.com/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^2.2.1",
+        "escape-string-regexp": "^1.0.2",
+        "has-ansi": "^2.0.0",
+        "strip-ansi": "^3.0.0",
+        "supports-color": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/svg-baker/node_modules/chalk/node_modules/supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
     "node_modules/svg-baker/node_modules/postcss": {
       "version": "5.2.18",
       "resolved": "https://registry.npmmirror.com/postcss/-/postcss-5.2.18.tgz",
@@ -6945,6 +7223,12 @@
       "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
       "dev": true
     },
+    "node_modules/tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
+      "dev": true
+    },
     "node_modules/typed-array-buffer": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
@@ -7018,6 +7302,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==",
+      "dev": true
+    },
     "node_modules/typedarray.prototype.slice": {
       "version": "1.0.3",
       "resolved": "https://registry.npmmirror.com/typedarray.prototype.slice/-/typedarray.prototype.slice-1.0.3.tgz",
@@ -7689,6 +7979,12 @@
         "url": "https://github.com/chalk/strip-ansi?sponsor=1"
       }
     },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true
+    },
     "node_modules/yallist": {
       "version": "3.1.1",
       "resolved": "https://registry.npmmirror.com/yallist/-/yallist-3.1.1.tgz",

+ 7 - 3
package.json

@@ -4,13 +4,14 @@
   "private": true,
   "type": "module",
   "scripts": {
-    "dev": "vite",
+    "dev": "vite && node ./deploy/index.js",
     "build:prod": "vite build",
-    "build:test": "vite build  --mode test",
+    "build:test": "vite build --mode test",
     "build-lint": "run-p type-check \"build-only {@}\" --",
     "preview": "vite preview",
     "build-only": "vite build",
-    "type-check": "vue-tsc --build --force"
+    "type-check": "vue-tsc --build --force",
+    "deploy": "node deploy/index.js --test"
   },
   "dependencies": {
     "@vueuse/core": "^10.9.0",
@@ -40,9 +41,12 @@
     "@vitejs/plugin-vue-jsx": "^3.1.0",
     "@vue/tsconfig": "^0.5.1",
     "autoprefixer": "^10.4.19",
+    "chalk": "^5.3.0",
     "dayjs": "^1.11.11",
     "npm-run-all2": "^6.1.2",
     "postcss": "^8.4.38",
+    "shelljs": "^0.8.5",
+    "ssh2-sftp-client": "^10.0.3",
     "tailwindcss": "^3.4.4",
     "typescript": "~5.4.0",
     "vite": "^5.2.8",