@cannbot-ai/install-helper 0.0.2-beta.10 → 0.0.2-beta.11
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 +286 -254
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -145,251 +145,6 @@ import { join as join2 } from "path";
|
|
|
145
145
|
import { homedir } from "os";
|
|
146
146
|
import { join } from "path";
|
|
147
147
|
import { existsSync } from "fs";
|
|
148
|
-
function detectTraeVariant() {
|
|
149
|
-
const home = homedir();
|
|
150
|
-
if (existsSync(join(home, ".trae-cn"))) return "ide";
|
|
151
|
-
if (existsSync(join(home, ".marscode"))) return "plugin";
|
|
152
|
-
if (existsSync(join(home, ".traecli"))) return "cli";
|
|
153
|
-
return "unknown";
|
|
154
|
-
}
|
|
155
|
-
function getConfigRoot(tool, level, base) {
|
|
156
|
-
const home = homedir();
|
|
157
|
-
if (level === "global") {
|
|
158
|
-
switch (tool) {
|
|
159
|
-
case "opencode":
|
|
160
|
-
return join(home, ".config", "opencode");
|
|
161
|
-
case "claude":
|
|
162
|
-
return join(home, ".claude");
|
|
163
|
-
case "trae": {
|
|
164
|
-
const variant = detectTraeVariant();
|
|
165
|
-
switch (variant) {
|
|
166
|
-
case "plugin":
|
|
167
|
-
return join(home, ".marscode");
|
|
168
|
-
case "cli":
|
|
169
|
-
return join(home, ".traecli");
|
|
170
|
-
default:
|
|
171
|
-
return join(home, ".trae-cn");
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
case "cursor":
|
|
175
|
-
return join(home, ".cursor");
|
|
176
|
-
case "copilot":
|
|
177
|
-
return join(home, ".copilot");
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const baseDir = base || process.cwd();
|
|
181
|
-
switch (tool) {
|
|
182
|
-
case "opencode":
|
|
183
|
-
return join(baseDir, ".opencode");
|
|
184
|
-
case "claude":
|
|
185
|
-
return join(baseDir, ".claude");
|
|
186
|
-
case "trae": {
|
|
187
|
-
const variant = detectTraeVariant();
|
|
188
|
-
switch (variant) {
|
|
189
|
-
case "plugin":
|
|
190
|
-
return join(baseDir, ".marscode");
|
|
191
|
-
case "cli":
|
|
192
|
-
return join(baseDir, ".traecli");
|
|
193
|
-
default:
|
|
194
|
-
return join(baseDir, ".trae");
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
case "cursor":
|
|
198
|
-
return join(baseDir, ".cursor");
|
|
199
|
-
case "copilot":
|
|
200
|
-
return join(baseDir, ".github");
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
function getConfigFileName(tool) {
|
|
204
|
-
return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
205
|
-
}
|
|
206
|
-
function getSkillsDir(configRoot) {
|
|
207
|
-
return join(configRoot, "skills");
|
|
208
|
-
}
|
|
209
|
-
function getAgentsDir(configRoot) {
|
|
210
|
-
return join(configRoot, "agents");
|
|
211
|
-
}
|
|
212
|
-
function getManifestPath(configRoot) {
|
|
213
|
-
return join(configRoot, "cannbot-manifest.json");
|
|
214
|
-
}
|
|
215
|
-
function getCannbotConfigDir() {
|
|
216
|
-
return join(homedir(), ".cannbot");
|
|
217
|
-
}
|
|
218
|
-
function getCannbotRepoPath() {
|
|
219
|
-
return join(getCannbotConfigDir(), "repo");
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// src/core/detector.ts
|
|
223
|
-
async function getCommandVersion(cmd, args = ["--version"]) {
|
|
224
|
-
try {
|
|
225
|
-
const result = await execa(cmd, args, { timeout: 5e3 });
|
|
226
|
-
const output = result.stdout.trim();
|
|
227
|
-
const match = output.match(/(\d+\.\d+\.\d+)/);
|
|
228
|
-
return match ? match[1] : output.split("\n")[0];
|
|
229
|
-
} catch {
|
|
230
|
-
return void 0;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
async function getCommandPath(cmd) {
|
|
234
|
-
try {
|
|
235
|
-
const result = await execa("which", [cmd], { timeout: 5e3 });
|
|
236
|
-
return result.stdout.trim();
|
|
237
|
-
} catch {
|
|
238
|
-
return void 0;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
async function detectOpenCode() {
|
|
242
|
-
const path = await getCommandPath("opencode");
|
|
243
|
-
if (!path) return void 0;
|
|
244
|
-
const version = await getCommandVersion("opencode");
|
|
245
|
-
return { name: "opencode", version, path };
|
|
246
|
-
}
|
|
247
|
-
async function detectClaude() {
|
|
248
|
-
const path = await getCommandPath("claude");
|
|
249
|
-
if (!path) return void 0;
|
|
250
|
-
const version = await getCommandVersion("claude");
|
|
251
|
-
return { name: "claude", version, path };
|
|
252
|
-
}
|
|
253
|
-
async function detectTrae() {
|
|
254
|
-
const home = homedir2();
|
|
255
|
-
const variant = detectTraeVariant();
|
|
256
|
-
let path;
|
|
257
|
-
if (variant === "ide" && existsSync2(join2(home, ".trae-cn"))) {
|
|
258
|
-
path = join2(home, ".trae-cn");
|
|
259
|
-
} else if (variant === "plugin" && existsSync2(join2(home, ".marscode"))) {
|
|
260
|
-
path = join2(home, ".marscode");
|
|
261
|
-
} else if (variant === "cli" && existsSync2(join2(home, ".traecli"))) {
|
|
262
|
-
path = join2(home, ".traecli");
|
|
263
|
-
} else if (variant === "unknown") {
|
|
264
|
-
const cmdPath = await getCommandPath("trae");
|
|
265
|
-
if (cmdPath) path = cmdPath;
|
|
266
|
-
}
|
|
267
|
-
if (!path) return void 0;
|
|
268
|
-
return { name: "trae", version: variant, path };
|
|
269
|
-
}
|
|
270
|
-
async function detectCursor() {
|
|
271
|
-
const path = await getCommandPath("cursor");
|
|
272
|
-
if (path) {
|
|
273
|
-
const version = await getCommandVersion("cursor");
|
|
274
|
-
return { name: "cursor", version, path };
|
|
275
|
-
}
|
|
276
|
-
if (process.platform === "darwin") {
|
|
277
|
-
const appPath = "/Applications/Cursor.app";
|
|
278
|
-
if (existsSync2(appPath)) {
|
|
279
|
-
return { name: "cursor", path: appPath };
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return void 0;
|
|
283
|
-
}
|
|
284
|
-
async function detectCopilot() {
|
|
285
|
-
const path = await getCommandPath("gh");
|
|
286
|
-
if (!path) return void 0;
|
|
287
|
-
try {
|
|
288
|
-
await execa("gh", ["extension", "list"], { timeout: 5e3 });
|
|
289
|
-
return { name: "copilot", path };
|
|
290
|
-
} catch {
|
|
291
|
-
return void 0;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
async function detectTools() {
|
|
295
|
-
const detectors = [
|
|
296
|
-
detectOpenCode,
|
|
297
|
-
detectClaude,
|
|
298
|
-
detectTrae,
|
|
299
|
-
detectCursor,
|
|
300
|
-
detectCopilot
|
|
301
|
-
];
|
|
302
|
-
const results = await Promise.allSettled(detectors.map((d) => d()));
|
|
303
|
-
const tools = [];
|
|
304
|
-
for (const result of results) {
|
|
305
|
-
if (result.status === "fulfilled" && result.value) {
|
|
306
|
-
tools.push(result.value);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
return tools;
|
|
310
|
-
}
|
|
311
|
-
function getToolDisplayName(tool) {
|
|
312
|
-
const names = {
|
|
313
|
-
opencode: "OpenCode",
|
|
314
|
-
claude: "Claude Code",
|
|
315
|
-
trae: "Trae",
|
|
316
|
-
cursor: "Cursor",
|
|
317
|
-
copilot: "GitHub Copilot"
|
|
318
|
-
};
|
|
319
|
-
return names[tool];
|
|
320
|
-
}
|
|
321
|
-
function getAllTools() {
|
|
322
|
-
return ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// src/core/manifest.ts
|
|
326
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
327
|
-
import { join as join3 } from "path";
|
|
328
|
-
function readManifest(configRoot) {
|
|
329
|
-
const manifestPath = getManifestPath(configRoot);
|
|
330
|
-
if (existsSync3(manifestPath)) {
|
|
331
|
-
try {
|
|
332
|
-
const content = readFileSync(manifestPath, "utf-8");
|
|
333
|
-
return JSON.parse(content);
|
|
334
|
-
} catch {
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
return null;
|
|
338
|
-
}
|
|
339
|
-
function readAllManifests(configRoot) {
|
|
340
|
-
const manifests = [];
|
|
341
|
-
const plugins = getAllPlugins();
|
|
342
|
-
const standardPath = getManifestPath(configRoot);
|
|
343
|
-
if (existsSync3(standardPath)) {
|
|
344
|
-
try {
|
|
345
|
-
const content = readFileSync(standardPath, "utf-8");
|
|
346
|
-
manifests.push(JSON.parse(content));
|
|
347
|
-
} catch {
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
for (const plugin of plugins) {
|
|
351
|
-
const pluginManifestPath = join3(configRoot, `${plugin.id}-manifest.json`);
|
|
352
|
-
if (existsSync3(pluginManifestPath)) {
|
|
353
|
-
try {
|
|
354
|
-
const content = readFileSync(pluginManifestPath, "utf-8");
|
|
355
|
-
manifests.push(JSON.parse(content));
|
|
356
|
-
} catch {
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
return manifests;
|
|
361
|
-
}
|
|
362
|
-
function scanInstalled() {
|
|
363
|
-
const plugins = getAllPlugins();
|
|
364
|
-
const installed = [];
|
|
365
|
-
const tools = ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
366
|
-
const levels = ["project", "global"];
|
|
367
|
-
for (const tool of tools) {
|
|
368
|
-
for (const level of levels) {
|
|
369
|
-
const configRoot = getConfigRoot(tool, level);
|
|
370
|
-
const manifests = readAllManifests(configRoot);
|
|
371
|
-
for (const manifest of manifests) {
|
|
372
|
-
const plugin = plugins.find((p) => p.id === manifest.team);
|
|
373
|
-
if (!plugin) continue;
|
|
374
|
-
const alreadyAdded = installed.some(
|
|
375
|
-
(p) => p.id === plugin.id && p.tool === tool && p.level === level
|
|
376
|
-
);
|
|
377
|
-
if (alreadyAdded) continue;
|
|
378
|
-
installed.push({
|
|
379
|
-
id: plugin.id,
|
|
380
|
-
displayName: plugin.displayName,
|
|
381
|
-
tool,
|
|
382
|
-
level,
|
|
383
|
-
skillsCount: manifest.installed_skills?.length || 0,
|
|
384
|
-
agentsCount: manifest.installed_agents?.length || 0,
|
|
385
|
-
installTime: manifest.install_time,
|
|
386
|
-
configRoot
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return installed;
|
|
392
|
-
}
|
|
393
148
|
|
|
394
149
|
// src/utils/i18n.ts
|
|
395
150
|
var zh_CN = {
|
|
@@ -454,6 +209,8 @@ var zh_CN = {
|
|
|
454
209
|
error_tool_not_found: "\u672A\u68C0\u6D4B\u5230\u4EFB\u4F55 AI \u7F16\u7A0B\u5DE5\u5177",
|
|
455
210
|
error_plugin_not_found: "\u672A\u627E\u5230\u63D2\u4EF6",
|
|
456
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}",
|
|
457
214
|
quick_start: "\u542F\u52A8\u547D\u4EE4",
|
|
458
215
|
quick_start_hint: "\u8BD5\u8BD5\u8F93\u5165: \u5E2E\u6211\u5F00\u53D1\u4E00\u4E2A Abs \u7B97\u5B50",
|
|
459
216
|
skill_select_category: "\u9009\u62E9 Skill \u7C7B\u522B",
|
|
@@ -589,6 +346,8 @@ var en_US = {
|
|
|
589
346
|
error_tool_not_found: "No AI coding tool detected",
|
|
590
347
|
error_plugin_not_found: "Plugin not found",
|
|
591
348
|
error_repo_not_found: "Repository not found",
|
|
349
|
+
error_invalid_tool: "Unsupported AI tool: {tool}\nSupported tools: {tools}",
|
|
350
|
+
error_invalid_level: "Unsupported install level: {level}\nSupported levels: {levels}",
|
|
592
351
|
quick_start: "Launch command",
|
|
593
352
|
quick_start_hint: "Try: help me develop an Abs operator",
|
|
594
353
|
skill_select_category: "Select Skill category",
|
|
@@ -670,6 +429,279 @@ function t(key) {
|
|
|
670
429
|
return currentLang === "zh_CN" ? zh_CN[key] : en_US[key];
|
|
671
430
|
}
|
|
672
431
|
|
|
432
|
+
// src/utils/paths.ts
|
|
433
|
+
var VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
434
|
+
var VALID_LEVELS = ["project", "global"];
|
|
435
|
+
function validateTool(tool) {
|
|
436
|
+
if (!VALID_TOOLS.includes(tool)) {
|
|
437
|
+
throw new Error(
|
|
438
|
+
t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
return tool;
|
|
442
|
+
}
|
|
443
|
+
function validateLevel(level) {
|
|
444
|
+
if (!VALID_LEVELS.includes(level)) {
|
|
445
|
+
throw new Error(
|
|
446
|
+
t("error_invalid_level").replace("{level}", level).replace("{levels}", VALID_LEVELS.join(", "))
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
return level;
|
|
450
|
+
}
|
|
451
|
+
function detectTraeVariant() {
|
|
452
|
+
const home = homedir();
|
|
453
|
+
if (existsSync(join(home, ".trae-cn"))) return "ide";
|
|
454
|
+
if (existsSync(join(home, ".marscode"))) return "plugin";
|
|
455
|
+
if (existsSync(join(home, ".traecli"))) return "cli";
|
|
456
|
+
return "unknown";
|
|
457
|
+
}
|
|
458
|
+
function getConfigRoot(tool, level, base) {
|
|
459
|
+
const home = homedir();
|
|
460
|
+
if (level === "global") {
|
|
461
|
+
switch (tool) {
|
|
462
|
+
case "opencode":
|
|
463
|
+
return join(home, ".config", "opencode");
|
|
464
|
+
case "claude":
|
|
465
|
+
return join(home, ".claude");
|
|
466
|
+
case "trae": {
|
|
467
|
+
const variant = detectTraeVariant();
|
|
468
|
+
switch (variant) {
|
|
469
|
+
case "plugin":
|
|
470
|
+
return join(home, ".marscode");
|
|
471
|
+
case "cli":
|
|
472
|
+
return join(home, ".traecli");
|
|
473
|
+
default:
|
|
474
|
+
return join(home, ".trae-cn");
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
case "cursor":
|
|
478
|
+
return join(home, ".cursor");
|
|
479
|
+
case "copilot":
|
|
480
|
+
return join(home, ".copilot");
|
|
481
|
+
default:
|
|
482
|
+
throw new Error(
|
|
483
|
+
t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const baseDir = base || process.cwd();
|
|
488
|
+
switch (tool) {
|
|
489
|
+
case "opencode":
|
|
490
|
+
return join(baseDir, ".opencode");
|
|
491
|
+
case "claude":
|
|
492
|
+
return join(baseDir, ".claude");
|
|
493
|
+
case "trae": {
|
|
494
|
+
const variant = detectTraeVariant();
|
|
495
|
+
switch (variant) {
|
|
496
|
+
case "plugin":
|
|
497
|
+
return join(baseDir, ".marscode");
|
|
498
|
+
case "cli":
|
|
499
|
+
return join(baseDir, ".traecli");
|
|
500
|
+
default:
|
|
501
|
+
return join(baseDir, ".trae");
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
case "cursor":
|
|
505
|
+
return join(baseDir, ".cursor");
|
|
506
|
+
case "copilot":
|
|
507
|
+
return join(baseDir, ".github");
|
|
508
|
+
default:
|
|
509
|
+
throw new Error(
|
|
510
|
+
t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
function getConfigFileName(tool) {
|
|
515
|
+
return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
516
|
+
}
|
|
517
|
+
function getSkillsDir(configRoot) {
|
|
518
|
+
return join(configRoot, "skills");
|
|
519
|
+
}
|
|
520
|
+
function getAgentsDir(configRoot) {
|
|
521
|
+
return join(configRoot, "agents");
|
|
522
|
+
}
|
|
523
|
+
function getManifestPath(configRoot) {
|
|
524
|
+
return join(configRoot, "cannbot-manifest.json");
|
|
525
|
+
}
|
|
526
|
+
function getCannbotConfigDir() {
|
|
527
|
+
return join(homedir(), ".cannbot");
|
|
528
|
+
}
|
|
529
|
+
function getCannbotRepoPath() {
|
|
530
|
+
return join(getCannbotConfigDir(), "repo");
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// src/core/detector.ts
|
|
534
|
+
async function getCommandVersion(cmd, args = ["--version"]) {
|
|
535
|
+
try {
|
|
536
|
+
const result = await execa(cmd, args, { timeout: 5e3 });
|
|
537
|
+
const output = result.stdout.trim();
|
|
538
|
+
const match = output.match(/(\d+\.\d+\.\d+)/);
|
|
539
|
+
return match ? match[1] : output.split("\n")[0];
|
|
540
|
+
} catch {
|
|
541
|
+
return void 0;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
async function getCommandPath(cmd) {
|
|
545
|
+
try {
|
|
546
|
+
const result = await execa("which", [cmd], { timeout: 5e3 });
|
|
547
|
+
return result.stdout.trim();
|
|
548
|
+
} catch {
|
|
549
|
+
return void 0;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
async function detectOpenCode() {
|
|
553
|
+
const path = await getCommandPath("opencode");
|
|
554
|
+
if (!path) return void 0;
|
|
555
|
+
const version = await getCommandVersion("opencode");
|
|
556
|
+
return { name: "opencode", version, path };
|
|
557
|
+
}
|
|
558
|
+
async function detectClaude() {
|
|
559
|
+
const path = await getCommandPath("claude");
|
|
560
|
+
if (!path) return void 0;
|
|
561
|
+
const version = await getCommandVersion("claude");
|
|
562
|
+
return { name: "claude", version, path };
|
|
563
|
+
}
|
|
564
|
+
async function detectTrae() {
|
|
565
|
+
const home = homedir2();
|
|
566
|
+
const variant = detectTraeVariant();
|
|
567
|
+
let path;
|
|
568
|
+
if (variant === "ide" && existsSync2(join2(home, ".trae-cn"))) {
|
|
569
|
+
path = join2(home, ".trae-cn");
|
|
570
|
+
} else if (variant === "plugin" && existsSync2(join2(home, ".marscode"))) {
|
|
571
|
+
path = join2(home, ".marscode");
|
|
572
|
+
} else if (variant === "cli" && existsSync2(join2(home, ".traecli"))) {
|
|
573
|
+
path = join2(home, ".traecli");
|
|
574
|
+
} else if (variant === "unknown") {
|
|
575
|
+
const cmdPath = await getCommandPath("trae");
|
|
576
|
+
if (cmdPath) path = cmdPath;
|
|
577
|
+
}
|
|
578
|
+
if (!path) return void 0;
|
|
579
|
+
return { name: "trae", version: variant, path };
|
|
580
|
+
}
|
|
581
|
+
async function detectCursor() {
|
|
582
|
+
const path = await getCommandPath("cursor");
|
|
583
|
+
if (path) {
|
|
584
|
+
const version = await getCommandVersion("cursor");
|
|
585
|
+
return { name: "cursor", version, path };
|
|
586
|
+
}
|
|
587
|
+
if (process.platform === "darwin") {
|
|
588
|
+
const appPath = "/Applications/Cursor.app";
|
|
589
|
+
if (existsSync2(appPath)) {
|
|
590
|
+
return { name: "cursor", path: appPath };
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return void 0;
|
|
594
|
+
}
|
|
595
|
+
async function detectCopilot() {
|
|
596
|
+
const path = await getCommandPath("gh");
|
|
597
|
+
if (!path) return void 0;
|
|
598
|
+
try {
|
|
599
|
+
await execa("gh", ["extension", "list"], { timeout: 5e3 });
|
|
600
|
+
return { name: "copilot", path };
|
|
601
|
+
} catch {
|
|
602
|
+
return void 0;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
async function detectTools() {
|
|
606
|
+
const detectors = [
|
|
607
|
+
detectOpenCode,
|
|
608
|
+
detectClaude,
|
|
609
|
+
detectTrae,
|
|
610
|
+
detectCursor,
|
|
611
|
+
detectCopilot
|
|
612
|
+
];
|
|
613
|
+
const results = await Promise.allSettled(detectors.map((d) => d()));
|
|
614
|
+
const tools = [];
|
|
615
|
+
for (const result of results) {
|
|
616
|
+
if (result.status === "fulfilled" && result.value) {
|
|
617
|
+
tools.push(result.value);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
return tools;
|
|
621
|
+
}
|
|
622
|
+
function getToolDisplayName(tool) {
|
|
623
|
+
const names = {
|
|
624
|
+
opencode: "OpenCode",
|
|
625
|
+
claude: "Claude Code",
|
|
626
|
+
trae: "Trae",
|
|
627
|
+
cursor: "Cursor",
|
|
628
|
+
copilot: "GitHub Copilot"
|
|
629
|
+
};
|
|
630
|
+
return names[tool];
|
|
631
|
+
}
|
|
632
|
+
function getAllTools() {
|
|
633
|
+
return ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// src/core/manifest.ts
|
|
637
|
+
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
638
|
+
import { join as join3 } from "path";
|
|
639
|
+
function readManifest(configRoot) {
|
|
640
|
+
const manifestPath = getManifestPath(configRoot);
|
|
641
|
+
if (existsSync3(manifestPath)) {
|
|
642
|
+
try {
|
|
643
|
+
const content = readFileSync(manifestPath, "utf-8");
|
|
644
|
+
return JSON.parse(content);
|
|
645
|
+
} catch {
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
function readAllManifests(configRoot) {
|
|
651
|
+
const manifests = [];
|
|
652
|
+
const plugins = getAllPlugins();
|
|
653
|
+
const standardPath = getManifestPath(configRoot);
|
|
654
|
+
if (existsSync3(standardPath)) {
|
|
655
|
+
try {
|
|
656
|
+
const content = readFileSync(standardPath, "utf-8");
|
|
657
|
+
manifests.push(JSON.parse(content));
|
|
658
|
+
} catch {
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
for (const plugin of plugins) {
|
|
662
|
+
const pluginManifestPath = join3(configRoot, `${plugin.id}-manifest.json`);
|
|
663
|
+
if (existsSync3(pluginManifestPath)) {
|
|
664
|
+
try {
|
|
665
|
+
const content = readFileSync(pluginManifestPath, "utf-8");
|
|
666
|
+
manifests.push(JSON.parse(content));
|
|
667
|
+
} catch {
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return manifests;
|
|
672
|
+
}
|
|
673
|
+
function scanInstalled() {
|
|
674
|
+
const plugins = getAllPlugins();
|
|
675
|
+
const installed = [];
|
|
676
|
+
const tools = ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
677
|
+
const levels = ["project", "global"];
|
|
678
|
+
for (const tool of tools) {
|
|
679
|
+
for (const level of levels) {
|
|
680
|
+
const configRoot = getConfigRoot(tool, level);
|
|
681
|
+
const manifests = readAllManifests(configRoot);
|
|
682
|
+
for (const manifest of manifests) {
|
|
683
|
+
const plugin = plugins.find((p) => p.id === manifest.team);
|
|
684
|
+
if (!plugin) continue;
|
|
685
|
+
const alreadyAdded = installed.some(
|
|
686
|
+
(p) => p.id === plugin.id && p.tool === tool && p.level === level
|
|
687
|
+
);
|
|
688
|
+
if (alreadyAdded) continue;
|
|
689
|
+
installed.push({
|
|
690
|
+
id: plugin.id,
|
|
691
|
+
displayName: plugin.displayName,
|
|
692
|
+
tool,
|
|
693
|
+
level,
|
|
694
|
+
skillsCount: manifest.installed_skills?.length || 0,
|
|
695
|
+
agentsCount: manifest.installed_agents?.length || 0,
|
|
696
|
+
installTime: manifest.install_time,
|
|
697
|
+
configRoot
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
return installed;
|
|
703
|
+
}
|
|
704
|
+
|
|
673
705
|
// src/utils/logger.ts
|
|
674
706
|
import chalk from "chalk";
|
|
675
707
|
import ora from "ora";
|
|
@@ -2772,7 +2804,7 @@ async function installCommand(names, options) {
|
|
|
2772
2804
|
}
|
|
2773
2805
|
let tool2;
|
|
2774
2806
|
if (options.tool) {
|
|
2775
|
-
tool2 = options.tool;
|
|
2807
|
+
tool2 = validateTool(options.tool);
|
|
2776
2808
|
} else {
|
|
2777
2809
|
const detected = await selectToolWithDetection();
|
|
2778
2810
|
if (detected === "back") return;
|
|
@@ -2800,7 +2832,7 @@ async function installCommand(names, options) {
|
|
|
2800
2832
|
const repoPath = await repoManager.ensureRepo();
|
|
2801
2833
|
spinner.succeed("\u63D2\u4EF6\u6570\u636E\u52A0\u8F7D\u5B8C\u6210");
|
|
2802
2834
|
logger.info(`${t("skill_install_progress")} ${chalk9.bold(names.length)} \u4E2A Skills...`);
|
|
2803
|
-
const level2 = options.level
|
|
2835
|
+
const level2 = options.level ? validateLevel(options.level) : "project";
|
|
2804
2836
|
const results = await installSkills(names, tool2, level2, repoPath);
|
|
2805
2837
|
let successCount = 0;
|
|
2806
2838
|
let failCount = 0;
|
|
@@ -2861,13 +2893,13 @@ async function installCommand(names, options) {
|
|
|
2861
2893
|
}
|
|
2862
2894
|
let tool;
|
|
2863
2895
|
if (options.tool) {
|
|
2864
|
-
tool = options.tool;
|
|
2896
|
+
tool = validateTool(options.tool);
|
|
2865
2897
|
} else {
|
|
2866
2898
|
const detected = await selectToolWithDetection();
|
|
2867
2899
|
if (detected === "back") return;
|
|
2868
2900
|
tool = detected;
|
|
2869
2901
|
}
|
|
2870
|
-
const level = options.level
|
|
2902
|
+
const level = options.level ? validateLevel(options.level) : "project";
|
|
2871
2903
|
if (plugins.length > 0) {
|
|
2872
2904
|
const configRoot = getConfigRoot(tool, level);
|
|
2873
2905
|
const manifests = readAllManifests(configRoot);
|
|
@@ -2983,8 +3015,8 @@ async function installPlugins(pluginIds, tool, level, repoPath) {
|
|
|
2983
3015
|
import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync5, lstatSync as lstatSync4 } from "fs";
|
|
2984
3016
|
import chalk10 from "chalk";
|
|
2985
3017
|
async function uninstallCommand(names, options) {
|
|
2986
|
-
const tool = options.tool
|
|
2987
|
-
const level = options.level
|
|
3018
|
+
const tool = options.tool ? validateTool(options.tool) : "opencode";
|
|
3019
|
+
const level = options.level ? validateLevel(options.level) : "project";
|
|
2988
3020
|
const plugins = [];
|
|
2989
3021
|
const skills = [];
|
|
2990
3022
|
for (const name of names) {
|
|
@@ -3098,13 +3130,13 @@ import chalk11 from "chalk";
|
|
|
3098
3130
|
async function updateCommand(pluginNames, options) {
|
|
3099
3131
|
let tool;
|
|
3100
3132
|
if (options.tool) {
|
|
3101
|
-
tool = options.tool;
|
|
3133
|
+
tool = validateTool(options.tool);
|
|
3102
3134
|
} else {
|
|
3103
3135
|
const detected = await selectToolWithDetection();
|
|
3104
3136
|
if (detected === "back") return;
|
|
3105
3137
|
tool = detected;
|
|
3106
3138
|
}
|
|
3107
|
-
const level = options.level
|
|
3139
|
+
const level = options.level ? validateLevel(options.level) : "project";
|
|
3108
3140
|
let pluginsToUpdate = [];
|
|
3109
3141
|
if (pluginNames.length === 0) {
|
|
3110
3142
|
const configRoot = getConfigRoot(tool, level);
|
|
@@ -3263,7 +3295,7 @@ function createCLI() {
|
|
|
3263
3295
|
setLanguage(config.language);
|
|
3264
3296
|
}
|
|
3265
3297
|
const program2 = new Command();
|
|
3266
|
-
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.
|
|
3298
|
+
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.11");
|
|
3267
3299
|
program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
|
|
3268
3300
|
await initCommand();
|
|
3269
3301
|
});
|