@cannbot-ai/install-helper 1.0.2 → 1.0.4

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
@@ -12,108 +12,46 @@ import { select, checkbox, Separator } from "@inquirer/prompts";
12
12
  import chalk2 from "chalk";
13
13
 
14
14
  // src/core/registry.ts
15
- var PLUGIN_REGISTRY = [
16
- {
17
- id: "ops-direct-invoke",
18
- dir: "plugins-official/ops-direct-invoke",
19
- displayName: "AscendC Kernel \u76F4\u8C03",
20
- script: "init.sh",
21
- aliases: ["ops-direct", "ascendc-direct", "direct", "kernel"],
22
- skills: 16,
23
- agents: 3,
24
- description: "Ascend C Kernel <<<>>> \u76F4\u8C03\u7B97\u5B50\u5F00\u53D1\u5168\u6D41\u7A0B"
25
- },
26
- {
27
- id: "ops-direct-invoke-flash",
28
- dir: "plugins-official/ops-direct-invoke-flash",
29
- displayName: "AscendC Kernel \u4ECE\u96F6\u6784\u5EFA",
30
- script: "init.sh",
31
- aliases: ["flash", "kernel-flash"],
32
- skills: 1,
33
- agents: 1,
34
- description: "Ascend C / Ascend950 Reg API \u6838\u51FD\u6570\u4ECE\u96F6\u6784\u5EFA"
35
- },
36
- {
37
- id: "ops-registry-invoke",
38
- dir: "plugins-official/ops-registry-invoke",
39
- displayName: "AscendC \u7B97\u5B50\u6CE8\u518C\u8C03\u7528",
40
- script: "init.sh",
41
- aliases: ["ops-registry", "ascendc-registry", "registry"],
42
- skills: 12,
43
- agents: 4,
44
- description: "Ascend C \u7B97\u5B50\u6CE8\u518C\u8C03\u7528\u5F00\u53D1\u6D41\u7A0B"
45
- },
46
- {
47
- id: "pypto-op-orchestrator",
48
- dir: "plugins-official/pypto-op-orchestrator",
49
- displayName: "PyPTO \u7B97\u5B50",
50
- script: "init.sh",
51
- aliases: ["pypto", "pytorch"],
52
- skills: 8,
53
- agents: 3,
54
- description: "PyPTO \u7B97\u5B50\u7AEF\u5230\u7AEF\u5F00\u53D1\u7F16\u6392"
55
- },
56
- {
57
- id: "triton-op-generator",
58
- dir: "plugins-official/triton-op-generator",
59
- displayName: "Triton \u7B97\u5B50\u751F\u6210",
60
- script: "install.sh",
61
- aliases: ["triton"],
62
- skills: 6,
63
- agents: 0,
64
- description: "Triton-Ascend \u7B97\u5B50\u4EE3\u7801\u751F\u6210\u4E0E\u4F18\u5316"
65
- },
66
- {
67
- id: "tilelang-op-orchestrator",
68
- dir: "plugins-official/tilelang-op-orchestrator",
69
- displayName: "TileLang \u7B97\u5B50",
70
- script: "init.sh",
71
- aliases: ["tilelang"],
72
- skills: 9,
73
- agents: 3,
74
- description: "TileLang \u7B97\u5B50\u5F00\u53D1\u6D41\u7A0B"
75
- },
76
- {
77
- id: "model-infer-optimize",
78
- dir: "plugins-official/model-infer-optimize",
79
- displayName: "NPU \u63A8\u7406\u4F18\u5316",
80
- script: "init.sh",
81
- aliases: ["model-infer", "infer", "inference"],
82
- skills: 11,
83
- agents: 3,
84
- description: "NPU \u6A21\u578B\u63A8\u7406\u7AEF\u5230\u7AEF\u4F18\u5316"
85
- },
86
- {
87
- id: "catlass-op-generator",
88
- dir: "plugins-official/catlass-op-generator",
89
- displayName: "Catlass \u7B97\u5B50\u76F4\u8C03",
90
- script: "init.sh",
91
- aliases: ["catlass"],
92
- skills: 10,
93
- agents: 3,
94
- description: "Catlass \u7B97\u5B50\u76F4\u8C03\u5F00\u53D1"
95
- },
96
- {
97
- id: "ops-code-reviewer",
98
- dir: "plugins-official/ops-code-reviewer",
99
- displayName: "\u4EE3\u7801\u68C0\u89C6",
100
- script: "init.sh",
101
- aliases: ["code-review", "reviewer", "review"],
102
- skills: 5,
103
- agents: 1,
104
- description: "\u4EE3\u7801\u68C0\u89C6\u4E0E\u89C4\u8303\u68C0\u67E5"
105
- },
106
- {
107
- id: "torch-compile",
108
- dir: "plugins-official/torch-compile",
109
- displayName: "torch.compile \u56FE\u6A21\u5F0F",
110
- script: "init.sh",
111
- aliases: ["torch", "compile", "graph"],
112
- skills: 6,
113
- agents: 1,
114
- description: "PyTorch torch.compile \u56FE\u6A21\u5F0F\u9002\u914D"
15
+ import { readdirSync, readFileSync } from "fs";
16
+ import { join, dirname } from "path";
17
+ import { fileURLToPath } from "url";
18
+ import { parse as parseYaml } from "yaml";
19
+ var __filename = fileURLToPath(import.meta.url);
20
+ var __dirname = dirname(__filename);
21
+ function loadPluginsFromYaml() {
22
+ const pluginsDir = join(__dirname, "plugins.d");
23
+ const defaultsPath = join(pluginsDir, "_defaults.yml");
24
+ let defaults = {};
25
+ try {
26
+ defaults = parseYaml(readFileSync(defaultsPath, "utf-8")) || {};
27
+ } catch {
115
28
  }
116
- ];
29
+ const plugins = [];
30
+ try {
31
+ for (const file of readdirSync(pluginsDir)) {
32
+ if (file.startsWith("_") || !file.endsWith(".yml")) continue;
33
+ try {
34
+ const content = parseYaml(readFileSync(join(pluginsDir, file), "utf-8"));
35
+ if (!content || !content.id) continue;
36
+ plugins.push({
37
+ id: content.id,
38
+ dir: content.dir,
39
+ displayName: content.displayName || content.id,
40
+ script: content.script || defaults.script || "init.sh",
41
+ aliases: content.aliases || [],
42
+ skills: content.skills ?? defaults.skills ?? 0,
43
+ agents: content.agents ?? defaults.agents ?? 0,
44
+ description: content.description || ""
45
+ });
46
+ } catch {
47
+ }
48
+ }
49
+ } catch {
50
+ }
51
+ plugins.sort((a, b) => a.displayName < b.displayName ? -1 : a.displayName > b.displayName ? 1 : 0);
52
+ return plugins;
53
+ }
54
+ var PLUGIN_REGISTRY = loadPluginsFromYaml();
117
55
  function findPlugin(query) {
118
56
  const normalized = query.toLowerCase().trim();
119
57
  const exactMatch = PLUGIN_REGISTRY.find(
@@ -139,356 +77,42 @@ function getPluginById(id) {
139
77
  import { execa } from "execa";
140
78
  import { existsSync as existsSync2 } from "fs";
141
79
  import { homedir as homedir2 } from "os";
142
- import { join as join2 } from "path";
80
+ import { join as join4 } from "path";
143
81
 
144
82
  // src/utils/paths.ts
145
83
  import { homedir } from "os";
146
- import { join } from "path";
84
+ import { join as join3 } from "path";
147
85
  import { existsSync } from "fs";
148
86
 
149
87
  // src/utils/i18n.ts
150
- var zh_CN = {
151
- wizard_title: "CANNBot Install Helper",
152
- wizard_detect: "\u6B63\u5728\u68C0\u6D4B\u5DF2\u5B89\u88C5\u7684 AI \u7F16\u7A0B\u5DE5\u5177...",
153
- wizard_select_tool: "\u9009\u62E9 AI \u7F16\u7A0B\u5DE5\u5177",
154
- wizard_select_level: "\u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E",
155
- wizard_select_plugins: "\u9009\u62E9\u8981\u5B89\u88C5\u7684\u63D2\u4EF6",
156
- wizard_confirm: "\u786E\u8BA4\u5B89\u88C5",
157
- wizard_detected_tool: "\u68C0\u6D4B\u5230",
158
- wizard_confirm_tool: "\u4F7F\u7528",
159
- wizard_last_used: "\u4E0A\u6B21\u4F7F\u7528",
160
- wizard_already_installed: "\u5DF2\u5B89\u88C5",
161
- install_cloning: "\u6B63\u5728\u514B\u9686 cannbot-skills \u4ED3\u5E93...",
162
- install_repo_ready: "\u4ED3\u5E93\u5C31\u7EEA",
163
- install_progress: "\u6B63\u5728\u5B89\u88C5",
164
- install_done: "\u5B89\u88C5\u5B8C\u6210",
165
- install_success: "\u6210\u529F",
166
- install_failed: "\u5931\u8D25",
167
- install_already_installed: "\u5DF2\u5B89\u88C5",
168
- install_reinstall_confirm: "\u662F\u5426\u91CD\u65B0\u5B89\u88C5\uFF08\u8986\u76D6\uFF09",
169
- install_skip: "\u8DF3\u8FC7",
170
- install_enhanced_next_steps: "\u4E0B\u4E00\u6B65",
171
- install_enhanced_launch: "\u542F\u52A8",
172
- install_enhanced_try: "\u8BD5\u8BD5",
173
- install_enhanced_more: "\u66F4\u591A",
174
- install_enhanced_check: "\u68C0\u67E5",
175
- install_enhanced_docs: "\u6587\u6863",
176
- update_title: "\u66F4\u65B0\u5DF2\u5B89\u88C5\u7684 Skills",
177
- update_updating: "\u6B63\u5728\u66F4\u65B0",
178
- update_done: "\u66F4\u65B0\u5B8C\u6210",
179
- update_no_plugins: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6",
180
- doctor_title: "CANNBot Doctor",
181
- doctor_tools: "AI \u5DE5\u5177",
182
- doctor_plugins: "\u5DF2\u5B89\u88C5\u63D2\u4EF6",
183
- doctor_links: "\u94FE\u63A5\u5B8C\u6574\u6027",
184
- doctor_config: "\u914D\u7F6E\u6587\u4EF6",
185
- doctor_result: "\u7ED3\u679C",
186
- doctor_fix_title: "\u81EA\u52A8\u4FEE\u590D",
187
- doctor_fix_cleaning: "\u6E05\u7406\u5931\u6548\u94FE\u63A5",
188
- doctor_fix_rebuilding: "\u91CD\u5EFA\u76EE\u5F55",
189
- doctor_fix_done: "\u4FEE\u590D\u5B8C\u6210",
190
- info_title: "\u63D2\u4EF6\u8BE6\u60C5",
191
- info_description: "\u63CF\u8FF0",
192
- info_skills: "Skills",
193
- info_agents: "Agents",
194
- info_status: "\u72B6\u6001",
195
- info_quickstart: "\u5FEB\u901F\u5F00\u59CB",
196
- info_not_found: "\u672A\u627E\u5230\u63D2\u4EF6",
197
- lang_title: "\u8BED\u8A00\u8BBE\u7F6E",
198
- lang_current: "\u5F53\u524D\u8BED\u8A00",
199
- lang_set: "\u8BED\u8A00\u5DF2\u8BBE\u7F6E\u4E3A",
200
- lang_invalid: "\u65E0\u6548\u7684\u8BED\u8A00\uFF0C\u652F\u6301: zh_CN, en_US",
201
- list_title: "\u53EF\u7528\u573A\u666F",
202
- list_id: "\u5E8F\u53F7",
203
- list_name: "\u573A\u666F\u540D",
204
- list_status: "\u72B6\u6001",
205
- list_skills: "Skills",
206
- list_agents: "Agents",
207
- status_installed: "\u5DF2\u88C5",
208
- status_not_installed: "\u672A\u88C5",
209
- error_tool_not_found: "\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 AI \u7F16\u7A0B\u5DE5\u5177",
210
- error_plugin_not_found: "\u672A\u627E\u5230\u63D2\u4EF6",
211
- error_repo_not_found: "\u4ED3\u5E93\u672A\u627E\u5230",
212
- error_invalid_tool: "\u6682\u4E0D\u652F\u6301\u7684 AI \u5DE5\u5177: {tool}\n\u652F\u6301\u7684\u5DE5\u5177: {tools}",
213
- error_invalid_level: "\u6682\u4E0D\u652F\u6301\u7684\u5B89\u88C5\u7EA7\u522B: {level}\n\u652F\u6301\u7684\u7EA7\u522B: {levels}",
214
- quick_start: "\u542F\u52A8\u547D\u4EE4",
215
- quick_start_hint: "\u8BD5\u8BD5\u8F93\u5165: \u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50",
216
- skill_select_category: "\u9009\u62E9 Skill \u7C7B\u522B",
217
- skill_select_items: "\u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills",
218
- skill_already_installed: "\u5DF2\u5B89\u88C5",
219
- skill_install_progress: "\u6B63\u5728\u5B89\u88C5",
220
- skill_install_done: "Skill \u5B89\u88C5\u5B8C\u6210",
221
- skill_uninstall_done: "Skill \u5378\u8F7D\u5B8C\u6210",
222
- skill_list_title: "\u53EF\u7528 Skills",
223
- wizard_select_mode: "\u9009\u62E9\u5B89\u88C5\u7C7B\u578B",
224
- wizard_mode_plugin: "\u5B89\u88C5 Plugin",
225
- wizard_mode_plugin_desc: "\u5B8C\u6574\u5F00\u53D1\u5DE5\u4F5C\u6D41\uFF08Skills + Agents + \u914D\u7F6E\u6587\u4EF6\uFF09",
226
- wizard_mode_skill: "\u5B89\u88C5 Skill",
227
- wizard_mode_skill_desc: "\u4EC5\u5B89\u88C5\u9886\u57DF\u77E5\u8BC6\u6280\u80FD\uFF0C\u8BA9 AI \u638C\u63E1\u7279\u5B9A\u80FD\u529B",
228
- wizard_back: "\u8FD4\u56DE",
229
- wizard_cancel: "\u9000\u51FA",
230
- wizard_no_selection: "\u672A\u9009\u62E9\u4EFB\u4F55\u9879\uFF0C\u8BF7\u9009\u62E9\u64CD\u4F5C",
231
- wizard_back_to_reselect: "\u8FD4\u56DE",
232
- status_title: "\u5DF2\u5B89\u88C5\u63D2\u4EF6",
233
- status_none: "\u6682\u65E0\u5DF2\u5B89\u88C5\u7684\u63D2\u4EF6",
234
- status_hint: "\u8FD0\u884C install-helper init \u5F00\u59CB\u5B89\u88C5",
235
- status_install_time: "\u5B89\u88C5\u65F6\u95F4",
236
- install_installed_to: "\u5B89\u88C5\u5230",
237
- install_skills_count: "Skills",
238
- install_agents_count: "Agents",
239
- lang_supported: "\u652F\u6301\u7684\u8BED\u8A00: zh_CN, en_US",
240
- lang_usage: "\u7528\u6CD5: install-helper lang set <language>",
241
- lang_specify: "\u8BF7\u6307\u5B9A\u8BED\u8A00: install-helper lang set zh_CN",
242
- lang_unknown_action: "\u672A\u77E5\u64CD\u4F5C",
243
- lang_supported_actions: "\u652F\u6301\u7684\u64CD\u4F5C: show, set",
244
- info_aliases: "\u522B\u540D",
245
- uninstall_not_found: "\u672A\u627E\u5230",
246
- uninstall_no_record: "\u672A\u627E\u5230\u5B89\u88C5\u8BB0\u5F55\uFF0C\u53EF\u80FD\u672A\u5B89\u88C5\u6216\u5B89\u88C5\u8BB0\u5F55\u5DF2\u635F\u574F",
247
- 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",
248
- uninstall_in_progress: "\u6B63\u5728\u5378\u8F7D",
249
- uninstall_removed: "\u5DF2\u5378\u8F7D",
250
- uninstall_files_gone: "\u7684\u6587\u4EF6\u5DF2\u4E0D\u5B58\u5728\uFF0C\u5DF2\u6E05\u7406\u5B89\u88C5\u8BB0\u5F55",
251
- uninstall_skills_in_progress: "\u6B63\u5728\u5378\u8F7D",
252
- init_pkg_dir_warn: "\u5F53\u524D\u76EE\u5F55\u770B\u8D77\u6765\u662F install-helper \u5305\u76EE\u5F55",
253
- 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",
254
- init_pkg_dir_example: "\u793A\u4F8B\uFF1Acd ~/my-project && install-helper",
255
- init_cancelled: "\u5DF2\u53D6\u6D88\u5B89\u88C5",
256
- backup_detected: "\u68C0\u6D4B\u5230\u5F53\u524D\u76EE\u5F55\u5DF2\u5B89\u88C5\u63D2\u4EF6",
257
- backup_current: "\u5F53\u524D\u5B89\u88C5",
258
- backup_installing: "\u5373\u5C06\u5B89\u88C5",
259
- backup_overwrite_warning: "\u7EE7\u7EED\u5B89\u88C5\u5C06\u8986\u76D6\u73B0\u6709\u7684 AGENTS.md \u914D\u7F6E\u6587\u4EF6\u3002",
260
- backup_auto_create: "\u7CFB\u7EDF\u4F1A\u81EA\u52A8\u521B\u5EFA\u5907\u4EFD\uFF0C\u4EE5\u4FBF\u540E\u7EED\u6062\u590D\u3002",
261
- backup_overwrite: "\u8986\u76D6\u5B89\u88C5\uFF08\u81EA\u52A8\u5907\u4EFD\uFF09",
262
- backup_cancel: "\u53D6\u6D88\u5B89\u88C5",
263
- backup_restore_prompt: "\u68C0\u6D4B\u5230\u5907\u4EFD\u914D\u7F6E\uFF0C\u662F\u5426\u6062\u590D\uFF1F",
264
- backup_restore: "\u6062\u590D",
265
- backup_only_uninstall: "\u4EC5\u5378\u8F7D\uFF08\u4E0D\u6062\u590D\uFF09",
266
- backup_select_action: "\u8BF7\u9009\u62E9\u64CD\u4F5C",
267
- backup_restore_success: "\u5DF2\u6062\u590D\u914D\u7F6E",
268
- backup_created: "\u5DF2\u521B\u5EFA\u5907\u4EFD",
269
- loading_skills_list: "\u6B63\u5728\u52A0\u8F7D Skills \u5217\u8868...",
270
- loading_skills_list_complete: "Skills \u5217\u8868\u52A0\u8F7D\u5B8C\u6210",
271
- loading_plugin_data: "\u6B63\u5728\u52A0\u8F7D\u63D2\u4EF6\u6570\u636E...",
272
- loading_plugin_data_complete: "\u63D2\u4EF6\u6570\u636E\u52A0\u8F7D\u5B8C\u6210",
273
- loading_skills_list_failed: "Skills \u5217\u8868\u52A0\u8F7D\u5931\u8D25\uFF0C\u5C06\u4F7F\u7528\u5185\u7F6E\u6570\u636E",
274
- install_no_skill_selected: "\u672A\u9009\u62E9\u4EFB\u4F55 Skill",
275
- install_to: "\u5B89\u88C5\u5230",
276
- start_to_use: "\u542F\u52A8 {tool} \u5373\u53EF\u4F7F\u7528",
277
- wizard_step_1_title: "[1/4] \u9009\u62E9 AI \u7F16\u7A0B\u5DE5\u5177",
278
- wizard_step_2_title: "[2/4] \u9009\u62E9\u5B89\u88C5\u4F4D\u7F6E",
279
- wizard_step_3_title: "[3/4] \u9009\u62E9\u8981\u5B89\u88C5\u7684\u63D2\u4EF6",
280
- wizard_step_4_title: "[4/4] \u786E\u8BA4\u5B89\u88C5",
281
- wizard_step_3_skill_title: "[3/4] \u9009\u62E9 Skill \u7C7B\u522B",
282
- wizard_step_4_skill_title: "[4/4] \u9009\u62E9\u8981\u5B89\u88C5\u7684 Skills \u2014 {category}",
283
- install_level_project: "\u5B89\u88C5\u5230\u5F53\u524D\u76EE\u5F55\uFF08\u63A8\u8350\uFF0C\u4EC5\u5F53\u524D\u9879\u76EE\u53EF\u7528\uFF09",
284
- install_level_global: "\u5B89\u88C5\u5230\u5168\u5C40\uFF08\u6240\u6709\u9879\u76EE\u5171\u4EAB\uFF09",
285
- wizard_select_mode_title: "\u9009\u62E9\u5B89\u88C5\u7C7B\u578B",
286
- skill_count_format: "{count} \u4E2A Skills",
287
- result_success_format: "{count} \u6210\u529F",
288
- result_failed_format: "{count} \u5931\u8D25",
289
- uninstall_remove_label: "\u79FB\u9664",
290
- uninstall_remove_file_format: "\u79FB\u9664 {count} \u4E2A\u6587\u4EF6",
291
- uninstall_remove_dir_format: "{count} \u4E2A\u76EE\u5F55",
292
- uninstall_clean_empty_dir: "\u6E05\u7406\u7A7A\u76EE\u5F55",
293
- uninstall_skill_not_installed: "\u672A\u5B89\u88C5",
294
- available_plugins: "\u53EF\u7528\u63D2\u4EF6",
295
- available_skills: "\u53EF\u7528 Skills",
296
- skill_total_count: "\u5171 {count} \u4E2A Skills",
297
- wizard_confirm_install_format: "\u5373\u5C06\u5B89\u88C5 {count} \u4E2A\u63D2\u4EF6\u5230 {tool}\uFF08{level} \u7EA7\u522B\uFF09\uFF1A",
298
- wizard_install_path: "\u5B89\u88C5\u8DEF\u5F84",
299
- update_install_hint: "\u4F7F\u7528 {cmd} \u5B89\u88C5\u63D2\u4EF6",
300
- hint_select_move: "\u79FB\u52A8",
301
- hint_select_space: "\u7A7A\u683C",
302
- hint_select_check: "\u52FE\u9009",
303
- hint_select_confirm: "\u786E\u8BA4",
304
- hint_checkbox_suffix: "\u4E0D\u9009\u6309\u56DE\u8F66\u53EF\u8FD4\u56DE",
305
- doctor_not_installed: "\u672A\u5B89\u88C5",
306
- doctor_links_valid: "{count} \u4E2A\u8F6F\u94FE\u63A5\u5747\u6709\u6548",
307
- doctor_broken_links: "{count} \u4E2A\u5931\u6548\u94FE\u63A5",
308
- doctor_fixed: "\u5DF2\u6E05\u7406 {count} \u4E2A\u5931\u6548\u94FE\u63A5",
309
- doctor_not_exist: "\u4E0D\u5B58\u5728",
310
- doctor_created: "\u5DF2\u521B\u5EFA {path}",
311
- doctor_config_exists: "\u5B58\u5728",
312
- doctor_config_not_exist: "\u4E0D\u5B58\u5728",
313
- doctor_result_with_fix: "{warnings} \u4E2A\u8B66\u544A, {errors} \u4E2A\u9519\u8BEF, {fixes} \u9879\u5DF2\u4FEE\u590D",
314
- doctor_result_without_fix: "{warnings} \u4E2A\u8B66\u544A, {errors} \u4E2A\u9519\u8BEF",
315
- count_suffix: "\u4E2A",
316
- try_prompt: "\u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50"
317
- };
318
- var en_US = {
319
- wizard_title: "CANNBot Install Helper",
320
- wizard_detect: "Detecting installed AI coding tools...",
321
- wizard_select_tool: "Select AI coding tool",
322
- wizard_select_level: "Select install level",
323
- wizard_select_plugins: "Select scenarios to install",
324
- wizard_confirm: "Confirm installation",
325
- wizard_detected_tool: "Detected",
326
- wizard_confirm_tool: "Confirm using",
327
- wizard_last_used: "last used",
328
- wizard_already_installed: "installed",
329
- install_cloning: "Cloning cannbot-skills repository...",
330
- install_repo_ready: "Repository ready",
331
- install_progress: "Installing",
332
- install_done: "Installation complete",
333
- install_success: "success",
334
- install_failed: "failed",
335
- install_already_installed: "already installed",
336
- install_reinstall_confirm: "Reinstall (overwrite)",
337
- install_skip: "skipped",
338
- install_enhanced_next_steps: "Next steps",
339
- install_enhanced_launch: "Launch",
340
- install_enhanced_try: "Try",
341
- install_enhanced_more: "More",
342
- install_enhanced_check: "Check",
343
- install_enhanced_docs: "Docs",
344
- update_title: "Update installed Skills",
345
- update_updating: "Updating",
346
- update_done: "Update complete",
347
- update_no_plugins: "No installed plugins",
348
- doctor_title: "CANNBot Doctor",
349
- doctor_tools: "AI Tools",
350
- doctor_plugins: "Installed Plugins",
351
- doctor_links: "Link Integrity",
352
- doctor_config: "Configuration",
353
- doctor_result: "Result",
354
- doctor_fix_title: "Auto-fix",
355
- doctor_fix_cleaning: "Cleaning broken links",
356
- doctor_fix_rebuilding: "Rebuilding directories",
357
- doctor_fix_done: "Fix complete",
358
- info_title: "Plugin Details",
359
- info_description: "Description",
360
- info_skills: "Skills",
361
- info_agents: "Agents",
362
- info_status: "Status",
363
- info_quickstart: "Quick Start",
364
- info_not_found: "Plugin not found",
365
- lang_title: "Language Settings",
366
- lang_current: "Current language",
367
- lang_set: "Language set to",
368
- lang_invalid: "Invalid language, supported: zh_CN, en_US",
369
- list_title: "Available Scenarios",
370
- list_id: "#",
371
- list_name: "Name",
372
- list_status: "Status",
373
- list_skills: "Skills",
374
- list_agents: "Agents",
375
- status_installed: "installed",
376
- status_not_installed: "not installed",
377
- error_tool_not_found: "No AI coding tool detected",
378
- error_plugin_not_found: "Plugin not found",
379
- error_repo_not_found: "Repository not found",
380
- error_invalid_tool: "Unsupported AI tool: {tool}\nSupported tools: {tools}",
381
- error_invalid_level: "Unsupported install level: {level}\nSupported levels: {levels}",
382
- quick_start: "Launch command",
383
- quick_start_hint: "Try: help me develop an Abs operator",
384
- skill_select_category: "Select Skill category",
385
- skill_select_items: "Select Skills to install (space to toggle, enter to confirm)",
386
- skill_already_installed: "installed",
387
- skill_install_progress: "Installing",
388
- skill_install_done: "Skill installation complete",
389
- skill_uninstall_done: "Skill uninstallation complete",
390
- skill_list_title: "Available Skills",
391
- wizard_select_mode: "Select installation mode",
392
- wizard_mode_plugin: "Install Plugin",
393
- wizard_mode_plugin_desc: "Full development workflow (Skills + Agents + config)",
394
- wizard_mode_skill: "Install Skill",
395
- wizard_mode_skill_desc: "Domain knowledge only, give AI specific capabilities",
396
- wizard_back: "Go back",
397
- wizard_cancel: "Cancel installation",
398
- wizard_no_selection: "No items selected, please choose an action",
399
- wizard_back_to_reselect: "Go back",
400
- status_title: "Installed Plugins",
401
- status_none: "No installed plugins",
402
- status_hint: "Run install-helper init to start",
403
- status_install_time: "Installed at",
404
- install_installed_to: "Installed to",
405
- install_skills_count: "Skills",
406
- install_agents_count: "Agents",
407
- lang_supported: "Supported languages: zh_CN, en_US",
408
- lang_usage: "Usage: install-helper lang set <language>",
409
- lang_specify: "Please specify language: install-helper lang set zh_CN",
410
- lang_unknown_action: "Unknown action",
411
- lang_supported_actions: "Supported actions: show, set",
412
- info_aliases: "Aliases",
413
- uninstall_not_found: "Not found",
414
- uninstall_no_record: "No install record found, may not be installed or record is corrupted",
415
- uninstall_no_record_hint: "For manual cleanup, delete related files in .opencode/ or .claude/ directory",
416
- uninstall_in_progress: "Uninstalling",
417
- uninstall_removed: "Uninstalled",
418
- uninstall_files_gone: " files no longer exist, install record cleaned",
419
- uninstall_skills_in_progress: "Uninstalling",
420
- init_pkg_dir_warn: "Current directory appears to be the install-helper package directory",
421
- init_pkg_dir_hint: "Please run this command in your project directory, not in the install-helper package directory",
422
- init_pkg_dir_example: "Example: cd ~/my-project && install-helper",
423
- init_cancelled: "Installation cancelled",
424
- backup_detected: "Plugin already installed in current directory",
425
- backup_current: "Currently installed",
426
- backup_installing: "About to install",
427
- backup_overwrite_warning: "Continuing will overwrite existing AGENTS.md configuration.",
428
- backup_auto_create: "System will automatically create backup for future restoration.",
429
- backup_overwrite: "Overwrite (auto backup)",
430
- backup_cancel: "Cancel installation",
431
- backup_restore_prompt: "Backup configuration detected, restore?",
432
- backup_restore: "Restore",
433
- backup_only_uninstall: "Uninstall only (no restore)",
434
- backup_select_action: "Please select an action",
435
- backup_restore_success: "Configuration restored",
436
- backup_created: "Backup created",
437
- loading_skills_list: "Loading Skills list...",
438
- loading_skills_list_complete: "Skills list loaded",
439
- loading_plugin_data: "Loading plugin data...",
440
- loading_plugin_data_complete: "Plugin data loaded",
441
- loading_skills_list_failed: "Failed to load Skills list, using built-in data",
442
- install_no_skill_selected: "No Skill selected",
443
- install_to: "Install to",
444
- start_to_use: "Start {tool} to use",
445
- wizard_step_1_title: "[1/4] Select AI coding tool",
446
- wizard_step_2_title: "[2/4] Select installation location",
447
- wizard_step_3_title: "[3/4] Select plugins to install",
448
- wizard_step_4_title: "[4/4] Confirm installation",
449
- wizard_step_3_skill_title: "[3/4] Select Skill category",
450
- wizard_step_4_skill_title: "[4/4] Select Skills to install \u2014 {category}",
451
- install_level_project: "Install to current directory (recommended, current project only)",
452
- install_level_global: "Install globally (all projects)",
453
- wizard_select_mode_title: "Select installation type",
454
- skill_count_format: "{count} Skills",
455
- result_success_format: "{count} succeeded",
456
- result_failed_format: "{count} failed",
457
- uninstall_remove_label: "Removed",
458
- uninstall_remove_file_format: "Removed {count} files",
459
- uninstall_remove_dir_format: "{count} directories",
460
- uninstall_clean_empty_dir: "Cleaned empty directory",
461
- uninstall_skill_not_installed: "Not installed",
462
- available_plugins: "Available plugins",
463
- available_skills: "Available Skills",
464
- skill_total_count: "Total {count} Skills",
465
- wizard_confirm_install_format: "About to install {count} plugins to {tool} ({level} level):",
466
- wizard_install_path: "Install path",
467
- update_install_hint: "Use {cmd} to install plugins",
468
- hint_select_move: "Navigate",
469
- hint_select_space: "Space",
470
- hint_select_check: "Toggle",
471
- hint_select_confirm: "Confirm",
472
- hint_checkbox_suffix: "Press enter without selection to go back",
473
- doctor_not_installed: "Not installed",
474
- doctor_links_valid: "{count} symlinks all valid",
475
- doctor_broken_links: "{count} broken links",
476
- doctor_fixed: "Cleaned {count} broken links",
477
- doctor_not_exist: "Does not exist",
478
- doctor_created: "Created {path}",
479
- doctor_config_exists: "Exists",
480
- doctor_config_not_exist: "Does not exist",
481
- doctor_result_with_fix: "{warnings} warnings, {errors} errors, {fixes} fixed",
482
- doctor_result_without_fix: "{warnings} warnings, {errors} errors",
483
- count_suffix: "",
484
- try_prompt: "help me develop an Abs operator"
485
- };
88
+ import { readFileSync as readFileSync2 } from "fs";
89
+ import { join as join2, dirname as dirname2 } from "path";
90
+ import { fileURLToPath as fileURLToPath2 } from "url";
91
+ var __filename2 = fileURLToPath2(import.meta.url);
92
+ var __dirname2 = dirname2(__filename2);
93
+ function loadLocale(locale) {
94
+ const localePath = join2(__dirname2, "locales", `${locale}.json`);
95
+ try {
96
+ const content = readFileSync2(localePath, "utf-8");
97
+ return JSON.parse(content);
98
+ } catch {
99
+ const fallbackPath = join2(__dirname2, "locales", "zh_CN.json");
100
+ try {
101
+ const content = readFileSync2(fallbackPath, "utf-8");
102
+ return JSON.parse(content);
103
+ } catch {
104
+ return {};
105
+ }
106
+ }
107
+ }
486
108
  var currentLang = "zh_CN";
109
+ var messages = loadLocale("zh_CN");
487
110
  function setLanguage(lang) {
488
111
  currentLang = lang;
112
+ messages = loadLocale(lang);
489
113
  }
490
114
  function t(key) {
491
- return currentLang === "zh_CN" ? zh_CN[key] : en_US[key];
115
+ return messages[key] !== void 0 ? messages[key] : key;
492
116
  }
493
117
 
494
118
  // src/utils/paths.ts
@@ -512,9 +136,9 @@ function validateLevel(level) {
512
136
  }
513
137
  function detectTraeVariant() {
514
138
  const home = homedir();
515
- if (existsSync(join(home, ".trae-cn"))) return "ide";
516
- if (existsSync(join(home, ".marscode"))) return "plugin";
517
- if (existsSync(join(home, ".traecli"))) return "cli";
139
+ if (existsSync(join3(home, ".trae-cn"))) return "ide";
140
+ if (existsSync(join3(home, ".marscode"))) return "plugin";
141
+ if (existsSync(join3(home, ".traecli"))) return "cli";
518
142
  return "unknown";
519
143
  }
520
144
  function getConfigRoot(tool, level, base) {
@@ -522,24 +146,24 @@ function getConfigRoot(tool, level, base) {
522
146
  if (level === "global") {
523
147
  switch (tool) {
524
148
  case "opencode":
525
- return join(home, ".config", "opencode");
149
+ return join3(home, ".config", "opencode");
526
150
  case "claude":
527
- return join(home, ".claude");
151
+ return join3(home, ".claude");
528
152
  case "trae": {
529
153
  const variant = detectTraeVariant();
530
154
  switch (variant) {
531
155
  case "plugin":
532
- return join(home, ".marscode");
156
+ return join3(home, ".marscode");
533
157
  case "cli":
534
- return join(home, ".traecli");
158
+ return join3(home, ".traecli");
535
159
  default:
536
- return join(home, ".trae-cn");
160
+ return join3(home, ".trae-cn");
537
161
  }
538
162
  }
539
163
  case "cursor":
540
- return join(home, ".cursor");
164
+ return join3(home, ".cursor");
541
165
  case "copilot":
542
- return join(home, ".copilot");
166
+ return join3(home, ".copilot");
543
167
  default:
544
168
  throw new Error(
545
169
  t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
@@ -549,24 +173,24 @@ function getConfigRoot(tool, level, base) {
549
173
  const baseDir = base || process.cwd();
550
174
  switch (tool) {
551
175
  case "opencode":
552
- return join(baseDir, ".opencode");
176
+ return join3(baseDir, ".opencode");
553
177
  case "claude":
554
- return join(baseDir, ".claude");
178
+ return join3(baseDir, ".claude");
555
179
  case "trae": {
556
180
  const variant = detectTraeVariant();
557
181
  switch (variant) {
558
182
  case "plugin":
559
- return join(baseDir, ".marscode");
183
+ return join3(baseDir, ".marscode");
560
184
  case "cli":
561
- return join(baseDir, ".traecli");
185
+ return join3(baseDir, ".traecli");
562
186
  default:
563
- return join(baseDir, ".trae");
187
+ return join3(baseDir, ".trae");
564
188
  }
565
189
  }
566
190
  case "cursor":
567
- return join(baseDir, ".cursor");
191
+ return join3(baseDir, ".cursor");
568
192
  case "copilot":
569
- return join(baseDir, ".github");
193
+ return join3(baseDir, ".github");
570
194
  default:
571
195
  throw new Error(
572
196
  t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
@@ -577,19 +201,19 @@ function getConfigFileName(tool) {
577
201
  return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
578
202
  }
579
203
  function getSkillsDir(configRoot) {
580
- return join(configRoot, "skills");
204
+ return join3(configRoot, "skills");
581
205
  }
582
206
  function getAgentsDir(configRoot) {
583
- return join(configRoot, "agents");
207
+ return join3(configRoot, "agents");
584
208
  }
585
209
  function getManifestPath(configRoot) {
586
- return join(configRoot, "cannbot-manifest.json");
210
+ return join3(configRoot, "cannbot-manifest.json");
587
211
  }
588
212
  function getCannbotConfigDir() {
589
- return join(homedir(), ".cannbot");
213
+ return join3(homedir(), ".cannbot");
590
214
  }
591
215
  function getCannbotRepoPath() {
592
- return join(getCannbotConfigDir(), "repo");
216
+ return join3(getCannbotConfigDir(), "repo");
593
217
  }
594
218
 
595
219
  // src/core/detector.ts
@@ -627,12 +251,12 @@ async function detectTrae() {
627
251
  const home = homedir2();
628
252
  const variant = detectTraeVariant();
629
253
  let path;
630
- if (variant === "ide" && existsSync2(join2(home, ".trae-cn"))) {
631
- path = join2(home, ".trae-cn");
632
- } else if (variant === "plugin" && existsSync2(join2(home, ".marscode"))) {
633
- path = join2(home, ".marscode");
634
- } else if (variant === "cli" && existsSync2(join2(home, ".traecli"))) {
635
- path = join2(home, ".traecli");
254
+ if (variant === "ide" && existsSync2(join4(home, ".trae-cn"))) {
255
+ path = join4(home, ".trae-cn");
256
+ } else if (variant === "plugin" && existsSync2(join4(home, ".marscode"))) {
257
+ path = join4(home, ".marscode");
258
+ } else if (variant === "cli" && existsSync2(join4(home, ".traecli"))) {
259
+ path = join4(home, ".traecli");
636
260
  } else if (variant === "unknown") {
637
261
  const cmdPath = await getCommandPath("trae");
638
262
  if (cmdPath) path = cmdPath;
@@ -696,13 +320,13 @@ function getAllTools() {
696
320
  }
697
321
 
698
322
  // src/core/manifest.ts
699
- import { existsSync as existsSync3, readFileSync } from "fs";
700
- import { join as join3 } from "path";
323
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
324
+ import { join as join5 } from "path";
701
325
  function readManifest(configRoot) {
702
326
  const manifestPath = getManifestPath(configRoot);
703
327
  if (existsSync3(manifestPath)) {
704
328
  try {
705
- const content = readFileSync(manifestPath, "utf-8");
329
+ const content = readFileSync3(manifestPath, "utf-8");
706
330
  return JSON.parse(content);
707
331
  } catch {
708
332
  }
@@ -715,16 +339,16 @@ function readAllManifests(configRoot) {
715
339
  const standardPath = getManifestPath(configRoot);
716
340
  if (existsSync3(standardPath)) {
717
341
  try {
718
- const content = readFileSync(standardPath, "utf-8");
342
+ const content = readFileSync3(standardPath, "utf-8");
719
343
  manifests.push(JSON.parse(content));
720
344
  } catch {
721
345
  }
722
346
  }
723
347
  for (const plugin of plugins) {
724
- const pluginManifestPath = join3(configRoot, `${plugin.id}-manifest.json`);
348
+ const pluginManifestPath = join5(configRoot, `${plugin.id}-manifest.json`);
725
349
  if (existsSync3(pluginManifestPath)) {
726
350
  try {
727
- const content = readFileSync(pluginManifestPath, "utf-8");
351
+ const content = readFileSync3(pluginManifestPath, "utf-8");
728
352
  manifests.push(JSON.parse(content));
729
353
  } catch {
730
354
  }
@@ -767,27 +391,27 @@ function scanInstalled() {
767
391
  return installed;
768
392
  }
769
393
  function verifyPluginFilesExist(configRoot, manifest, tool, level) {
770
- const skillsDir = join3(configRoot, "skills");
771
- const agentsDir = join3(configRoot, "agents");
394
+ const skillsDir = join5(configRoot, "skills");
395
+ const agentsDir = join5(configRoot, "agents");
772
396
  if (manifest.installed_skills && manifest.installed_skills.length > 0) {
773
397
  const hasAnySkill = manifest.installed_skills.some((skillId) => {
774
- const skillPath = join3(skillsDir, skillId);
398
+ const skillPath = join5(skillsDir, skillId);
775
399
  return existsSync3(skillPath);
776
400
  });
777
401
  if (!hasAnySkill) return false;
778
402
  }
779
403
  if (manifest.installed_agents && manifest.installed_agents.length > 0) {
780
404
  const hasAnyAgent = manifest.installed_agents.some((agentId) => {
781
- const agentPath = join3(agentsDir, agentId);
405
+ const agentPath = join5(agentsDir, agentId);
782
406
  return existsSync3(agentPath);
783
407
  });
784
408
  if (!hasAnyAgent) return false;
785
409
  }
786
410
  let agentsMdPath;
787
411
  if (tool === "opencode" && level === "project") {
788
- agentsMdPath = join3(configRoot, "..", "AGENTS.md");
412
+ agentsMdPath = join5(configRoot, "..", "AGENTS.md");
789
413
  } else {
790
- agentsMdPath = join3(configRoot, "AGENTS.md");
414
+ agentsMdPath = join5(configRoot, "AGENTS.md");
791
415
  }
792
416
  if (!existsSync3(agentsMdPath)) return false;
793
417
  return true;
@@ -856,15 +480,15 @@ function showOperationHints(isCheckbox = false) {
856
480
  }
857
481
 
858
482
  // src/utils/config.ts
859
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
860
- import { join as join4 } from "path";
483
+ import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
484
+ import { join as join6 } from "path";
861
485
  import { homedir as homedir3 } from "os";
862
486
  import { parse, stringify } from "yaml";
863
487
  function getConfigDir() {
864
- return join4(homedir3(), ".cannbot");
488
+ return join6(homedir3(), ".cannbot");
865
489
  }
866
490
  function getConfigPath() {
867
- return join4(getConfigDir(), "config.yaml");
491
+ return join6(getConfigDir(), "config.yaml");
868
492
  }
869
493
  function readConfig() {
870
494
  const configPath = getConfigPath();
@@ -875,7 +499,7 @@ function readConfig() {
875
499
  };
876
500
  }
877
501
  try {
878
- const content = readFileSync2(configPath, "utf-8");
502
+ const content = readFileSync4(configPath, "utf-8");
879
503
  const parsed = parse(content);
880
504
  return {
881
505
  language: parsed.language || "zh_CN",
@@ -1181,14 +805,19 @@ async function stepConfirm(tool, level, plugins) {
1181
805
  }
1182
806
 
1183
807
  // src/core/repository.ts
1184
- import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1185
- import { join as join6 } from "path";
808
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6 } from "fs";
809
+ import { join as join8, dirname as dirname4 } from "path";
810
+ import { fileURLToPath as fileURLToPath4 } from "url";
1186
811
  import { execa as execa2 } from "execa";
812
+ import { parse as parseYaml3 } from "yaml";
1187
813
 
1188
814
  // src/core/scanner.ts
1189
- import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync3, statSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1190
- import { join as join5, dirname } from "path";
1191
- import { parse as parseYaml } from "yaml";
815
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
816
+ import { join as join7, dirname as dirname3 } from "path";
817
+ import { fileURLToPath as fileURLToPath3 } from "url";
818
+ import { parse as parseYaml2 } from "yaml";
819
+ var __filename3 = fileURLToPath3(import.meta.url);
820
+ var __dirname3 = dirname3(__filename3);
1192
821
  var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
1193
822
  "node_modules",
1194
823
  ".git",
@@ -1209,36 +838,43 @@ var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
1209
838
  "docs",
1210
839
  "scripts"
1211
840
  ]);
1212
- var SKILL_SCAN_DIRS = [
1213
- "ops",
1214
- "model",
1215
- "graph",
1216
- "infra",
1217
- "ops-lab"
1218
- ];
1219
- var PLUGIN_SCAN_DIRS = [
1220
- "plugins-official",
1221
- "plugins-community"
1222
- ];
841
+ function loadScanConfig() {
842
+ const configPath = join7(__dirname3, "config", "repository.yaml");
843
+ try {
844
+ const config = parseYaml2(readFileSync5(configPath, "utf-8"));
845
+ return {
846
+ skillDirs: config.scanDirs || ["ops", "model", "graph", "infra", "ops-lab"],
847
+ pluginDirs: config.pluginDirs || ["plugins-official", "plugins-community"]
848
+ };
849
+ } catch {
850
+ return {
851
+ skillDirs: ["ops", "model", "graph", "infra", "ops-lab"],
852
+ pluginDirs: ["plugins-official", "plugins-community"]
853
+ };
854
+ }
855
+ }
856
+ var scanConfig = loadScanConfig();
857
+ var SKILL_SCAN_DIRS = scanConfig.skillDirs;
858
+ var PLUGIN_SCAN_DIRS = scanConfig.pluginDirs;
1223
859
  function scanSkills(repoPath) {
1224
860
  const skills = [];
1225
861
  const seen = /* @__PURE__ */ new Set();
1226
862
  for (const dir of SKILL_SCAN_DIRS) {
1227
- const fullPath = join5(repoPath, dir);
863
+ const fullPath = join7(repoPath, dir);
1228
864
  if (!existsSync5(fullPath)) continue;
1229
865
  scanDirectory(fullPath, repoPath, dir, skills, seen);
1230
866
  }
1231
867
  for (const pluginDir of PLUGIN_SCAN_DIRS) {
1232
- const pluginParent = join5(repoPath, pluginDir);
868
+ const pluginParent = join7(repoPath, pluginDir);
1233
869
  if (!existsSync5(pluginParent)) continue;
1234
870
  for (const plugin of safeReaddir(pluginParent)) {
1235
- const pluginPath = join5(pluginParent, plugin);
871
+ const pluginPath = join7(pluginParent, plugin);
1236
872
  if (!isDirectory(pluginPath)) continue;
1237
- const skillsDir = join5(pluginPath, "skills");
873
+ const skillsDir = join7(pluginPath, "skills");
1238
874
  if (existsSync5(skillsDir)) {
1239
875
  scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
1240
876
  }
1241
- const skillDir = join5(pluginPath, "skill");
877
+ const skillDir = join7(pluginPath, "skill");
1242
878
  if (existsSync5(skillDir)) {
1243
879
  scanDirectory(skillDir, repoPath, `${pluginDir}/${plugin}/skill`, skills, seen);
1244
880
  }
@@ -1248,7 +884,7 @@ function scanSkills(repoPath) {
1248
884
  }
1249
885
  function parseFrontmatter(filePath) {
1250
886
  try {
1251
- const content = readFileSync3(filePath, "utf-8");
887
+ const content = readFileSync5(filePath, "utf-8");
1252
888
  const lines = content.split("\n");
1253
889
  if (lines.length < 3) return null;
1254
890
  if (lines[0].trim() !== "---") return null;
@@ -1261,7 +897,7 @@ function parseFrontmatter(filePath) {
1261
897
  }
1262
898
  if (endIndex === -1) return null;
1263
899
  const yamlBlock = lines.slice(1, endIndex).map((l) => l.replace(/\r$/, "")).join("\n");
1264
- const parsed = parseYaml(yamlBlock);
900
+ const parsed = parseYaml2(yamlBlock);
1265
901
  if (!parsed || typeof parsed !== "object") return null;
1266
902
  if (!parsed.name || typeof parsed.name !== "string") return null;
1267
903
  return {
@@ -1274,17 +910,17 @@ function parseFrontmatter(filePath) {
1274
910
  }
1275
911
  function getCurrentCommit(repoPath) {
1276
912
  try {
1277
- const headFile = join5(repoPath, ".git", "HEAD");
913
+ const headFile = join7(repoPath, ".git", "HEAD");
1278
914
  if (!existsSync5(headFile)) return "unknown";
1279
- const headContent = readFileSync3(headFile, "utf-8").trim();
915
+ const headContent = readFileSync5(headFile, "utf-8").trim();
1280
916
  if (headContent.startsWith("ref: ")) {
1281
- const refPath = join5(repoPath, ".git", headContent.slice(5));
917
+ const refPath = join7(repoPath, ".git", headContent.slice(5));
1282
918
  if (existsSync5(refPath)) {
1283
- return readFileSync3(refPath, "utf-8").trim();
919
+ return readFileSync5(refPath, "utf-8").trim();
1284
920
  }
1285
- const packedRefsPath = join5(repoPath, ".git", "packed-refs");
921
+ const packedRefsPath = join7(repoPath, ".git", "packed-refs");
1286
922
  if (existsSync5(packedRefsPath)) {
1287
- const packedRefs = readFileSync3(packedRefsPath, "utf-8");
923
+ const packedRefs = readFileSync5(packedRefsPath, "utf-8");
1288
924
  const refName = headContent.slice(5);
1289
925
  const lines = packedRefs.split("\n");
1290
926
  for (const line of lines) {
@@ -1303,7 +939,7 @@ function readScanCache() {
1303
939
  try {
1304
940
  const cachePath = getCachePath();
1305
941
  if (!existsSync5(cachePath)) return null;
1306
- const content = readFileSync3(cachePath, "utf-8");
942
+ const content = readFileSync5(cachePath, "utf-8");
1307
943
  const cache = JSON.parse(content);
1308
944
  if (!cache.skills || !cache.timestamp) return null;
1309
945
  const age = Date.now() - cache.timestamp;
@@ -1316,7 +952,7 @@ function readScanCache() {
1316
952
  function writeScanCache(cache) {
1317
953
  try {
1318
954
  const cachePath = getCachePath();
1319
- const cacheDir = dirname(cachePath);
955
+ const cacheDir = dirname3(cachePath);
1320
956
  if (!existsSync5(cacheDir)) {
1321
957
  mkdirSync2(cacheDir, { recursive: true });
1322
958
  }
@@ -1325,10 +961,10 @@ function writeScanCache(cache) {
1325
961
  }
1326
962
  }
1327
963
  function getCachePath() {
1328
- return join5(getCannbotConfigDir(), "scan-cache.json");
964
+ return join7(getCannbotConfigDir(), "scan-cache.json");
1329
965
  }
1330
966
  function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1331
- const selfSkillMd = join5(dirPath, "SKILL.md");
967
+ const selfSkillMd = join7(dirPath, "SKILL.md");
1332
968
  if (existsSync5(selfSkillMd)) {
1333
969
  const frontmatter = parseFrontmatter(selfSkillMd);
1334
970
  if (frontmatter && !seen.has(frontmatter.name)) {
@@ -1343,10 +979,10 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1343
979
  return;
1344
980
  }
1345
981
  for (const entry of safeReaddir(dirPath)) {
1346
- const fullPath = join5(dirPath, entry);
982
+ const fullPath = join7(dirPath, entry);
1347
983
  if (EXCLUDE_DIRS.has(entry)) continue;
1348
984
  if (!isDirectory(fullPath)) continue;
1349
- const skillMd = join5(fullPath, "SKILL.md");
985
+ const skillMd = join7(fullPath, "SKILL.md");
1350
986
  if (existsSync5(skillMd)) {
1351
987
  const frontmatter = parseFrontmatter(skillMd);
1352
988
  if (frontmatter && !seen.has(frontmatter.name)) {
@@ -1365,7 +1001,7 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1365
1001
  }
1366
1002
  function safeReaddir(dir) {
1367
1003
  try {
1368
- return readdirSync(dir);
1004
+ return readdirSync2(dir);
1369
1005
  } catch {
1370
1006
  return [];
1371
1007
  }
@@ -1605,7 +1241,21 @@ function getAllCategories() {
1605
1241
  }
1606
1242
 
1607
1243
  // src/core/repository.ts
1608
- var REPO_URL = "https://gitcode.com/cann/cannbot-skills.git";
1244
+ var __filename4 = fileURLToPath4(import.meta.url);
1245
+ var __dirname4 = dirname4(__filename4);
1246
+ function loadRepoUrl() {
1247
+ if (process.env.CANNBOT_REPO_URL) {
1248
+ return process.env.CANNBOT_REPO_URL;
1249
+ }
1250
+ const configPath = join8(__dirname4, "config", "repository.yaml");
1251
+ try {
1252
+ const config = parseYaml3(readFileSync6(configPath, "utf-8"));
1253
+ return config.repository?.url || "https://gitcode.com/cann/cannbot-skills.git";
1254
+ } catch {
1255
+ return "https://gitcode.com/cann/cannbot-skills.git";
1256
+ }
1257
+ }
1258
+ var REPO_URL = loadRepoUrl();
1609
1259
  var RepositoryManager = class {
1610
1260
  repoPath;
1611
1261
  constructor(customPath) {
@@ -1663,8 +1313,8 @@ var RepositoryManager = class {
1663
1313
  }
1664
1314
  isValidRepo(path) {
1665
1315
  if (!existsSync6(path)) return false;
1666
- const gitDir = join6(path, ".git");
1667
- const pluginsDir = join6(path, "plugins-official");
1316
+ const gitDir = join8(path, ".git");
1317
+ const pluginsDir = join8(path, "plugins-official");
1668
1318
  return existsSync6(gitDir) && existsSync6(pluginsDir);
1669
1319
  }
1670
1320
  async cloneRepo() {
@@ -1700,17 +1350,17 @@ function createRepositoryManager(customPath) {
1700
1350
 
1701
1351
  // src/core/installer.ts
1702
1352
  import { existsSync as existsSync9 } from "fs";
1703
- import { join as join9 } from "path";
1353
+ import { join as join11 } from "path";
1704
1354
  import { execa as execa3 } from "execa";
1705
1355
 
1706
1356
  // src/core/record.ts
1707
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, lstatSync, unlinkSync } from "fs";
1708
- import { join as join7 } from "path";
1357
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, lstatSync, unlinkSync } from "fs";
1358
+ import { join as join9 } from "path";
1709
1359
  function getInstallsDir() {
1710
- return join7(getCannbotConfigDir(), "installs");
1360
+ return join9(getCannbotConfigDir(), "installs");
1711
1361
  }
1712
1362
  function getRecordPath(pluginId) {
1713
- return join7(getInstallsDir(), `${pluginId}.json`);
1363
+ return join9(getInstallsDir(), `${pluginId}.json`);
1714
1364
  }
1715
1365
  function readRecord(pluginId) {
1716
1366
  const recordPath = getRecordPath(pluginId);
@@ -1718,7 +1368,7 @@ function readRecord(pluginId) {
1718
1368
  return null;
1719
1369
  }
1720
1370
  try {
1721
- const content = readFileSync4(recordPath, "utf-8");
1371
+ const content = readFileSync7(recordPath, "utf-8");
1722
1372
  return JSON.parse(content);
1723
1373
  } catch {
1724
1374
  return null;
@@ -1742,22 +1392,22 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1742
1392
  const files = [];
1743
1393
  const directories = [];
1744
1394
  if (manifest) {
1745
- const skillsDir = join7(configRoot, "skills");
1395
+ const skillsDir = join9(configRoot, "skills");
1746
1396
  if (existsSync7(skillsDir)) {
1747
1397
  directories.push(skillsDir);
1748
1398
  for (const skillName of manifest.installed_skills || []) {
1749
- const skillPath = join7(skillsDir, skillName);
1399
+ const skillPath = join9(skillsDir, skillName);
1750
1400
  if (existsSync7(skillPath) || isSymlink(skillPath)) {
1751
1401
  files.push(skillPath);
1752
1402
  }
1753
1403
  }
1754
1404
  }
1755
- const agentsDir = join7(configRoot, "agents");
1405
+ const agentsDir = join9(configRoot, "agents");
1756
1406
  if (existsSync7(agentsDir)) {
1757
1407
  directories.push(agentsDir);
1758
1408
  for (const agentName of manifest.installed_agents || []) {
1759
- const agentPath = join7(agentsDir, agentName);
1760
- const agentPathMd = join7(agentsDir, agentName + ".md");
1409
+ const agentPath = join9(agentsDir, agentName);
1410
+ const agentPathMd = join9(agentsDir, agentName + ".md");
1761
1411
  if (existsSync7(agentPath) || isSymlink(agentPath)) {
1762
1412
  files.push(agentPath);
1763
1413
  } else if (existsSync7(agentPathMd) || isSymlink(agentPathMd)) {
@@ -1766,30 +1416,30 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1766
1416
  }
1767
1417
  }
1768
1418
  }
1769
- const workflowsLink = join7(configRoot, "workflows");
1419
+ const workflowsLink = join9(configRoot, "workflows");
1770
1420
  if (isSymlink(workflowsLink)) {
1771
1421
  files.push(workflowsLink);
1772
1422
  }
1773
- const manifestPath = join7(configRoot, "cannbot-manifest.json");
1423
+ const manifestPath = join9(configRoot, "cannbot-manifest.json");
1774
1424
  if (existsSync7(manifestPath)) {
1775
1425
  files.push(manifestPath);
1776
1426
  }
1777
- const pluginManifestPath = join7(configRoot, `${pluginId}-manifest.json`);
1427
+ const pluginManifestPath = join9(configRoot, `${pluginId}-manifest.json`);
1778
1428
  if (existsSync7(pluginManifestPath)) {
1779
1429
  files.push(pluginManifestPath);
1780
1430
  }
1781
1431
  const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1782
- const configFilePath = level === "project" ? join7(installPath, configFileName) : join7(configRoot, configFileName);
1432
+ const configFilePath = level === "project" ? join9(installPath, configFileName) : join9(configRoot, configFileName);
1783
1433
  if (existsSync7(configFilePath)) {
1784
1434
  files.push(configFilePath);
1785
1435
  }
1786
1436
  const repoLinks = ["asc-devkit", "pypto", "tilelang-ascend", "cann-recipes-infer", "cann-samples"];
1787
1437
  for (const repoName of repoLinks) {
1788
- const repoLinkPath = join7(installPath, repoName);
1438
+ const repoLinkPath = join9(installPath, repoName);
1789
1439
  if (isSymlink(repoLinkPath)) {
1790
1440
  files.push(repoLinkPath);
1791
1441
  }
1792
- const repoLinkInConfig = join7(configRoot, repoName);
1442
+ const repoLinkInConfig = join9(configRoot, repoName);
1793
1443
  if (isSymlink(repoLinkInConfig)) {
1794
1444
  files.push(repoLinkInConfig);
1795
1445
  }
@@ -1814,7 +1464,7 @@ function isSymlink(path) {
1814
1464
  }
1815
1465
  }
1816
1466
  function getSkillRecordPath() {
1817
- return join7(getInstallsDir(), "skills.json");
1467
+ return join9(getInstallsDir(), "skills.json");
1818
1468
  }
1819
1469
  function readSkillRecord() {
1820
1470
  const recordPath = getSkillRecordPath();
@@ -1822,7 +1472,7 @@ function readSkillRecord() {
1822
1472
  return {};
1823
1473
  }
1824
1474
  try {
1825
- const content = readFileSync4(recordPath, "utf-8");
1475
+ const content = readFileSync7(recordPath, "utf-8");
1826
1476
  return JSON.parse(content);
1827
1477
  } catch {
1828
1478
  return {};
@@ -1872,16 +1522,16 @@ function getInstalledSkills(tool, level, installPath) {
1872
1522
  const record = readSkillRecord();
1873
1523
  const recordedSkills = record[tool]?.[level]?.[installPath]?.skills || [];
1874
1524
  const configRoot = getConfigRoot(tool, level);
1875
- const skillsDir = join7(configRoot, "skills");
1525
+ const skillsDir = join9(configRoot, "skills");
1876
1526
  return recordedSkills.filter((skillId) => {
1877
- const skillPath = join7(skillsDir, skillId);
1527
+ const skillPath = join9(skillsDir, skillId);
1878
1528
  return existsSync7(skillPath) || isSymlink(skillPath);
1879
1529
  });
1880
1530
  }
1881
1531
 
1882
1532
  // src/core/backup.ts
1883
- import { existsSync as existsSync8, copyFileSync, readdirSync as readdirSync2, unlinkSync as unlinkSync2 } from "fs";
1884
- import { join as join8 } from "path";
1533
+ import { existsSync as existsSync8, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
1534
+ import { join as join10 } from "path";
1885
1535
  function getAgentsFileName(tool) {
1886
1536
  return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1887
1537
  }
@@ -1896,7 +1546,7 @@ function detectCurrentPlugin(configRoot, tool) {
1896
1546
  };
1897
1547
  }
1898
1548
  }
1899
- const agentsFile = join8(configRoot, getAgentsFileName(tool));
1549
+ const agentsFile = join10(configRoot, getAgentsFileName(tool));
1900
1550
  if (!existsSync8(agentsFile)) {
1901
1551
  return null;
1902
1552
  }
@@ -1915,13 +1565,13 @@ function detectCurrentPlugin(configRoot, tool) {
1915
1565
  return null;
1916
1566
  }
1917
1567
  function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
1918
- const agentsFile = join8(configRoot, getAgentsFileName(tool));
1568
+ const agentsFile = join10(configRoot, getAgentsFileName(tool));
1919
1569
  if (!existsSync8(agentsFile)) {
1920
1570
  return null;
1921
1571
  }
1922
1572
  const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
1923
1573
  const backupFileName = `${getAgentsFileName(tool)}.cannbot-backup.${fromPluginId}.${timestamp}`;
1924
- const backupPath = join8(configRoot, backupFileName);
1574
+ const backupPath = join10(configRoot, backupFileName);
1925
1575
  try {
1926
1576
  copyFileSync(agentsFile, backupPath);
1927
1577
  return {
@@ -1938,7 +1588,7 @@ function findBackups(configRoot) {
1938
1588
  if (!existsSync8(configRoot)) {
1939
1589
  return [];
1940
1590
  }
1941
- const files = readdirSync2(configRoot);
1591
+ const files = readdirSync3(configRoot);
1942
1592
  const backups = [];
1943
1593
  for (const file of files) {
1944
1594
  if (file.includes(".cannbot-backup.")) {
@@ -1951,7 +1601,7 @@ function findBackups(configRoot) {
1951
1601
  const timestamp = pluginIdAndTime.substring(lastDotIndex + 1);
1952
1602
  const plugin = findPlugin(pluginId);
1953
1603
  backups.push({
1954
- filePath: join8(configRoot, file),
1604
+ filePath: join10(configRoot, file),
1955
1605
  pluginId,
1956
1606
  pluginName: plugin?.displayName || pluginId,
1957
1607
  backupTime: timestamp
@@ -1964,7 +1614,7 @@ function findBackups(configRoot) {
1964
1614
  }
1965
1615
  function restoreBackup(backupPath, configRoot, tool) {
1966
1616
  try {
1967
- const agentsFile = join8(configRoot, getAgentsFileName(tool));
1617
+ const agentsFile = join10(configRoot, getAgentsFileName(tool));
1968
1618
  copyFileSync(backupPath, agentsFile);
1969
1619
  return true;
1970
1620
  } catch {
@@ -2065,7 +1715,7 @@ async function installPlugin(opts) {
2065
1715
  warnings: []
2066
1716
  };
2067
1717
  }
2068
- const scriptPath = join9(opts.repoPath, plugin.dir, plugin.script);
1718
+ const scriptPath = join11(opts.repoPath, plugin.dir, plugin.script);
2069
1719
  if (!existsSync9(scriptPath)) {
2070
1720
  return {
2071
1721
  success: false,
@@ -2082,7 +1732,7 @@ async function installPlugin(opts) {
2082
1732
  }
2083
1733
  const cwd = opts.installPath || process.cwd();
2084
1734
  const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
2085
- const agentsFile = join9(configRoot, getAgentsFileName(opts.tool));
1735
+ const agentsFile = join11(configRoot, getAgentsFileName(opts.tool));
2086
1736
  let backupInfo = null;
2087
1737
  if (existsSync9(agentsFile)) {
2088
1738
  const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
@@ -2177,14 +1827,14 @@ async function installPlugin(opts) {
2177
1827
  }
2178
1828
 
2179
1829
  // src/core/skill-installer.ts
2180
- import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as readdirSync3, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
2181
- import { join as join10 } from "path";
1830
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as readdirSync4, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
1831
+ import { join as join12 } from "path";
2182
1832
  import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
2183
1833
  import chalk4 from "chalk";
2184
1834
  import Table from "cli-table3";
2185
1835
  async function installSkills(skillIds, tool, level, repoPath) {
2186
1836
  const configRoot = getConfigRoot(tool, level);
2187
- const skillsDir = join10(configRoot, "skills");
1837
+ const skillsDir = join12(configRoot, "skills");
2188
1838
  const installPath = level === "project" ? process.cwd() : configRoot;
2189
1839
  if (!existsSync10(skillsDir)) {
2190
1840
  mkdirSync5(skillsDir, { recursive: true });
@@ -2197,8 +1847,8 @@ async function installSkills(skillIds, tool, level, repoPath) {
2197
1847
  results.push({ skillId, success: false, error: "Skill not found in registry" });
2198
1848
  continue;
2199
1849
  }
2200
- const sourcePath = join10(repoPath, skill.source, skill.id);
2201
- const targetPath = join10(skillsDir, skillId);
1850
+ const sourcePath = join12(repoPath, skill.source, skill.id);
1851
+ const targetPath = join12(skillsDir, skillId);
2202
1852
  if (!existsSync10(sourcePath)) {
2203
1853
  results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
2204
1854
  continue;
@@ -2221,12 +1871,12 @@ async function installSkills(skillIds, tool, level, repoPath) {
2221
1871
  }
2222
1872
  async function uninstallSkills(skillIds, tool, level) {
2223
1873
  const configRoot = getConfigRoot(tool, level);
2224
- const skillsDir = join10(configRoot, "skills");
1874
+ const skillsDir = join12(configRoot, "skills");
2225
1875
  const installPath = level === "project" ? process.cwd() : configRoot;
2226
1876
  const results = [];
2227
1877
  const removedIds = [];
2228
1878
  for (const skillId of skillIds) {
2229
- const targetPath = join10(skillsDir, skillId);
1879
+ const targetPath = join12(skillsDir, skillId);
2230
1880
  try {
2231
1881
  if (existsSync10(targetPath) || isSymlink2(targetPath)) {
2232
1882
  unlinkSync3(targetPath);
@@ -2246,7 +1896,7 @@ async function uninstallSkills(skillIds, tool, level) {
2246
1896
  }
2247
1897
  if (existsSync10(skillsDir)) {
2248
1898
  try {
2249
- const entries = readdirSync3(skillsDir);
1899
+ const entries = readdirSync4(skillsDir);
2250
1900
  if (entries.length === 0) {
2251
1901
  rmdirSync(skillsDir);
2252
1902
  logger.step(` ${t("uninstall_clean_empty_dir")}: skills/`);
@@ -2444,8 +2094,10 @@ function printEnhancedSummary(results, tool, configRoot) {
2444
2094
  ""
2445
2095
  ];
2446
2096
  if (successResults.length === 1) {
2097
+ const plugin = findPlugin(successResults[0].pluginId);
2098
+ const docsPath = plugin ? `${plugin.dir}/quickstart.md` : `${successResults[0].pluginId}/quickstart.md`;
2447
2099
  lines.push(
2448
- ` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(`plugins-official/${successResults[0].pluginId}/quickstart.md`)}`
2100
+ ` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(docsPath)}`
2449
2101
  );
2450
2102
  }
2451
2103
  console.log();
@@ -2456,15 +2108,15 @@ function printEnhancedSummary(results, tool, configRoot) {
2456
2108
  }
2457
2109
 
2458
2110
  // src/commands/init.ts
2459
- import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
2460
- import { join as join11 } from "path";
2111
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
2112
+ import { join as join13 } from "path";
2461
2113
  var BACK2 = "__back__";
2462
2114
  var CANCEL2 = "__cancel__";
2463
2115
  async function initCommand() {
2464
2116
  const cwd = process.cwd();
2465
- if (existsSync11(join11(cwd, "package.json")) && (() => {
2117
+ if (existsSync11(join13(cwd, "package.json")) && (() => {
2466
2118
  try {
2467
- const pkg = JSON.parse(readFileSync5(join11(cwd, "package.json"), "utf-8"));
2119
+ const pkg = JSON.parse(readFileSync8(join13(cwd, "package.json"), "utf-8"));
2468
2120
  return pkg.name === "@cannbot-ai/install-helper";
2469
2121
  } catch {
2470
2122
  return false;
@@ -2690,8 +2342,8 @@ async function listCommand() {
2690
2342
 
2691
2343
  // src/commands/doctor.ts
2692
2344
  import chalk7 from "chalk";
2693
- import { existsSync as existsSync12, readdirSync as readdirSync4, lstatSync as lstatSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
2694
- import { join as join12 } from "path";
2345
+ import { existsSync as existsSync12, readdirSync as readdirSync5, lstatSync as lstatSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
2346
+ import { join as join14 } from "path";
2695
2347
  async function doctorCommand(options = {}) {
2696
2348
  console.log();
2697
2349
  console.log(chalk7.bold(` ${t("doctor_title")}`));
@@ -2737,7 +2389,7 @@ async function doctorCommand(options = {}) {
2737
2389
  if (existsSync12(skillsDir)) {
2738
2390
  const brokenLinks = checkBrokenLinks(skillsDir);
2739
2391
  if (brokenLinks === 0) {
2740
- const count = readdirSync4(skillsDir).length;
2392
+ const count = readdirSync5(skillsDir).length;
2741
2393
  console.log(chalk7.green(" \u2713") + ` ${skillsDir} \u2014 ${t("doctor_links_valid").replace("{count}", String(count))}`);
2742
2394
  } else {
2743
2395
  console.log(chalk7.yellow(" \u26A0") + ` ${skillsDir} \u2014 ${t("doctor_broken_links").replace("{count}", String(brokenLinks))}`);
@@ -2759,7 +2411,7 @@ async function doctorCommand(options = {}) {
2759
2411
  if (existsSync12(agentsDir)) {
2760
2412
  const brokenLinks = checkBrokenLinks(agentsDir);
2761
2413
  if (brokenLinks === 0) {
2762
- const count = readdirSync4(agentsDir).length;
2414
+ const count = readdirSync5(agentsDir).length;
2763
2415
  console.log(chalk7.green(" \u2713") + ` ${agentsDir} \u2014 ${t("doctor_links_valid").replace("{count}", String(count))}`);
2764
2416
  } else {
2765
2417
  console.log(chalk7.yellow(" \u26A0") + ` ${agentsDir} \u2014 ${t("doctor_broken_links").replace("{count}", String(brokenLinks))}`);
@@ -2781,7 +2433,7 @@ async function doctorCommand(options = {}) {
2781
2433
  console.log();
2782
2434
  console.log(chalk7.bold(` ${t("doctor_config")}`));
2783
2435
  const configFile = getConfigFileName(primaryTool);
2784
- const configPath = join12(process.cwd(), configFile);
2436
+ const configPath = join14(process.cwd(), configFile);
2785
2437
  if (existsSync12(configPath)) {
2786
2438
  console.log(chalk7.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
2787
2439
  } else {
@@ -2803,9 +2455,9 @@ async function doctorCommand(options = {}) {
2803
2455
  function checkBrokenLinks(dir) {
2804
2456
  let broken = 0;
2805
2457
  try {
2806
- const entries = readdirSync4(dir);
2458
+ const entries = readdirSync5(dir);
2807
2459
  for (const entry of entries) {
2808
- const fullPath = join12(dir, entry);
2460
+ const fullPath = join14(dir, entry);
2809
2461
  try {
2810
2462
  const stats = lstatSync3(fullPath);
2811
2463
  if (stats.isSymbolicLink()) {
@@ -2824,9 +2476,9 @@ function checkBrokenLinks(dir) {
2824
2476
  function fixBrokenLinks(dir) {
2825
2477
  let fixed = 0;
2826
2478
  try {
2827
- const entries = readdirSync4(dir);
2479
+ const entries = readdirSync5(dir);
2828
2480
  for (const entry of entries) {
2829
- const fullPath = join12(dir, entry);
2481
+ const fullPath = join14(dir, entry);
2830
2482
  try {
2831
2483
  const stats = lstatSync3(fullPath);
2832
2484
  if (stats.isSymbolicLink()) {
@@ -3105,7 +2757,7 @@ async function installPlugins(pluginIds, tool, level, repoPath) {
3105
2757
  }
3106
2758
 
3107
2759
  // src/commands/uninstall.ts
3108
- import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync5, lstatSync as lstatSync4 } from "fs";
2760
+ import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync6, lstatSync as lstatSync4 } from "fs";
3109
2761
  import chalk10 from "chalk";
3110
2762
  async function uninstallCommand(names, options) {
3111
2763
  const tool = options.tool ? validateTool(options.tool) : "opencode";
@@ -3156,7 +2808,7 @@ async function uninstallCommand(names, options) {
3156
2808
  continue;
3157
2809
  }
3158
2810
  if (existsSync13(dirPath)) {
3159
- const entries = readdirSync5(dirPath);
2811
+ const entries = readdirSync6(dirPath);
3160
2812
  if (entries.length === 0) {
3161
2813
  rmdirSync2(dirPath);
3162
2814
  const name = dirPath.split("/").pop() || dirPath;
@@ -3300,8 +2952,8 @@ async function updateCommand(pluginNames, options) {
3300
2952
 
3301
2953
  // src/commands/info.ts
3302
2954
  import chalk12 from "chalk";
3303
- import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
3304
- import { join as join13 } from "path";
2955
+ import { existsSync as existsSync14, readdirSync as readdirSync7 } from "fs";
2956
+ import { join as join15 } from "path";
3305
2957
  async function infoCommand(pluginName) {
3306
2958
  const plugin = findPlugin(pluginName);
3307
2959
  if (!plugin) {
@@ -3325,13 +2977,13 @@ async function infoCommand(pluginName) {
3325
2977
  try {
3326
2978
  const repoManager = createRepositoryManager();
3327
2979
  const repoPath = await repoManager.ensureRepo();
3328
- const quickstartPath = join13(repoPath, plugin.dir, "quickstart.md");
2980
+ const quickstartPath = join15(repoPath, plugin.dir, "quickstart.md");
3329
2981
  if (existsSync14(quickstartPath)) {
3330
2982
  console.log(` ${chalk12.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
3331
2983
  }
3332
- const agentsDir = join13(repoPath, plugin.dir, "agents");
2984
+ const agentsDir = join15(repoPath, plugin.dir, "agents");
3333
2985
  if (existsSync14(agentsDir)) {
3334
- const agentFiles = readdirSync6(agentsDir).filter((f) => f.endsWith(".md"));
2986
+ const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
3335
2987
  if (agentFiles.length > 0) {
3336
2988
  console.log();
3337
2989
  console.log(` ${chalk12.bold("Agents:")}`);
@@ -3388,7 +3040,7 @@ function createCLI() {
3388
3040
  setLanguage(config.language);
3389
3041
  }
3390
3042
  const program2 = new Command();
3391
- program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("1.0.2");
3043
+ program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("1.0.4");
3392
3044
  program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
3393
3045
  await initCommand();
3394
3046
  });