@zhipu/zp-cli 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +9 -0
  2. package/dist/cli.mjs +275 -66
  3. package/package.json +25 -1
package/README.md CHANGED
@@ -16,8 +16,17 @@ zpc pack
16
16
  # 在服务器上:目录内需有 <projectName>-dist.zip + zpc.config.*(配置不要打进压缩包)
17
17
  zpc deploy
18
18
  zpc deploy --force # 允许抢占冲突的 nginx proxy
19
+
20
+ # 盘点部署目录与 nginx 配置,标注已记录 / 未记录 / 记录但缺失
21
+ zpc check
19
22
  ```
20
23
 
24
+ `zpc deploy` 若发现无 `~/.zpc` 部署记录、但 api/web 部署目录非空或已有本项目 nginx 配置,会交互询问:
25
+
26
+ 1. 清空目标文件夹并覆盖(全量,旧目录备份为带时间戳的 `.bak-*`)
27
+ 2. 使用增量部署(api 保留 `public`,跳过 web)
28
+ 3. 取消部署(默认;非交互环境同样默认取消)
29
+
21
30
  可选环境变量:`DEPLOY_DIR`、`DEPLOY_FORCE`;`ZPC_HOME` 覆盖 `~/.zpc`(部署状态记录);测试可用 `ZPC_API_ROOT` / `ZPC_WEB_ROOT` / `ZPC_NGINX_DEFAULT_D` / `ZPC_DEPLOY_SKIP_RUNTIME`。
22
31
 
23
32
  ## 部署约定
package/dist/cli.mjs CHANGED
@@ -8,7 +8,7 @@ import os, { tmpdir } from "node:os";
8
8
  import chalk from "chalk";
9
9
  import zlib from "node:zlib";
10
10
  //#region package.json
11
- var version = "0.0.2";
11
+ var version = "0.0.3";
12
12
  var description = "内部单命令部署工具";
13
13
  //#endregion
14
14
  //#region src/utils/deploy-paths.ts
@@ -321,17 +321,20 @@ function listNamedDirs(parent) {
321
321
  if (!fs.existsSync(parent)) return [];
322
322
  return fs.readdirSync(parent, { withFileTypes: true }).filter((d) => d.isDirectory() && isSafeDirName(d.name) && !d.name.startsWith(".")).map((d) => d.name);
323
323
  }
324
- /** 原子风格替换目录:删旧 `.bak` → 现目录改名为 `.bak` → 拷入新内容。 */
324
+ function backupTimestamp() {
325
+ const d = /* @__PURE__ */ new Date();
326
+ const pad = (n) => String(n).padStart(2, "0");
327
+ return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
328
+ }
329
+ /**
330
+ * 原子风格替换目录:现目录改名为带时间戳的唯一 `.bak-*` 备份 → 拷入新内容。
331
+ * 备份名含时间戳,多次覆盖不会互相覆盖,历史版本得以保留;失败从该备份恢复。
332
+ */
325
333
  function deployDir(src, dest, log) {
326
334
  fs.mkdirSync(path.dirname(dest), { recursive: true });
327
- const bak = `${dest}.bak`;
328
- if (fs.existsSync(bak)) {
329
- log(`删除旧备份 ${bak}`);
330
- fs.rmSync(bak, {
331
- recursive: true,
332
- force: true
333
- });
334
- }
335
+ const stamp = backupTimestamp();
336
+ let bak = `${dest}.bak-${stamp}`;
337
+ for (let i = 1; fs.existsSync(bak); i++) bak = `${dest}.bak-${stamp}-${i}`;
335
338
  if (fs.existsSync(dest)) {
336
339
  log(`备份 ${dest} -> ${bak}`);
337
340
  fs.renameSync(dest, bak);
@@ -488,6 +491,115 @@ function markProjectFullDeployed(root, projectName) {
488
491
  };
489
492
  writeDeployStateFile(state);
490
493
  }
494
+ /** 返回 ~/.zpc/deploy-state.json 中已记录的所有 projectName(去重、排序)。 */
495
+ function listRecordedProjectNames() {
496
+ const state = readDeployStateFile();
497
+ return [...new Set(Object.values(state.projects).map((p) => p.projectName))].sort();
498
+ }
499
+ //#endregion
500
+ //#region src/utils/check-state.ts
501
+ /** 从 nginx 配置的 `owned-by: projectName/name` 头解析出 projectName。 */
502
+ function nginxProjectName(text) {
503
+ const owned = parseNginxOwnedBy(text);
504
+ if (!owned) return null;
505
+ const idx = owned.indexOf("/");
506
+ return idx >= 0 ? owned.slice(0, idx) : owned;
507
+ }
508
+ /** 盘点部署痕迹(api/web 目录 + nginx 配置)与部署记录,合并成按系统分组的结果。 */
509
+ function collectSystemChecks() {
510
+ const recorded = new Set(listRecordedProjectNames());
511
+ const apiByProject = /* @__PURE__ */ new Map();
512
+ for (const projectName of listNamedDirs(getApiRoot())) apiByProject.set(projectName, listNamedDirs(path.join(getApiRoot(), projectName)));
513
+ const webByProject = /* @__PURE__ */ new Map();
514
+ for (const projectName of listNamedDirs(getWebRoot())) webByProject.set(projectName, listNamedDirs(path.join(getWebRoot(), projectName)));
515
+ const nginxByProject = /* @__PURE__ */ new Map();
516
+ const unownedNginxConfs = [];
517
+ const nginxDir = getNginxDefaultD();
518
+ if (fs.existsSync(nginxDir)) for (const name of fs.readdirSync(nginxDir)) {
519
+ if (!name.endsWith(".conf")) continue;
520
+ const full = path.join(nginxDir, name);
521
+ let text = "";
522
+ try {
523
+ text = fs.readFileSync(full, "utf8");
524
+ } catch {}
525
+ const projectName = nginxProjectName(text);
526
+ if (projectName) {
527
+ const arr = nginxByProject.get(projectName) ?? [];
528
+ arr.push(full);
529
+ nginxByProject.set(projectName, arr);
530
+ } else unownedNginxConfs.push(full);
531
+ }
532
+ return {
533
+ systems: [.../* @__PURE__ */ new Set([
534
+ ...recorded,
535
+ ...apiByProject.keys(),
536
+ ...webByProject.keys(),
537
+ ...nginxByProject.keys()
538
+ ])].sort().map((projectName) => ({
539
+ projectName,
540
+ recorded: recorded.has(projectName),
541
+ apiDirs: apiByProject.get(projectName) ?? [],
542
+ webDirs: webByProject.get(projectName) ?? [],
543
+ nginxConfs: nginxByProject.get(projectName) ?? []
544
+ })),
545
+ unownedNginxConfs
546
+ };
547
+ }
548
+ //#endregion
549
+ //#region src/utils/log.ts
550
+ function tagged(tag, message) {
551
+ return `${chalk.cyan(`[${tag}]`)} ${message}`;
552
+ }
553
+ /** 带命令前缀的彩色日志:info 默认、success 绿、warn 黄。 */
554
+ function createLogger(tag) {
555
+ return {
556
+ info: (message) => {
557
+ console.log(tagged(tag, message));
558
+ },
559
+ success: (message) => {
560
+ console.log(tagged(tag, chalk.green(message)));
561
+ },
562
+ warn: (message) => {
563
+ console.log(tagged(tag, chalk.yellow(message)));
564
+ }
565
+ };
566
+ }
567
+ function logError(message) {
568
+ console.error(chalk.red(message));
569
+ }
570
+ //#endregion
571
+ //#region src/commands/check.ts
572
+ const log$3 = createLogger("check");
573
+ function systemStatus(system) {
574
+ if (!system.recorded) return "未记录";
575
+ return system.apiDirs.length > 0 || system.webDirs.length > 0 || system.nginxConfs.length > 0 ? "已记录" : "记录但缺失";
576
+ }
577
+ function runCheck() {
578
+ const { systems, unownedNginxConfs } = collectSystemChecks();
579
+ if (systems.length === 0 && unownedNginxConfs.length === 0) {
580
+ log$3.info("未发现任何部署记录或部署痕迹");
581
+ return;
582
+ }
583
+ for (const system of systems) {
584
+ const status = systemStatus(system);
585
+ const head = `[${status}] ${system.projectName}`;
586
+ if (status === "已记录") log$3.info(head);
587
+ else log$3.warn(head);
588
+ if (!(system.apiDirs.length > 0 || system.webDirs.length > 0 || system.nginxConfs.length > 0)) continue;
589
+ if (system.apiDirs.length > 0) log$3.info(` api: ${system.apiDirs.join(", ")}`);
590
+ if (system.webDirs.length > 0) log$3.info(` web: ${system.webDirs.join(", ")}`);
591
+ if (system.nginxConfs.length > 0) log$3.info(` nginx: ${system.nginxConfs.join(", ")}`);
592
+ }
593
+ if (unownedNginxConfs.length > 0) {
594
+ log$3.warn(`[未归属 nginx 配置] ${unownedNginxConfs.length} 个`);
595
+ for (const conf of unownedNginxConfs) log$3.warn(` ${conf}`);
596
+ }
597
+ }
598
+ function createCheckCommand() {
599
+ return new Command("check").description("盘点部署目录与 nginx 配置,标注已记录 / 未记录 / 记录但缺失").action(async () => {
600
+ runCheck();
601
+ });
602
+ }
491
603
  //#endregion
492
604
  //#region src/utils/dist-zip.ts
493
605
  const ZPC_GITIGNORE_HEADER = "# zpc files";
@@ -511,8 +623,8 @@ function ensureZpcGitignore(projectRoot) {
511
623
  return true;
512
624
  }
513
625
  //#endregion
514
- //#region src/utils/incremental-mode.ts
515
- function isDirectoryNonEmpty(dir) {
626
+ //#region src/utils/deploy-conflict.ts
627
+ function isDirectoryNonEmpty$1(dir) {
516
628
  if (!fs.existsSync(dir)) return false;
517
629
  try {
518
630
  return fs.readdirSync(dir).length > 0;
@@ -520,55 +632,80 @@ function isDirectoryNonEmpty(dir) {
520
632
  return false;
521
633
  }
522
634
  }
523
- /** 配置中 api 在部署根目录下已存在且非空的目录。 */
524
- function findNonemptyApiDeployDirs(config) {
635
+ /** 收集「无 ~/.zpc 记录」时应提示用户的部署痕迹:api/web 目录非空、已存在/冲突的 nginx 配置。 */
636
+ function collectDeployConflicts(config) {
525
637
  const projectName = config.projectName;
526
- if (!projectName) return [];
527
- const found = [];
638
+ const conflicts = [];
639
+ if (!projectName) return conflicts;
528
640
  for (const item of config.api ?? []) {
529
- const deployDir = path.join(getApiRoot(), projectName, item.name);
530
- if (isDirectoryNonEmpty(deployDir)) found.push(deployDir);
641
+ const dir = path.join(getApiRoot(), projectName, item.name);
642
+ if (isDirectoryNonEmpty$1(dir)) conflicts.push({
643
+ kind: "api-dir",
644
+ message: `api 部署目录非空: ${dir}`
645
+ });
531
646
  }
532
- return found;
533
- }
534
- /**
535
- * 全量 / 增量判定(pack 只读、deploy 读后写入):
536
- * 1. ~/.zpc/deploy-state.json 有记录 → 增量
537
- * 2. 无记录但 api 部署目录非空 → 增量并提示
538
- * 3. 无记录但 zip 含增量标记 → 增量
539
- * 4. 否则全量
540
- */
541
- function resolveIncrementalMode(projectRoot, config, options = {}) {
542
- if (hasFullDeployRecord(projectRoot)) return { incremental: true };
543
- const existingDeployDirs = findNonemptyApiDeployDirs(config);
544
- if (existingDeployDirs.length > 0) return {
545
- incremental: true,
546
- existingDeployHint: `无 ~/.zpc 部署记录,但检测到 api 部署目录非空:${existingDeployDirs.map((dir) => path.normalize(dir)).join(", ")}。将按增量处理(api 保留 public,跳过 web);若确需全量请清空部署目录并删除 deploy-state 中对应记录`
547
- };
548
- if (options.zipIsIncremental) return { incremental: true };
549
- return { incremental: false };
550
- }
551
- //#endregion
552
- //#region src/utils/log.ts
553
- function tagged(tag, message) {
554
- return `${chalk.cyan(`[${tag}]`)} ${message}`;
555
- }
556
- /** 带命令前缀的彩色日志:info 默认、success 绿、warn 黄。 */
557
- function createLogger(tag) {
558
- return {
559
- info: (message) => {
560
- console.log(tagged(tag, message));
561
- },
562
- success: (message) => {
563
- console.log(tagged(tag, chalk.green(message)));
564
- },
565
- warn: (message) => {
566
- console.log(tagged(tag, chalk.yellow(message)));
647
+ for (const item of config.web ?? []) {
648
+ const dir = path.join(getWebRoot(), projectName, item.name);
649
+ if (isDirectoryNonEmpty$1(dir)) conflicts.push({
650
+ kind: "web-dir",
651
+ message: `web 部署目录非空: ${dir}`
652
+ });
653
+ }
654
+ const defaultD = getNginxDefaultD();
655
+ if (!fs.existsSync(defaultD)) return conflicts;
656
+ const proxies = (config.api ?? []).map((item) => item.proxy).filter((p) => !!p);
657
+ for (const name of fs.readdirSync(defaultD)) {
658
+ if (!name.endsWith(".conf")) continue;
659
+ const full = path.join(defaultD, name);
660
+ let text;
661
+ try {
662
+ text = fs.readFileSync(full, "utf8");
663
+ } catch {
664
+ continue;
567
665
  }
568
- };
569
- }
570
- function logError(message) {
571
- console.error(chalk.red(message));
666
+ const owned = parseNginxOwnedBy(text);
667
+ if (owned?.startsWith(`${projectName}/`) || name.startsWith(`${projectName}-`)) {
668
+ conflicts.push({
669
+ kind: "nginx",
670
+ message: `已存在本项目 nginx 配置: ${full}`
671
+ });
672
+ continue;
673
+ }
674
+ for (const proxy of proxies) if (confDefinesProxy(text, proxy)) {
675
+ conflicts.push({
676
+ kind: "nginx",
677
+ message: `nginx 配置 ${full} 已定义 proxy ${nginxLocation(proxy)}(归属 ${owned ?? "未知"})`
678
+ });
679
+ break;
680
+ }
681
+ }
682
+ return conflicts;
683
+ }
684
+ function isInteractive() {
685
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
686
+ }
687
+ /** 交互询问部署方式;非 TTY 环境直接返回取消(默认)。 */
688
+ async function promptDeployResolution() {
689
+ if (!isInteractive()) return "cancel";
690
+ const { select } = await import("@inquirer/prompts");
691
+ return await select({
692
+ message: "检测到已有部署痕迹(无 ~/.zpc 记录),请选择部署方式:",
693
+ choices: [
694
+ {
695
+ name: "清空目标文件夹并覆盖(全量,旧目录将备份)",
696
+ value: "full"
697
+ },
698
+ {
699
+ name: "使用增量部署(api 保留 public,跳过 web)",
700
+ value: "incremental"
701
+ },
702
+ {
703
+ name: "取消部署",
704
+ value: "cancel"
705
+ }
706
+ ],
707
+ default: "cancel"
708
+ });
572
709
  }
573
710
  //#endregion
574
711
  //#region src/utils/zip.ts
@@ -715,7 +852,7 @@ async function deployKind(stagingDir, items, kind, destRoot, projectName, increm
715
852
  if (kind === "api" && !shouldSkipDeployRuntime()) await installAndReloadApi(pm2Name, dest, item, log$2.info);
716
853
  }
717
854
  }
718
- async function runDeploy(dir, options) {
855
+ async function runDeploy(dir, options, prompt = promptDeployResolution) {
719
856
  const force = Boolean(options.force) || process.env.DEPLOY_FORCE === "1" || process.env.DEPLOY_FORCE === "true";
720
857
  const projectDir = resolveProjectDir(dir);
721
858
  const stagingDir = path.join(projectDir, ".deploy-staging");
@@ -739,12 +876,30 @@ async function runDeploy(dir, options) {
739
876
  throw new Error(`[deploy] 解压失败: ${message}`);
740
877
  }
741
878
  const zipIsIncremental = fs.existsSync(path.join(stagingDir, INCREMENTAL_MARKER));
742
- const deployMode = resolveIncrementalMode(projectDir, config, { zipIsIncremental });
743
- const incremental = deployMode.incremental;
879
+ const hadRecord = hasFullDeployRecord(projectDir);
880
+ let incremental;
881
+ let resolvedFromConflicts = false;
882
+ if (hadRecord) incremental = true;
883
+ else {
884
+ const conflicts = collectDeployConflicts(config);
885
+ if (conflicts.length > 0) {
886
+ for (const conflict of conflicts) log$2.warn(conflict.message);
887
+ const choice = await prompt();
888
+ if (choice === "cancel") {
889
+ log$2.warn("已取消部署");
890
+ fs.rmSync(stagingDir, {
891
+ recursive: true,
892
+ force: true
893
+ });
894
+ return;
895
+ }
896
+ incremental = choice === "incremental";
897
+ resolvedFromConflicts = true;
898
+ } else incremental = zipIsIncremental;
899
+ }
744
900
  try {
745
901
  log$2.info(`模式: ${incremental ? "增量(api 保留 public,跳过 web)" : "全量"}`);
746
- if (deployMode.existingDeployHint) log$2.warn(deployMode.existingDeployHint);
747
- else if (!incremental) log$2.info("首次部署该项目,完成后将记录到 ~/.zpc/deploy-state.json");
902
+ if (!incremental && !hadRecord) log$2.info("首次部署该项目,完成后将记录到 ~/.zpc/deploy-state.json");
748
903
  if (force) log$2.warn("已启用 --force(允许抢占冲突的 nginx proxy)");
749
904
  await deployKind(stagingDir, config.api, "api", getApiRoot(), config.projectName, incremental);
750
905
  if (!incremental) await deployKind(stagingDir, config.web, "web", getWebRoot(), config.projectName, false);
@@ -762,7 +917,7 @@ async function runDeploy(dir, options) {
762
917
  if (!hasFullDeployRecord(projectDir)) {
763
918
  markProjectFullDeployed(projectDir, config.projectName);
764
919
  if (!incremental) log$2.info("已记录全量部署状态到 ~/.zpc/deploy-state.json,下次 deploy 将默认增量");
765
- else if (deployMode.existingDeployHint) log$2.info("已根据现有部署目录建立部署记录,下次 deploy 将默认增量");
920
+ else if (resolvedFromConflicts) log$2.info("已根据现有部署目录建立部署记录,下次 deploy 将默认增量");
766
921
  else if (zipIsIncremental) log$2.info("已记录部署状态,下次 deploy 将默认增量");
767
922
  }
768
923
  const apiCount = config.api?.length ?? 0;
@@ -808,6 +963,57 @@ function createInitCommand() {
808
963
  });
809
964
  }
810
965
  //#endregion
966
+ //#region src/utils/incremental-mode.ts
967
+ function isDirectoryNonEmpty(dir) {
968
+ if (!fs.existsSync(dir)) return false;
969
+ try {
970
+ return fs.readdirSync(dir).length > 0;
971
+ } catch {
972
+ return false;
973
+ }
974
+ }
975
+ /** 配置中所有部署目录(api + web)里已存在且非空的目录。 */
976
+ function findNonemptyDeployDirs(config) {
977
+ const projectName = config.projectName;
978
+ if (!projectName) return [];
979
+ const found = [];
980
+ for (const item of config.api ?? []) {
981
+ const deployDir = path.join(getApiRoot(), projectName, item.name);
982
+ if (isDirectoryNonEmpty(deployDir)) found.push(deployDir);
983
+ }
984
+ for (const item of config.web ?? []) {
985
+ const deployDir = path.join(getWebRoot(), projectName, item.name);
986
+ if (isDirectoryNonEmpty(deployDir)) found.push(deployDir);
987
+ }
988
+ return found;
989
+ }
990
+ /**
991
+ * 全量 / 增量判定(pack 只读、deploy 读后写入):
992
+ * 1. ~/.zpc/deploy-state.json 有记录 → 增量
993
+ * 2. 无记录但 api/web 部署目录非空 → 交由调用方决策(不直接判定)
994
+ * 3. 无记录但 zip 含增量标记 → 增量
995
+ * 4. 否则全量
996
+ */
997
+ function resolveIncrementalMode(projectRoot, config, options = {}) {
998
+ if (hasFullDeployRecord(projectRoot)) return {
999
+ incremental: true,
1000
+ existingDeployDirs: []
1001
+ };
1002
+ const existingDeployDirs = findNonemptyDeployDirs(config);
1003
+ if (existingDeployDirs.length > 0) return {
1004
+ incremental: false,
1005
+ existingDeployDirs
1006
+ };
1007
+ if (options.zipIsIncremental) return {
1008
+ incremental: true,
1009
+ existingDeployDirs: []
1010
+ };
1011
+ return {
1012
+ incremental: false,
1013
+ existingDeployDirs: []
1014
+ };
1015
+ }
1016
+ //#endregion
811
1017
  //#region src/commands/pack.ts
812
1018
  const log = createLogger("pack");
813
1019
  function resolveProjects(root, config, incremental) {
@@ -926,12 +1132,15 @@ async function runPack(dir, options) {
926
1132
  const { file, config } = await loadConfig(projectRoot);
927
1133
  const zipPath = distZipPath(projectRoot, config.projectName);
928
1134
  const packMode = resolveIncrementalMode(projectRoot, config);
929
- const incremental = packMode.incremental;
1135
+ const incremental = packMode.incremental || packMode.existingDeployDirs.length > 0;
930
1136
  log.info(`项目目录: ${projectRoot}`);
931
1137
  log.info(`配置: ${file}`);
932
1138
  log.info(`项目: ${config.projectName}`);
933
1139
  log.info(`模式: ${incremental ? "增量(仅 api,不含 public)" : "全量"}`);
934
- if (packMode.existingDeployHint) log.warn(packMode.existingDeployHint);
1140
+ if (packMode.existingDeployDirs.length > 0) {
1141
+ const listed = packMode.existingDeployDirs.map((dir) => path.normalize(dir)).join(", ");
1142
+ log.warn(`无 ~/.zpc 部署记录,但检测到部署目录非空:${listed}。将按增量处理(api 保留 public,跳过 web);若确需全量请清空部署目录并删除 deploy-state 中对应记录`);
1143
+ }
935
1144
  if (options.concurrency !== void 0) log.info(`并行上限: ${options.concurrency}`);
936
1145
  const projects = resolveProjects(projectRoot, config, incremental);
937
1146
  await buildAll(projects, config, options);
@@ -964,7 +1173,7 @@ function createPackCommand() {
964
1173
  //#endregion
965
1174
  //#region src/utils/program.ts
966
1175
  function createProgram() {
967
- const program = new Command().name("zpc").description(description).version(version).showHelpAfterError().addCommand(createInitCommand()).addCommand(createPackCommand()).addCommand(createDeployCommand());
1176
+ const program = new Command().name("zpc").description(description).version(version).showHelpAfterError().addCommand(createInitCommand()).addCommand(createPackCommand()).addCommand(createDeployCommand()).addCommand(createCheckCommand());
968
1177
  program.action(() => {
969
1178
  program.outputHelp();
970
1179
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhipu/zp-cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "内部单命令部署工具",
5
5
  "bin": {
6
6
  "zpc": "./dist/cli.mjs"
@@ -19,6 +19,7 @@
19
19
  },
20
20
  "dependencies": {
21
21
  "@commander-js/extra-typings": "^15.0.0",
22
+ "@inquirer/prompts": "^8.6.0",
22
23
  "@vue-tui/components": "^0.3.0",
23
24
  "@vue-tui/runtime": "^0.3.0",
24
25
  "chalk": "^6.0.0",
@@ -55,6 +56,21 @@
55
56
  "@alcalzone/ansi-tokenize": "0.3.0",
56
57
  "@babel/parser": "7.29.8",
57
58
  "@commander-js/extra-typings": "15.0.0",
59
+ "@inquirer/ansi": "2.0.7",
60
+ "@inquirer/checkbox": "5.2.2",
61
+ "@inquirer/confirm": "6.2.0",
62
+ "@inquirer/core": "12.0.0",
63
+ "@inquirer/editor": "5.3.0",
64
+ "@inquirer/expand": "5.1.2",
65
+ "@inquirer/external-editor": "3.0.4",
66
+ "@inquirer/figures": "2.0.8",
67
+ "@inquirer/input": "5.1.3",
68
+ "@inquirer/number": "4.2.0",
69
+ "@inquirer/password": "5.1.2",
70
+ "@inquirer/prompts": "8.6.0",
71
+ "@inquirer/rawlist": "5.3.2",
72
+ "@inquirer/search": "4.3.0",
73
+ "@inquirer/select": "5.2.2",
58
74
  "@vue-tui/components": "0.3.0",
59
75
  "@vue-tui/runtime": "0.3.0",
60
76
  "@vue/compiler-core": "3.5.41",
@@ -69,16 +85,24 @@
69
85
  "5.6.2",
70
86
  "6.0.0"
71
87
  ],
88
+ "chardet": "2.2.0",
72
89
  "cli-boxes": "3.0.0",
73
90
  "cli-truncate": "6.1.1",
91
+ "cli-width": "4.1.0",
74
92
  "commander": "15.0.0",
75
93
  "entities": "7.0.1",
76
94
  "environment": "1.1.0",
77
95
  "estree-walker": "2.0.2",
96
+ "fast-string-truncated-width": "3.0.3",
97
+ "fast-string-width": "3.0.2",
98
+ "fast-wrap-ansi": "0.2.2",
78
99
  "get-east-asian-width": "1.6.0",
100
+ "iconv-lite": "0.7.3",
79
101
  "is-fullwidth-code-point": "5.1.0",
80
102
  "jiti": "2.7.0",
103
+ "mute-stream": "3.0.0",
81
104
  "patch-console": "2.0.0",
105
+ "safer-buffer": "2.1.2",
82
106
  "signal-exit": "4.1.0",
83
107
  "slice-ansi": "9.0.0",
84
108
  "source-map-js": "1.2.1",