@cannbot-ai/install-helper 0.0.2-beta.15 → 0.0.2-beta.16
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/defaults.yaml +15 -0
- package/dist/index.js +213 -248
- package/dist/index.js.map +1 -1
- 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 +5 -3
- package/plugins.d/_defaults.yml +4 -0
- package/plugins.d/catlass-op-generator.yml +7 -0
- package/plugins.d/model-infer-optimize.yml +7 -0
- package/plugins.d/ops-code-reviewer.yml +7 -0
- package/plugins.d/ops-direct-invoke-flash.yml +7 -0
- package/plugins.d/ops-direct-invoke.yml +7 -0
- package/plugins.d/ops-registry-invoke.yml +7 -0
- package/plugins.d/pypto-op-orchestrator.yml +7 -0
- package/plugins.d/tilelang-op-orchestrator.yml +7 -0
- package/plugins.d/torch-compile.yml +7 -0
- package/plugins.d/triton-op-generator.yml +8 -0
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,11 +76,11 @@ 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 join3 } 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 join2 } from "path";
|
|
147
84
|
import { existsSync } from "fs";
|
|
148
85
|
|
|
149
86
|
// src/utils/i18n.ts
|
|
@@ -512,9 +449,9 @@ function validateLevel(level) {
|
|
|
512
449
|
}
|
|
513
450
|
function detectTraeVariant() {
|
|
514
451
|
const home = homedir();
|
|
515
|
-
if (existsSync(
|
|
516
|
-
if (existsSync(
|
|
517
|
-
if (existsSync(
|
|
452
|
+
if (existsSync(join2(home, ".trae-cn"))) return "ide";
|
|
453
|
+
if (existsSync(join2(home, ".marscode"))) return "plugin";
|
|
454
|
+
if (existsSync(join2(home, ".traecli"))) return "cli";
|
|
518
455
|
return "unknown";
|
|
519
456
|
}
|
|
520
457
|
function getConfigRoot(tool, level, base) {
|
|
@@ -522,24 +459,24 @@ function getConfigRoot(tool, level, base) {
|
|
|
522
459
|
if (level === "global") {
|
|
523
460
|
switch (tool) {
|
|
524
461
|
case "opencode":
|
|
525
|
-
return
|
|
462
|
+
return join2(home, ".config", "opencode");
|
|
526
463
|
case "claude":
|
|
527
|
-
return
|
|
464
|
+
return join2(home, ".claude");
|
|
528
465
|
case "trae": {
|
|
529
466
|
const variant = detectTraeVariant();
|
|
530
467
|
switch (variant) {
|
|
531
468
|
case "plugin":
|
|
532
|
-
return
|
|
469
|
+
return join2(home, ".marscode");
|
|
533
470
|
case "cli":
|
|
534
|
-
return
|
|
471
|
+
return join2(home, ".traecli");
|
|
535
472
|
default:
|
|
536
|
-
return
|
|
473
|
+
return join2(home, ".trae-cn");
|
|
537
474
|
}
|
|
538
475
|
}
|
|
539
476
|
case "cursor":
|
|
540
|
-
return
|
|
477
|
+
return join2(home, ".cursor");
|
|
541
478
|
case "copilot":
|
|
542
|
-
return
|
|
479
|
+
return join2(home, ".copilot");
|
|
543
480
|
default:
|
|
544
481
|
throw new Error(
|
|
545
482
|
t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
|
|
@@ -549,24 +486,24 @@ function getConfigRoot(tool, level, base) {
|
|
|
549
486
|
const baseDir = base || process.cwd();
|
|
550
487
|
switch (tool) {
|
|
551
488
|
case "opencode":
|
|
552
|
-
return
|
|
489
|
+
return join2(baseDir, ".opencode");
|
|
553
490
|
case "claude":
|
|
554
|
-
return
|
|
491
|
+
return join2(baseDir, ".claude");
|
|
555
492
|
case "trae": {
|
|
556
493
|
const variant = detectTraeVariant();
|
|
557
494
|
switch (variant) {
|
|
558
495
|
case "plugin":
|
|
559
|
-
return
|
|
496
|
+
return join2(baseDir, ".marscode");
|
|
560
497
|
case "cli":
|
|
561
|
-
return
|
|
498
|
+
return join2(baseDir, ".traecli");
|
|
562
499
|
default:
|
|
563
|
-
return
|
|
500
|
+
return join2(baseDir, ".trae");
|
|
564
501
|
}
|
|
565
502
|
}
|
|
566
503
|
case "cursor":
|
|
567
|
-
return
|
|
504
|
+
return join2(baseDir, ".cursor");
|
|
568
505
|
case "copilot":
|
|
569
|
-
return
|
|
506
|
+
return join2(baseDir, ".github");
|
|
570
507
|
default:
|
|
571
508
|
throw new Error(
|
|
572
509
|
t("error_invalid_tool").replace("{tool}", tool).replace("{tools}", VALID_TOOLS.join(", "))
|
|
@@ -577,19 +514,19 @@ function getConfigFileName(tool) {
|
|
|
577
514
|
return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
578
515
|
}
|
|
579
516
|
function getSkillsDir(configRoot) {
|
|
580
|
-
return
|
|
517
|
+
return join2(configRoot, "skills");
|
|
581
518
|
}
|
|
582
519
|
function getAgentsDir(configRoot) {
|
|
583
|
-
return
|
|
520
|
+
return join2(configRoot, "agents");
|
|
584
521
|
}
|
|
585
522
|
function getManifestPath(configRoot) {
|
|
586
|
-
return
|
|
523
|
+
return join2(configRoot, "cannbot-manifest.json");
|
|
587
524
|
}
|
|
588
525
|
function getCannbotConfigDir() {
|
|
589
|
-
return
|
|
526
|
+
return join2(homedir(), ".cannbot");
|
|
590
527
|
}
|
|
591
528
|
function getCannbotRepoPath() {
|
|
592
|
-
return
|
|
529
|
+
return join2(getCannbotConfigDir(), "repo");
|
|
593
530
|
}
|
|
594
531
|
|
|
595
532
|
// src/core/detector.ts
|
|
@@ -627,12 +564,12 @@ async function detectTrae() {
|
|
|
627
564
|
const home = homedir2();
|
|
628
565
|
const variant = detectTraeVariant();
|
|
629
566
|
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 =
|
|
567
|
+
if (variant === "ide" && existsSync2(join3(home, ".trae-cn"))) {
|
|
568
|
+
path = join3(home, ".trae-cn");
|
|
569
|
+
} else if (variant === "plugin" && existsSync2(join3(home, ".marscode"))) {
|
|
570
|
+
path = join3(home, ".marscode");
|
|
571
|
+
} else if (variant === "cli" && existsSync2(join3(home, ".traecli"))) {
|
|
572
|
+
path = join3(home, ".traecli");
|
|
636
573
|
} else if (variant === "unknown") {
|
|
637
574
|
const cmdPath = await getCommandPath("trae");
|
|
638
575
|
if (cmdPath) path = cmdPath;
|
|
@@ -696,13 +633,13 @@ function getAllTools() {
|
|
|
696
633
|
}
|
|
697
634
|
|
|
698
635
|
// src/core/manifest.ts
|
|
699
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
700
|
-
import { join as
|
|
636
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
637
|
+
import { join as join4 } from "path";
|
|
701
638
|
function readManifest(configRoot) {
|
|
702
639
|
const manifestPath = getManifestPath(configRoot);
|
|
703
640
|
if (existsSync3(manifestPath)) {
|
|
704
641
|
try {
|
|
705
|
-
const content =
|
|
642
|
+
const content = readFileSync2(manifestPath, "utf-8");
|
|
706
643
|
return JSON.parse(content);
|
|
707
644
|
} catch {
|
|
708
645
|
}
|
|
@@ -715,16 +652,16 @@ function readAllManifests(configRoot) {
|
|
|
715
652
|
const standardPath = getManifestPath(configRoot);
|
|
716
653
|
if (existsSync3(standardPath)) {
|
|
717
654
|
try {
|
|
718
|
-
const content =
|
|
655
|
+
const content = readFileSync2(standardPath, "utf-8");
|
|
719
656
|
manifests.push(JSON.parse(content));
|
|
720
657
|
} catch {
|
|
721
658
|
}
|
|
722
659
|
}
|
|
723
660
|
for (const plugin of plugins) {
|
|
724
|
-
const pluginManifestPath =
|
|
661
|
+
const pluginManifestPath = join4(configRoot, `${plugin.id}-manifest.json`);
|
|
725
662
|
if (existsSync3(pluginManifestPath)) {
|
|
726
663
|
try {
|
|
727
|
-
const content =
|
|
664
|
+
const content = readFileSync2(pluginManifestPath, "utf-8");
|
|
728
665
|
manifests.push(JSON.parse(content));
|
|
729
666
|
} catch {
|
|
730
667
|
}
|
|
@@ -767,27 +704,27 @@ function scanInstalled() {
|
|
|
767
704
|
return installed;
|
|
768
705
|
}
|
|
769
706
|
function verifyPluginFilesExist(configRoot, manifest, tool, level) {
|
|
770
|
-
const skillsDir =
|
|
771
|
-
const agentsDir =
|
|
707
|
+
const skillsDir = join4(configRoot, "skills");
|
|
708
|
+
const agentsDir = join4(configRoot, "agents");
|
|
772
709
|
if (manifest.installed_skills && manifest.installed_skills.length > 0) {
|
|
773
710
|
const hasAnySkill = manifest.installed_skills.some((skillId) => {
|
|
774
|
-
const skillPath =
|
|
711
|
+
const skillPath = join4(skillsDir, skillId);
|
|
775
712
|
return existsSync3(skillPath);
|
|
776
713
|
});
|
|
777
714
|
if (!hasAnySkill) return false;
|
|
778
715
|
}
|
|
779
716
|
if (manifest.installed_agents && manifest.installed_agents.length > 0) {
|
|
780
717
|
const hasAnyAgent = manifest.installed_agents.some((agentId) => {
|
|
781
|
-
const agentPath =
|
|
718
|
+
const agentPath = join4(agentsDir, agentId);
|
|
782
719
|
return existsSync3(agentPath);
|
|
783
720
|
});
|
|
784
721
|
if (!hasAnyAgent) return false;
|
|
785
722
|
}
|
|
786
723
|
let agentsMdPath;
|
|
787
724
|
if (tool === "opencode" && level === "project") {
|
|
788
|
-
agentsMdPath =
|
|
725
|
+
agentsMdPath = join4(configRoot, "..", "AGENTS.md");
|
|
789
726
|
} else {
|
|
790
|
-
agentsMdPath =
|
|
727
|
+
agentsMdPath = join4(configRoot, "AGENTS.md");
|
|
791
728
|
}
|
|
792
729
|
if (!existsSync3(agentsMdPath)) return false;
|
|
793
730
|
return true;
|
|
@@ -856,15 +793,15 @@ function showOperationHints(isCheckbox = false) {
|
|
|
856
793
|
}
|
|
857
794
|
|
|
858
795
|
// src/utils/config.ts
|
|
859
|
-
import { existsSync as existsSync4, mkdirSync, readFileSync as
|
|
860
|
-
import { join as
|
|
796
|
+
import { existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3, writeFileSync } from "fs";
|
|
797
|
+
import { join as join5 } from "path";
|
|
861
798
|
import { homedir as homedir3 } from "os";
|
|
862
799
|
import { parse, stringify } from "yaml";
|
|
863
800
|
function getConfigDir() {
|
|
864
|
-
return
|
|
801
|
+
return join5(homedir3(), ".cannbot");
|
|
865
802
|
}
|
|
866
803
|
function getConfigPath() {
|
|
867
|
-
return
|
|
804
|
+
return join5(getConfigDir(), "config.yaml");
|
|
868
805
|
}
|
|
869
806
|
function readConfig() {
|
|
870
807
|
const configPath = getConfigPath();
|
|
@@ -875,7 +812,7 @@ function readConfig() {
|
|
|
875
812
|
};
|
|
876
813
|
}
|
|
877
814
|
try {
|
|
878
|
-
const content =
|
|
815
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
879
816
|
const parsed = parse(content);
|
|
880
817
|
return {
|
|
881
818
|
language: parsed.language || "zh_CN",
|
|
@@ -1181,14 +1118,19 @@ async function stepConfirm(tool, level, plugins) {
|
|
|
1181
1118
|
}
|
|
1182
1119
|
|
|
1183
1120
|
// src/core/repository.ts
|
|
1184
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
1185
|
-
import { join as
|
|
1121
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5 } from "fs";
|
|
1122
|
+
import { join as join7, dirname as dirname3 } from "path";
|
|
1123
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1186
1124
|
import { execa as execa2 } from "execa";
|
|
1125
|
+
import { parse as parseYaml3 } from "yaml";
|
|
1187
1126
|
|
|
1188
1127
|
// src/core/scanner.ts
|
|
1189
|
-
import { existsSync as existsSync5, readdirSync, readFileSync as
|
|
1190
|
-
import { join as
|
|
1191
|
-
import {
|
|
1128
|
+
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
1129
|
+
import { join as join6, dirname as dirname2 } from "path";
|
|
1130
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1131
|
+
import { parse as parseYaml2 } from "yaml";
|
|
1132
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
1133
|
+
var __dirname2 = dirname2(__filename2);
|
|
1192
1134
|
var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
1193
1135
|
"node_modules",
|
|
1194
1136
|
".git",
|
|
@@ -1209,36 +1151,43 @@ var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
|
1209
1151
|
"docs",
|
|
1210
1152
|
"scripts"
|
|
1211
1153
|
]);
|
|
1212
|
-
|
|
1213
|
-
"
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
]
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
]
|
|
1154
|
+
function loadScanConfig() {
|
|
1155
|
+
const configPath = join6(__dirname2, "config", "defaults.yaml");
|
|
1156
|
+
try {
|
|
1157
|
+
const config = parseYaml2(readFileSync4(configPath, "utf-8"));
|
|
1158
|
+
return {
|
|
1159
|
+
skillDirs: config.scanDirs || ["ops", "model", "graph", "infra", "ops-lab"],
|
|
1160
|
+
pluginDirs: config.pluginDirs || ["plugins-official", "plugins-community"]
|
|
1161
|
+
};
|
|
1162
|
+
} catch {
|
|
1163
|
+
return {
|
|
1164
|
+
skillDirs: ["ops", "model", "graph", "infra", "ops-lab"],
|
|
1165
|
+
pluginDirs: ["plugins-official", "plugins-community"]
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
var scanConfig = loadScanConfig();
|
|
1170
|
+
var SKILL_SCAN_DIRS = scanConfig.skillDirs;
|
|
1171
|
+
var PLUGIN_SCAN_DIRS = scanConfig.pluginDirs;
|
|
1223
1172
|
function scanSkills(repoPath) {
|
|
1224
1173
|
const skills = [];
|
|
1225
1174
|
const seen = /* @__PURE__ */ new Set();
|
|
1226
1175
|
for (const dir of SKILL_SCAN_DIRS) {
|
|
1227
|
-
const fullPath =
|
|
1176
|
+
const fullPath = join6(repoPath, dir);
|
|
1228
1177
|
if (!existsSync5(fullPath)) continue;
|
|
1229
1178
|
scanDirectory(fullPath, repoPath, dir, skills, seen);
|
|
1230
1179
|
}
|
|
1231
1180
|
for (const pluginDir of PLUGIN_SCAN_DIRS) {
|
|
1232
|
-
const pluginParent =
|
|
1181
|
+
const pluginParent = join6(repoPath, pluginDir);
|
|
1233
1182
|
if (!existsSync5(pluginParent)) continue;
|
|
1234
1183
|
for (const plugin of safeReaddir(pluginParent)) {
|
|
1235
|
-
const pluginPath =
|
|
1184
|
+
const pluginPath = join6(pluginParent, plugin);
|
|
1236
1185
|
if (!isDirectory(pluginPath)) continue;
|
|
1237
|
-
const skillsDir =
|
|
1186
|
+
const skillsDir = join6(pluginPath, "skills");
|
|
1238
1187
|
if (existsSync5(skillsDir)) {
|
|
1239
1188
|
scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
|
|
1240
1189
|
}
|
|
1241
|
-
const skillDir =
|
|
1190
|
+
const skillDir = join6(pluginPath, "skill");
|
|
1242
1191
|
if (existsSync5(skillDir)) {
|
|
1243
1192
|
scanDirectory(skillDir, repoPath, `${pluginDir}/${plugin}/skill`, skills, seen);
|
|
1244
1193
|
}
|
|
@@ -1248,7 +1197,7 @@ function scanSkills(repoPath) {
|
|
|
1248
1197
|
}
|
|
1249
1198
|
function parseFrontmatter(filePath) {
|
|
1250
1199
|
try {
|
|
1251
|
-
const content =
|
|
1200
|
+
const content = readFileSync4(filePath, "utf-8");
|
|
1252
1201
|
const lines = content.split("\n");
|
|
1253
1202
|
if (lines.length < 3) return null;
|
|
1254
1203
|
if (lines[0].trim() !== "---") return null;
|
|
@@ -1261,7 +1210,7 @@ function parseFrontmatter(filePath) {
|
|
|
1261
1210
|
}
|
|
1262
1211
|
if (endIndex === -1) return null;
|
|
1263
1212
|
const yamlBlock = lines.slice(1, endIndex).map((l) => l.replace(/\r$/, "")).join("\n");
|
|
1264
|
-
const parsed =
|
|
1213
|
+
const parsed = parseYaml2(yamlBlock);
|
|
1265
1214
|
if (!parsed || typeof parsed !== "object") return null;
|
|
1266
1215
|
if (!parsed.name || typeof parsed.name !== "string") return null;
|
|
1267
1216
|
return {
|
|
@@ -1274,17 +1223,17 @@ function parseFrontmatter(filePath) {
|
|
|
1274
1223
|
}
|
|
1275
1224
|
function getCurrentCommit(repoPath) {
|
|
1276
1225
|
try {
|
|
1277
|
-
const headFile =
|
|
1226
|
+
const headFile = join6(repoPath, ".git", "HEAD");
|
|
1278
1227
|
if (!existsSync5(headFile)) return "unknown";
|
|
1279
|
-
const headContent =
|
|
1228
|
+
const headContent = readFileSync4(headFile, "utf-8").trim();
|
|
1280
1229
|
if (headContent.startsWith("ref: ")) {
|
|
1281
|
-
const refPath =
|
|
1230
|
+
const refPath = join6(repoPath, ".git", headContent.slice(5));
|
|
1282
1231
|
if (existsSync5(refPath)) {
|
|
1283
|
-
return
|
|
1232
|
+
return readFileSync4(refPath, "utf-8").trim();
|
|
1284
1233
|
}
|
|
1285
|
-
const packedRefsPath =
|
|
1234
|
+
const packedRefsPath = join6(repoPath, ".git", "packed-refs");
|
|
1286
1235
|
if (existsSync5(packedRefsPath)) {
|
|
1287
|
-
const packedRefs =
|
|
1236
|
+
const packedRefs = readFileSync4(packedRefsPath, "utf-8");
|
|
1288
1237
|
const refName = headContent.slice(5);
|
|
1289
1238
|
const lines = packedRefs.split("\n");
|
|
1290
1239
|
for (const line of lines) {
|
|
@@ -1303,7 +1252,7 @@ function readScanCache() {
|
|
|
1303
1252
|
try {
|
|
1304
1253
|
const cachePath = getCachePath();
|
|
1305
1254
|
if (!existsSync5(cachePath)) return null;
|
|
1306
|
-
const content =
|
|
1255
|
+
const content = readFileSync4(cachePath, "utf-8");
|
|
1307
1256
|
const cache = JSON.parse(content);
|
|
1308
1257
|
if (!cache.skills || !cache.timestamp) return null;
|
|
1309
1258
|
const age = Date.now() - cache.timestamp;
|
|
@@ -1316,7 +1265,7 @@ function readScanCache() {
|
|
|
1316
1265
|
function writeScanCache(cache) {
|
|
1317
1266
|
try {
|
|
1318
1267
|
const cachePath = getCachePath();
|
|
1319
|
-
const cacheDir =
|
|
1268
|
+
const cacheDir = dirname2(cachePath);
|
|
1320
1269
|
if (!existsSync5(cacheDir)) {
|
|
1321
1270
|
mkdirSync2(cacheDir, { recursive: true });
|
|
1322
1271
|
}
|
|
@@ -1325,10 +1274,10 @@ function writeScanCache(cache) {
|
|
|
1325
1274
|
}
|
|
1326
1275
|
}
|
|
1327
1276
|
function getCachePath() {
|
|
1328
|
-
return
|
|
1277
|
+
return join6(getCannbotConfigDir(), "scan-cache.json");
|
|
1329
1278
|
}
|
|
1330
1279
|
function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
|
|
1331
|
-
const selfSkillMd =
|
|
1280
|
+
const selfSkillMd = join6(dirPath, "SKILL.md");
|
|
1332
1281
|
if (existsSync5(selfSkillMd)) {
|
|
1333
1282
|
const frontmatter = parseFrontmatter(selfSkillMd);
|
|
1334
1283
|
if (frontmatter && !seen.has(frontmatter.name)) {
|
|
@@ -1343,10 +1292,10 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
|
|
|
1343
1292
|
return;
|
|
1344
1293
|
}
|
|
1345
1294
|
for (const entry of safeReaddir(dirPath)) {
|
|
1346
|
-
const fullPath =
|
|
1295
|
+
const fullPath = join6(dirPath, entry);
|
|
1347
1296
|
if (EXCLUDE_DIRS.has(entry)) continue;
|
|
1348
1297
|
if (!isDirectory(fullPath)) continue;
|
|
1349
|
-
const skillMd =
|
|
1298
|
+
const skillMd = join6(fullPath, "SKILL.md");
|
|
1350
1299
|
if (existsSync5(skillMd)) {
|
|
1351
1300
|
const frontmatter = parseFrontmatter(skillMd);
|
|
1352
1301
|
if (frontmatter && !seen.has(frontmatter.name)) {
|
|
@@ -1365,7 +1314,7 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
|
|
|
1365
1314
|
}
|
|
1366
1315
|
function safeReaddir(dir) {
|
|
1367
1316
|
try {
|
|
1368
|
-
return
|
|
1317
|
+
return readdirSync2(dir);
|
|
1369
1318
|
} catch {
|
|
1370
1319
|
return [];
|
|
1371
1320
|
}
|
|
@@ -1605,7 +1554,21 @@ function getAllCategories() {
|
|
|
1605
1554
|
}
|
|
1606
1555
|
|
|
1607
1556
|
// src/core/repository.ts
|
|
1608
|
-
var
|
|
1557
|
+
var __filename3 = fileURLToPath3(import.meta.url);
|
|
1558
|
+
var __dirname3 = dirname3(__filename3);
|
|
1559
|
+
function loadRepoUrl() {
|
|
1560
|
+
if (process.env.CANNBOT_REPO_URL) {
|
|
1561
|
+
return process.env.CANNBOT_REPO_URL;
|
|
1562
|
+
}
|
|
1563
|
+
const configPath = join7(__dirname3, "config", "defaults.yaml");
|
|
1564
|
+
try {
|
|
1565
|
+
const config = parseYaml3(readFileSync5(configPath, "utf-8"));
|
|
1566
|
+
return config.repository?.url || "https://gitcode.com/cann/cannbot-skills.git";
|
|
1567
|
+
} catch {
|
|
1568
|
+
return "https://gitcode.com/cann/cannbot-skills.git";
|
|
1569
|
+
}
|
|
1570
|
+
}
|
|
1571
|
+
var REPO_URL = loadRepoUrl();
|
|
1609
1572
|
var RepositoryManager = class {
|
|
1610
1573
|
repoPath;
|
|
1611
1574
|
constructor(customPath) {
|
|
@@ -1663,8 +1626,8 @@ var RepositoryManager = class {
|
|
|
1663
1626
|
}
|
|
1664
1627
|
isValidRepo(path) {
|
|
1665
1628
|
if (!existsSync6(path)) return false;
|
|
1666
|
-
const gitDir =
|
|
1667
|
-
const pluginsDir =
|
|
1629
|
+
const gitDir = join7(path, ".git");
|
|
1630
|
+
const pluginsDir = join7(path, "plugins-official");
|
|
1668
1631
|
return existsSync6(gitDir) && existsSync6(pluginsDir);
|
|
1669
1632
|
}
|
|
1670
1633
|
async cloneRepo() {
|
|
@@ -1700,17 +1663,17 @@ function createRepositoryManager(customPath) {
|
|
|
1700
1663
|
|
|
1701
1664
|
// src/core/installer.ts
|
|
1702
1665
|
import { existsSync as existsSync9 } from "fs";
|
|
1703
|
-
import { join as
|
|
1666
|
+
import { join as join10 } from "path";
|
|
1704
1667
|
import { execa as execa3 } from "execa";
|
|
1705
1668
|
|
|
1706
1669
|
// src/core/record.ts
|
|
1707
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as
|
|
1708
|
-
import { join as
|
|
1670
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync4, lstatSync, unlinkSync } from "fs";
|
|
1671
|
+
import { join as join8 } from "path";
|
|
1709
1672
|
function getInstallsDir() {
|
|
1710
|
-
return
|
|
1673
|
+
return join8(getCannbotConfigDir(), "installs");
|
|
1711
1674
|
}
|
|
1712
1675
|
function getRecordPath(pluginId) {
|
|
1713
|
-
return
|
|
1676
|
+
return join8(getInstallsDir(), `${pluginId}.json`);
|
|
1714
1677
|
}
|
|
1715
1678
|
function readRecord(pluginId) {
|
|
1716
1679
|
const recordPath = getRecordPath(pluginId);
|
|
@@ -1718,7 +1681,7 @@ function readRecord(pluginId) {
|
|
|
1718
1681
|
return null;
|
|
1719
1682
|
}
|
|
1720
1683
|
try {
|
|
1721
|
-
const content =
|
|
1684
|
+
const content = readFileSync6(recordPath, "utf-8");
|
|
1722
1685
|
return JSON.parse(content);
|
|
1723
1686
|
} catch {
|
|
1724
1687
|
return null;
|
|
@@ -1742,22 +1705,22 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
1742
1705
|
const files = [];
|
|
1743
1706
|
const directories = [];
|
|
1744
1707
|
if (manifest) {
|
|
1745
|
-
const skillsDir =
|
|
1708
|
+
const skillsDir = join8(configRoot, "skills");
|
|
1746
1709
|
if (existsSync7(skillsDir)) {
|
|
1747
1710
|
directories.push(skillsDir);
|
|
1748
1711
|
for (const skillName of manifest.installed_skills || []) {
|
|
1749
|
-
const skillPath =
|
|
1712
|
+
const skillPath = join8(skillsDir, skillName);
|
|
1750
1713
|
if (existsSync7(skillPath) || isSymlink(skillPath)) {
|
|
1751
1714
|
files.push(skillPath);
|
|
1752
1715
|
}
|
|
1753
1716
|
}
|
|
1754
1717
|
}
|
|
1755
|
-
const agentsDir =
|
|
1718
|
+
const agentsDir = join8(configRoot, "agents");
|
|
1756
1719
|
if (existsSync7(agentsDir)) {
|
|
1757
1720
|
directories.push(agentsDir);
|
|
1758
1721
|
for (const agentName of manifest.installed_agents || []) {
|
|
1759
|
-
const agentPath =
|
|
1760
|
-
const agentPathMd =
|
|
1722
|
+
const agentPath = join8(agentsDir, agentName);
|
|
1723
|
+
const agentPathMd = join8(agentsDir, agentName + ".md");
|
|
1761
1724
|
if (existsSync7(agentPath) || isSymlink(agentPath)) {
|
|
1762
1725
|
files.push(agentPath);
|
|
1763
1726
|
} else if (existsSync7(agentPathMd) || isSymlink(agentPathMd)) {
|
|
@@ -1766,30 +1729,30 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
1766
1729
|
}
|
|
1767
1730
|
}
|
|
1768
1731
|
}
|
|
1769
|
-
const workflowsLink =
|
|
1732
|
+
const workflowsLink = join8(configRoot, "workflows");
|
|
1770
1733
|
if (isSymlink(workflowsLink)) {
|
|
1771
1734
|
files.push(workflowsLink);
|
|
1772
1735
|
}
|
|
1773
|
-
const manifestPath =
|
|
1736
|
+
const manifestPath = join8(configRoot, "cannbot-manifest.json");
|
|
1774
1737
|
if (existsSync7(manifestPath)) {
|
|
1775
1738
|
files.push(manifestPath);
|
|
1776
1739
|
}
|
|
1777
|
-
const pluginManifestPath =
|
|
1740
|
+
const pluginManifestPath = join8(configRoot, `${pluginId}-manifest.json`);
|
|
1778
1741
|
if (existsSync7(pluginManifestPath)) {
|
|
1779
1742
|
files.push(pluginManifestPath);
|
|
1780
1743
|
}
|
|
1781
1744
|
const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
1782
|
-
const configFilePath = level === "project" ?
|
|
1745
|
+
const configFilePath = level === "project" ? join8(installPath, configFileName) : join8(configRoot, configFileName);
|
|
1783
1746
|
if (existsSync7(configFilePath)) {
|
|
1784
1747
|
files.push(configFilePath);
|
|
1785
1748
|
}
|
|
1786
1749
|
const repoLinks = ["asc-devkit", "pypto", "tilelang-ascend", "cann-recipes-infer", "cann-samples"];
|
|
1787
1750
|
for (const repoName of repoLinks) {
|
|
1788
|
-
const repoLinkPath =
|
|
1751
|
+
const repoLinkPath = join8(installPath, repoName);
|
|
1789
1752
|
if (isSymlink(repoLinkPath)) {
|
|
1790
1753
|
files.push(repoLinkPath);
|
|
1791
1754
|
}
|
|
1792
|
-
const repoLinkInConfig =
|
|
1755
|
+
const repoLinkInConfig = join8(configRoot, repoName);
|
|
1793
1756
|
if (isSymlink(repoLinkInConfig)) {
|
|
1794
1757
|
files.push(repoLinkInConfig);
|
|
1795
1758
|
}
|
|
@@ -1814,7 +1777,7 @@ function isSymlink(path) {
|
|
|
1814
1777
|
}
|
|
1815
1778
|
}
|
|
1816
1779
|
function getSkillRecordPath() {
|
|
1817
|
-
return
|
|
1780
|
+
return join8(getInstallsDir(), "skills.json");
|
|
1818
1781
|
}
|
|
1819
1782
|
function readSkillRecord() {
|
|
1820
1783
|
const recordPath = getSkillRecordPath();
|
|
@@ -1822,7 +1785,7 @@ function readSkillRecord() {
|
|
|
1822
1785
|
return {};
|
|
1823
1786
|
}
|
|
1824
1787
|
try {
|
|
1825
|
-
const content =
|
|
1788
|
+
const content = readFileSync6(recordPath, "utf-8");
|
|
1826
1789
|
return JSON.parse(content);
|
|
1827
1790
|
} catch {
|
|
1828
1791
|
return {};
|
|
@@ -1872,16 +1835,16 @@ function getInstalledSkills(tool, level, installPath) {
|
|
|
1872
1835
|
const record = readSkillRecord();
|
|
1873
1836
|
const recordedSkills = record[tool]?.[level]?.[installPath]?.skills || [];
|
|
1874
1837
|
const configRoot = getConfigRoot(tool, level);
|
|
1875
|
-
const skillsDir =
|
|
1838
|
+
const skillsDir = join8(configRoot, "skills");
|
|
1876
1839
|
return recordedSkills.filter((skillId) => {
|
|
1877
|
-
const skillPath =
|
|
1840
|
+
const skillPath = join8(skillsDir, skillId);
|
|
1878
1841
|
return existsSync7(skillPath) || isSymlink(skillPath);
|
|
1879
1842
|
});
|
|
1880
1843
|
}
|
|
1881
1844
|
|
|
1882
1845
|
// src/core/backup.ts
|
|
1883
|
-
import { existsSync as existsSync8, copyFileSync, readdirSync as
|
|
1884
|
-
import { join as
|
|
1846
|
+
import { existsSync as existsSync8, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
1847
|
+
import { join as join9 } from "path";
|
|
1885
1848
|
function getAgentsFileName(tool) {
|
|
1886
1849
|
return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
1887
1850
|
}
|
|
@@ -1896,7 +1859,7 @@ function detectCurrentPlugin(configRoot, tool) {
|
|
|
1896
1859
|
};
|
|
1897
1860
|
}
|
|
1898
1861
|
}
|
|
1899
|
-
const agentsFile =
|
|
1862
|
+
const agentsFile = join9(configRoot, getAgentsFileName(tool));
|
|
1900
1863
|
if (!existsSync8(agentsFile)) {
|
|
1901
1864
|
return null;
|
|
1902
1865
|
}
|
|
@@ -1915,13 +1878,13 @@ function detectCurrentPlugin(configRoot, tool) {
|
|
|
1915
1878
|
return null;
|
|
1916
1879
|
}
|
|
1917
1880
|
function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
|
|
1918
|
-
const agentsFile =
|
|
1881
|
+
const agentsFile = join9(configRoot, getAgentsFileName(tool));
|
|
1919
1882
|
if (!existsSync8(agentsFile)) {
|
|
1920
1883
|
return null;
|
|
1921
1884
|
}
|
|
1922
1885
|
const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
|
|
1923
1886
|
const backupFileName = `${getAgentsFileName(tool)}.cannbot-backup.${fromPluginId}.${timestamp}`;
|
|
1924
|
-
const backupPath =
|
|
1887
|
+
const backupPath = join9(configRoot, backupFileName);
|
|
1925
1888
|
try {
|
|
1926
1889
|
copyFileSync(agentsFile, backupPath);
|
|
1927
1890
|
return {
|
|
@@ -1938,7 +1901,7 @@ function findBackups(configRoot) {
|
|
|
1938
1901
|
if (!existsSync8(configRoot)) {
|
|
1939
1902
|
return [];
|
|
1940
1903
|
}
|
|
1941
|
-
const files =
|
|
1904
|
+
const files = readdirSync3(configRoot);
|
|
1942
1905
|
const backups = [];
|
|
1943
1906
|
for (const file of files) {
|
|
1944
1907
|
if (file.includes(".cannbot-backup.")) {
|
|
@@ -1951,7 +1914,7 @@ function findBackups(configRoot) {
|
|
|
1951
1914
|
const timestamp = pluginIdAndTime.substring(lastDotIndex + 1);
|
|
1952
1915
|
const plugin = findPlugin(pluginId);
|
|
1953
1916
|
backups.push({
|
|
1954
|
-
filePath:
|
|
1917
|
+
filePath: join9(configRoot, file),
|
|
1955
1918
|
pluginId,
|
|
1956
1919
|
pluginName: plugin?.displayName || pluginId,
|
|
1957
1920
|
backupTime: timestamp
|
|
@@ -1964,7 +1927,7 @@ function findBackups(configRoot) {
|
|
|
1964
1927
|
}
|
|
1965
1928
|
function restoreBackup(backupPath, configRoot, tool) {
|
|
1966
1929
|
try {
|
|
1967
|
-
const agentsFile =
|
|
1930
|
+
const agentsFile = join9(configRoot, getAgentsFileName(tool));
|
|
1968
1931
|
copyFileSync(backupPath, agentsFile);
|
|
1969
1932
|
return true;
|
|
1970
1933
|
} catch {
|
|
@@ -2065,7 +2028,7 @@ async function installPlugin(opts) {
|
|
|
2065
2028
|
warnings: []
|
|
2066
2029
|
};
|
|
2067
2030
|
}
|
|
2068
|
-
const scriptPath =
|
|
2031
|
+
const scriptPath = join10(opts.repoPath, plugin.dir, plugin.script);
|
|
2069
2032
|
if (!existsSync9(scriptPath)) {
|
|
2070
2033
|
return {
|
|
2071
2034
|
success: false,
|
|
@@ -2082,7 +2045,7 @@ async function installPlugin(opts) {
|
|
|
2082
2045
|
}
|
|
2083
2046
|
const cwd = opts.installPath || process.cwd();
|
|
2084
2047
|
const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
|
|
2085
|
-
const agentsFile =
|
|
2048
|
+
const agentsFile = join10(configRoot, getAgentsFileName(opts.tool));
|
|
2086
2049
|
let backupInfo = null;
|
|
2087
2050
|
if (existsSync9(agentsFile)) {
|
|
2088
2051
|
const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
|
|
@@ -2177,14 +2140,14 @@ async function installPlugin(opts) {
|
|
|
2177
2140
|
}
|
|
2178
2141
|
|
|
2179
2142
|
// src/core/skill-installer.ts
|
|
2180
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as
|
|
2181
|
-
import { join as
|
|
2143
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as readdirSync4, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
|
|
2144
|
+
import { join as join11 } from "path";
|
|
2182
2145
|
import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
|
|
2183
2146
|
import chalk4 from "chalk";
|
|
2184
2147
|
import Table from "cli-table3";
|
|
2185
2148
|
async function installSkills(skillIds, tool, level, repoPath) {
|
|
2186
2149
|
const configRoot = getConfigRoot(tool, level);
|
|
2187
|
-
const skillsDir =
|
|
2150
|
+
const skillsDir = join11(configRoot, "skills");
|
|
2188
2151
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
2189
2152
|
if (!existsSync10(skillsDir)) {
|
|
2190
2153
|
mkdirSync5(skillsDir, { recursive: true });
|
|
@@ -2197,8 +2160,8 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
2197
2160
|
results.push({ skillId, success: false, error: "Skill not found in registry" });
|
|
2198
2161
|
continue;
|
|
2199
2162
|
}
|
|
2200
|
-
const sourcePath =
|
|
2201
|
-
const targetPath =
|
|
2163
|
+
const sourcePath = join11(repoPath, skill.source, skill.id);
|
|
2164
|
+
const targetPath = join11(skillsDir, skillId);
|
|
2202
2165
|
if (!existsSync10(sourcePath)) {
|
|
2203
2166
|
results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
|
|
2204
2167
|
continue;
|
|
@@ -2221,12 +2184,12 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
2221
2184
|
}
|
|
2222
2185
|
async function uninstallSkills(skillIds, tool, level) {
|
|
2223
2186
|
const configRoot = getConfigRoot(tool, level);
|
|
2224
|
-
const skillsDir =
|
|
2187
|
+
const skillsDir = join11(configRoot, "skills");
|
|
2225
2188
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
2226
2189
|
const results = [];
|
|
2227
2190
|
const removedIds = [];
|
|
2228
2191
|
for (const skillId of skillIds) {
|
|
2229
|
-
const targetPath =
|
|
2192
|
+
const targetPath = join11(skillsDir, skillId);
|
|
2230
2193
|
try {
|
|
2231
2194
|
if (existsSync10(targetPath) || isSymlink2(targetPath)) {
|
|
2232
2195
|
unlinkSync3(targetPath);
|
|
@@ -2246,7 +2209,7 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
2246
2209
|
}
|
|
2247
2210
|
if (existsSync10(skillsDir)) {
|
|
2248
2211
|
try {
|
|
2249
|
-
const entries =
|
|
2212
|
+
const entries = readdirSync4(skillsDir);
|
|
2250
2213
|
if (entries.length === 0) {
|
|
2251
2214
|
rmdirSync(skillsDir);
|
|
2252
2215
|
logger.step(` ${t("uninstall_clean_empty_dir")}: skills/`);
|
|
@@ -2444,8 +2407,10 @@ function printEnhancedSummary(results, tool, configRoot) {
|
|
|
2444
2407
|
""
|
|
2445
2408
|
];
|
|
2446
2409
|
if (successResults.length === 1) {
|
|
2410
|
+
const plugin = findPlugin(successResults[0].pluginId);
|
|
2411
|
+
const docsPath = plugin ? `${plugin.dir}/quickstart.md` : `${successResults[0].pluginId}/quickstart.md`;
|
|
2447
2412
|
lines.push(
|
|
2448
|
-
` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(
|
|
2413
|
+
` ${chalk5.dim(t("install_enhanced_docs"))}: ${chalk5.dim(docsPath)}`
|
|
2449
2414
|
);
|
|
2450
2415
|
}
|
|
2451
2416
|
console.log();
|
|
@@ -2456,15 +2421,15 @@ function printEnhancedSummary(results, tool, configRoot) {
|
|
|
2456
2421
|
}
|
|
2457
2422
|
|
|
2458
2423
|
// src/commands/init.ts
|
|
2459
|
-
import { existsSync as existsSync11, readFileSync as
|
|
2460
|
-
import { join as
|
|
2424
|
+
import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
|
|
2425
|
+
import { join as join12 } from "path";
|
|
2461
2426
|
var BACK2 = "__back__";
|
|
2462
2427
|
var CANCEL2 = "__cancel__";
|
|
2463
2428
|
async function initCommand() {
|
|
2464
2429
|
const cwd = process.cwd();
|
|
2465
|
-
if (existsSync11(
|
|
2430
|
+
if (existsSync11(join12(cwd, "package.json")) && (() => {
|
|
2466
2431
|
try {
|
|
2467
|
-
const pkg = JSON.parse(
|
|
2432
|
+
const pkg = JSON.parse(readFileSync7(join12(cwd, "package.json"), "utf-8"));
|
|
2468
2433
|
return pkg.name === "@cannbot-ai/install-helper";
|
|
2469
2434
|
} catch {
|
|
2470
2435
|
return false;
|
|
@@ -2690,8 +2655,8 @@ async function listCommand() {
|
|
|
2690
2655
|
|
|
2691
2656
|
// src/commands/doctor.ts
|
|
2692
2657
|
import chalk7 from "chalk";
|
|
2693
|
-
import { existsSync as existsSync12, readdirSync as
|
|
2694
|
-
import { join as
|
|
2658
|
+
import { existsSync as existsSync12, readdirSync as readdirSync5, lstatSync as lstatSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
|
|
2659
|
+
import { join as join13 } from "path";
|
|
2695
2660
|
async function doctorCommand(options = {}) {
|
|
2696
2661
|
console.log();
|
|
2697
2662
|
console.log(chalk7.bold(` ${t("doctor_title")}`));
|
|
@@ -2737,7 +2702,7 @@ async function doctorCommand(options = {}) {
|
|
|
2737
2702
|
if (existsSync12(skillsDir)) {
|
|
2738
2703
|
const brokenLinks = checkBrokenLinks(skillsDir);
|
|
2739
2704
|
if (brokenLinks === 0) {
|
|
2740
|
-
const count =
|
|
2705
|
+
const count = readdirSync5(skillsDir).length;
|
|
2741
2706
|
console.log(chalk7.green(" \u2713") + ` ${skillsDir} \u2014 ${t("doctor_links_valid").replace("{count}", String(count))}`);
|
|
2742
2707
|
} else {
|
|
2743
2708
|
console.log(chalk7.yellow(" \u26A0") + ` ${skillsDir} \u2014 ${t("doctor_broken_links").replace("{count}", String(brokenLinks))}`);
|
|
@@ -2759,7 +2724,7 @@ async function doctorCommand(options = {}) {
|
|
|
2759
2724
|
if (existsSync12(agentsDir)) {
|
|
2760
2725
|
const brokenLinks = checkBrokenLinks(agentsDir);
|
|
2761
2726
|
if (brokenLinks === 0) {
|
|
2762
|
-
const count =
|
|
2727
|
+
const count = readdirSync5(agentsDir).length;
|
|
2763
2728
|
console.log(chalk7.green(" \u2713") + ` ${agentsDir} \u2014 ${t("doctor_links_valid").replace("{count}", String(count))}`);
|
|
2764
2729
|
} else {
|
|
2765
2730
|
console.log(chalk7.yellow(" \u26A0") + ` ${agentsDir} \u2014 ${t("doctor_broken_links").replace("{count}", String(brokenLinks))}`);
|
|
@@ -2781,7 +2746,7 @@ async function doctorCommand(options = {}) {
|
|
|
2781
2746
|
console.log();
|
|
2782
2747
|
console.log(chalk7.bold(` ${t("doctor_config")}`));
|
|
2783
2748
|
const configFile = getConfigFileName(primaryTool);
|
|
2784
|
-
const configPath =
|
|
2749
|
+
const configPath = join13(process.cwd(), configFile);
|
|
2785
2750
|
if (existsSync12(configPath)) {
|
|
2786
2751
|
console.log(chalk7.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
|
|
2787
2752
|
} else {
|
|
@@ -2803,9 +2768,9 @@ async function doctorCommand(options = {}) {
|
|
|
2803
2768
|
function checkBrokenLinks(dir) {
|
|
2804
2769
|
let broken = 0;
|
|
2805
2770
|
try {
|
|
2806
|
-
const entries =
|
|
2771
|
+
const entries = readdirSync5(dir);
|
|
2807
2772
|
for (const entry of entries) {
|
|
2808
|
-
const fullPath =
|
|
2773
|
+
const fullPath = join13(dir, entry);
|
|
2809
2774
|
try {
|
|
2810
2775
|
const stats = lstatSync3(fullPath);
|
|
2811
2776
|
if (stats.isSymbolicLink()) {
|
|
@@ -2824,9 +2789,9 @@ function checkBrokenLinks(dir) {
|
|
|
2824
2789
|
function fixBrokenLinks(dir) {
|
|
2825
2790
|
let fixed = 0;
|
|
2826
2791
|
try {
|
|
2827
|
-
const entries =
|
|
2792
|
+
const entries = readdirSync5(dir);
|
|
2828
2793
|
for (const entry of entries) {
|
|
2829
|
-
const fullPath =
|
|
2794
|
+
const fullPath = join13(dir, entry);
|
|
2830
2795
|
try {
|
|
2831
2796
|
const stats = lstatSync3(fullPath);
|
|
2832
2797
|
if (stats.isSymbolicLink()) {
|
|
@@ -3105,7 +3070,7 @@ async function installPlugins(pluginIds, tool, level, repoPath) {
|
|
|
3105
3070
|
}
|
|
3106
3071
|
|
|
3107
3072
|
// src/commands/uninstall.ts
|
|
3108
|
-
import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as
|
|
3073
|
+
import { existsSync as existsSync13, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync6, lstatSync as lstatSync4 } from "fs";
|
|
3109
3074
|
import chalk10 from "chalk";
|
|
3110
3075
|
async function uninstallCommand(names, options) {
|
|
3111
3076
|
const tool = options.tool ? validateTool(options.tool) : "opencode";
|
|
@@ -3156,7 +3121,7 @@ async function uninstallCommand(names, options) {
|
|
|
3156
3121
|
continue;
|
|
3157
3122
|
}
|
|
3158
3123
|
if (existsSync13(dirPath)) {
|
|
3159
|
-
const entries =
|
|
3124
|
+
const entries = readdirSync6(dirPath);
|
|
3160
3125
|
if (entries.length === 0) {
|
|
3161
3126
|
rmdirSync2(dirPath);
|
|
3162
3127
|
const name = dirPath.split("/").pop() || dirPath;
|
|
@@ -3300,8 +3265,8 @@ async function updateCommand(pluginNames, options) {
|
|
|
3300
3265
|
|
|
3301
3266
|
// src/commands/info.ts
|
|
3302
3267
|
import chalk12 from "chalk";
|
|
3303
|
-
import { existsSync as existsSync14, readdirSync as
|
|
3304
|
-
import { join as
|
|
3268
|
+
import { existsSync as existsSync14, readdirSync as readdirSync7 } from "fs";
|
|
3269
|
+
import { join as join14 } from "path";
|
|
3305
3270
|
async function infoCommand(pluginName) {
|
|
3306
3271
|
const plugin = findPlugin(pluginName);
|
|
3307
3272
|
if (!plugin) {
|
|
@@ -3325,13 +3290,13 @@ async function infoCommand(pluginName) {
|
|
|
3325
3290
|
try {
|
|
3326
3291
|
const repoManager = createRepositoryManager();
|
|
3327
3292
|
const repoPath = await repoManager.ensureRepo();
|
|
3328
|
-
const quickstartPath =
|
|
3293
|
+
const quickstartPath = join14(repoPath, plugin.dir, "quickstart.md");
|
|
3329
3294
|
if (existsSync14(quickstartPath)) {
|
|
3330
3295
|
console.log(` ${chalk12.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
|
|
3331
3296
|
}
|
|
3332
|
-
const agentsDir =
|
|
3297
|
+
const agentsDir = join14(repoPath, plugin.dir, "agents");
|
|
3333
3298
|
if (existsSync14(agentsDir)) {
|
|
3334
|
-
const agentFiles =
|
|
3299
|
+
const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
|
|
3335
3300
|
if (agentFiles.length > 0) {
|
|
3336
3301
|
console.log();
|
|
3337
3302
|
console.log(` ${chalk12.bold("Agents:")}`);
|
|
@@ -3388,7 +3353,7 @@ function createCLI() {
|
|
|
3388
3353
|
setLanguage(config.language);
|
|
3389
3354
|
}
|
|
3390
3355
|
const program2 = new Command();
|
|
3391
|
-
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.
|
|
3356
|
+
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.16");
|
|
3392
3357
|
program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
|
|
3393
3358
|
await initCommand();
|
|
3394
3359
|
});
|