@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/README.md +1 -1
- package/dist/config/repository.yaml +25 -0
- package/dist/index.js +236 -585
- package/dist/index.js.map +1 -1
- package/dist/locales/en_US.json +168 -0
- package/dist/locales/zh_CN.json +168 -0
- package/dist/plugins.d/_defaults.yml +4 -0
- package/dist/plugins.d/catlass-op-generator.yml +7 -0
- package/dist/plugins.d/model-infer-optimize.yml +7 -0
- package/dist/plugins.d/ops-code-reviewer.yml +7 -0
- package/dist/plugins.d/ops-direct-invoke-flash.yml +7 -0
- package/dist/plugins.d/ops-direct-invoke.yml +7 -0
- package/dist/plugins.d/ops-registry-invoke.yml +7 -0
- package/dist/plugins.d/pypto-op-orchestrator.yml +7 -0
- package/dist/plugins.d/tilelang-op-orchestrator.yml +7 -0
- package/dist/plugins.d/torch-compile.yml +7 -0
- package/dist/plugins.d/triton-op-generator.yml +8 -0
- package/package.json +3 -2
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
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
|
|
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(
|
|
516
|
-
if (existsSync(
|
|
517
|
-
if (existsSync(
|
|
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
|
|
148
|
+
return join3(home, ".config", "opencode");
|
|
526
149
|
case "claude":
|
|
527
|
-
return
|
|
150
|
+
return join3(home, ".claude");
|
|
528
151
|
case "trae": {
|
|
529
152
|
const variant = detectTraeVariant();
|
|
530
153
|
switch (variant) {
|
|
531
154
|
case "plugin":
|
|
532
|
-
return
|
|
155
|
+
return join3(home, ".marscode");
|
|
533
156
|
case "cli":
|
|
534
|
-
return
|
|
157
|
+
return join3(home, ".traecli");
|
|
535
158
|
default:
|
|
536
|
-
return
|
|
159
|
+
return join3(home, ".trae-cn");
|
|
537
160
|
}
|
|
538
161
|
}
|
|
539
162
|
case "cursor":
|
|
540
|
-
return
|
|
163
|
+
return join3(home, ".cursor");
|
|
541
164
|
case "copilot":
|
|
542
|
-
return
|
|
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
|
|
175
|
+
return join3(baseDir, ".opencode");
|
|
553
176
|
case "claude":
|
|
554
|
-
return
|
|
177
|
+
return join3(baseDir, ".claude");
|
|
555
178
|
case "trae": {
|
|
556
179
|
const variant = detectTraeVariant();
|
|
557
180
|
switch (variant) {
|
|
558
181
|
case "plugin":
|
|
559
|
-
return
|
|
182
|
+
return join3(baseDir, ".marscode");
|
|
560
183
|
case "cli":
|
|
561
|
-
return
|
|
184
|
+
return join3(baseDir, ".traecli");
|
|
562
185
|
default:
|
|
563
|
-
return
|
|
186
|
+
return join3(baseDir, ".trae");
|
|
564
187
|
}
|
|
565
188
|
}
|
|
566
189
|
case "cursor":
|
|
567
|
-
return
|
|
190
|
+
return join3(baseDir, ".cursor");
|
|
568
191
|
case "copilot":
|
|
569
|
-
return
|
|
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
|
|
203
|
+
return join3(configRoot, "skills");
|
|
581
204
|
}
|
|
582
205
|
function getAgentsDir(configRoot) {
|
|
583
|
-
return
|
|
206
|
+
return join3(configRoot, "agents");
|
|
584
207
|
}
|
|
585
208
|
function getManifestPath(configRoot) {
|
|
586
|
-
return
|
|
209
|
+
return join3(configRoot, "cannbot-manifest.json");
|
|
587
210
|
}
|
|
588
211
|
function getCannbotConfigDir() {
|
|
589
|
-
return
|
|
212
|
+
return join3(homedir(), ".cannbot");
|
|
590
213
|
}
|
|
591
214
|
function getCannbotRepoPath() {
|
|
592
|
-
return
|
|
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(
|
|
631
|
-
path =
|
|
632
|
-
} else if (variant === "plugin" && existsSync2(
|
|
633
|
-
path =
|
|
634
|
-
} else if (variant === "cli" && existsSync2(
|
|
635
|
-
path =
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
347
|
+
const pluginManifestPath = join5(configRoot, `${plugin.id}-manifest.json`);
|
|
725
348
|
if (existsSync3(pluginManifestPath)) {
|
|
726
349
|
try {
|
|
727
|
-
const content =
|
|
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 =
|
|
771
|
-
const agentsDir =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
411
|
+
agentsMdPath = join5(configRoot, "..", "AGENTS.md");
|
|
789
412
|
} else {
|
|
790
|
-
agentsMdPath =
|
|
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
|
|
860
|
-
import { join as
|
|
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
|
|
487
|
+
return join6(homedir3(), ".cannbot");
|
|
865
488
|
}
|
|
866
489
|
function getConfigPath() {
|
|
867
|
-
return
|
|
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 =
|
|
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
|
|
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
|
|
1190
|
-
import { join as
|
|
1191
|
-
import {
|
|
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
|
-
|
|
1213
|
-
"
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
]
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
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 =
|
|
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 =
|
|
867
|
+
const pluginParent = join7(repoPath, pluginDir);
|
|
1233
868
|
if (!existsSync5(pluginParent)) continue;
|
|
1234
869
|
for (const plugin of safeReaddir(pluginParent)) {
|
|
1235
|
-
const pluginPath =
|
|
870
|
+
const pluginPath = join7(pluginParent, plugin);
|
|
1236
871
|
if (!isDirectory(pluginPath)) continue;
|
|
1237
|
-
const skillsDir =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
912
|
+
const headFile = join7(repoPath, ".git", "HEAD");
|
|
1278
913
|
if (!existsSync5(headFile)) return "unknown";
|
|
1279
|
-
const headContent =
|
|
914
|
+
const headContent = readFileSync5(headFile, "utf-8").trim();
|
|
1280
915
|
if (headContent.startsWith("ref: ")) {
|
|
1281
|
-
const refPath =
|
|
916
|
+
const refPath = join7(repoPath, ".git", headContent.slice(5));
|
|
1282
917
|
if (existsSync5(refPath)) {
|
|
1283
|
-
return
|
|
918
|
+
return readFileSync5(refPath, "utf-8").trim();
|
|
1284
919
|
}
|
|
1285
|
-
const packedRefsPath =
|
|
920
|
+
const packedRefsPath = join7(repoPath, ".git", "packed-refs");
|
|
1286
921
|
if (existsSync5(packedRefsPath)) {
|
|
1287
|
-
const packedRefs =
|
|
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 =
|
|
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 =
|
|
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
|
|
963
|
+
return join7(getCannbotConfigDir(), "scan-cache.json");
|
|
1329
964
|
}
|
|
1330
965
|
function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
|
|
1331
|
-
const selfSkillMd =
|
|
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 =
|
|
981
|
+
const fullPath = join7(dirPath, entry);
|
|
1347
982
|
if (EXCLUDE_DIRS.has(entry)) continue;
|
|
1348
983
|
if (!isDirectory(fullPath)) continue;
|
|
1349
|
-
const skillMd =
|
|
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
|
|
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
|
|
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 =
|
|
1667
|
-
const pluginsDir =
|
|
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
|
|
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
|
|
1708
|
-
import { join as
|
|
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
|
|
1359
|
+
return join9(getCannbotConfigDir(), "installs");
|
|
1711
1360
|
}
|
|
1712
1361
|
function getRecordPath(pluginId) {
|
|
1713
|
-
return
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
1760
|
-
const agentPathMd =
|
|
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 =
|
|
1418
|
+
const workflowsLink = join9(configRoot, "workflows");
|
|
1770
1419
|
if (isSymlink(workflowsLink)) {
|
|
1771
1420
|
files.push(workflowsLink);
|
|
1772
1421
|
}
|
|
1773
|
-
const manifestPath =
|
|
1422
|
+
const manifestPath = join9(configRoot, "cannbot-manifest.json");
|
|
1774
1423
|
if (existsSync7(manifestPath)) {
|
|
1775
1424
|
files.push(manifestPath);
|
|
1776
1425
|
}
|
|
1777
|
-
const pluginManifestPath =
|
|
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" ?
|
|
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 =
|
|
1437
|
+
const repoLinkPath = join9(installPath, repoName);
|
|
1789
1438
|
if (isSymlink(repoLinkPath)) {
|
|
1790
1439
|
files.push(repoLinkPath);
|
|
1791
1440
|
}
|
|
1792
|
-
const repoLinkInConfig =
|
|
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
|
|
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 =
|
|
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 =
|
|
1524
|
+
const skillsDir = join9(configRoot, "skills");
|
|
1876
1525
|
return recordedSkills.filter((skillId) => {
|
|
1877
|
-
const skillPath =
|
|
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
|
|
1884
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
2181
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
2201
|
-
const targetPath =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
2460
|
-
import { join as
|
|
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(
|
|
2116
|
+
if (existsSync11(join13(cwd, "package.json")) && (() => {
|
|
2466
2117
|
try {
|
|
2467
|
-
const pkg = JSON.parse(
|
|
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
|
|
2694
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
2457
|
+
const entries = readdirSync5(dir);
|
|
2807
2458
|
for (const entry of entries) {
|
|
2808
|
-
const fullPath =
|
|
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 =
|
|
2478
|
+
const entries = readdirSync5(dir);
|
|
2828
2479
|
for (const entry of entries) {
|
|
2829
|
-
const fullPath =
|
|
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
|
|
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 =
|
|
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
|
|
3304
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
2983
|
+
const agentsDir = join15(repoPath, plugin.dir, "agents");
|
|
3333
2984
|
if (existsSync14(agentsDir)) {
|
|
3334
|
-
const agentFiles =
|
|
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.
|
|
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
|
});
|