@cannbot-ai/install-helper 0.0.2-beta.0 → 0.0.2-beta.10

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.
package/dist/index.js CHANGED
@@ -4,8 +4,8 @@
4
4
  import { Command } from "commander";
5
5
 
6
6
  // src/commands/init.ts
7
- import { select as select3, Separator as Separator3 } from "@inquirer/prompts";
8
- import chalk5 from "chalk";
7
+ import { select as select4, Separator as Separator3 } from "@inquirer/prompts";
8
+ import chalk6 from "chalk";
9
9
 
10
10
  // src/ui/wizard.ts
11
11
  import { select, checkbox, Separator } from "@inquirer/prompts";
@@ -232,7 +232,7 @@ async function getCommandVersion(cmd, args = ["--version"]) {
232
232
  }
233
233
  async function getCommandPath(cmd) {
234
234
  try {
235
- const result = await execa("sh", ["-c", `command -v ${cmd}`], { timeout: 5e3 });
235
+ const result = await execa("which", [cmd], { timeout: 5e3 });
236
236
  return result.stdout.trim();
237
237
  } catch {
238
238
  return void 0;
@@ -475,10 +475,60 @@ var zh_CN = {
475
475
  status_title: "\u5DF2\u5B89\u88C5\u63D2\u4EF6",
476
476
  status_none: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6",
477
477
  status_hint: "\u8FD0\u884C install-helper init \u5F00\u59CB\u5B89\u88C5",
478
- status_install_time: "\u5B89\u88C5\u65F6\u95F4"
478
+ status_install_time: "\u5B89\u88C5\u65F6\u95F4",
479
+ install_installed_to: "\u5B89\u88C5\u5230",
480
+ install_skills_count: "Skills",
481
+ install_agents_count: "Agents",
482
+ lang_supported: "\u652F\u6301\u7684\u8BED\u8A00: zh_CN, en_US",
483
+ lang_usage: "\u7528\u6CD5: install-helper lang set <language>",
484
+ lang_specify: "\u8BF7\u6307\u5B9A\u8BED\u8A00: install-helper lang set zh_CN",
485
+ lang_unknown_action: "\u672A\u77E5\u64CD\u4F5C",
486
+ lang_supported_actions: "\u652F\u6301\u7684\u64CD\u4F5C: show, set",
487
+ info_aliases: "\u522B\u540D",
488
+ uninstall_not_found: "\u672A\u627E\u5230",
489
+ uninstall_no_record: "\u672A\u627E\u5230\u5B89\u88C5\u8BB0\u5F55\uFF0C\u53EF\u80FD\u672A\u5B89\u88C5\u6216\u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F",
490
+ uninstall_no_record_hint: "\u5982\u9700\u5F3A\u5236\u6E05\u7406\uFF0C\u8BF7\u624B\u52A8\u5220\u9664 .opencode/ \u6216 .claude/ \u76EE\u5F55\u4E2D\u7684\u76F8\u5173\u6587\u4EF6",
491
+ uninstall_in_progress: "\u6B63\u5728\u5378\u8F7D",
492
+ uninstall_removed: "\u5DF2\u5378\u8F7D",
493
+ uninstall_files_gone: "\u7684\u6587\u4EF6\u5DF2\u4E0D\u5B58\u5728\uFF0C\u5DF2\u6E05\u7406\u5B89\u88C5\u8BB0\u5F55",
494
+ uninstall_skills_in_progress: "\u6B63\u5728\u5378\u8F7D",
495
+ init_pkg_dir_warn: "\u5F53\u524D\u76EE\u5F55\u770B\u8D77\u6765\u662F install-helper \u5305\u76EE\u5F55",
496
+ init_pkg_dir_hint: "\u8BF7\u5728\u4F60\u7684\u9879\u76EE\u76EE\u5F55\u4E2D\u8FD0\u884C\u6B64\u547D\u4EE4\uFF0C\u800C\u4E0D\u662F\u5728 install-helper \u5B89\u88C5\u76EE\u5F55\u4E2D",
497
+ init_pkg_dir_example: "\u793A\u4F8B\uFF1Acd ~/my-project && install-helper",
498
+ init_cancelled: "\u5DF2\u53D6\u6D88\u5B89\u88C5",
499
+ backup_detected: "\u68C0\u6D4B\u5230\u5F53\u524D\u76EE\u5F55\u5DF2\u5B89\u88C5\u63D2\u4EF6",
500
+ backup_current: "\u5F53\u524D\u5B89\u88C5",
501
+ backup_installing: "\u5373\u5C06\u5B89\u88C5",
502
+ backup_overwrite_warning: "\u7EE7\u7EED\u5B89\u88C5\u5C06\u8986\u76D6\u73B0\u6709\u7684 AGENTS.md \u914D\u7F6E\u6587\u4EF6\u3002",
503
+ backup_auto_create: "\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u521B\u5EFA\u5907\u4EFD\uFF0C\u4EE5\u4FBF\u540E\u7EED\u6062\u590D\u3002",
504
+ backup_overwrite: "\u8986\u76D6\u5B89\u88C5\uFF08\u81EA\u52A8\u5907\u4EFD\uFF09",
505
+ backup_cancel: "\u53D6\u6D88\u5B89\u88C5",
506
+ backup_restore_prompt: "\u68C0\u6D4B\u5230\u5907\u4EFD\u914D\u7F6E\uFF0C\u662F\u5426\u6062\u590D\uFF1F",
507
+ backup_restore: "\u6062\u590D",
508
+ backup_only_uninstall: "\u4EC5\u5378\u8F7D\uFF08\u4E0D\u6062\u590D\uFF09",
509
+ backup_select_action: "\u8BF7\u9009\u62E9\u64CD\u4F5C",
510
+ backup_restore_success: "\u5DF2\u6062\u590D\u914D\u7F6E",
511
+ backup_created: "\u5DF2\u521B\u5EFA\u5907\u4EFD",
512
+ loading_skills_list: "\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...",
513
+ loading_skills_list_complete: "Skills \u5217\u8868\u52A0\u8F7D\u5B8C\u6210",
514
+ loading_plugin_data: "\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6\u6570\u636E...",
515
+ loading_plugin_data_complete: "\u63D2\u4EF6\u6570\u636E\u52A0\u8F7D\u5B8C\u6210",
516
+ loading_skills_list_failed: "Skills \u5217\u8868\u52A0\u8F7D\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u5185\u7F6E\u6570\u636E",
517
+ install_no_skill_selected: "\u672A\u9009\u62E9\u4EFB\u4F55 Skill",
518
+ install_to: "\u5B89\u88C5\u5230",
519
+ start_to_use: "\u542F\u52A8 {tool} \u5373\u53EF\u4F7F\u7528",
520
+ wizard_step_1_title: "[1/4] \u9009\u62E9 AI \u7F16\u7A0B\u5DE5\u5177",
521
+ wizard_step_2_title: "[2/4] \u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E",
522
+ wizard_step_3_title: "[3/4] \u9009\u62E9\u8981\u5B89\u88C5\u7684\u63D2\u4EF6",
523
+ wizard_step_4_title: "[4/4] \u786E\u8BA4\u5B89\u88C5",
524
+ wizard_step_3_skill_title: "[3/4] \u9009\u62E9 Skill \u7C7B\u522B",
525
+ wizard_step_4_skill_title: "[4/4] \u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills \u2014 {category}",
526
+ install_level_project: "\u5B89\u88C5\u5230\u5F53\u524D\u76EE\u5F55\uFF08\u63A8\u8350\uFF0C\u4EC5\u5F53\u524D\u9879\u76EE\u53EF\u7528\uFF09",
527
+ install_level_global: "\u5B89\u88C5\u5230\u5168\u5C40\uFF08\u6240\u6709\u9879\u76EE\u5171\u4EAB\uFF09",
528
+ wizard_select_mode_title: "\u9009\u62E9\u5B89\u88C5\u7C7B\u578B"
479
529
  };
480
530
  var en_US = {
481
- wizard_title: "CANNBot Skills Setup Wizard",
531
+ wizard_title: "CANNBot Install Helper",
482
532
  wizard_detect: "Detecting installed AI coding tools...",
483
533
  wizard_select_tool: "Select AI coding tool",
484
534
  wizard_select_level: "Select install level",
@@ -560,7 +610,57 @@ var en_US = {
560
610
  status_title: "Installed Plugins",
561
611
  status_none: "No installed plugins",
562
612
  status_hint: "Run install-helper init to start",
563
- status_install_time: "Installed at"
613
+ status_install_time: "Installed at",
614
+ install_installed_to: "Installed to",
615
+ install_skills_count: "Skills",
616
+ install_agents_count: "Agents",
617
+ lang_supported: "Supported languages: zh_CN, en_US",
618
+ lang_usage: "Usage: install-helper lang set <language>",
619
+ lang_specify: "Please specify language: install-helper lang set zh_CN",
620
+ lang_unknown_action: "Unknown action",
621
+ lang_supported_actions: "Supported actions: show, set",
622
+ info_aliases: "Aliases",
623
+ uninstall_not_found: "Not found",
624
+ uninstall_no_record: "No install record found, may not be installed or record is corrupted",
625
+ uninstall_no_record_hint: "For manual cleanup, delete related files in .opencode/ or .claude/ directory",
626
+ uninstall_in_progress: "Uninstalling",
627
+ uninstall_removed: "Uninstalled",
628
+ uninstall_files_gone: " files no longer exist, install record cleaned",
629
+ uninstall_skills_in_progress: "Uninstalling",
630
+ init_pkg_dir_warn: "Current directory appears to be the install-helper package directory",
631
+ init_pkg_dir_hint: "Please run this command in your project directory, not in the install-helper package directory",
632
+ init_pkg_dir_example: "Example: cd ~/my-project && install-helper",
633
+ init_cancelled: "Installation cancelled",
634
+ backup_detected: "Plugin already installed in current directory",
635
+ backup_current: "Currently installed",
636
+ backup_installing: "About to install",
637
+ backup_overwrite_warning: "Continuing will overwrite existing AGENTS.md configuration.",
638
+ backup_auto_create: "System will automatically create backup for future restoration.",
639
+ backup_overwrite: "Overwrite (auto backup)",
640
+ backup_cancel: "Cancel installation",
641
+ backup_restore_prompt: "Backup configuration detected, restore?",
642
+ backup_restore: "Restore",
643
+ backup_only_uninstall: "Uninstall only (no restore)",
644
+ backup_select_action: "Please select an action",
645
+ backup_restore_success: "Configuration restored",
646
+ backup_created: "Backup created",
647
+ loading_skills_list: "Loading Skills list...",
648
+ loading_skills_list_complete: "Skills list loaded",
649
+ loading_plugin_data: "Loading plugin data...",
650
+ loading_plugin_data_complete: "Plugin data loaded",
651
+ loading_skills_list_failed: "Failed to load Skills list, using built-in data",
652
+ install_no_skill_selected: "No Skill selected",
653
+ install_to: "Install to",
654
+ start_to_use: "Start {tool} to use",
655
+ wizard_step_1_title: "[1/4] Select AI coding tool",
656
+ wizard_step_2_title: "[2/4] Select installation location",
657
+ wizard_step_3_title: "[3/4] Select plugins to install",
658
+ wizard_step_4_title: "[4/4] Confirm installation",
659
+ wizard_step_3_skill_title: "[3/4] Select Skill category",
660
+ wizard_step_4_skill_title: "[4/4] Select Skills to install \u2014 {category}",
661
+ install_level_project: "Install to current directory (recommended, current project only)",
662
+ install_level_global: "Install globally (all projects)",
663
+ wizard_select_mode_title: "Select installation type"
564
664
  };
565
665
  var currentLang = "zh_CN";
566
666
  function setLanguage(lang) {
@@ -624,7 +724,7 @@ function printBoxTitle(title, width = 65) {
624
724
  }
625
725
  function showOperationHints(isCheckbox = false) {
626
726
  if (isCheckbox) {
627
- console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m \u79FB\u52A8 | \x1B[36m\u7A7A\u683C\x1B[0m \u9009\u62E9 | \x1B[36m\u23CE\x1B[0m \u786E\u8BA4
727
+ console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m \u79FB\u52A8 | \x1B[36m\u7A7A\u683C\x1B[0m \u52FE\u9009 | \x1B[36m\u23CE\x1B[0m \u786E\u8BA4\uFF08\u4E0D\u9009\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE\uFF09
628
728
  `);
629
729
  } else {
630
730
  console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m \u79FB\u52A8 | \x1B[36m\u23CE\x1B[0m \u786E\u8BA4
@@ -713,7 +813,7 @@ var checkboxTheme = {
713
813
 
714
814
  // src/ui/wizard.ts
715
815
  var BACK = "__back__";
716
- var CANCEL2 = "__cancel__";
816
+ var CANCEL = "__cancel__";
717
817
  async function selectToolWithDetection() {
718
818
  const config = readConfig();
719
819
  logger.blank();
@@ -723,7 +823,7 @@ async function selectToolWithDetection() {
723
823
  spinner.stop();
724
824
  const result = await stepTool(detectedTools, config.lastTool);
725
825
  if (result === BACK) return "back";
726
- if (result === CANCEL2) return "cancel";
826
+ if (result === CANCEL) return "cancel";
727
827
  return result;
728
828
  }
729
829
  async function runWizard() {
@@ -744,7 +844,7 @@ async function runWizard() {
744
844
  if (result === BACK) {
745
845
  return { language: config.language || "zh_CN", tool: "opencode", level: "project", plugins: [], confirmed: false, back: true };
746
846
  }
747
- if (result === CANCEL2) {
847
+ if (result === CANCEL) {
748
848
  return { language: config.language || "zh_CN", tool: "opencode", level: "project", plugins: [], confirmed: false };
749
849
  }
750
850
  selectedTool = result;
@@ -757,7 +857,7 @@ async function runWizard() {
757
857
  step = 0;
758
858
  break;
759
859
  }
760
- if (result === CANCEL2) {
860
+ if (result === CANCEL) {
761
861
  return { language: config.language || "zh_CN", tool: selectedTool, level: "project", plugins: [], confirmed: false };
762
862
  }
763
863
  level = result;
@@ -770,7 +870,7 @@ async function runWizard() {
770
870
  step = 1;
771
871
  break;
772
872
  }
773
- if (result === CANCEL2) {
873
+ if (result === CANCEL) {
774
874
  return { language: config.language || "zh_CN", tool: selectedTool, level, plugins: [], confirmed: false };
775
875
  }
776
876
  plugins = result;
@@ -783,7 +883,7 @@ async function runWizard() {
783
883
  step = 2;
784
884
  break;
785
885
  }
786
- if (result === CANCEL2 || result === false) {
886
+ if (result === CANCEL || result === false) {
787
887
  return { language: config.language || "zh_CN", tool: selectedTool, level, plugins: [], confirmed: false };
788
888
  }
789
889
  updateConfig({ lastTool: selectedTool, lastLevel: level });
@@ -793,7 +893,7 @@ async function runWizard() {
793
893
  }
794
894
  }
795
895
  async function stepTool(detectedTools, lastTool) {
796
- printBoxTitle("\u9009\u62E9 AI \u7F16\u7A0B\u5DE5\u5177");
896
+ printBoxTitle(t("wizard_step_1_title"));
797
897
  if (detectedTools.length === 0) {
798
898
  logger.error(t("error_tool_not_found"));
799
899
  const choices2 = [
@@ -803,12 +903,12 @@ async function stepTool(detectedTools, lastTool) {
803
903
  })),
804
904
  new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
805
905
  { name: "<- " + t("wizard_back"), value: BACK },
806
- { name: "x " + t("wizard_cancel"), value: CANCEL2 }
906
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
807
907
  ];
808
908
  showOperationHints();
809
909
  const result2 = await select({ message: t("wizard_select_tool"), choices: choices2, default: lastTool, loop: false, theme: selectTheme });
810
910
  if (result2 === BACK) return BACK;
811
- if (result2 === CANCEL2) return CANCEL2;
911
+ if (result2 === CANCEL) return CANCEL;
812
912
  return result2;
813
913
  }
814
914
  if (detectedTools.length === 1) {
@@ -823,12 +923,12 @@ async function stepTool(detectedTools, lastTool) {
823
923
  { name: `> ${t("wizard_select_tool")}`, value: "manual" },
824
924
  new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
825
925
  { name: "<- " + t("wizard_back"), value: BACK },
826
- { name: "x " + t("wizard_cancel"), value: CANCEL2 }
926
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
827
927
  ];
828
928
  showOperationHints();
829
929
  const result2 = await select({ message: t("wizard_select_tool"), choices: choices2, loop: false, theme: selectTheme });
830
930
  if (result2 === BACK) return BACK;
831
- if (result2 === CANCEL2) return CANCEL2;
931
+ if (result2 === CANCEL) return CANCEL;
832
932
  if (result2 === "manual") {
833
933
  return stepToolManual(lastTool);
834
934
  }
@@ -844,11 +944,11 @@ async function stepTool(detectedTools, lastTool) {
844
944
  });
845
945
  choices.push(new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
846
946
  choices.push({ name: "<- " + t("wizard_back"), value: BACK });
847
- choices.push({ name: "x " + t("wizard_cancel"), value: CANCEL2 });
947
+ choices.push({ name: "x " + t("wizard_cancel"), value: CANCEL });
848
948
  showOperationHints();
849
949
  const result = await select({ message: t("wizard_select_tool"), choices, default: lastTool, loop: false, theme: selectTheme });
850
950
  if (result === BACK) return BACK;
851
- if (result === CANCEL2) return CANCEL2;
951
+ if (result === CANCEL) return CANCEL;
852
952
  return result;
853
953
  }
854
954
  async function stepToolManual(lastTool) {
@@ -859,22 +959,22 @@ async function stepToolManual(lastTool) {
859
959
  })),
860
960
  new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
861
961
  { name: "<- " + t("wizard_back"), value: BACK },
862
- { name: "x " + t("wizard_cancel"), value: CANCEL2 }
962
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
863
963
  ];
864
964
  showOperationHints();
865
965
  const result = await select({ message: t("wizard_select_tool"), choices, default: lastTool, loop: false, theme: selectTheme });
866
966
  if (result === BACK) return BACK;
867
- if (result === CANCEL2) return CANCEL2;
967
+ if (result === CANCEL) return CANCEL;
868
968
  return result;
869
969
  }
870
970
  async function stepLevel(lastLevel) {
871
- printBoxTitle("\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E");
971
+ printBoxTitle(t("wizard_step_2_title"));
872
972
  const choices = [
873
- { name: "> project \u2014 \u5B89\u88C5\u5230\u5F53\u524D\u76EE\u5F55\uFF08\u63A8\u8350\uFF0C\u4EC5\u5F53\u524D\u9879\u76EE\u53EF\u7528\uFF09", value: "project" },
874
- { name: "> global \u2014 \u5B89\u88C5\u5230\u5168\u5C40\uFF08\u6240\u6709\u9879\u76EE\u5171\u4EAB\uFF09", value: "global" },
973
+ { name: `> project \u2014 ${t("install_level_project")}`, value: "project" },
974
+ { name: `> global \u2014 ${t("install_level_global")}`, value: "global" },
875
975
  new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
876
976
  { name: "<- " + t("wizard_back"), value: BACK },
877
- { name: "x " + t("wizard_cancel"), value: CANCEL2 }
977
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
878
978
  ];
879
979
  showOperationHints();
880
980
  const result = await select({
@@ -885,11 +985,11 @@ async function stepLevel(lastLevel) {
885
985
  theme: selectTheme
886
986
  });
887
987
  if (result === BACK) return BACK;
888
- if (result === CANCEL2) return CANCEL2;
988
+ if (result === CANCEL) return CANCEL;
889
989
  return result;
890
990
  }
891
991
  async function stepPlugins(tool, level) {
892
- printBoxTitle("\u9009\u62E9\u8981\u5B89\u88C5\u7684\u63D2\u4EF6");
992
+ printBoxTitle(t("wizard_step_3_title"));
893
993
  const plugins = getAllPlugins();
894
994
  const configRoot = getConfigRoot(tool, level);
895
995
  const manifests = readAllManifests(configRoot);
@@ -898,25 +998,21 @@ async function stepPlugins(tool, level) {
898
998
  const isInstalled = installedSet.has(p.id);
899
999
  const suffix = isInstalled ? ` [${t("wizard_already_installed")}]` : "";
900
1000
  return {
901
- name: `${p.displayName}${suffix}`,
1001
+ name: `${p.displayName}${suffix} \u2014 ${p.description}`,
902
1002
  value: p.id,
903
1003
  checked: false
904
1004
  };
905
1005
  });
906
- choices.push(new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
907
- choices.push({ name: "<- " + t("wizard_back"), value: BACK, checked: false });
908
- choices.push({ name: "x " + t("wizard_cancel"), value: CANCEL2, checked: false });
909
1006
  showOperationHints(true);
910
1007
  const selected = await checkbox({
911
1008
  message: t("wizard_select_plugins"),
912
1009
  choices,
913
1010
  loop: false,
914
1011
  instructions: false,
915
- theme: checkboxTheme
1012
+ theme: checkboxTheme,
1013
+ pageSize: 15
916
1014
  });
917
- if (selected.includes(BACK)) return BACK;
918
- if (selected.includes(CANCEL2)) return CANCEL2;
919
- const pluginIds = selected.filter((v) => v !== BACK && v !== CANCEL2);
1015
+ const pluginIds = selected;
920
1016
  if (pluginIds.length === 0) {
921
1017
  const action = await select({
922
1018
  message: t("wizard_no_selection"),
@@ -929,19 +1025,22 @@ async function stepPlugins(tool, level) {
929
1025
  theme: selectTheme
930
1026
  });
931
1027
  if (action === "back") return BACK;
932
- return CANCEL2;
1028
+ return CANCEL;
933
1029
  }
934
1030
  return pluginIds;
935
1031
  }
936
1032
  async function stepConfirm(tool, level, plugins) {
937
- printBoxTitle("\u786E\u8BA4\u5B89\u88C5");
1033
+ printBoxTitle(t("wizard_step_4_title"));
938
1034
  const allPlugins = getAllPlugins();
939
1035
  const selectedPlugins = plugins.map((id) => allPlugins.find((p) => p.id === id));
940
1036
  const displayPath = getConfigRoot(tool, level);
941
- logger.info(`\u5373\u5C06\u5B89\u88C5 ${chalk2.bold(plugins.length)} \u4E2A\u573A\u666F\u5230 ${chalk2.cyan(displayPath)}\uFF1A`);
1037
+ const toolName = getToolDisplayName(tool);
1038
+ const levelText = level === "project" ? "project" : "global";
1039
+ logger.info(`\u5373\u5C06\u5B89\u88C5 ${chalk2.bold(plugins.length)} \u4E2A\u63D2\u4EF6\u5230 ${chalk2.green(toolName)}\uFF08${chalk2.cyan(levelText)} \u7EA7\u522B\uFF09\uFF1A`);
1040
+ logger.info(`\u5B89\u88C5\u8DEF\u5F84: ${chalk2.cyan(displayPath)}`);
942
1041
  for (const plugin of selectedPlugins) {
943
1042
  if (plugin) {
944
- logger.step(` \u2022 ${chalk2.bold(plugin.displayName)} ${chalk2.dim(`(${plugin.skills} skills, ${plugin.agents} agents)`)}`);
1043
+ logger.step(` \u2022 ${chalk2.bold(plugin.displayName)}`);
945
1044
  }
946
1045
  }
947
1046
  logger.blank();
@@ -949,12 +1048,12 @@ async function stepConfirm(tool, level, plugins) {
949
1048
  { name: "> " + t("wizard_confirm"), value: "confirm" },
950
1049
  new Separator("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
951
1050
  { name: "<- " + t("wizard_back"), value: BACK },
952
- { name: "x " + t("wizard_cancel"), value: CANCEL2 }
1051
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
953
1052
  ];
954
1053
  showOperationHints();
955
1054
  const result = await select({ message: t("wizard_confirm"), choices, loop: false, theme: selectTheme });
956
1055
  if (result === BACK) return BACK;
957
- if (result === CANCEL2) return CANCEL2;
1056
+ if (result === CANCEL) return CANCEL;
958
1057
  return true;
959
1058
  }
960
1059
 
@@ -965,7 +1064,7 @@ import { execa as execa2 } from "execa";
965
1064
 
966
1065
  // src/core/scanner.ts
967
1066
  import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync3, statSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
968
- import { join as join5, dirname } from "path";
1067
+ import { join as join5 } from "path";
969
1068
  import { parse as parseYaml } from "yaml";
970
1069
  var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
971
1070
  "node_modules",
@@ -1103,8 +1202,7 @@ function writeScanCache(cache) {
1103
1202
  }
1104
1203
  }
1105
1204
  function getCachePath() {
1106
- const homeDir = process.env.HOME || process.env.USERPROFILE || "/tmp";
1107
- return join5(homeDir, ".cannbot", "scan-cache.json");
1205
+ return join5(getCannbotConfigDir(), "scan-cache.json");
1108
1206
  }
1109
1207
  function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1110
1208
  const selfSkillMd = join5(dirPath, "SKILL.md");
@@ -1478,8 +1576,8 @@ function createRepositoryManager(customPath) {
1478
1576
  }
1479
1577
 
1480
1578
  // src/core/installer.ts
1481
- import { existsSync as existsSync8 } from "fs";
1482
- import { join as join8 } from "path";
1579
+ import { existsSync as existsSync9 } from "fs";
1580
+ import { join as join9 } from "path";
1483
1581
  import { execa as execa3 } from "execa";
1484
1582
 
1485
1583
  // src/core/record.ts
@@ -1573,7 +1671,6 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1573
1671
  files.push(repoLinkInConfig);
1574
1672
  }
1575
1673
  }
1576
- directories.push(configRoot);
1577
1674
  return {
1578
1675
  pluginId,
1579
1676
  displayName,
@@ -1653,6 +1750,179 @@ function getInstalledSkills(tool, level, installPath) {
1653
1750
  return record[tool]?.[level]?.[installPath]?.skills || [];
1654
1751
  }
1655
1752
 
1753
+ // src/core/backup.ts
1754
+ import { existsSync as existsSync8, copyFileSync, readdirSync as readdirSync2, unlinkSync as unlinkSync2 } from "fs";
1755
+ import { join as join8 } from "path";
1756
+ function getAgentsFileName(tool) {
1757
+ return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1758
+ }
1759
+ function detectCurrentPlugin(configRoot, tool) {
1760
+ const manifest = readManifest(configRoot);
1761
+ if (manifest?.team) {
1762
+ const plugin = findPlugin(manifest.team);
1763
+ if (plugin) {
1764
+ return {
1765
+ pluginId: plugin.id,
1766
+ pluginName: plugin.displayName
1767
+ };
1768
+ }
1769
+ }
1770
+ const agentsFile = join8(configRoot, getAgentsFileName(tool));
1771
+ if (!existsSync8(agentsFile)) {
1772
+ return null;
1773
+ }
1774
+ const allRecords = readAllRecords();
1775
+ for (const record of allRecords) {
1776
+ if (record.configRoot === configRoot && record.tool === tool) {
1777
+ const plugin = findPlugin(record.pluginId);
1778
+ if (plugin) {
1779
+ return {
1780
+ pluginId: plugin.id,
1781
+ pluginName: plugin.displayName
1782
+ };
1783
+ }
1784
+ }
1785
+ }
1786
+ return null;
1787
+ }
1788
+ function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
1789
+ const agentsFile = join8(configRoot, getAgentsFileName(tool));
1790
+ if (!existsSync8(agentsFile)) {
1791
+ return null;
1792
+ }
1793
+ const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
1794
+ const backupFileName = `${getAgentsFileName(tool)}.cannbot-backup.${fromPluginId}.${timestamp}`;
1795
+ const backupPath = join8(configRoot, backupFileName);
1796
+ try {
1797
+ copyFileSync(agentsFile, backupPath);
1798
+ return {
1799
+ filePath: backupPath,
1800
+ pluginId: fromPluginId,
1801
+ pluginName: fromPluginName,
1802
+ backupTime: timestamp
1803
+ };
1804
+ } catch {
1805
+ return null;
1806
+ }
1807
+ }
1808
+ function findBackups(configRoot) {
1809
+ if (!existsSync8(configRoot)) {
1810
+ return [];
1811
+ }
1812
+ const files = readdirSync2(configRoot);
1813
+ const backups = [];
1814
+ for (const file of files) {
1815
+ if (file.includes(".cannbot-backup.")) {
1816
+ const parts = file.split(".cannbot-backup.");
1817
+ if (parts.length === 2) {
1818
+ const pluginIdAndTime = parts[1];
1819
+ const lastDotIndex = pluginIdAndTime.lastIndexOf(".");
1820
+ if (lastDotIndex > 0) {
1821
+ const pluginId = pluginIdAndTime.substring(0, lastDotIndex);
1822
+ const timestamp = pluginIdAndTime.substring(lastDotIndex + 1);
1823
+ const plugin = findPlugin(pluginId);
1824
+ backups.push({
1825
+ filePath: join8(configRoot, file),
1826
+ pluginId,
1827
+ pluginName: plugin?.displayName || pluginId,
1828
+ backupTime: timestamp
1829
+ });
1830
+ }
1831
+ }
1832
+ }
1833
+ }
1834
+ return backups.sort((a, b) => b.backupTime.localeCompare(a.backupTime));
1835
+ }
1836
+ function restoreBackup(backupPath, configRoot, tool) {
1837
+ try {
1838
+ const agentsFile = join8(configRoot, getAgentsFileName(tool));
1839
+ copyFileSync(backupPath, agentsFile);
1840
+ return true;
1841
+ } catch {
1842
+ return false;
1843
+ }
1844
+ }
1845
+ function deleteBackup(backupPath) {
1846
+ try {
1847
+ if (existsSync8(backupPath)) {
1848
+ unlinkSync2(backupPath);
1849
+ return true;
1850
+ }
1851
+ return false;
1852
+ } catch {
1853
+ return false;
1854
+ }
1855
+ }
1856
+ function formatTimestamp(date) {
1857
+ const year = date.getFullYear();
1858
+ const month = String(date.getMonth() + 1).padStart(2, "0");
1859
+ const day = String(date.getDate()).padStart(2, "0");
1860
+ const hours = String(date.getHours()).padStart(2, "0");
1861
+ const minutes = String(date.getMinutes()).padStart(2, "0");
1862
+ const seconds = String(date.getSeconds()).padStart(2, "0");
1863
+ return `${year}${month}${day}-${hours}${minutes}${seconds}`;
1864
+ }
1865
+ function readAllRecords() {
1866
+ const records = [];
1867
+ const plugins = [
1868
+ "ops-direct-invoke",
1869
+ "ops-direct-invoke-flash",
1870
+ "ops-registry-invoke",
1871
+ "pypto-op-orchestrator",
1872
+ "triton-op-generator",
1873
+ "tilelang-op-orchestrator",
1874
+ "model-infer-optimize",
1875
+ "catlass-op-generator",
1876
+ "ops-code-reviewer",
1877
+ "torch-compile"
1878
+ ];
1879
+ for (const pluginId of plugins) {
1880
+ const record = readRecord(pluginId);
1881
+ if (record) {
1882
+ records.push(record);
1883
+ }
1884
+ }
1885
+ return records;
1886
+ }
1887
+
1888
+ // src/ui/backup-prompts.ts
1889
+ import { select as select2 } from "@inquirer/prompts";
1890
+ import chalk3 from "chalk";
1891
+ async function showOverwriteWarning(currentPluginName, newPluginName) {
1892
+ console.log();
1893
+ console.log(chalk3.yellow(` \u26A0\uFE0F ${t("backup_detected")}`));
1894
+ console.log();
1895
+ console.log(` ${t("backup_current")}: ${chalk3.cyan(currentPluginName)}`);
1896
+ console.log(` ${t("backup_installing")}: ${chalk3.cyan(newPluginName)}`);
1897
+ console.log();
1898
+ console.log(` ${t("backup_overwrite_warning")}`);
1899
+ console.log(` ${t("backup_auto_create")}`);
1900
+ console.log();
1901
+ const choice = await select2({
1902
+ message: t("backup_select_action"),
1903
+ choices: [
1904
+ { name: t("backup_overwrite"), value: "overwrite" },
1905
+ { name: t("backup_cancel"), value: "cancel" }
1906
+ ]
1907
+ });
1908
+ return choice;
1909
+ }
1910
+ async function showRestorePrompt(backups) {
1911
+ console.log();
1912
+ console.log(chalk3.cyan(` ${t("backup_restore_prompt")}`));
1913
+ console.log();
1914
+ const choices = backups.map((b) => ({
1915
+ name: `${t("backup_restore")} ${b.pluginName} (${b.backupTime})`,
1916
+ value: b.filePath
1917
+ }));
1918
+ choices.push({ name: t("backup_only_uninstall"), value: "none" });
1919
+ const choice = await select2({
1920
+ message: t("backup_select_action"),
1921
+ choices
1922
+ });
1923
+ return choice;
1924
+ }
1925
+
1656
1926
  // src/core/installer.ts
1657
1927
  async function installPlugin(opts) {
1658
1928
  const plugin = getPluginById(opts.pluginId);
@@ -1666,8 +1936,8 @@ async function installPlugin(opts) {
1666
1936
  warnings: []
1667
1937
  };
1668
1938
  }
1669
- const scriptPath = join8(opts.repoPath, plugin.dir, plugin.script);
1670
- if (!existsSync8(scriptPath)) {
1939
+ const scriptPath = join9(opts.repoPath, plugin.dir, plugin.script);
1940
+ if (!existsSync9(scriptPath)) {
1671
1941
  return {
1672
1942
  success: false,
1673
1943
  pluginId: opts.pluginId,
@@ -1682,13 +1952,49 @@ async function installPlugin(opts) {
1682
1952
  args.push(opts.installPath);
1683
1953
  }
1684
1954
  const cwd = opts.installPath || process.cwd();
1955
+ const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
1956
+ const agentsFile = join9(configRoot, getAgentsFileName(opts.tool));
1957
+ let backupInfo = null;
1958
+ if (existsSync9(agentsFile)) {
1959
+ const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
1960
+ if (currentPlugin && currentPlugin.pluginId !== opts.pluginId) {
1961
+ let choice = "overwrite";
1962
+ if (!opts.yes) {
1963
+ choice = await showOverwriteWarning(
1964
+ currentPlugin.pluginName,
1965
+ plugin.displayName
1966
+ );
1967
+ }
1968
+ if (choice === "cancel") {
1969
+ logger.info(t("backup_cancel"));
1970
+ return {
1971
+ success: false,
1972
+ pluginId: opts.pluginId,
1973
+ skillsCount: 0,
1974
+ agentsCount: 0,
1975
+ errors: [t("backup_cancel")],
1976
+ warnings: []
1977
+ };
1978
+ }
1979
+ backupInfo = createBackup(
1980
+ configRoot,
1981
+ opts.tool,
1982
+ currentPlugin.pluginId,
1983
+ currentPlugin.pluginName
1984
+ );
1985
+ if (backupInfo) {
1986
+ logger.success(`${t("backup_created")}: ${backupInfo.filePath}`);
1987
+ }
1988
+ }
1989
+ }
1685
1990
  try {
1686
- await execa3("bash", [scriptPath, ...args], {
1991
+ const execOptions = {
1687
1992
  cwd,
1688
1993
  timeout: 3e5,
1689
- stdio: "pipe"
1690
- });
1691
- const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
1994
+ stdio: "pipe",
1995
+ input: opts.yes ? "y\n" : void 0
1996
+ };
1997
+ await execa3("bash", [scriptPath, ...args], execOptions);
1692
1998
  const manifest = readManifest(configRoot);
1693
1999
  let skillsCount = 0;
1694
2000
  let agentsCount = 0;
@@ -1709,6 +2015,14 @@ async function installPlugin(opts) {
1709
2015
  configRoot,
1710
2016
  manifest
1711
2017
  );
2018
+ if (backupInfo) {
2019
+ record.backup = {
2020
+ filePath: backupInfo.filePath,
2021
+ fromPluginId: backupInfo.pluginId,
2022
+ fromPluginName: backupInfo.pluginName,
2023
+ backupTime: backupInfo.backupTime
2024
+ };
2025
+ }
1712
2026
  writeRecord(record);
1713
2027
  } catch {
1714
2028
  }
@@ -1734,16 +2048,16 @@ async function installPlugin(opts) {
1734
2048
  }
1735
2049
 
1736
2050
  // src/core/skill-installer.ts
1737
- import { existsSync as existsSync9, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync2, readdirSync as readdirSync3, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
1738
- import { join as join9 } from "path";
1739
- import { select as select2, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
1740
- import chalk3 from "chalk";
2051
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as readdirSync3, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
2052
+ import { join as join10 } from "path";
2053
+ import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
2054
+ import chalk4 from "chalk";
1741
2055
  import Table from "cli-table3";
1742
2056
  async function installSkills(skillIds, tool, level, repoPath) {
1743
2057
  const configRoot = getConfigRoot(tool, level);
1744
- const skillsDir = join9(configRoot, "skills");
2058
+ const skillsDir = join10(configRoot, "skills");
1745
2059
  const installPath = level === "project" ? process.cwd() : configRoot;
1746
- if (!existsSync9(skillsDir)) {
2060
+ if (!existsSync10(skillsDir)) {
1747
2061
  mkdirSync5(skillsDir, { recursive: true });
1748
2062
  }
1749
2063
  const results = [];
@@ -1754,15 +2068,15 @@ async function installSkills(skillIds, tool, level, repoPath) {
1754
2068
  results.push({ skillId, success: false, error: "Skill not found in registry" });
1755
2069
  continue;
1756
2070
  }
1757
- const sourcePath = join9(repoPath, skill.source, skill.id);
1758
- const targetPath = join9(skillsDir, skillId);
1759
- if (!existsSync9(sourcePath)) {
2071
+ const sourcePath = join10(repoPath, skill.source, skill.id);
2072
+ const targetPath = join10(skillsDir, skillId);
2073
+ if (!existsSync10(sourcePath)) {
1760
2074
  results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
1761
2075
  continue;
1762
2076
  }
1763
2077
  try {
1764
- if (existsSync9(targetPath) || isSymlink2(targetPath)) {
1765
- unlinkSync2(targetPath);
2078
+ if (existsSync10(targetPath) || isSymlink2(targetPath)) {
2079
+ unlinkSync3(targetPath);
1766
2080
  }
1767
2081
  symlinkSync(realpathSync(sourcePath), targetPath);
1768
2082
  results.push({ skillId, success: true });
@@ -1778,15 +2092,15 @@ async function installSkills(skillIds, tool, level, repoPath) {
1778
2092
  }
1779
2093
  async function uninstallSkills(skillIds, tool, level) {
1780
2094
  const configRoot = getConfigRoot(tool, level);
1781
- const skillsDir = join9(configRoot, "skills");
2095
+ const skillsDir = join10(configRoot, "skills");
1782
2096
  const installPath = level === "project" ? process.cwd() : configRoot;
1783
2097
  const results = [];
1784
2098
  const removedIds = [];
1785
2099
  for (const skillId of skillIds) {
1786
- const targetPath = join9(skillsDir, skillId);
2100
+ const targetPath = join10(skillsDir, skillId);
1787
2101
  try {
1788
- if (existsSync9(targetPath) || isSymlink2(targetPath)) {
1789
- unlinkSync2(targetPath);
2102
+ if (existsSync10(targetPath) || isSymlink2(targetPath)) {
2103
+ unlinkSync3(targetPath);
1790
2104
  results.push({ skillId, success: true });
1791
2105
  removedIds.push(skillId);
1792
2106
  logger.step(` \u79FB\u9664: ${skillId}`);
@@ -1801,7 +2115,7 @@ async function uninstallSkills(skillIds, tool, level) {
1801
2115
  if (removedIds.length > 0) {
1802
2116
  removeSkillsFromRecord(removedIds, tool, level, installPath);
1803
2117
  }
1804
- if (existsSync9(skillsDir)) {
2118
+ if (existsSync10(skillsDir)) {
1805
2119
  try {
1806
2120
  const entries = readdirSync3(skillsDir);
1807
2121
  if (entries.length === 0) {
@@ -1811,16 +2125,6 @@ async function uninstallSkills(skillIds, tool, level) {
1811
2125
  } catch {
1812
2126
  }
1813
2127
  }
1814
- if (existsSync9(configRoot)) {
1815
- try {
1816
- const entries = readdirSync3(configRoot);
1817
- if (entries.length === 0) {
1818
- rmdirSync(configRoot);
1819
- logger.step(` \u6E05\u7406\u7A7A\u76EE\u5F55: ${configRoot.split("/").pop()}/`);
1820
- }
1821
- } catch {
1822
- }
1823
- }
1824
2128
  return results;
1825
2129
  }
1826
2130
  async function interactiveSkillSelect() {
@@ -1832,7 +2136,7 @@ async function interactiveSkillSelect() {
1832
2136
  while (true) {
1833
2137
  switch (step) {
1834
2138
  case 0: {
1835
- printBoxTitle("\u9009\u62E9 Skill \u7C7B\u522B");
2139
+ printBoxTitle(t("wizard_step_3_skill_title"));
1836
2140
  const categoryChoices = [
1837
2141
  ...categories.map((cat) => ({
1838
2142
  name: `> ${cat.name} (${cat.skills.length} skills)`,
@@ -1843,11 +2147,12 @@ async function interactiveSkillSelect() {
1843
2147
  { name: "x " + t("wizard_cancel"), value: CANCEL3 }
1844
2148
  ];
1845
2149
  showOperationHints();
1846
- selectedCategoryId = await select2({
2150
+ selectedCategoryId = await select3({
1847
2151
  message: t("skill_select_category"),
1848
2152
  choices: categoryChoices,
1849
2153
  loop: false,
1850
- theme: selectTheme
2154
+ theme: selectTheme,
2155
+ pageSize: 15
1851
2156
  });
1852
2157
  if (selectedCategoryId === BACK3) return "back";
1853
2158
  if (selectedCategoryId === CANCEL3) return "cancel";
@@ -1857,7 +2162,7 @@ async function interactiveSkillSelect() {
1857
2162
  case 1: {
1858
2163
  const category = categories.find((c) => c.id === selectedCategoryId);
1859
2164
  if (!category) return [];
1860
- printBoxTitle(`\u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills \u2014 ${category.name}`);
2165
+ printBoxTitle(t("wizard_step_4_skill_title").replace("{category}", category.name));
1861
2166
  const tools = ["opencode", "claude", "trae", "cursor", "copilot"];
1862
2167
  const levels = ["project", "global"];
1863
2168
  const installedSkills = [];
@@ -1877,25 +2182,18 @@ async function interactiveSkillSelect() {
1877
2182
  checked: false
1878
2183
  };
1879
2184
  });
1880
- skillChoices.push(new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
1881
- skillChoices.push({ name: "<- " + t("wizard_back"), value: BACK3, checked: false });
1882
- skillChoices.push({ name: "x " + t("wizard_cancel"), value: CANCEL3, checked: false });
1883
2185
  showOperationHints(true);
1884
2186
  const selectedSkills = await checkbox2({
1885
2187
  message: t("skill_select_items"),
1886
2188
  choices: skillChoices,
1887
2189
  loop: false,
1888
2190
  instructions: false,
1889
- theme: checkboxTheme
2191
+ theme: checkboxTheme,
2192
+ pageSize: 15
1890
2193
  });
1891
- if (selectedSkills.includes(BACK3)) {
1892
- step = 0;
1893
- break;
1894
- }
1895
- if (selectedSkills.includes(CANCEL3)) return "cancel";
1896
- const skillIds = selectedSkills.filter((v) => v !== BACK3 && v !== CANCEL3);
2194
+ const skillIds = selectedSkills;
1897
2195
  if (skillIds.length === 0) {
1898
- const action = await select2({
2196
+ const action = await select3({
1899
2197
  message: t("wizard_no_selection"),
1900
2198
  choices: [
1901
2199
  new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
@@ -1919,11 +2217,11 @@ async function interactiveSkillSelect() {
1919
2217
  function listAllSkills() {
1920
2218
  const categories = getAllCategories();
1921
2219
  console.log();
1922
- console.log(chalk3.bold(` ${t("skill_list_title")}`));
1923
- console.log(chalk3.dim(" " + "\u2500".repeat(60)));
2220
+ console.log(chalk4.bold(` ${t("skill_list_title")}`));
2221
+ console.log(chalk4.dim(" " + "\u2500".repeat(60)));
1924
2222
  for (const category of categories) {
1925
2223
  console.log();
1926
- console.log(chalk3.bold(` ${category.name}`) + chalk3.dim(` (${category.skills.length} skills)`));
2224
+ console.log(chalk4.bold(` ${category.name}`) + chalk4.dim(` (${category.skills.length} skills)`));
1927
2225
  const table = new Table({
1928
2226
  style: { head: [], border: [] },
1929
2227
  colWidths: [35, 45],
@@ -1931,14 +2229,14 @@ function listAllSkills() {
1931
2229
  });
1932
2230
  for (const skill of category.skills) {
1933
2231
  table.push([
1934
- chalk3.cyan(skill.id),
2232
+ chalk4.cyan(skill.id),
1935
2233
  skill.description
1936
2234
  ]);
1937
2235
  }
1938
2236
  console.log(table.toString());
1939
2237
  }
1940
2238
  console.log();
1941
- console.log(chalk3.dim(` \u5171 ${getAllSkills().length} \u4E2A Skills`));
2239
+ console.log(chalk4.dim(` \u5171 ${getAllSkills().length} \u4E2A Skills`));
1942
2240
  console.log();
1943
2241
  }
1944
2242
  function isSymlink2(path) {
@@ -1950,22 +2248,22 @@ function isSymlink2(path) {
1950
2248
  }
1951
2249
 
1952
2250
  // src/ui/display.ts
1953
- import chalk4 from "chalk";
2251
+ import chalk5 from "chalk";
1954
2252
  import Table2 from "cli-table3";
1955
2253
  function printPluginList(plugins, installed) {
1956
2254
  const table = new Table2({
1957
2255
  head: [
1958
- chalk4.cyan(t("list_id")),
1959
- chalk4.cyan(t("list_name")),
1960
- chalk4.cyan(t("list_status")),
1961
- chalk4.cyan(t("list_skills")),
1962
- chalk4.cyan(t("list_agents"))
2256
+ chalk5.cyan(t("list_id")),
2257
+ chalk5.cyan(t("list_name")),
2258
+ chalk5.cyan(t("list_status")),
2259
+ chalk5.cyan(t("list_skills")),
2260
+ chalk5.cyan(t("list_agents"))
1963
2261
  ],
1964
2262
  style: { head: [], border: [] }
1965
2263
  });
1966
2264
  plugins.forEach((plugin, index) => {
1967
2265
  const isInstalled = installed.has(plugin.id);
1968
- const status = isInstalled ? chalk4.green(`\u2713 ${t("status_installed")}`) : chalk4.dim(`\u2014`);
2266
+ const status = isInstalled ? chalk5.green(`\u2713 ${t("status_installed")}`) : chalk5.dim(`\u2014`);
1969
2267
  table.push([
1970
2268
  String(index + 1),
1971
2269
  plugin.displayName,
@@ -1975,7 +2273,7 @@ function printPluginList(plugins, installed) {
1975
2273
  ]);
1976
2274
  });
1977
2275
  console.log();
1978
- console.log(chalk4.bold(` ${t("list_title")} (${plugins.length} \u4E2A)`));
2276
+ console.log(chalk5.bold(` ${t("list_title")} (${plugins.length} \u4E2A)`));
1979
2277
  console.log(table.toString());
1980
2278
  console.log();
1981
2279
  }
@@ -1984,7 +2282,7 @@ function printInstallSummary(results) {
1984
2282
  const totalCount = results.length;
1985
2283
  console.log();
1986
2284
  console.log(
1987
- chalk4.bold(
2285
+ chalk5.bold(
1988
2286
  ` ${t("install_done")}! ${successCount}/${totalCount} ${t("install_success")}`
1989
2287
  )
1990
2288
  );
@@ -1992,10 +2290,10 @@ function printInstallSummary(results) {
1992
2290
  for (const result of results) {
1993
2291
  if (result.success) {
1994
2292
  console.log(
1995
- chalk4.green(" \u2713") + ` ${result.displayName} (${result.skillsCount} skills, ${result.agentsCount} agents)`
2293
+ chalk5.green(" \u2713") + ` ${result.displayName} (${result.skillsCount} skills, ${result.agentsCount} agents)`
1996
2294
  );
1997
2295
  } else {
1998
- console.log(chalk4.red(" \u2717") + ` ${result.displayName}`);
2296
+ console.log(chalk5.red(" \u2717") + ` ${result.displayName}`);
1999
2297
  }
2000
2298
  }
2001
2299
  console.log();
@@ -2009,21 +2307,21 @@ function printEnhancedSummary(results, tool, configRoot) {
2009
2307
  }
2010
2308
  const toolName = getToolDisplayName(tool);
2011
2309
  const lines = [
2012
- chalk4.bold(` ${t("install_done")}!`),
2310
+ chalk5.bold(` ${t("install_done")}!`),
2013
2311
  "",
2014
- ` ${chalk4.dim("\u5B89\u88C5\u5230:")} ${configRoot}`,
2015
- ` ${chalk4.dim("Skills:")} ${totalSkills} \u4E2A ${chalk4.dim("|")} ${chalk4.dim("Agents:")} ${totalAgents} \u4E2A`,
2312
+ ` ${chalk5.dim(t("install_installed_to") + ":")} ${configRoot}`,
2313
+ ` ${chalk5.dim(t("install_skills_count") + ":")} ${totalSkills} \u4E2A ${chalk5.dim("|")} ${chalk5.dim(t("install_agents_count") + ":")} ${totalAgents} \u4E2A`,
2016
2314
  "",
2017
- chalk4.bold(` ${t("install_enhanced_next_steps")}:`),
2018
- ` ${chalk4.cyan("1.")} ${t("install_enhanced_launch")}: ${chalk4.green(toolName.toLowerCase())}`,
2019
- ` ${chalk4.cyan("2.")} ${t("install_enhanced_try")}: ${chalk4.green("\u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50")}`,
2020
- ` ${chalk4.cyan("3.")} ${t("install_enhanced_more")}: ${chalk4.green("install-helper list")}`,
2021
- ` ${chalk4.cyan("4.")} ${t("install_enhanced_check")}: ${chalk4.green("install-helper doctor")}`,
2315
+ chalk5.bold(` ${t("install_enhanced_next_steps")}:`),
2316
+ ` ${chalk5.cyan("1.")} ${t("install_enhanced_launch")}: ${chalk5.green(toolName.toLowerCase())}`,
2317
+ ` ${chalk5.cyan("2.")} ${t("install_enhanced_try")}: ${chalk5.green("\u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50")}`,
2318
+ ` ${chalk5.cyan("3.")} ${t("install_enhanced_more")}: ${chalk5.green("install-helper list")}`,
2319
+ ` ${chalk5.cyan("4.")} ${t("install_enhanced_check")}: ${chalk5.green("install-helper doctor")}`,
2022
2320
  ""
2023
2321
  ];
2024
2322
  if (successResults.length === 1) {
2025
2323
  lines.push(
2026
- ` ${chalk4.dim(t("install_enhanced_docs"))}: ${chalk4.dim(`plugins-official/${successResults[0].pluginId}/quickstart.md`)}`
2324
+ ` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(`plugins-official/${successResults[0].pluginId}/quickstart.md`)}`
2027
2325
  );
2028
2326
  }
2029
2327
  console.log();
@@ -2034,33 +2332,34 @@ function printEnhancedSummary(results, tool, configRoot) {
2034
2332
  }
2035
2333
 
2036
2334
  // src/commands/init.ts
2037
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
2038
- import { join as join10 } from "path";
2335
+ import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
2336
+ import { join as join11 } from "path";
2039
2337
  var BACK2 = "__back__";
2338
+ var CANCEL2 = "__cancel__";
2040
2339
  async function initCommand() {
2041
2340
  const cwd = process.cwd();
2042
- if (existsSync10(join10(cwd, "package.json")) && (() => {
2341
+ if (existsSync11(join11(cwd, "package.json")) && (() => {
2043
2342
  try {
2044
- const pkg = JSON.parse(readFileSync5(join10(cwd, "package.json"), "utf-8"));
2343
+ const pkg = JSON.parse(readFileSync5(join11(cwd, "package.json"), "utf-8"));
2045
2344
  return pkg.name === "@cannbot-ai/install-helper";
2046
2345
  } catch {
2047
2346
  return false;
2048
2347
  }
2049
2348
  })()) {
2050
- logger.warn("\u5F53\u524D\u76EE\u5F55\u770B\u8D77\u6765\u662F install-helper \u5305\u76EE\u5F55");
2051
- logger.info("\u8BF7\u5728\u4F60\u7684\u9879\u76EE\u76EE\u5F55\u4E2D\u8FD0\u884C\u6B64\u547D\u4EE4\uFF0C\u800C\u4E0D\u662F\u5728 install-helper \u5B89\u88C5\u76EE\u5F55\u4E2D");
2052
- logger.info("\u793A\u4F8B\uFF1Acd ~/my-project && install-helper");
2349
+ logger.warn(t("init_pkg_dir_warn"));
2350
+ logger.info(t("init_pkg_dir_hint"));
2351
+ logger.info(t("init_pkg_dir_example"));
2053
2352
  return;
2054
2353
  }
2055
2354
  printBanner(t("wizard_title"));
2056
- const spinner = createSpinner("\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...");
2355
+ const spinner = createSpinner(t("loading_skills_list"));
2057
2356
  spinner.start();
2058
2357
  try {
2059
2358
  const repoManager = createRepositoryManager();
2060
2359
  await repoManager.ensureRepoAndScan();
2061
- spinner.succeed("Skills \u5217\u8868\u52A0\u8F7D\u5B8C\u6210");
2360
+ spinner.succeed(t("loading_skills_list_complete"));
2062
2361
  } catch {
2063
- spinner.warn("Skills \u5217\u8868\u52A0\u8F7D\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u5185\u7F6E\u6570\u636E");
2362
+ spinner.warn(t("loading_skills_list_failed"));
2064
2363
  }
2065
2364
  let step = 0;
2066
2365
  let mode = "plugin";
@@ -2094,7 +2393,7 @@ async function initCommand() {
2094
2393
  }
2095
2394
  }
2096
2395
  async function selectMode() {
2097
- printBoxTitle("\u9009\u62E9\u5B89\u88C5\u7C7B\u578B");
2396
+ printBoxTitle(t("wizard_select_mode_title"));
2098
2397
  const CANCEL3 = "__cancel__";
2099
2398
  const choices = [
2100
2399
  {
@@ -2109,7 +2408,7 @@ async function selectMode() {
2109
2408
  { name: "x " + t("wizard_cancel"), value: CANCEL3 }
2110
2409
  ];
2111
2410
  showOperationHints();
2112
- const result = await select3({
2411
+ const result = await select4({
2113
2412
  message: t("wizard_select_mode"),
2114
2413
  choices,
2115
2414
  loop: false,
@@ -2122,14 +2421,14 @@ async function pluginInstallFlow() {
2122
2421
  const answers = await runWizard();
2123
2422
  if (!answers.confirmed) {
2124
2423
  if (answers.back) return "back";
2125
- logger.info("\u5DF2\u53D6\u6D88\u5B89\u88C5");
2424
+ logger.info(t("init_cancelled"));
2126
2425
  return "done";
2127
2426
  }
2128
2427
  const repoManager = createRepositoryManager();
2129
- const spinner = createSpinner(t("install_cloning"));
2428
+ const spinner = createSpinner(t("loading_plugin_data"));
2130
2429
  spinner.start();
2131
2430
  const repoPath = await repoManager.ensureRepo();
2132
- spinner.succeed(t("install_repo_ready"));
2431
+ spinner.succeed(t("loading_plugin_data_complete"));
2133
2432
  const allPlugins = getAllPlugins();
2134
2433
  const selectedPlugins = answers.plugins.map(
2135
2434
  (id) => allPlugins.find((p) => p.id === id)
@@ -2183,7 +2482,7 @@ async function skillInstallFlow() {
2183
2482
  const result = await selectToolWithDetection();
2184
2483
  if (result === "back") return "back";
2185
2484
  if (result === "cancel") {
2186
- logger.info("\u5DF2\u53D6\u6D88\u5B89\u88C5");
2485
+ logger.info(t("init_cancelled"));
2187
2486
  return "done";
2188
2487
  }
2189
2488
  tool = result;
@@ -2196,8 +2495,8 @@ async function skillInstallFlow() {
2196
2495
  step = 0;
2197
2496
  break;
2198
2497
  }
2199
- if (result === CANCEL) {
2200
- logger.info("\u5DF2\u53D6\u6D88\u5B89\u88C5");
2498
+ if (result === CANCEL2) {
2499
+ logger.info(t("init_cancelled"));
2201
2500
  return "done";
2202
2501
  }
2203
2502
  level = result;
@@ -2211,37 +2510,40 @@ async function skillInstallFlow() {
2211
2510
  break;
2212
2511
  }
2213
2512
  if (selectedSkills === "cancel") {
2214
- logger.info("\u5DF2\u53D6\u6D88\u5B89\u88C5");
2513
+ logger.info(t("init_cancelled"));
2215
2514
  return "done";
2216
2515
  }
2217
2516
  if (selectedSkills.length === 0) {
2218
- logger.info("\u672A\u9009\u62E9\u4EFB\u4F55 Skill");
2517
+ logger.info(t("install_no_skill_selected"));
2219
2518
  return "done";
2220
2519
  }
2221
2520
  const repoManager = createRepositoryManager();
2222
- const spinner = createSpinner(t("install_cloning"));
2521
+ const spinner = createSpinner(t("loading_plugin_data"));
2223
2522
  spinner.start();
2224
2523
  const repoPath = await repoManager.ensureRepo();
2225
- spinner.succeed(t("install_repo_ready"));
2226
- logger.info(`${t("skill_install_progress")} ${chalk5.bold(selectedSkills.length)} \u4E2A Skills...`);
2524
+ spinner.succeed(t("loading_plugin_data_complete"));
2525
+ logger.info(`${t("skill_install_progress")} ${chalk6.bold(selectedSkills.length)} \u4E2A Skills...`);
2227
2526
  const results = await installSkills(selectedSkills, tool, level, repoPath);
2228
2527
  let successCount = 0;
2229
2528
  let failCount = 0;
2230
- for (const result of results) {
2529
+ const total = results.length;
2530
+ for (let i = 0; i < results.length; i++) {
2531
+ const result = results[i];
2532
+ const progress = `[${i + 1}/${total}]`;
2231
2533
  if (result.success) {
2232
- logger.success(`${result.skillId}`);
2534
+ logger.success(`${progress} ${result.skillId}`);
2233
2535
  successCount++;
2234
2536
  } else {
2235
- logger.error(`${result.skillId}: ${result.error}`);
2537
+ logger.error(`${progress} ${result.skillId}: ${result.error}`);
2236
2538
  failCount++;
2237
2539
  }
2238
2540
  }
2239
2541
  const configRoot = getConfigRoot(tool, level);
2240
2542
  logger.blank();
2241
- logger.success(`${t("skill_install_done")}: ${chalk5.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk5.red(failCount + " \u5931\u8D25") : chalk5.dim(failCount + " \u5931\u8D25")}`);
2543
+ logger.success(`${t("skill_install_done")}: ${chalk6.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk6.red(failCount + " \u5931\u8D25") : chalk6.dim(failCount + " \u5931\u8D25")}`);
2242
2544
  logger.blank();
2243
- logger.info(`\u5B89\u88C5\u5230: ${chalk5.cyan(configRoot + "/skills/")}`);
2244
- logger.info(`\u542F\u52A8 ${chalk5.green(tool)} \u5373\u53EF\u4F7F\u7528`);
2545
+ logger.info(`${t("install_to")}: ${chalk6.cyan(configRoot + "/skills/")}`);
2546
+ logger.info(`${t("start_to_use").replace("{tool}", chalk6.green(tool))}`);
2245
2547
  logger.blank();
2246
2548
  return "done";
2247
2549
  }
@@ -2263,32 +2565,32 @@ async function listCommand() {
2263
2565
  }
2264
2566
 
2265
2567
  // src/commands/doctor.ts
2266
- import chalk6 from "chalk";
2267
- import { existsSync as existsSync11, readdirSync as readdirSync4, lstatSync as lstatSync3, unlinkSync as unlinkSync3, mkdirSync as mkdirSync6 } from "fs";
2268
- import { join as join11 } from "path";
2568
+ import chalk7 from "chalk";
2569
+ import { existsSync as existsSync12, readdirSync as readdirSync4, lstatSync as lstatSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
2570
+ import { join as join12 } from "path";
2269
2571
  async function doctorCommand(options = {}) {
2270
2572
  console.log();
2271
- console.log(chalk6.bold(` ${t("doctor_title")}`));
2272
- console.log(chalk6.dim(" " + "\u2500".repeat(46)));
2573
+ console.log(chalk7.bold(` ${t("doctor_title")}`));
2574
+ console.log(chalk7.dim(" " + "\u2500".repeat(46)));
2273
2575
  let errors = 0;
2274
2576
  let warnings = 0;
2275
2577
  let fixes = 0;
2276
2578
  console.log();
2277
- console.log(chalk6.bold(` ${t("doctor_tools")}`));
2579
+ console.log(chalk7.bold(` ${t("doctor_tools")}`));
2278
2580
  const detectedTools = await detectTools();
2279
2581
  const allTools = getAllTools();
2280
2582
  for (const tool of allTools) {
2281
2583
  const detected = detectedTools.find((d) => d.name === tool);
2282
2584
  if (detected) {
2283
2585
  console.log(
2284
- chalk6.green(" \u2713") + ` ${getToolDisplayName(tool)}${detected.version ? ` v${detected.version}` : ""}`
2586
+ chalk7.green(" \u2713") + ` ${getToolDisplayName(tool)}${detected.version ? ` v${detected.version}` : ""}`
2285
2587
  );
2286
2588
  } else {
2287
- console.log(chalk6.dim(" \u2014") + ` ${getToolDisplayName(tool)} \u2014 \u672A\u5B89\u88C5`);
2589
+ console.log(chalk7.dim(" \u2014") + ` ${getToolDisplayName(tool)} \u2014 \u672A\u5B89\u88C5`);
2288
2590
  }
2289
2591
  }
2290
2592
  console.log();
2291
- console.log(chalk6.bold(` ${t("doctor_plugins")}`));
2593
+ console.log(chalk7.bold(` ${t("doctor_plugins")}`));
2292
2594
  const plugins = getAllPlugins();
2293
2595
  const installed = scanInstalled();
2294
2596
  const installedMap = new Map(installed.map((p) => [p.id, p]));
@@ -2296,73 +2598,73 @@ async function doctorCommand(options = {}) {
2296
2598
  const inst = installedMap.get(plugin.id);
2297
2599
  if (inst) {
2298
2600
  console.log(
2299
- chalk6.green(" \u2713") + ` ${plugin.id.padEnd(30)} ${inst.skillsCount} skills, ${inst.agentsCount} agents`
2601
+ chalk7.green(" \u2713") + ` ${plugin.id.padEnd(30)} ${inst.skillsCount} skills, ${inst.agentsCount} agents`
2300
2602
  );
2301
2603
  } else {
2302
- console.log(chalk6.dim(" \u2014") + ` ${plugin.id.padEnd(30)} \u2014 \u672A\u5B89\u88C5`);
2604
+ console.log(chalk7.dim(" \u2014") + ` ${plugin.id.padEnd(30)} \u2014 \u672A\u5B89\u88C5`);
2303
2605
  }
2304
2606
  }
2305
2607
  console.log();
2306
- console.log(chalk6.bold(` ${t("doctor_links")}`));
2608
+ console.log(chalk7.bold(` ${t("doctor_links")}`));
2307
2609
  const primaryTool = detectedTools[0]?.name || "opencode";
2308
2610
  const configRoot = getConfigRoot(primaryTool, "project");
2309
2611
  const skillsDir = getSkillsDir(configRoot);
2310
2612
  const agentsDir = getAgentsDir(configRoot);
2311
- if (existsSync11(skillsDir)) {
2613
+ if (existsSync12(skillsDir)) {
2312
2614
  const brokenLinks = checkBrokenLinks(skillsDir);
2313
2615
  if (brokenLinks === 0) {
2314
2616
  const count = readdirSync4(skillsDir).length;
2315
- console.log(chalk6.green(" \u2713") + ` ${skillsDir} \u2014 ${count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548`);
2617
+ console.log(chalk7.green(" \u2713") + ` ${skillsDir} \u2014 ${count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548`);
2316
2618
  } else {
2317
- console.log(chalk6.yellow(" \u26A0") + ` ${skillsDir} \u2014 ${brokenLinks} \u4E2A\u5931\u6548\u94FE\u63A5`);
2619
+ console.log(chalk7.yellow(" \u26A0") + ` ${skillsDir} \u2014 ${brokenLinks} \u4E2A\u5931\u6548\u94FE\u63A5`);
2318
2620
  warnings++;
2319
2621
  if (options.fix) {
2320
2622
  const fixed = fixBrokenLinks(skillsDir);
2321
2623
  fixes += fixed;
2322
- console.log(chalk6.green(" \u2713") + ` ${t("doctor_fix_cleaning")}: \u5DF2\u6E05\u7406 ${fixed} \u4E2A\u5931\u6548\u94FE\u63A5`);
2624
+ console.log(chalk7.green(" \u2713") + ` ${t("doctor_fix_cleaning")}: \u5DF2\u6E05\u7406 ${fixed} \u4E2A\u5931\u6548\u94FE\u63A5`);
2323
2625
  }
2324
2626
  }
2325
2627
  } else {
2326
- console.log(chalk6.dim(" \u2014") + ` ${skillsDir} \u2014 \u4E0D\u5B58\u5728`);
2628
+ console.log(chalk7.dim(" \u2014") + ` ${skillsDir} \u2014 \u4E0D\u5B58\u5728`);
2327
2629
  if (options.fix) {
2328
2630
  mkdirSync6(skillsDir, { recursive: true });
2329
2631
  fixes++;
2330
- console.log(chalk6.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: \u5DF2\u521B\u5EFA ${skillsDir}`);
2632
+ console.log(chalk7.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: \u5DF2\u521B\u5EFA ${skillsDir}`);
2331
2633
  }
2332
2634
  }
2333
- if (existsSync11(agentsDir)) {
2635
+ if (existsSync12(agentsDir)) {
2334
2636
  const brokenLinks = checkBrokenLinks(agentsDir);
2335
2637
  if (brokenLinks === 0) {
2336
2638
  const count = readdirSync4(agentsDir).length;
2337
- console.log(chalk6.green(" \u2713") + ` ${agentsDir} \u2014 ${count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548`);
2639
+ console.log(chalk7.green(" \u2713") + ` ${agentsDir} \u2014 ${count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548`);
2338
2640
  } else {
2339
- console.log(chalk6.yellow(" \u26A0") + ` ${agentsDir} \u2014 ${brokenLinks} \u4E2A\u5931\u6548\u94FE\u63A5`);
2641
+ console.log(chalk7.yellow(" \u26A0") + ` ${agentsDir} \u2014 ${brokenLinks} \u4E2A\u5931\u6548\u94FE\u63A5`);
2340
2642
  warnings++;
2341
2643
  if (options.fix) {
2342
2644
  const fixed = fixBrokenLinks(agentsDir);
2343
2645
  fixes += fixed;
2344
- console.log(chalk6.green(" \u2713") + ` ${t("doctor_fix_cleaning")}: \u5DF2\u6E05\u7406 ${fixed} \u4E2A\u5931\u6548\u94FE\u63A5`);
2646
+ console.log(chalk7.green(" \u2713") + ` ${t("doctor_fix_cleaning")}: \u5DF2\u6E05\u7406 ${fixed} \u4E2A\u5931\u6548\u94FE\u63A5`);
2345
2647
  }
2346
2648
  }
2347
2649
  } else {
2348
- console.log(chalk6.dim(" \u2014") + ` ${agentsDir} \u2014 \u4E0D\u5B58\u5728`);
2650
+ console.log(chalk7.dim(" \u2014") + ` ${agentsDir} \u2014 \u4E0D\u5B58\u5728`);
2349
2651
  if (options.fix) {
2350
2652
  mkdirSync6(agentsDir, { recursive: true });
2351
2653
  fixes++;
2352
- console.log(chalk6.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: \u5DF2\u521B\u5EFA ${agentsDir}`);
2654
+ console.log(chalk7.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: \u5DF2\u521B\u5EFA ${agentsDir}`);
2353
2655
  }
2354
2656
  }
2355
2657
  console.log();
2356
- console.log(chalk6.bold(` ${t("doctor_config")}`));
2658
+ console.log(chalk7.bold(` ${t("doctor_config")}`));
2357
2659
  const configFile = getConfigFileName(primaryTool);
2358
- const configPath = join11(process.cwd(), configFile);
2359
- if (existsSync11(configPath)) {
2360
- console.log(chalk6.green(" \u2713") + ` ${configFile} \u5B58\u5728`);
2660
+ const configPath = join12(process.cwd(), configFile);
2661
+ if (existsSync12(configPath)) {
2662
+ console.log(chalk7.green(" \u2713") + ` ${configFile} \u5B58\u5728`);
2361
2663
  } else {
2362
- console.log(chalk6.dim(" \u2014") + ` ${configFile} \u4E0D\u5B58\u5728`);
2664
+ console.log(chalk7.dim(" \u2014") + ` ${configFile} \u4E0D\u5B58\u5728`);
2363
2665
  }
2364
2666
  console.log();
2365
- console.log(chalk6.dim(" " + "\u2500".repeat(46)));
2667
+ console.log(chalk7.dim(" " + "\u2500".repeat(46)));
2366
2668
  if (options.fix && fixes > 0) {
2367
2669
  console.log(
2368
2670
  ` ${t("doctor_result")}: ${warnings} \u4E2A\u8B66\u544A, ${errors} \u4E2A\u9519\u8BEF, ${fixes} \u9879\u5DF2\u4FEE\u590D`
@@ -2379,11 +2681,11 @@ function checkBrokenLinks(dir) {
2379
2681
  try {
2380
2682
  const entries = readdirSync4(dir);
2381
2683
  for (const entry of entries) {
2382
- const fullPath = join11(dir, entry);
2684
+ const fullPath = join12(dir, entry);
2383
2685
  try {
2384
2686
  const stats = lstatSync3(fullPath);
2385
2687
  if (stats.isSymbolicLink()) {
2386
- if (!existsSync11(fullPath)) {
2688
+ if (!existsSync12(fullPath)) {
2387
2689
  broken++;
2388
2690
  }
2389
2691
  }
@@ -2400,12 +2702,12 @@ function fixBrokenLinks(dir) {
2400
2702
  try {
2401
2703
  const entries = readdirSync4(dir);
2402
2704
  for (const entry of entries) {
2403
- const fullPath = join11(dir, entry);
2705
+ const fullPath = join12(dir, entry);
2404
2706
  try {
2405
2707
  const stats = lstatSync3(fullPath);
2406
2708
  if (stats.isSymbolicLink()) {
2407
- if (!existsSync11(fullPath)) {
2408
- unlinkSync3(fullPath);
2709
+ if (!existsSync12(fullPath)) {
2710
+ unlinkSync4(fullPath);
2409
2711
  fixed++;
2410
2712
  }
2411
2713
  }
@@ -2418,36 +2720,36 @@ function fixBrokenLinks(dir) {
2418
2720
  }
2419
2721
 
2420
2722
  // src/commands/status.ts
2421
- import chalk7 from "chalk";
2723
+ import chalk8 from "chalk";
2422
2724
  async function statusCommand() {
2423
2725
  const plugins = getAllPlugins();
2424
2726
  const installed = scanInstalled();
2425
2727
  const installedMap = new Map(installed.map((p) => [p.id, p]));
2426
2728
  console.log();
2427
- console.log(chalk7.bold(` ${t("status_title")}`));
2729
+ console.log(chalk8.bold(` ${t("status_title")}`));
2428
2730
  console.log();
2429
2731
  if (installed.length === 0) {
2430
- console.log(chalk7.dim(` ${t("status_none")}`));
2431
- console.log(chalk7.dim(` ${t("status_hint")}`));
2732
+ console.log(chalk8.dim(` ${t("status_none")}`));
2733
+ console.log(chalk8.dim(` ${t("status_hint")}`));
2432
2734
  console.log();
2433
2735
  return;
2434
2736
  }
2435
2737
  for (const inst of installed) {
2436
2738
  console.log(
2437
- chalk7.green(" \u2713") + ` ${inst.displayName}` + chalk7.dim(` (${inst.tool}, ${inst.level})`)
2739
+ chalk8.green(" \u2713") + ` ${inst.displayName}` + chalk8.dim(` (${inst.tool}, ${inst.level})`)
2438
2740
  );
2439
2741
  console.log(
2440
- chalk7.dim(` ${inst.skillsCount} skills, ${inst.agentsCount} agents`)
2742
+ chalk8.dim(` ${inst.skillsCount} skills, ${inst.agentsCount} agents`)
2441
2743
  );
2442
- console.log(chalk7.dim(` ${inst.configRoot}`));
2443
- console.log(chalk7.dim(` ${t("status_install_time")}: ${inst.installTime}`));
2744
+ console.log(chalk8.dim(` ${inst.configRoot}`));
2745
+ console.log(chalk8.dim(` ${t("status_install_time")}: ${inst.installTime}`));
2444
2746
  console.log();
2445
2747
  }
2446
2748
  }
2447
2749
 
2448
2750
  // src/commands/install.ts
2449
2751
  import { confirm } from "@inquirer/prompts";
2450
- import chalk8 from "chalk";
2752
+ import chalk9 from "chalk";
2451
2753
  async function installCommand(names, options) {
2452
2754
  if (options.list) {
2453
2755
  try {
@@ -2459,7 +2761,7 @@ async function installCommand(names, options) {
2459
2761
  return;
2460
2762
  }
2461
2763
  if (names.length === 0) {
2462
- const scanSpinner2 = createSpinner("\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...");
2764
+ const scanSpinner2 = createSpinner(t("loading_skills_list"));
2463
2765
  scanSpinner2.start();
2464
2766
  try {
2465
2767
  const scanRepoManager = createRepositoryManager();
@@ -2488,42 +2790,45 @@ async function installCommand(names, options) {
2488
2790
  break;
2489
2791
  }
2490
2792
  if (selectedSkills.length === 0) {
2491
- logger.info("\u672A\u9009\u62E9\u4EFB\u4F55 Skill");
2793
+ logger.info(t("install_no_skill_selected"));
2492
2794
  return;
2493
2795
  }
2494
2796
  names = selectedSkills;
2495
2797
  const repoManager = createRepositoryManager();
2496
- const spinner = createSpinner(t("install_cloning"));
2798
+ const spinner = createSpinner(t("loading_plugin_data"));
2497
2799
  spinner.start();
2498
2800
  const repoPath = await repoManager.ensureRepo();
2499
- spinner.succeed(t("install_repo_ready"));
2500
- logger.info(`${t("skill_install_progress")} ${chalk8.bold(names.length)} \u4E2A Skills...`);
2801
+ spinner.succeed("\u63D2\u4EF6\u6570\u636E\u52A0\u8F7D\u5B8C\u6210");
2802
+ logger.info(`${t("skill_install_progress")} ${chalk9.bold(names.length)} \u4E2A Skills...`);
2501
2803
  const level2 = options.level || "project";
2502
2804
  const results = await installSkills(names, tool2, level2, repoPath);
2503
2805
  let successCount = 0;
2504
2806
  let failCount = 0;
2505
- for (const result of results) {
2807
+ const total = results.length;
2808
+ for (let i = 0; i < results.length; i++) {
2809
+ const result = results[i];
2810
+ const progress = `[${i + 1}/${total}]`;
2506
2811
  if (result.success) {
2507
- logger.success(`${result.skillId}`);
2812
+ logger.success(`${progress} ${result.skillId}`);
2508
2813
  successCount++;
2509
2814
  } else {
2510
- logger.error(`${result.skillId}: ${result.error}`);
2815
+ logger.error(`${progress} ${result.skillId}: ${result.error}`);
2511
2816
  failCount++;
2512
2817
  }
2513
2818
  }
2514
2819
  const configRoot = getConfigRoot(tool2, level2);
2515
2820
  logger.blank();
2516
- logger.success(`${t("skill_install_done")}: ${chalk8.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk8.red(failCount + " \u5931\u8D25") : chalk8.dim(failCount + " \u5931\u8D25")}`);
2821
+ logger.success(`${t("skill_install_done")}: ${chalk9.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk9.red(failCount + " \u5931\u8D25") : chalk9.dim(failCount + " \u5931\u8D25")}`);
2517
2822
  logger.blank();
2518
- logger.info(`\u5B89\u88C5\u5230: ${chalk8.cyan(configRoot + "/skills/")}`);
2519
- logger.info(`\u542F\u52A8 ${chalk8.green(tool2)} \u5373\u53EF\u4F7F\u7528`);
2823
+ logger.info(`${t("install_to")}: ${chalk9.cyan(configRoot + "/skills/")}`);
2824
+ logger.info(`${t("start_to_use").replace("{tool}", chalk9.green(tool2))}`);
2520
2825
  logger.blank();
2521
2826
  return;
2522
2827
  }
2523
2828
  }
2524
2829
  }
2525
2830
  }
2526
- const scanSpinner = createSpinner("\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...");
2831
+ const scanSpinner = createSpinner(t("loading_skills_list"));
2527
2832
  scanSpinner.start();
2528
2833
  try {
2529
2834
  const scanRepoManager = createRepositoryManager();
@@ -2551,7 +2856,7 @@ async function installCommand(names, options) {
2551
2856
  for (const p of allPlugins) {
2552
2857
  logger.step(` ${p.id} (${p.aliases.join(", ")})`);
2553
2858
  }
2554
- logger.info(`\u53EF\u7528 Skills: ${chalk8.cyan("install-helper install --list")}`);
2859
+ logger.info(`\u53EF\u7528 Skills: ${chalk9.cyan("install-helper install --list")}`);
2555
2860
  return;
2556
2861
  }
2557
2862
  let tool;
@@ -2590,16 +2895,18 @@ async function installCommand(names, options) {
2590
2895
  }
2591
2896
  if (pluginsToInstall.length > 0) {
2592
2897
  const repoManager = createRepositoryManager();
2593
- const spinner = createSpinner(t("install_cloning"));
2898
+ const spinner = createSpinner(t("loading_plugin_data"));
2594
2899
  spinner.start();
2595
2900
  const repoPath = await repoManager.ensureRepo();
2596
- spinner.succeed(t("install_repo_ready"));
2901
+ spinner.succeed(t("loading_plugin_data_complete"));
2597
2902
  const allPlugins = getAllPlugins();
2598
2903
  const results = await installPlugins(
2599
2904
  pluginsToInstall,
2600
2905
  tool,
2601
2906
  level,
2602
- repoPath
2907
+ repoPath,
2908
+ void 0,
2909
+ options.yes
2603
2910
  );
2604
2911
  const summary = results.map((result) => {
2605
2912
  const plugin = allPlugins.find((p) => p.id === result.pluginId);
@@ -2617,28 +2924,31 @@ async function installCommand(names, options) {
2617
2924
  }
2618
2925
  if (skills.length > 0) {
2619
2926
  const repoManager = createRepositoryManager();
2620
- const spinner = createSpinner(t("install_cloning"));
2927
+ const spinner = createSpinner(t("loading_plugin_data"));
2621
2928
  spinner.start();
2622
2929
  const repoPath = await repoManager.ensureRepo();
2623
- spinner.succeed(t("install_repo_ready"));
2624
- logger.info(`${t("skill_install_progress")} ${chalk8.bold(skills.length)} \u4E2A Skills...`);
2930
+ spinner.succeed(t("loading_plugin_data_complete"));
2931
+ logger.info(`${t("skill_install_progress")} ${chalk9.bold(skills.length)} \u4E2A Skills...`);
2625
2932
  const results = await installSkills(skills, tool, level, repoPath);
2626
2933
  let successCount = 0;
2627
2934
  let failCount = 0;
2628
- for (const result of results) {
2935
+ const total = results.length;
2936
+ for (let i = 0; i < results.length; i++) {
2937
+ const result = results[i];
2938
+ const progress = `[${i + 1}/${total}]`;
2629
2939
  if (result.success) {
2630
- logger.success(`${result.skillId}`);
2940
+ logger.success(`${progress} ${result.skillId}`);
2631
2941
  successCount++;
2632
2942
  } else {
2633
- logger.error(`${result.skillId}: ${result.error}`);
2943
+ logger.error(`${progress} ${result.skillId}: ${result.error}`);
2634
2944
  failCount++;
2635
2945
  }
2636
2946
  }
2637
2947
  logger.blank();
2638
- logger.success(`${t("skill_install_done")}: ${chalk8.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk8.red(failCount + " \u5931\u8D25") : chalk8.dim(failCount + " \u5931\u8D25")}`);
2948
+ logger.success(`${t("skill_install_done")}: ${chalk9.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk9.red(failCount + " \u5931\u8D25") : chalk9.dim(failCount + " \u5931\u8D25")}`);
2639
2949
  logger.blank();
2640
- logger.info(`\u5B89\u88C5\u5230: ${chalk8.cyan(getConfigRoot(tool, level) + "/skills/")}`);
2641
- logger.info(`\u542F\u52A8 ${chalk8.green(tool)} \u5373\u53EF\u4F7F\u7528`);
2950
+ logger.info(`${t("install_to")}: ${chalk9.cyan(getConfigRoot(tool, level) + "/skills/")}`);
2951
+ logger.info(`${t("start_to_use").replace("{tool}", chalk9.green(tool))}`);
2642
2952
  logger.blank();
2643
2953
  }
2644
2954
  }
@@ -2670,8 +2980,8 @@ async function installPlugins(pluginIds, tool, level, repoPath) {
2670
2980
  }
2671
2981
 
2672
2982
  // src/commands/uninstall.ts
2673
- import { existsSync as existsSync12, unlinkSync as unlinkSync4, rmdirSync as rmdirSync2, readdirSync as readdirSync5, lstatSync as lstatSync4 } from "fs";
2674
- import chalk9 from "chalk";
2983
+ import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync5, lstatSync as lstatSync4 } from "fs";
2984
+ import chalk10 from "chalk";
2675
2985
  async function uninstallCommand(names, options) {
2676
2986
  const tool = options.tool || "opencode";
2677
2987
  const level = options.level || "project";
@@ -2688,24 +2998,24 @@ async function uninstallCommand(names, options) {
2688
2998
  skills.push(skill.id);
2689
2999
  continue;
2690
3000
  }
2691
- logger.error(`\u672A\u627E\u5230: ${name}`);
3001
+ logger.error(`${t("uninstall_not_found")}: ${name}`);
2692
3002
  }
2693
3003
  for (const pluginId of plugins) {
2694
3004
  const plugin = findPlugin(pluginId);
2695
3005
  if (!plugin) continue;
2696
3006
  const record = readRecord(plugin.id);
2697
3007
  if (!record) {
2698
- logger.warn(`${plugin.displayName} \u672A\u627E\u5230\u5B89\u88C5\u8BB0\u5F55\uFF0C\u53EF\u80FD\u672A\u5B89\u88C5\u6216\u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F`);
2699
- logger.info(`\u5982\u9700\u5F3A\u5236\u6E05\u7406\uFF0C\u8BF7\u624B\u52A8\u5220\u9664 .opencode/ \u6216 .claude/ \u76EE\u5F55\u4E2D\u7684\u76F8\u5173\u6587\u4EF6`);
3008
+ logger.warn(`${plugin.displayName} ${t("uninstall_no_record")}`);
3009
+ logger.info(`${t("uninstall_no_record_hint")}`);
2700
3010
  continue;
2701
3011
  }
2702
- logger.info(`\u6B63\u5728\u5378\u8F7D ${plugin.displayName}...`);
3012
+ logger.info(`${t("uninstall_in_progress")} ${plugin.displayName}...`);
2703
3013
  let removedFiles = 0;
2704
3014
  let removedDirs = 0;
2705
3015
  for (const filePath of record.files) {
2706
3016
  try {
2707
- if (existsSync12(filePath) || isSymlink3(filePath)) {
2708
- unlinkSync4(filePath);
3017
+ if (existsSync13(filePath) || isSymlink3(filePath)) {
3018
+ unlinkSync5(filePath);
2709
3019
  const name = filePath.split("/").pop() || filePath;
2710
3020
  logger.step(` \u79FB\u9664: ${name}`);
2711
3021
  removedFiles++;
@@ -2713,10 +3023,14 @@ async function uninstallCommand(names, options) {
2713
3023
  } catch {
2714
3024
  }
2715
3025
  }
3026
+ const configRoot = getConfigRoot(record.tool, record.level);
2716
3027
  const sortedDirs = [...record.directories].sort((a, b) => b.length - a.length);
2717
3028
  for (const dirPath of sortedDirs) {
2718
3029
  try {
2719
- if (existsSync12(dirPath)) {
3030
+ if (dirPath === configRoot) {
3031
+ continue;
3032
+ }
3033
+ if (existsSync13(dirPath)) {
2720
3034
  const entries = readdirSync5(dirPath);
2721
3035
  if (entries.length === 0) {
2722
3036
  rmdirSync2(dirPath);
@@ -2730,15 +3044,32 @@ async function uninstallCommand(names, options) {
2730
3044
  }
2731
3045
  deleteRecord(plugin.id);
2732
3046
  removeInstalledPlugin(plugin.id);
3047
+ const backups = findBackups(configRoot);
3048
+ const otherBackups = backups.filter((b) => b.pluginId !== pluginId);
3049
+ if (otherBackups.length > 0) {
3050
+ const choice = await showRestorePrompt(otherBackups);
3051
+ if (choice !== "none") {
3052
+ const restored = restoreBackup(choice, configRoot, record.tool);
3053
+ if (restored) {
3054
+ const backupInfo = otherBackups.find((b) => b.filePath === choice);
3055
+ logger.success(`${t("backup_restore_success")}: ${backupInfo?.pluginName || ""}`);
3056
+ deleteBackup(choice);
3057
+ }
3058
+ }
3059
+ }
3060
+ const currentBackups = backups.filter((b) => b.pluginId === pluginId);
3061
+ for (const backup of currentBackups) {
3062
+ deleteBackup(backup.filePath);
3063
+ }
2733
3064
  const totalRemoved = removedFiles + removedDirs;
2734
3065
  if (totalRemoved > 0) {
2735
- logger.success(`\u5DF2\u5378\u8F7D ${plugin.displayName}\uFF08\u79FB\u9664 ${removedFiles} \u4E2A\u6587\u4EF6\uFF0C${removedDirs} \u4E2A\u76EE\u5F55\uFF09`);
3066
+ logger.success(`${t("uninstall_removed")} ${plugin.displayName}\uFF08\u79FB\u9664 ${removedFiles} \u4E2A\u6587\u4EF6\uFF0C${removedDirs} \u4E2A\u76EE\u5F55\uFF09`);
2736
3067
  } else {
2737
- logger.warn(`${plugin.displayName} \u7684\u6587\u4EF6\u5DF2\u4E0D\u5B58\u5728\uFF0C\u5DF2\u6E05\u7406\u5B89\u88C5\u8BB0\u5F55`);
3068
+ logger.warn(`${plugin.displayName}${t("uninstall_files_gone")}`);
2738
3069
  }
2739
3070
  }
2740
3071
  if (skills.length > 0) {
2741
- logger.info(`\u6B63\u5728\u5378\u8F7D ${skills.length} \u4E2A Skills...`);
3072
+ logger.info(`${t("uninstall_skills_in_progress")} ${skills.length} \u4E2A Skills...`);
2742
3073
  const results = await uninstallSkills(skills, tool, level);
2743
3074
  let successCount = 0;
2744
3075
  let failCount = 0;
@@ -2750,7 +3081,7 @@ async function uninstallCommand(names, options) {
2750
3081
  }
2751
3082
  }
2752
3083
  logger.blank();
2753
- logger.success(`${t("skill_uninstall_done")}: ${chalk9.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk9.red(failCount + " \u5931\u8D25") : chalk9.dim(failCount + " \u5931\u8D25")}`);
3084
+ logger.success(`${t("skill_uninstall_done")}: ${chalk10.green(successCount + " \u6210\u529F")}, ${failCount > 0 ? chalk10.red(failCount + " \u5931\u8D25") : chalk10.dim(failCount + " \u5931\u8D25")}`);
2754
3085
  logger.blank();
2755
3086
  }
2756
3087
  }
@@ -2763,7 +3094,7 @@ function isSymlink3(path) {
2763
3094
  }
2764
3095
 
2765
3096
  // src/commands/update.ts
2766
- import chalk10 from "chalk";
3097
+ import chalk11 from "chalk";
2767
3098
  async function updateCommand(pluginNames, options) {
2768
3099
  let tool;
2769
3100
  if (options.tool) {
@@ -2781,7 +3112,7 @@ async function updateCommand(pluginNames, options) {
2781
3112
  pluginsToUpdate = manifests.map((m) => m.team);
2782
3113
  if (pluginsToUpdate.length === 0) {
2783
3114
  logger.info(t("update_no_plugins"));
2784
- logger.info(`\u4F7F\u7528 ${chalk10.cyan("install-helper install <plugin>")} \u5B89\u88C5\u63D2\u4EF6`);
3115
+ logger.info(`\u4F7F\u7528 ${chalk11.cyan("install-helper install <plugin>")} \u5B89\u88C5\u63D2\u4EF6`);
2785
3116
  return;
2786
3117
  }
2787
3118
  } else {
@@ -2843,42 +3174,42 @@ async function updateCommand(pluginNames, options) {
2843
3174
  }
2844
3175
 
2845
3176
  // src/commands/info.ts
2846
- import chalk11 from "chalk";
2847
- import { existsSync as existsSync13, readdirSync as readdirSync6 } from "fs";
2848
- import { join as join12 } from "path";
3177
+ import chalk12 from "chalk";
3178
+ import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
3179
+ import { join as join13 } from "path";
2849
3180
  async function infoCommand(pluginName) {
2850
3181
  const plugin = findPlugin(pluginName);
2851
3182
  if (!plugin) {
2852
- console.log(chalk11.red(` ${t("info_not_found")}: ${pluginName}`));
3183
+ console.log(chalk12.red(` ${t("info_not_found")}: ${pluginName}`));
2853
3184
  return;
2854
3185
  }
2855
3186
  const installed = scanInstalled();
2856
3187
  const isInstalled = installed.some((p) => p.id === plugin.id);
2857
- const statusText = isInstalled ? chalk11.green(`\u2713 ${t("status_installed")}`) : chalk11.dim(`\u2014 ${t("status_not_installed")}`);
3188
+ const statusText = isInstalled ? chalk12.green(`\u2713 ${t("status_installed")}`) : chalk12.dim(`\u2014 ${t("status_not_installed")}`);
2858
3189
  console.log();
2859
- console.log(chalk11.bold(` ${plugin.displayName}`));
2860
- console.log(chalk11.dim(" " + "\u2500".repeat(40)));
3190
+ console.log(chalk12.bold(` ${plugin.displayName}`));
3191
+ console.log(chalk12.dim(" " + "\u2500".repeat(40)));
2861
3192
  console.log();
2862
- console.log(` ${chalk11.dim(t("info_description") + ":")} ${plugin.description}`);
2863
- console.log(` ${chalk11.dim("ID:")} ${plugin.id}`);
2864
- console.log(` ${chalk11.dim(t("info_status") + ":")} ${statusText}`);
2865
- console.log(` ${chalk11.dim(t("info_skills") + ":")} ${plugin.skills}`);
2866
- console.log(` ${chalk11.dim(t("info_agents") + ":")} ${plugin.agents}`);
2867
- console.log(` ${chalk11.dim("\u522B\u540D:")} ${plugin.aliases.join(", ")}`);
3193
+ console.log(` ${chalk12.dim(t("info_description") + ":")} ${plugin.description}`);
3194
+ console.log(` ${chalk12.dim("ID:")} ${plugin.id}`);
3195
+ console.log(` ${chalk12.dim(t("info_status") + ":")} ${statusText}`);
3196
+ console.log(` ${chalk12.dim(t("info_skills") + ":")} ${plugin.skills}`);
3197
+ console.log(` ${chalk12.dim(t("info_agents") + ":")} ${plugin.agents}`);
3198
+ console.log(` ${chalk12.dim(t("info_aliases") + ":")} ${plugin.aliases.join(", ")}`);
2868
3199
  console.log();
2869
3200
  try {
2870
3201
  const repoManager = createRepositoryManager();
2871
3202
  const repoPath = await repoManager.ensureRepo();
2872
- const quickstartPath = join12(repoPath, plugin.dir, "quickstart.md");
2873
- if (existsSync13(quickstartPath)) {
2874
- console.log(` ${chalk11.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
3203
+ const quickstartPath = join13(repoPath, plugin.dir, "quickstart.md");
3204
+ if (existsSync14(quickstartPath)) {
3205
+ console.log(` ${chalk12.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
2875
3206
  }
2876
- const agentsDir = join12(repoPath, plugin.dir, "agents");
2877
- if (existsSync13(agentsDir)) {
3207
+ const agentsDir = join13(repoPath, plugin.dir, "agents");
3208
+ if (existsSync14(agentsDir)) {
2878
3209
  const agentFiles = readdirSync6(agentsDir).filter((f) => f.endsWith(".md"));
2879
3210
  if (agentFiles.length > 0) {
2880
3211
  console.log();
2881
- console.log(` ${chalk11.bold("Agents:")}`);
3212
+ console.log(` ${chalk12.bold("Agents:")}`);
2882
3213
  for (const agent of agentFiles) {
2883
3214
  console.log(` \u2022 ${agent.replace(".md", "")}`);
2884
3215
  }
@@ -2890,39 +3221,39 @@ async function infoCommand(pluginName) {
2890
3221
  }
2891
3222
 
2892
3223
  // src/commands/lang.ts
2893
- import chalk12 from "chalk";
3224
+ import chalk13 from "chalk";
2894
3225
  async function langCommand(action, value) {
2895
3226
  const config = readConfig();
2896
3227
  if (!action || action === "show") {
2897
3228
  console.log();
2898
- console.log(chalk12.bold(` ${t("lang_title")}`));
2899
- console.log(chalk12.dim(" " + "\u2500".repeat(40)));
3229
+ console.log(chalk13.bold(` ${t("lang_title")}`));
3230
+ console.log(chalk13.dim(" " + "\u2500".repeat(40)));
2900
3231
  console.log();
2901
- console.log(` ${chalk12.dim(t("lang_current") + ":")} ${config.language}`);
3232
+ console.log(` ${chalk13.dim(t("lang_current") + ":")} ${config.language}`);
2902
3233
  console.log();
2903
- console.log(chalk12.dim(" \u652F\u6301\u7684\u8BED\u8A00: zh_CN, en_US"));
2904
- console.log(chalk12.dim(" \u7528\u6CD5: install-helper lang set <language>"));
3234
+ console.log(chalk13.dim(` ${t("lang_supported")}`));
3235
+ console.log(chalk13.dim(` ${t("lang_usage")}`));
2905
3236
  console.log();
2906
3237
  return;
2907
3238
  }
2908
3239
  if (action === "set") {
2909
3240
  if (!value) {
2910
- console.log(chalk12.red(" \u8BF7\u6307\u5B9A\u8BED\u8A00: install-helper lang set zh_CN"));
3241
+ console.log(chalk13.red(` ${t("lang_specify")}`));
2911
3242
  return;
2912
3243
  }
2913
3244
  if (value !== "zh_CN" && value !== "en_US") {
2914
- console.log(chalk12.red(` ${t("lang_invalid")}`));
3245
+ console.log(chalk13.red(` ${t("lang_invalid")}`));
2915
3246
  return;
2916
3247
  }
2917
3248
  updateConfig({ language: value });
2918
3249
  setLanguage(value);
2919
3250
  console.log();
2920
- console.log(chalk12.green(` \u2713 ${t("lang_set")} ${value}`));
3251
+ console.log(chalk13.green(` \u2713 ${t("lang_set")} ${value}`));
2921
3252
  console.log();
2922
3253
  return;
2923
3254
  }
2924
- console.log(chalk12.red(` \u672A\u77E5\u64CD\u4F5C: ${action}`));
2925
- console.log(chalk12.dim(" \u652F\u6301\u7684\u64CD\u4F5C: show, set"));
3255
+ console.log(chalk13.red(` ${t("lang_unknown_action")}: ${action}`));
3256
+ console.log(chalk13.dim(` ${t("lang_supported_actions")}`));
2926
3257
  }
2927
3258
 
2928
3259
  // src/cli.ts
@@ -2932,7 +3263,7 @@ function createCLI() {
2932
3263
  setLanguage(config.language);
2933
3264
  }
2934
3265
  const program2 = new Command();
2935
- program2.name("install-helper").description("Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.0");
3266
+ program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.10");
2936
3267
  program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
2937
3268
  await initCommand();
2938
3269
  });