@cannbot-ai/install-helper 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12,108 +12,45 @@ 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
+ return plugins;
52
+ }
53
+ var PLUGIN_REGISTRY = loadPluginsFromYaml();
117
54
  function findPlugin(query) {
118
55
  const normalized = query.toLowerCase().trim();
119
56
  const exactMatch = PLUGIN_REGISTRY.find(
@@ -139,356 +76,42 @@ function getPluginById(id) {
139
76
  import { execa } from "execa";
140
77
  import { existsSync as existsSync2 } from "fs";
141
78
  import { homedir as homedir2 } from "os";
142
- import { join as join2 } from "path";
79
+ import { join as join4 } from "path";
143
80
 
144
81
  // src/utils/paths.ts
145
82
  import { homedir } from "os";
146
- import { join } from "path";
83
+ import { join as join3 } from "path";
147
84
  import { existsSync } from "fs";
148
85
 
149
86
  // 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
- };
87
+ import { readFileSync as readFileSync2 } from "fs";
88
+ import { join as join2, dirname as dirname2 } from "path";
89
+ import { fileURLToPath as fileURLToPath2 } from "url";
90
+ var __filename2 = fileURLToPath2(import.meta.url);
91
+ var __dirname2 = dirname2(__filename2);
92
+ function loadLocale(locale) {
93
+ const localePath = join2(__dirname2, "locales", `${locale}.json`);
94
+ try {
95
+ const content = readFileSync2(localePath, "utf-8");
96
+ return JSON.parse(content);
97
+ } catch {
98
+ const fallbackPath = join2(__dirname2, "locales", "zh_CN.json");
99
+ try {
100
+ const content = readFileSync2(fallbackPath, "utf-8");
101
+ return JSON.parse(content);
102
+ } catch {
103
+ return {};
104
+ }
105
+ }
106
+ }
486
107
  var currentLang = "zh_CN";
108
+ var messages = loadLocale("zh_CN");
487
109
  function setLanguage(lang) {
488
110
  currentLang = lang;
111
+ messages = loadLocale(lang);
489
112
  }
490
113
  function t(key) {
491
- return currentLang === "zh_CN" ? zh_CN[key] : en_US[key];
114
+ return messages[key] !== void 0 ? messages[key] : key;
492
115
  }
493
116
 
494
117
  // src/utils/paths.ts
@@ -512,9 +135,9 @@ function validateLevel(level) {
512
135
  }
513
136
  function detectTraeVariant() {
514
137
  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";
138
+ if (existsSync(join3(home, ".trae-cn"))) return "ide";
139
+ if (existsSync(join3(home, ".marscode"))) return "plugin";
140
+ if (existsSync(join3(home, ".traecli"))) return "cli";
518
141
  return "unknown";
519
142
  }
520
143
  function getConfigRoot(tool, level, base) {
@@ -522,24 +145,24 @@ function getConfigRoot(tool, level, base) {
522
145
  if (level === "global") {
523
146
  switch (tool) {
524
147
  case "opencode":
525
- return join(home, ".config", "opencode");
148
+ return join3(home, ".config", "opencode");
526
149
  case "claude":
527
- return join(home, ".claude");
150
+ return join3(home, ".claude");
528
151
  case "trae": {
529
152
  const variant = detectTraeVariant();
530
153
  switch (variant) {
531
154
  case "plugin":
532
- return join(home, ".marscode");
155
+ return join3(home, ".marscode");
533
156
  case "cli":
534
- return join(home, ".traecli");
157
+ return join3(home, ".traecli");
535
158
  default:
536
- return join(home, ".trae-cn");
159
+ return join3(home, ".trae-cn");
537
160
  }
538
161
  }
539
162
  case "cursor":
540
- return join(home, ".cursor");
163
+ return join3(home, ".cursor");
541
164
  case "copilot":
542
- return join(home, ".copilot");
165
+ return join3(home, ".copilot");
543
166
  default:
544
167
  throw new Error(
545
168
  t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
@@ -549,24 +172,24 @@ function getConfigRoot(tool, level, base) {
549
172
  const baseDir = base || process.cwd();
550
173
  switch (tool) {
551
174
  case "opencode":
552
- return join(baseDir, ".opencode");
175
+ return join3(baseDir, ".opencode");
553
176
  case "claude":
554
- return join(baseDir, ".claude");
177
+ return join3(baseDir, ".claude");
555
178
  case "trae": {
556
179
  const variant = detectTraeVariant();
557
180
  switch (variant) {
558
181
  case "plugin":
559
- return join(baseDir, ".marscode");
182
+ return join3(baseDir, ".marscode");
560
183
  case "cli":
561
- return join(baseDir, ".traecli");
184
+ return join3(baseDir, ".traecli");
562
185
  default:
563
- return join(baseDir, ".trae");
186
+ return join3(baseDir, ".trae");
564
187
  }
565
188
  }
566
189
  case "cursor":
567
- return join(baseDir, ".cursor");
190
+ return join3(baseDir, ".cursor");
568
191
  case "copilot":
569
- return join(baseDir, ".github");
192
+ return join3(baseDir, ".github");
570
193
  default:
571
194
  throw new Error(
572
195
  t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
@@ -577,19 +200,19 @@ function getConfigFileName(tool) {
577
200
  return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
578
201
  }
579
202
  function getSkillsDir(configRoot) {
580
- return join(configRoot, "skills");
203
+ return join3(configRoot, "skills");
581
204
  }
582
205
  function getAgentsDir(configRoot) {
583
- return join(configRoot, "agents");
206
+ return join3(configRoot, "agents");
584
207
  }
585
208
  function getManifestPath(configRoot) {
586
- return join(configRoot, "cannbot-manifest.json");
209
+ return join3(configRoot, "cannbot-manifest.json");
587
210
  }
588
211
  function getCannbotConfigDir() {
589
- return join(homedir(), ".cannbot");
212
+ return join3(homedir(), ".cannbot");
590
213
  }
591
214
  function getCannbotRepoPath() {
592
- return join(getCannbotConfigDir(), "repo");
215
+ return join3(getCannbotConfigDir(), "repo");
593
216
  }
594
217
 
595
218
  // src/core/detector.ts
@@ -627,12 +250,12 @@ async function detectTrae() {
627
250
  const home = homedir2();
628
251
  const variant = detectTraeVariant();
629
252
  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");
253
+ if (variant === "ide" && existsSync2(join4(home, ".trae-cn"))) {
254
+ path = join4(home, ".trae-cn");
255
+ } else if (variant === "plugin" && existsSync2(join4(home, ".marscode"))) {
256
+ path = join4(home, ".marscode");
257
+ } else if (variant === "cli" && existsSync2(join4(home, ".traecli"))) {
258
+ path = join4(home, ".traecli");
636
259
  } else if (variant === "unknown") {
637
260
  const cmdPath = await getCommandPath("trae");
638
261
  if (cmdPath) path = cmdPath;
@@ -696,13 +319,13 @@ function getAllTools() {
696
319
  }
697
320
 
698
321
  // src/core/manifest.ts
699
- import { existsSync as existsSync3, readFileSync } from "fs";
700
- import { join as join3 } from "path";
322
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
323
+ import { join as join5 } from "path";
701
324
  function readManifest(configRoot) {
702
325
  const manifestPath = getManifestPath(configRoot);
703
326
  if (existsSync3(manifestPath)) {
704
327
  try {
705
- const content = readFileSync(manifestPath, "utf-8");
328
+ const content = readFileSync3(manifestPath, "utf-8");
706
329
  return JSON.parse(content);
707
330
  } catch {
708
331
  }
@@ -715,16 +338,16 @@ function readAllManifests(configRoot) {
715
338
  const standardPath = getManifestPath(configRoot);
716
339
  if (existsSync3(standardPath)) {
717
340
  try {
718
- const content = readFileSync(standardPath, "utf-8");
341
+ const content = readFileSync3(standardPath, "utf-8");
719
342
  manifests.push(JSON.parse(content));
720
343
  } catch {
721
344
  }
722
345
  }
723
346
  for (const plugin of plugins) {
724
- const pluginManifestPath = join3(configRoot, `${plugin.id}-manifest.json`);
347
+ const pluginManifestPath = join5(configRoot, `${plugin.id}-manifest.json`);
725
348
  if (existsSync3(pluginManifestPath)) {
726
349
  try {
727
- const content = readFileSync(pluginManifestPath, "utf-8");
350
+ const content = readFileSync3(pluginManifestPath, "utf-8");
728
351
  manifests.push(JSON.parse(content));
729
352
  } catch {
730
353
  }
@@ -767,27 +390,27 @@ function scanInstalled() {
767
390
  return installed;
768
391
  }
769
392
  function verifyPluginFilesExist(configRoot, manifest, tool, level) {
770
- const skillsDir = join3(configRoot, "skills");
771
- const agentsDir = join3(configRoot, "agents");
393
+ const skillsDir = join5(configRoot, "skills");
394
+ const agentsDir = join5(configRoot, "agents");
772
395
  if (manifest.installed_skills && manifest.installed_skills.length > 0) {
773
396
  const hasAnySkill = manifest.installed_skills.some((skillId) => {
774
- const skillPath = join3(skillsDir, skillId);
397
+ const skillPath = join5(skillsDir, skillId);
775
398
  return existsSync3(skillPath);
776
399
  });
777
400
  if (!hasAnySkill) return false;
778
401
  }
779
402
  if (manifest.installed_agents && manifest.installed_agents.length > 0) {
780
403
  const hasAnyAgent = manifest.installed_agents.some((agentId) => {
781
- const agentPath = join3(agentsDir, agentId);
404
+ const agentPath = join5(agentsDir, agentId);
782
405
  return existsSync3(agentPath);
783
406
  });
784
407
  if (!hasAnyAgent) return false;
785
408
  }
786
409
  let agentsMdPath;
787
410
  if (tool === "opencode" && level === "project") {
788
- agentsMdPath = join3(configRoot, "..", "AGENTS.md");
411
+ agentsMdPath = join5(configRoot, "..", "AGENTS.md");
789
412
  } else {
790
- agentsMdPath = join3(configRoot, "AGENTS.md");
413
+ agentsMdPath = join5(configRoot, "AGENTS.md");
791
414
  }
792
415
  if (!existsSync3(agentsMdPath)) return false;
793
416
  return true;
@@ -856,15 +479,15 @@ function showOperationHints(isCheckbox = false) {
856
479
  }
857
480
 
858
481
  // src/utils/config.ts
859
- import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync2, writeFileSync } from "fs";
860
- import { join as join4 } from "path";
482
+ import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
483
+ import { join as join6 } from "path";
861
484
  import { homedir as homedir3 } from "os";
862
485
  import { parse, stringify } from "yaml";
863
486
  function getConfigDir() {
864
- return join4(homedir3(), ".cannbot");
487
+ return join6(homedir3(), ".cannbot");
865
488
  }
866
489
  function getConfigPath() {
867
- return join4(getConfigDir(), "config.yaml");
490
+ return join6(getConfigDir(), "config.yaml");
868
491
  }
869
492
  function readConfig() {
870
493
  const configPath = getConfigPath();
@@ -875,7 +498,7 @@ function readConfig() {
875
498
  };
876
499
  }
877
500
  try {
878
- const content = readFileSync2(configPath, "utf-8");
501
+ const content = readFileSync4(configPath, "utf-8");
879
502
  const parsed = parse(content);
880
503
  return {
881
504
  language: parsed.language || "zh_CN",
@@ -1181,14 +804,19 @@ async function stepConfirm(tool, level, plugins) {
1181
804
  }
1182
805
 
1183
806
  // src/core/repository.ts
1184
- import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
1185
- import { join as join6 } from "path";
807
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync6 } from "fs";
808
+ import { join as join8, dirname as dirname4 } from "path";
809
+ import { fileURLToPath as fileURLToPath4 } from "url";
1186
810
  import { execa as execa2 } from "execa";
811
+ import { parse as parseYaml3 } from "yaml";
1187
812
 
1188
813
  // 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";
814
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
815
+ import { join as join7, dirname as dirname3 } from "path";
816
+ import { fileURLToPath as fileURLToPath3 } from "url";
817
+ import { parse as parseYaml2 } from "yaml";
818
+ var __filename3 = fileURLToPath3(import.meta.url);
819
+ var __dirname3 = dirname3(__filename3);
1192
820
  var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
1193
821
  "node_modules",
1194
822
  ".git",
@@ -1209,36 +837,43 @@ var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
1209
837
  "docs",
1210
838
  "scripts"
1211
839
  ]);
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
- ];
840
+ function loadScanConfig() {
841
+ const configPath = join7(__dirname3, "config", "repository.yaml");
842
+ try {
843
+ const config = parseYaml2(readFileSync5(configPath, "utf-8"));
844
+ return {
845
+ skillDirs: config.scanDirs || ["ops", "model", "graph", "infra", "ops-lab"],
846
+ pluginDirs: config.pluginDirs || ["plugins-official", "plugins-community"]
847
+ };
848
+ } catch {
849
+ return {
850
+ skillDirs: ["ops", "model", "graph", "infra", "ops-lab"],
851
+ pluginDirs: ["plugins-official", "plugins-community"]
852
+ };
853
+ }
854
+ }
855
+ var scanConfig = loadScanConfig();
856
+ var SKILL_SCAN_DIRS = scanConfig.skillDirs;
857
+ var PLUGIN_SCAN_DIRS = scanConfig.pluginDirs;
1223
858
  function scanSkills(repoPath) {
1224
859
  const skills = [];
1225
860
  const seen = /* @__PURE__ */ new Set();
1226
861
  for (const dir of SKILL_SCAN_DIRS) {
1227
- const fullPath = join5(repoPath, dir);
862
+ const fullPath = join7(repoPath, dir);
1228
863
  if (!existsSync5(fullPath)) continue;
1229
864
  scanDirectory(fullPath, repoPath, dir, skills, seen);
1230
865
  }
1231
866
  for (const pluginDir of PLUGIN_SCAN_DIRS) {
1232
- const pluginParent = join5(repoPath, pluginDir);
867
+ const pluginParent = join7(repoPath, pluginDir);
1233
868
  if (!existsSync5(pluginParent)) continue;
1234
869
  for (const plugin of safeReaddir(pluginParent)) {
1235
- const pluginPath = join5(pluginParent, plugin);
870
+ const pluginPath = join7(pluginParent, plugin);
1236
871
  if (!isDirectory(pluginPath)) continue;
1237
- const skillsDir = join5(pluginPath, "skills");
872
+ const skillsDir = join7(pluginPath, "skills");
1238
873
  if (existsSync5(skillsDir)) {
1239
874
  scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
1240
875
  }
1241
- const skillDir = join5(pluginPath, "skill");
876
+ const skillDir = join7(pluginPath, "skill");
1242
877
  if (existsSync5(skillDir)) {
1243
878
  scanDirectory(skillDir, repoPath, `${pluginDir}/${plugin}/skill`, skills, seen);
1244
879
  }
@@ -1248,7 +883,7 @@ function scanSkills(repoPath) {
1248
883
  }
1249
884
  function parseFrontmatter(filePath) {
1250
885
  try {
1251
- const content = readFileSync3(filePath, "utf-8");
886
+ const content = readFileSync5(filePath, "utf-8");
1252
887
  const lines = content.split("\n");
1253
888
  if (lines.length < 3) return null;
1254
889
  if (lines[0].trim() !== "---") return null;
@@ -1261,7 +896,7 @@ function parseFrontmatter(filePath) {
1261
896
  }
1262
897
  if (endIndex === -1) return null;
1263
898
  const yamlBlock = lines.slice(1, endIndex).map((l) => l.replace(/\r$/, "")).join("\n");
1264
- const parsed = parseYaml(yamlBlock);
899
+ const parsed = parseYaml2(yamlBlock);
1265
900
  if (!parsed || typeof parsed !== "object") return null;
1266
901
  if (!parsed.name || typeof parsed.name !== "string") return null;
1267
902
  return {
@@ -1274,17 +909,17 @@ function parseFrontmatter(filePath) {
1274
909
  }
1275
910
  function getCurrentCommit(repoPath) {
1276
911
  try {
1277
- const headFile = join5(repoPath, ".git", "HEAD");
912
+ const headFile = join7(repoPath, ".git", "HEAD");
1278
913
  if (!existsSync5(headFile)) return "unknown";
1279
- const headContent = readFileSync3(headFile, "utf-8").trim();
914
+ const headContent = readFileSync5(headFile, "utf-8").trim();
1280
915
  if (headContent.startsWith("ref: ")) {
1281
- const refPath = join5(repoPath, ".git", headContent.slice(5));
916
+ const refPath = join7(repoPath, ".git", headContent.slice(5));
1282
917
  if (existsSync5(refPath)) {
1283
- return readFileSync3(refPath, "utf-8").trim();
918
+ return readFileSync5(refPath, "utf-8").trim();
1284
919
  }
1285
- const packedRefsPath = join5(repoPath, ".git", "packed-refs");
920
+ const packedRefsPath = join7(repoPath, ".git", "packed-refs");
1286
921
  if (existsSync5(packedRefsPath)) {
1287
- const packedRefs = readFileSync3(packedRefsPath, "utf-8");
922
+ const packedRefs = readFileSync5(packedRefsPath, "utf-8");
1288
923
  const refName = headContent.slice(5);
1289
924
  const lines = packedRefs.split("\n");
1290
925
  for (const line of lines) {
@@ -1303,7 +938,7 @@ function readScanCache() {
1303
938
  try {
1304
939
  const cachePath = getCachePath();
1305
940
  if (!existsSync5(cachePath)) return null;
1306
- const content = readFileSync3(cachePath, "utf-8");
941
+ const content = readFileSync5(cachePath, "utf-8");
1307
942
  const cache = JSON.parse(content);
1308
943
  if (!cache.skills || !cache.timestamp) return null;
1309
944
  const age = Date.now() - cache.timestamp;
@@ -1316,7 +951,7 @@ function readScanCache() {
1316
951
  function writeScanCache(cache) {
1317
952
  try {
1318
953
  const cachePath = getCachePath();
1319
- const cacheDir = dirname(cachePath);
954
+ const cacheDir = dirname3(cachePath);
1320
955
  if (!existsSync5(cacheDir)) {
1321
956
  mkdirSync2(cacheDir, { recursive: true });
1322
957
  }
@@ -1325,10 +960,10 @@ function writeScanCache(cache) {
1325
960
  }
1326
961
  }
1327
962
  function getCachePath() {
1328
- return join5(getCannbotConfigDir(), "scan-cache.json");
963
+ return join7(getCannbotConfigDir(), "scan-cache.json");
1329
964
  }
1330
965
  function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1331
- const selfSkillMd = join5(dirPath, "SKILL.md");
966
+ const selfSkillMd = join7(dirPath, "SKILL.md");
1332
967
  if (existsSync5(selfSkillMd)) {
1333
968
  const frontmatter = parseFrontmatter(selfSkillMd);
1334
969
  if (frontmatter && !seen.has(frontmatter.name)) {
@@ -1343,10 +978,10 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1343
978
  return;
1344
979
  }
1345
980
  for (const entry of safeReaddir(dirPath)) {
1346
- const fullPath = join5(dirPath, entry);
981
+ const fullPath = join7(dirPath, entry);
1347
982
  if (EXCLUDE_DIRS.has(entry)) continue;
1348
983
  if (!isDirectory(fullPath)) continue;
1349
- const skillMd = join5(fullPath, "SKILL.md");
984
+ const skillMd = join7(fullPath, "SKILL.md");
1350
985
  if (existsSync5(skillMd)) {
1351
986
  const frontmatter = parseFrontmatter(skillMd);
1352
987
  if (frontmatter && !seen.has(frontmatter.name)) {
@@ -1365,7 +1000,7 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1365
1000
  }
1366
1001
  function safeReaddir(dir) {
1367
1002
  try {
1368
- return readdirSync(dir);
1003
+ return readdirSync2(dir);
1369
1004
  } catch {
1370
1005
  return [];
1371
1006
  }
@@ -1605,7 +1240,21 @@ function getAllCategories() {
1605
1240
  }
1606
1241
 
1607
1242
  // src/core/repository.ts
1608
- var REPO_URL = "https://gitcode.com/cann/cannbot-skills.git";
1243
+ var __filename4 = fileURLToPath4(import.meta.url);
1244
+ var __dirname4 = dirname4(__filename4);
1245
+ function loadRepoUrl() {
1246
+ if (process.env.CANNBOT_REPO_URL) {
1247
+ return process.env.CANNBOT_REPO_URL;
1248
+ }
1249
+ const configPath = join8(__dirname4, "config", "repository.yaml");
1250
+ try {
1251
+ const config = parseYaml3(readFileSync6(configPath, "utf-8"));
1252
+ return config.repository?.url || "https://gitcode.com/cann/cannbot-skills.git";
1253
+ } catch {
1254
+ return "https://gitcode.com/cann/cannbot-skills.git";
1255
+ }
1256
+ }
1257
+ var REPO_URL = loadRepoUrl();
1609
1258
  var RepositoryManager = class {
1610
1259
  repoPath;
1611
1260
  constructor(customPath) {
@@ -1663,8 +1312,8 @@ var RepositoryManager = class {
1663
1312
  }
1664
1313
  isValidRepo(path) {
1665
1314
  if (!existsSync6(path)) return false;
1666
- const gitDir = join6(path, ".git");
1667
- const pluginsDir = join6(path, "plugins-official");
1315
+ const gitDir = join8(path, ".git");
1316
+ const pluginsDir = join8(path, "plugins-official");
1668
1317
  return existsSync6(gitDir) && existsSync6(pluginsDir);
1669
1318
  }
1670
1319
  async cloneRepo() {
@@ -1700,17 +1349,17 @@ function createRepositoryManager(customPath) {
1700
1349
 
1701
1350
  // src/core/installer.ts
1702
1351
  import { existsSync as existsSync9 } from "fs";
1703
- import { join as join9 } from "path";
1352
+ import { join as join11 } from "path";
1704
1353
  import { execa as execa3 } from "execa";
1705
1354
 
1706
1355
  // 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";
1356
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, lstatSync, unlinkSync } from "fs";
1357
+ import { join as join9 } from "path";
1709
1358
  function getInstallsDir() {
1710
- return join7(getCannbotConfigDir(), "installs");
1359
+ return join9(getCannbotConfigDir(), "installs");
1711
1360
  }
1712
1361
  function getRecordPath(pluginId) {
1713
- return join7(getInstallsDir(), `${pluginId}.json`);
1362
+ return join9(getInstallsDir(), `${pluginId}.json`);
1714
1363
  }
1715
1364
  function readRecord(pluginId) {
1716
1365
  const recordPath = getRecordPath(pluginId);
@@ -1718,7 +1367,7 @@ function readRecord(pluginId) {
1718
1367
  return null;
1719
1368
  }
1720
1369
  try {
1721
- const content = readFileSync4(recordPath, "utf-8");
1370
+ const content = readFileSync7(recordPath, "utf-8");
1722
1371
  return JSON.parse(content);
1723
1372
  } catch {
1724
1373
  return null;
@@ -1742,22 +1391,22 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1742
1391
  const files = [];
1743
1392
  const directories = [];
1744
1393
  if (manifest) {
1745
- const skillsDir = join7(configRoot, "skills");
1394
+ const skillsDir = join9(configRoot, "skills");
1746
1395
  if (existsSync7(skillsDir)) {
1747
1396
  directories.push(skillsDir);
1748
1397
  for (const skillName of manifest.installed_skills || []) {
1749
- const skillPath = join7(skillsDir, skillName);
1398
+ const skillPath = join9(skillsDir, skillName);
1750
1399
  if (existsSync7(skillPath) || isSymlink(skillPath)) {
1751
1400
  files.push(skillPath);
1752
1401
  }
1753
1402
  }
1754
1403
  }
1755
- const agentsDir = join7(configRoot, "agents");
1404
+ const agentsDir = join9(configRoot, "agents");
1756
1405
  if (existsSync7(agentsDir)) {
1757
1406
  directories.push(agentsDir);
1758
1407
  for (const agentName of manifest.installed_agents || []) {
1759
- const agentPath = join7(agentsDir, agentName);
1760
- const agentPathMd = join7(agentsDir, agentName + ".md");
1408
+ const agentPath = join9(agentsDir, agentName);
1409
+ const agentPathMd = join9(agentsDir, agentName + ".md");
1761
1410
  if (existsSync7(agentPath) || isSymlink(agentPath)) {
1762
1411
  files.push(agentPath);
1763
1412
  } else if (existsSync7(agentPathMd) || isSymlink(agentPathMd)) {
@@ -1766,30 +1415,30 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1766
1415
  }
1767
1416
  }
1768
1417
  }
1769
- const workflowsLink = join7(configRoot, "workflows");
1418
+ const workflowsLink = join9(configRoot, "workflows");
1770
1419
  if (isSymlink(workflowsLink)) {
1771
1420
  files.push(workflowsLink);
1772
1421
  }
1773
- const manifestPath = join7(configRoot, "cannbot-manifest.json");
1422
+ const manifestPath = join9(configRoot, "cannbot-manifest.json");
1774
1423
  if (existsSync7(manifestPath)) {
1775
1424
  files.push(manifestPath);
1776
1425
  }
1777
- const pluginManifestPath = join7(configRoot, `${pluginId}-manifest.json`);
1426
+ const pluginManifestPath = join9(configRoot, `${pluginId}-manifest.json`);
1778
1427
  if (existsSync7(pluginManifestPath)) {
1779
1428
  files.push(pluginManifestPath);
1780
1429
  }
1781
1430
  const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1782
- const configFilePath = level === "project" ? join7(installPath, configFileName) : join7(configRoot, configFileName);
1431
+ const configFilePath = level === "project" ? join9(installPath, configFileName) : join9(configRoot, configFileName);
1783
1432
  if (existsSync7(configFilePath)) {
1784
1433
  files.push(configFilePath);
1785
1434
  }
1786
1435
  const repoLinks = ["asc-devkit", "pypto", "tilelang-ascend", "cann-recipes-infer", "cann-samples"];
1787
1436
  for (const repoName of repoLinks) {
1788
- const repoLinkPath = join7(installPath, repoName);
1437
+ const repoLinkPath = join9(installPath, repoName);
1789
1438
  if (isSymlink(repoLinkPath)) {
1790
1439
  files.push(repoLinkPath);
1791
1440
  }
1792
- const repoLinkInConfig = join7(configRoot, repoName);
1441
+ const repoLinkInConfig = join9(configRoot, repoName);
1793
1442
  if (isSymlink(repoLinkInConfig)) {
1794
1443
  files.push(repoLinkInConfig);
1795
1444
  }
@@ -1814,7 +1463,7 @@ function isSymlink(path) {
1814
1463
  }
1815
1464
  }
1816
1465
  function getSkillRecordPath() {
1817
- return join7(getInstallsDir(), "skills.json");
1466
+ return join9(getInstallsDir(), "skills.json");
1818
1467
  }
1819
1468
  function readSkillRecord() {
1820
1469
  const recordPath = getSkillRecordPath();
@@ -1822,7 +1471,7 @@ function readSkillRecord() {
1822
1471
  return {};
1823
1472
  }
1824
1473
  try {
1825
- const content = readFileSync4(recordPath, "utf-8");
1474
+ const content = readFileSync7(recordPath, "utf-8");
1826
1475
  return JSON.parse(content);
1827
1476
  } catch {
1828
1477
  return {};
@@ -1872,16 +1521,16 @@ function getInstalledSkills(tool, level, installPath) {
1872
1521
  const record = readSkillRecord();
1873
1522
  const recordedSkills = record[tool]?.[level]?.[installPath]?.skills || [];
1874
1523
  const configRoot = getConfigRoot(tool, level);
1875
- const skillsDir = join7(configRoot, "skills");
1524
+ const skillsDir = join9(configRoot, "skills");
1876
1525
  return recordedSkills.filter((skillId) => {
1877
- const skillPath = join7(skillsDir, skillId);
1526
+ const skillPath = join9(skillsDir, skillId);
1878
1527
  return existsSync7(skillPath) || isSymlink(skillPath);
1879
1528
  });
1880
1529
  }
1881
1530
 
1882
1531
  // 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";
1532
+ import { existsSync as existsSync8, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
1533
+ import { join as join10 } from "path";
1885
1534
  function getAgentsFileName(tool) {
1886
1535
  return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1887
1536
  }
@@ -1896,7 +1545,7 @@ function detectCurrentPlugin(configRoot, tool) {
1896
1545
  };
1897
1546
  }
1898
1547
  }
1899
- const agentsFile = join8(configRoot, getAgentsFileName(tool));
1548
+ const agentsFile = join10(configRoot, getAgentsFileName(tool));
1900
1549
  if (!existsSync8(agentsFile)) {
1901
1550
  return null;
1902
1551
  }
@@ -1915,13 +1564,13 @@ function detectCurrentPlugin(configRoot, tool) {
1915
1564
  return null;
1916
1565
  }
1917
1566
  function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
1918
- const agentsFile = join8(configRoot, getAgentsFileName(tool));
1567
+ const agentsFile = join10(configRoot, getAgentsFileName(tool));
1919
1568
  if (!existsSync8(agentsFile)) {
1920
1569
  return null;
1921
1570
  }
1922
1571
  const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
1923
1572
  const backupFileName = `${getAgentsFileName(tool)}.cannbot-backup.${fromPluginId}.${timestamp}`;
1924
- const backupPath = join8(configRoot, backupFileName);
1573
+ const backupPath = join10(configRoot, backupFileName);
1925
1574
  try {
1926
1575
  copyFileSync(agentsFile, backupPath);
1927
1576
  return {
@@ -1938,7 +1587,7 @@ function findBackups(configRoot) {
1938
1587
  if (!existsSync8(configRoot)) {
1939
1588
  return [];
1940
1589
  }
1941
- const files = readdirSync2(configRoot);
1590
+ const files = readdirSync3(configRoot);
1942
1591
  const backups = [];
1943
1592
  for (const file of files) {
1944
1593
  if (file.includes(".cannbot-backup.")) {
@@ -1951,7 +1600,7 @@ function findBackups(configRoot) {
1951
1600
  const timestamp = pluginIdAndTime.substring(lastDotIndex + 1);
1952
1601
  const plugin = findPlugin(pluginId);
1953
1602
  backups.push({
1954
- filePath: join8(configRoot, file),
1603
+ filePath: join10(configRoot, file),
1955
1604
  pluginId,
1956
1605
  pluginName: plugin?.displayName || pluginId,
1957
1606
  backupTime: timestamp
@@ -1964,7 +1613,7 @@ function findBackups(configRoot) {
1964
1613
  }
1965
1614
  function restoreBackup(backupPath, configRoot, tool) {
1966
1615
  try {
1967
- const agentsFile = join8(configRoot, getAgentsFileName(tool));
1616
+ const agentsFile = join10(configRoot, getAgentsFileName(tool));
1968
1617
  copyFileSync(backupPath, agentsFile);
1969
1618
  return true;
1970
1619
  } catch {
@@ -2065,7 +1714,7 @@ async function installPlugin(opts) {
2065
1714
  warnings: []
2066
1715
  };
2067
1716
  }
2068
- const scriptPath = join9(opts.repoPath, plugin.dir, plugin.script);
1717
+ const scriptPath = join11(opts.repoPath, plugin.dir, plugin.script);
2069
1718
  if (!existsSync9(scriptPath)) {
2070
1719
  return {
2071
1720
  success: false,
@@ -2082,7 +1731,7 @@ async function installPlugin(opts) {
2082
1731
  }
2083
1732
  const cwd = opts.installPath || process.cwd();
2084
1733
  const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
2085
- const agentsFile = join9(configRoot, getAgentsFileName(opts.tool));
1734
+ const agentsFile = join11(configRoot, getAgentsFileName(opts.tool));
2086
1735
  let backupInfo = null;
2087
1736
  if (existsSync9(agentsFile)) {
2088
1737
  const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
@@ -2177,14 +1826,14 @@ async function installPlugin(opts) {
2177
1826
  }
2178
1827
 
2179
1828
  // 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";
1829
+ import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as readdirSync4, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
1830
+ import { join as join12 } from "path";
2182
1831
  import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
2183
1832
  import chalk4 from "chalk";
2184
1833
  import Table from "cli-table3";
2185
1834
  async function installSkills(skillIds, tool, level, repoPath) {
2186
1835
  const configRoot = getConfigRoot(tool, level);
2187
- const skillsDir = join10(configRoot, "skills");
1836
+ const skillsDir = join12(configRoot, "skills");
2188
1837
  const installPath = level === "project" ? process.cwd() : configRoot;
2189
1838
  if (!existsSync10(skillsDir)) {
2190
1839
  mkdirSync5(skillsDir, { recursive: true });
@@ -2197,8 +1846,8 @@ async function installSkills(skillIds, tool, level, repoPath) {
2197
1846
  results.push({ skillId, success: false, error: "Skill not found in registry" });
2198
1847
  continue;
2199
1848
  }
2200
- const sourcePath = join10(repoPath, skill.source, skill.id);
2201
- const targetPath = join10(skillsDir, skillId);
1849
+ const sourcePath = join12(repoPath, skill.source, skill.id);
1850
+ const targetPath = join12(skillsDir, skillId);
2202
1851
  if (!existsSync10(sourcePath)) {
2203
1852
  results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
2204
1853
  continue;
@@ -2221,12 +1870,12 @@ async function installSkills(skillIds, tool, level, repoPath) {
2221
1870
  }
2222
1871
  async function uninstallSkills(skillIds, tool, level) {
2223
1872
  const configRoot = getConfigRoot(tool, level);
2224
- const skillsDir = join10(configRoot, "skills");
1873
+ const skillsDir = join12(configRoot, "skills");
2225
1874
  const installPath = level === "project" ? process.cwd() : configRoot;
2226
1875
  const results = [];
2227
1876
  const removedIds = [];
2228
1877
  for (const skillId of skillIds) {
2229
- const targetPath = join10(skillsDir, skillId);
1878
+ const targetPath = join12(skillsDir, skillId);
2230
1879
  try {
2231
1880
  if (existsSync10(targetPath) || isSymlink2(targetPath)) {
2232
1881
  unlinkSync3(targetPath);
@@ -2246,7 +1895,7 @@ async function uninstallSkills(skillIds, tool, level) {
2246
1895
  }
2247
1896
  if (existsSync10(skillsDir)) {
2248
1897
  try {
2249
- const entries = readdirSync3(skillsDir);
1898
+ const entries = readdirSync4(skillsDir);
2250
1899
  if (entries.length === 0) {
2251
1900
  rmdirSync(skillsDir);
2252
1901
  logger.step(` ${t("uninstall_clean_empty_dir")}: skills/`);
@@ -2444,8 +2093,10 @@ function printEnhancedSummary(results, tool, configRoot) {
2444
2093
  ""
2445
2094
  ];
2446
2095
  if (successResults.length === 1) {
2096
+ const plugin = findPlugin(successResults[0].pluginId);
2097
+ const docsPath = plugin ? `${plugin.dir}/quickstart.md` : `${successResults[0].pluginId}/quickstart.md`;
2447
2098
  lines.push(
2448
- ` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(`plugins-official/${successResults[0].pluginId}/quickstart.md`)}`
2099
+ ` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(docsPath)}`
2449
2100
  );
2450
2101
  }
2451
2102
  console.log();
@@ -2456,15 +2107,15 @@ function printEnhancedSummary(results, tool, configRoot) {
2456
2107
  }
2457
2108
 
2458
2109
  // src/commands/init.ts
2459
- import { existsSync as existsSync11, readFileSync as readFileSync5 } from "fs";
2460
- import { join as join11 } from "path";
2110
+ import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
2111
+ import { join as join13 } from "path";
2461
2112
  var BACK2 = "__back__";
2462
2113
  var CANCEL2 = "__cancel__";
2463
2114
  async function initCommand() {
2464
2115
  const cwd = process.cwd();
2465
- if (existsSync11(join11(cwd, "package.json")) && (() => {
2116
+ if (existsSync11(join13(cwd, "package.json")) && (() => {
2466
2117
  try {
2467
- const pkg = JSON.parse(readFileSync5(join11(cwd, "package.json"), "utf-8"));
2118
+ const pkg = JSON.parse(readFileSync8(join13(cwd, "package.json"), "utf-8"));
2468
2119
  return pkg.name === "@cannbot-ai/install-helper";
2469
2120
  } catch {
2470
2121
  return false;
@@ -2690,8 +2341,8 @@ async function listCommand() {
2690
2341
 
2691
2342
  // src/commands/doctor.ts
2692
2343
  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";
2344
+ import { existsSync as existsSync12, readdirSync as readdirSync5, lstatSync as lstatSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
2345
+ import { join as join14 } from "path";
2695
2346
  async function doctorCommand(options = {}) {
2696
2347
  console.log();
2697
2348
  console.log(chalk7.bold(` ${t("doctor_title")}`));
@@ -2737,7 +2388,7 @@ async function doctorCommand(options = {}) {
2737
2388
  if (existsSync12(skillsDir)) {
2738
2389
  const brokenLinks = checkBrokenLinks(skillsDir);
2739
2390
  if (brokenLinks === 0) {
2740
- const count = readdirSync4(skillsDir).length;
2391
+ const count = readdirSync5(skillsDir).length;
2741
2392
  console.log(chalk7.green(" \u2713") + ` ${skillsDir} \u2014 ${t("doctor_links_valid").replace("{count}", String(count))}`);
2742
2393
  } else {
2743
2394
  console.log(chalk7.yellow(" \u26A0") + ` ${skillsDir} \u2014 ${t("doctor_broken_links").replace("{count}", String(brokenLinks))}`);
@@ -2759,7 +2410,7 @@ async function doctorCommand(options = {}) {
2759
2410
  if (existsSync12(agentsDir)) {
2760
2411
  const brokenLinks = checkBrokenLinks(agentsDir);
2761
2412
  if (brokenLinks === 0) {
2762
- const count = readdirSync4(agentsDir).length;
2413
+ const count = readdirSync5(agentsDir).length;
2763
2414
  console.log(chalk7.green(" \u2713") + ` ${agentsDir} \u2014 ${t("doctor_links_valid").replace("{count}", String(count))}`);
2764
2415
  } else {
2765
2416
  console.log(chalk7.yellow(" \u26A0") + ` ${agentsDir} \u2014 ${t("doctor_broken_links").replace("{count}", String(brokenLinks))}`);
@@ -2781,7 +2432,7 @@ async function doctorCommand(options = {}) {
2781
2432
  console.log();
2782
2433
  console.log(chalk7.bold(` ${t("doctor_config")}`));
2783
2434
  const configFile = getConfigFileName(primaryTool);
2784
- const configPath = join12(process.cwd(), configFile);
2435
+ const configPath = join14(process.cwd(), configFile);
2785
2436
  if (existsSync12(configPath)) {
2786
2437
  console.log(chalk7.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
2787
2438
  } else {
@@ -2803,9 +2454,9 @@ async function doctorCommand(options = {}) {
2803
2454
  function checkBrokenLinks(dir) {
2804
2455
  let broken = 0;
2805
2456
  try {
2806
- const entries = readdirSync4(dir);
2457
+ const entries = readdirSync5(dir);
2807
2458
  for (const entry of entries) {
2808
- const fullPath = join12(dir, entry);
2459
+ const fullPath = join14(dir, entry);
2809
2460
  try {
2810
2461
  const stats = lstatSync3(fullPath);
2811
2462
  if (stats.isSymbolicLink()) {
@@ -2824,9 +2475,9 @@ function checkBrokenLinks(dir) {
2824
2475
  function fixBrokenLinks(dir) {
2825
2476
  let fixed = 0;
2826
2477
  try {
2827
- const entries = readdirSync4(dir);
2478
+ const entries = readdirSync5(dir);
2828
2479
  for (const entry of entries) {
2829
- const fullPath = join12(dir, entry);
2480
+ const fullPath = join14(dir, entry);
2830
2481
  try {
2831
2482
  const stats = lstatSync3(fullPath);
2832
2483
  if (stats.isSymbolicLink()) {
@@ -3105,7 +2756,7 @@ async function installPlugins(pluginIds, tool, level, repoPath) {
3105
2756
  }
3106
2757
 
3107
2758
  // src/commands/uninstall.ts
3108
- import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync5, lstatSync as lstatSync4 } from "fs";
2759
+ import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync6, lstatSync as lstatSync4 } from "fs";
3109
2760
  import chalk10 from "chalk";
3110
2761
  async function uninstallCommand(names, options) {
3111
2762
  const tool = options.tool ? validateTool(options.tool) : "opencode";
@@ -3156,7 +2807,7 @@ async function uninstallCommand(names, options) {
3156
2807
  continue;
3157
2808
  }
3158
2809
  if (existsSync13(dirPath)) {
3159
- const entries = readdirSync5(dirPath);
2810
+ const entries = readdirSync6(dirPath);
3160
2811
  if (entries.length === 0) {
3161
2812
  rmdirSync2(dirPath);
3162
2813
  const name = dirPath.split("/").pop() || dirPath;
@@ -3300,8 +2951,8 @@ async function updateCommand(pluginNames, options) {
3300
2951
 
3301
2952
  // src/commands/info.ts
3302
2953
  import chalk12 from "chalk";
3303
- import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
3304
- import { join as join13 } from "path";
2954
+ import { existsSync as existsSync14, readdirSync as readdirSync7 } from "fs";
2955
+ import { join as join15 } from "path";
3305
2956
  async function infoCommand(pluginName) {
3306
2957
  const plugin = findPlugin(pluginName);
3307
2958
  if (!plugin) {
@@ -3325,13 +2976,13 @@ async function infoCommand(pluginName) {
3325
2976
  try {
3326
2977
  const repoManager = createRepositoryManager();
3327
2978
  const repoPath = await repoManager.ensureRepo();
3328
- const quickstartPath = join13(repoPath, plugin.dir, "quickstart.md");
2979
+ const quickstartPath = join15(repoPath, plugin.dir, "quickstart.md");
3329
2980
  if (existsSync14(quickstartPath)) {
3330
2981
  console.log(` ${chalk12.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
3331
2982
  }
3332
- const agentsDir = join13(repoPath, plugin.dir, "agents");
2983
+ const agentsDir = join15(repoPath, plugin.dir, "agents");
3333
2984
  if (existsSync14(agentsDir)) {
3334
- const agentFiles = readdirSync6(agentsDir).filter((f) => f.endsWith(".md"));
2985
+ const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
3335
2986
  if (agentFiles.length > 0) {
3336
2987
  console.log();
3337
2988
  console.log(` ${chalk12.bold("Agents:")}`);
@@ -3388,7 +3039,7 @@ function createCLI() {
3388
3039
  setLanguage(config.language);
3389
3040
  }
3390
3041
  const program2 = new Command();
3391
- program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("1.0.2");
3042
+ program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("1.0.3");
3392
3043
  program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
3393
3044
  await initCommand();
3394
3045
  });