@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 +595 -264
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
8
|
-
import
|
|
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("
|
|
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
|
|
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
|
|
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
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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 ===
|
|
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("
|
|
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:
|
|
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 ===
|
|
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:
|
|
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 ===
|
|
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:
|
|
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 ===
|
|
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:
|
|
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 ===
|
|
967
|
+
if (result === CANCEL) return CANCEL;
|
|
868
968
|
return result;
|
|
869
969
|
}
|
|
870
970
|
async function stepLevel(lastLevel) {
|
|
871
|
-
printBoxTitle("
|
|
971
|
+
printBoxTitle(t("wizard_step_2_title"));
|
|
872
972
|
const choices = [
|
|
873
|
-
{ name:
|
|
874
|
-
{ name:
|
|
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:
|
|
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 ===
|
|
988
|
+
if (result === CANCEL) return CANCEL;
|
|
889
989
|
return result;
|
|
890
990
|
}
|
|
891
991
|
async function stepPlugins(tool, level) {
|
|
892
|
-
printBoxTitle("
|
|
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
|
-
|
|
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
|
|
1028
|
+
return CANCEL;
|
|
933
1029
|
}
|
|
934
1030
|
return pluginIds;
|
|
935
1031
|
}
|
|
936
1032
|
async function stepConfirm(tool, level, plugins) {
|
|
937
|
-
printBoxTitle("
|
|
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
|
-
|
|
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)}
|
|
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:
|
|
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 ===
|
|
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
|
|
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
|
-
|
|
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
|
|
1482
|
-
import { join as
|
|
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 =
|
|
1670
|
-
if (!
|
|
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
|
-
|
|
1991
|
+
const execOptions = {
|
|
1687
1992
|
cwd,
|
|
1688
1993
|
timeout: 3e5,
|
|
1689
|
-
stdio: "pipe"
|
|
1690
|
-
|
|
1691
|
-
|
|
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
|
|
1738
|
-
import { join as
|
|
1739
|
-
import { select as
|
|
1740
|
-
import
|
|
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 =
|
|
2058
|
+
const skillsDir = join10(configRoot, "skills");
|
|
1745
2059
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
1746
|
-
if (!
|
|
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 =
|
|
1758
|
-
const targetPath =
|
|
1759
|
-
if (!
|
|
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 (
|
|
1765
|
-
|
|
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 =
|
|
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 =
|
|
2100
|
+
const targetPath = join10(skillsDir, skillId);
|
|
1787
2101
|
try {
|
|
1788
|
-
if (
|
|
1789
|
-
|
|
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 (
|
|
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("
|
|
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
|
|
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(
|
|
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
|
-
|
|
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
|
|
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(
|
|
1923
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
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 ?
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
2293
|
+
chalk5.green(" \u2713") + ` ${result.displayName} (${result.skillsCount} skills, ${result.agentsCount} agents)`
|
|
1996
2294
|
);
|
|
1997
2295
|
} else {
|
|
1998
|
-
console.log(
|
|
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
|
-
|
|
2310
|
+
chalk5.bold(` ${t("install_done")}!`),
|
|
2013
2311
|
"",
|
|
2014
|
-
` ${
|
|
2015
|
-
` ${
|
|
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
|
-
|
|
2018
|
-
` ${
|
|
2019
|
-
` ${
|
|
2020
|
-
` ${
|
|
2021
|
-
` ${
|
|
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
|
-
` ${
|
|
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
|
|
2038
|
-
import { join as
|
|
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 (
|
|
2341
|
+
if (existsSync11(join11(cwd, "package.json")) && (() => {
|
|
2043
2342
|
try {
|
|
2044
|
-
const pkg = JSON.parse(readFileSync5(
|
|
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("
|
|
2051
|
-
logger.info("
|
|
2052
|
-
logger.info("
|
|
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("
|
|
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("
|
|
2360
|
+
spinner.succeed(t("loading_skills_list_complete"));
|
|
2062
2361
|
} catch {
|
|
2063
|
-
spinner.warn("
|
|
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("
|
|
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
|
|
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("
|
|
2424
|
+
logger.info(t("init_cancelled"));
|
|
2126
2425
|
return "done";
|
|
2127
2426
|
}
|
|
2128
2427
|
const repoManager = createRepositoryManager();
|
|
2129
|
-
const spinner = createSpinner(t("
|
|
2428
|
+
const spinner = createSpinner(t("loading_plugin_data"));
|
|
2130
2429
|
spinner.start();
|
|
2131
2430
|
const repoPath = await repoManager.ensureRepo();
|
|
2132
|
-
spinner.succeed(t("
|
|
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("
|
|
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 ===
|
|
2200
|
-
logger.info("
|
|
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("
|
|
2513
|
+
logger.info(t("init_cancelled"));
|
|
2215
2514
|
return "done";
|
|
2216
2515
|
}
|
|
2217
2516
|
if (selectedSkills.length === 0) {
|
|
2218
|
-
logger.info("
|
|
2517
|
+
logger.info(t("install_no_skill_selected"));
|
|
2219
2518
|
return "done";
|
|
2220
2519
|
}
|
|
2221
2520
|
const repoManager = createRepositoryManager();
|
|
2222
|
-
const spinner = createSpinner(t("
|
|
2521
|
+
const spinner = createSpinner(t("loading_plugin_data"));
|
|
2223
2522
|
spinner.start();
|
|
2224
2523
|
const repoPath = await repoManager.ensureRepo();
|
|
2225
|
-
spinner.succeed(t("
|
|
2226
|
-
logger.info(`${t("skill_install_progress")} ${
|
|
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
|
-
|
|
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")}: ${
|
|
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(
|
|
2244
|
-
logger.info(
|
|
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
|
|
2267
|
-
import { existsSync as
|
|
2268
|
-
import { join as
|
|
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(
|
|
2272
|
-
console.log(
|
|
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(
|
|
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
|
-
|
|
2586
|
+
chalk7.green(" \u2713") + ` ${getToolDisplayName(tool)}${detected.version ? ` v${detected.version}` : ""}`
|
|
2285
2587
|
);
|
|
2286
2588
|
} else {
|
|
2287
|
-
console.log(
|
|
2589
|
+
console.log(chalk7.dim(" \u2014") + ` ${getToolDisplayName(tool)} \u2014 \u672A\u5B89\u88C5`);
|
|
2288
2590
|
}
|
|
2289
2591
|
}
|
|
2290
2592
|
console.log();
|
|
2291
|
-
console.log(
|
|
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
|
-
|
|
2601
|
+
chalk7.green(" \u2713") + ` ${plugin.id.padEnd(30)} ${inst.skillsCount} skills, ${inst.agentsCount} agents`
|
|
2300
2602
|
);
|
|
2301
2603
|
} else {
|
|
2302
|
-
console.log(
|
|
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(
|
|
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 (
|
|
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(
|
|
2617
|
+
console.log(chalk7.green(" \u2713") + ` ${skillsDir} \u2014 ${count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548`);
|
|
2316
2618
|
} else {
|
|
2317
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
2632
|
+
console.log(chalk7.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: \u5DF2\u521B\u5EFA ${skillsDir}`);
|
|
2331
2633
|
}
|
|
2332
2634
|
}
|
|
2333
|
-
if (
|
|
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(
|
|
2639
|
+
console.log(chalk7.green(" \u2713") + ` ${agentsDir} \u2014 ${count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548`);
|
|
2338
2640
|
} else {
|
|
2339
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
2658
|
+
console.log(chalk7.bold(` ${t("doctor_config")}`));
|
|
2357
2659
|
const configFile = getConfigFileName(primaryTool);
|
|
2358
|
-
const configPath =
|
|
2359
|
-
if (
|
|
2360
|
-
console.log(
|
|
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(
|
|
2664
|
+
console.log(chalk7.dim(" \u2014") + ` ${configFile} \u4E0D\u5B58\u5728`);
|
|
2363
2665
|
}
|
|
2364
2666
|
console.log();
|
|
2365
|
-
console.log(
|
|
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 =
|
|
2684
|
+
const fullPath = join12(dir, entry);
|
|
2383
2685
|
try {
|
|
2384
2686
|
const stats = lstatSync3(fullPath);
|
|
2385
2687
|
if (stats.isSymbolicLink()) {
|
|
2386
|
-
if (!
|
|
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 =
|
|
2705
|
+
const fullPath = join12(dir, entry);
|
|
2404
2706
|
try {
|
|
2405
2707
|
const stats = lstatSync3(fullPath);
|
|
2406
2708
|
if (stats.isSymbolicLink()) {
|
|
2407
|
-
if (!
|
|
2408
|
-
|
|
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
|
|
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(
|
|
2729
|
+
console.log(chalk8.bold(` ${t("status_title")}`));
|
|
2428
2730
|
console.log();
|
|
2429
2731
|
if (installed.length === 0) {
|
|
2430
|
-
console.log(
|
|
2431
|
-
console.log(
|
|
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
|
-
|
|
2739
|
+
chalk8.green(" \u2713") + ` ${inst.displayName}` + chalk8.dim(` (${inst.tool}, ${inst.level})`)
|
|
2438
2740
|
);
|
|
2439
2741
|
console.log(
|
|
2440
|
-
|
|
2742
|
+
chalk8.dim(` ${inst.skillsCount} skills, ${inst.agentsCount} agents`)
|
|
2441
2743
|
);
|
|
2442
|
-
console.log(
|
|
2443
|
-
console.log(
|
|
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
|
|
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("
|
|
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("
|
|
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("
|
|
2798
|
+
const spinner = createSpinner(t("loading_plugin_data"));
|
|
2497
2799
|
spinner.start();
|
|
2498
2800
|
const repoPath = await repoManager.ensureRepo();
|
|
2499
|
-
spinner.succeed(
|
|
2500
|
-
logger.info(`${t("skill_install_progress")} ${
|
|
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
|
-
|
|
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")}: ${
|
|
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(
|
|
2519
|
-
logger.info(
|
|
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("
|
|
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: ${
|
|
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("
|
|
2898
|
+
const spinner = createSpinner(t("loading_plugin_data"));
|
|
2594
2899
|
spinner.start();
|
|
2595
2900
|
const repoPath = await repoManager.ensureRepo();
|
|
2596
|
-
spinner.succeed(t("
|
|
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("
|
|
2927
|
+
const spinner = createSpinner(t("loading_plugin_data"));
|
|
2621
2928
|
spinner.start();
|
|
2622
2929
|
const repoPath = await repoManager.ensureRepo();
|
|
2623
|
-
spinner.succeed(t("
|
|
2624
|
-
logger.info(`${t("skill_install_progress")} ${
|
|
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
|
-
|
|
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")}: ${
|
|
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(
|
|
2641
|
-
logger.info(
|
|
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
|
|
2674
|
-
import
|
|
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(
|
|
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}
|
|
2699
|
-
logger.info(
|
|
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(
|
|
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 (
|
|
2708
|
-
|
|
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 (
|
|
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(
|
|
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}
|
|
3068
|
+
logger.warn(`${plugin.displayName}${t("uninstall_files_gone")}`);
|
|
2738
3069
|
}
|
|
2739
3070
|
}
|
|
2740
3071
|
if (skills.length > 0) {
|
|
2741
|
-
logger.info(
|
|
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")}: ${
|
|
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
|
|
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 ${
|
|
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
|
|
2847
|
-
import { existsSync as
|
|
2848
|
-
import { join as
|
|
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(
|
|
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 ?
|
|
3188
|
+
const statusText = isInstalled ? chalk12.green(`\u2713 ${t("status_installed")}`) : chalk12.dim(`\u2014 ${t("status_not_installed")}`);
|
|
2858
3189
|
console.log();
|
|
2859
|
-
console.log(
|
|
2860
|
-
console.log(
|
|
3190
|
+
console.log(chalk12.bold(` ${plugin.displayName}`));
|
|
3191
|
+
console.log(chalk12.dim(" " + "\u2500".repeat(40)));
|
|
2861
3192
|
console.log();
|
|
2862
|
-
console.log(` ${
|
|
2863
|
-
console.log(` ${
|
|
2864
|
-
console.log(` ${
|
|
2865
|
-
console.log(` ${
|
|
2866
|
-
console.log(` ${
|
|
2867
|
-
console.log(` ${
|
|
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 =
|
|
2873
|
-
if (
|
|
2874
|
-
console.log(` ${
|
|
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 =
|
|
2877
|
-
if (
|
|
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(` ${
|
|
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
|
|
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(
|
|
2899
|
-
console.log(
|
|
3229
|
+
console.log(chalk13.bold(` ${t("lang_title")}`));
|
|
3230
|
+
console.log(chalk13.dim(" " + "\u2500".repeat(40)));
|
|
2900
3231
|
console.log();
|
|
2901
|
-
console.log(` ${
|
|
3232
|
+
console.log(` ${chalk13.dim(t("lang_current") + ":")} ${config.language}`);
|
|
2902
3233
|
console.log();
|
|
2903
|
-
console.log(
|
|
2904
|
-
console.log(
|
|
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(
|
|
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(
|
|
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(
|
|
3251
|
+
console.log(chalk13.green(` \u2713 ${t("lang_set")} ${value}`));
|
|
2921
3252
|
console.log();
|
|
2922
3253
|
return;
|
|
2923
3254
|
}
|
|
2924
|
-
console.log(
|
|
2925
|
-
console.log(
|
|
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.
|
|
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
|
});
|