@cannbot-ai/install-helper 0.0.2-beta.33 → 0.0.2-beta.34
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 +238 -191
- package/dist/index.js.map +1 -1
- package/dist/locales/en_US.json +6 -0
- package/dist/locales/zh_CN.json +6 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -12,18 +12,115 @@ import { select, checkbox, Separator } from "@inquirer/prompts";
|
|
|
12
12
|
import chalk3 from "chalk";
|
|
13
13
|
|
|
14
14
|
// src/core/registry.ts
|
|
15
|
-
import { readdirSync, readFileSync, existsSync, statSync } from "fs";
|
|
15
|
+
import { readdirSync, readFileSync as readFileSync2, existsSync, statSync } from "fs";
|
|
16
|
+
import { join as join2, dirname as dirname2 } from "path";
|
|
17
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18
|
+
import { parse as parseYaml } from "yaml";
|
|
19
|
+
|
|
20
|
+
// src/utils/logger.ts
|
|
21
|
+
import chalk from "chalk";
|
|
22
|
+
import ora from "ora";
|
|
23
|
+
|
|
24
|
+
// src/utils/i18n.ts
|
|
25
|
+
import { readFileSync } from "fs";
|
|
16
26
|
import { join, dirname } from "path";
|
|
17
27
|
import { fileURLToPath } from "url";
|
|
18
|
-
import { parse as parseYaml } from "yaml";
|
|
19
28
|
var __filename = fileURLToPath(import.meta.url);
|
|
20
29
|
var __dirname = dirname(__filename);
|
|
30
|
+
function loadLocale(locale) {
|
|
31
|
+
const localePath = join(__dirname, "locales", `${locale}.json`);
|
|
32
|
+
try {
|
|
33
|
+
const content = readFileSync(localePath, "utf-8");
|
|
34
|
+
return JSON.parse(content);
|
|
35
|
+
} catch {
|
|
36
|
+
const fallbackPath = join(__dirname, "locales", "zh_CN.json");
|
|
37
|
+
try {
|
|
38
|
+
const content = readFileSync(fallbackPath, "utf-8");
|
|
39
|
+
return JSON.parse(content);
|
|
40
|
+
} catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var currentLang = "zh_CN";
|
|
46
|
+
var messages = loadLocale("zh_CN");
|
|
47
|
+
function setLanguage(lang) {
|
|
48
|
+
currentLang = lang;
|
|
49
|
+
messages = loadLocale(lang);
|
|
50
|
+
}
|
|
51
|
+
function t(key) {
|
|
52
|
+
return messages[key] !== void 0 ? messages[key] : key;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// src/utils/logger.ts
|
|
56
|
+
var logger = {
|
|
57
|
+
success: (msg) => console.log(chalk.green("\u2713") + " " + msg),
|
|
58
|
+
error: (msg) => console.log(chalk.red("\u2717") + " " + msg),
|
|
59
|
+
warn: (msg) => console.log(chalk.yellow("\u26A0") + " " + msg),
|
|
60
|
+
info: (msg) => console.log(chalk.cyan("\u2192") + " " + msg),
|
|
61
|
+
step: (msg) => console.log(chalk.dim(msg)),
|
|
62
|
+
blank: () => console.log()
|
|
63
|
+
};
|
|
64
|
+
function createSpinner(text) {
|
|
65
|
+
return ora({ text, color: "cyan" });
|
|
66
|
+
}
|
|
67
|
+
function printBanner(subtitle) {
|
|
68
|
+
console.log(chalk.cyan(`
|
|
69
|
+
____ _ _ _ _ _ ____ _
|
|
70
|
+
/ ___| / \\ | \\ | | \\ | | __ ) ___ | |_
|
|
71
|
+
| | / _ \\ | \\| | \\| | _ \\ / _ \\| __|
|
|
72
|
+
| |___ / ___ \\| |\\ | |\\ | |_) | (_) | |_
|
|
73
|
+
\\____/_/ \\_\\_| \\_|_| \\_|____/ \\___/ \\__|
|
|
74
|
+
`));
|
|
75
|
+
if (subtitle) {
|
|
76
|
+
console.log(chalk.bold(` ${subtitle}`));
|
|
77
|
+
console.log();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function getDisplayWidth(str) {
|
|
81
|
+
let width = 0;
|
|
82
|
+
for (const ch of str) {
|
|
83
|
+
const code = ch.codePointAt(0);
|
|
84
|
+
if (code >= 11904 && code <= 40959 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65103 || code >= 65280 && code <= 65519 || code >= 13312 && code <= 19903 || code >= 131072 && code <= 173791 || code >= 173824 && code <= 177983 || code >= 177984 && code <= 178207 || code >= 178208 && code <= 183983) {
|
|
85
|
+
width += 2;
|
|
86
|
+
} else {
|
|
87
|
+
width += 1;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return width;
|
|
91
|
+
}
|
|
92
|
+
function printBoxTitle(title, width = 65) {
|
|
93
|
+
const border = "\u2550".repeat(width);
|
|
94
|
+
const displayWidth = getDisplayWidth(title);
|
|
95
|
+
const totalPadding = width - displayWidth;
|
|
96
|
+
const leftPadding = Math.floor(totalPadding / 2);
|
|
97
|
+
const rightPadding = totalPadding - leftPadding;
|
|
98
|
+
const paddedTitle = " ".repeat(Math.max(0, leftPadding)) + title + " ".repeat(Math.max(0, rightPadding));
|
|
99
|
+
console.log();
|
|
100
|
+
console.log(chalk.cyan.bold(` \u2554${border}\u2557`));
|
|
101
|
+
console.log(chalk.cyan.bold(` \u2551`) + chalk.cyan.bold(paddedTitle) + chalk.cyan.bold(`\u2551`));
|
|
102
|
+
console.log(chalk.cyan.bold(` \u255A${border}\u255D`));
|
|
103
|
+
console.log();
|
|
104
|
+
}
|
|
105
|
+
function showOperationHints(isCheckbox = false) {
|
|
106
|
+
if (isCheckbox) {
|
|
107
|
+
console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m ${t("hint_select_move")} | \x1B[36m${t("hint_select_space")}\x1B[0m ${t("hint_select_check")} | \x1B[36m\u23CE\x1B[0m ${t("hint_select_confirm")}\uFF08${t("hint_checkbox_suffix")}\uFF09
|
|
108
|
+
`);
|
|
109
|
+
} else {
|
|
110
|
+
console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m ${t("hint_select_move")} | \x1B[36m\u23CE\x1B[0m ${t("hint_select_confirm")}
|
|
111
|
+
`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/core/registry.ts
|
|
116
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
117
|
+
var __dirname2 = dirname2(__filename2);
|
|
21
118
|
function loadPluginsFromYaml() {
|
|
22
|
-
const pluginsDir =
|
|
23
|
-
const defaultsPath =
|
|
119
|
+
const pluginsDir = join2(__dirname2, "plugins.d");
|
|
120
|
+
const defaultsPath = join2(pluginsDir, "_defaults.yml");
|
|
24
121
|
let defaults = {};
|
|
25
122
|
try {
|
|
26
|
-
defaults = parseYaml(
|
|
123
|
+
defaults = parseYaml(readFileSync2(defaultsPath, "utf-8")) || {};
|
|
27
124
|
} catch {
|
|
28
125
|
}
|
|
29
126
|
const plugins = [];
|
|
@@ -31,7 +128,7 @@ function loadPluginsFromYaml() {
|
|
|
31
128
|
for (const file of readdirSync(pluginsDir)) {
|
|
32
129
|
if (file.startsWith("_") || !file.endsWith(".yml")) continue;
|
|
33
130
|
try {
|
|
34
|
-
const content = parseYaml(
|
|
131
|
+
const content = parseYaml(readFileSync2(join2(pluginsDir, file), "utf-8"));
|
|
35
132
|
if (!content || !content.id) continue;
|
|
36
133
|
plugins.push({
|
|
37
134
|
id: content.id,
|
|
@@ -44,6 +141,7 @@ function loadPluginsFromYaml() {
|
|
|
44
141
|
description: content.description || ""
|
|
45
142
|
});
|
|
46
143
|
} catch {
|
|
144
|
+
logger.warn(t("plugin_yaml_error").replace("{file}", file));
|
|
47
145
|
}
|
|
48
146
|
}
|
|
49
147
|
} catch {
|
|
@@ -60,7 +158,7 @@ function mergeDynamicPlugins(repoPath) {
|
|
|
60
158
|
const existingIds = new Set(PLUGIN_REGISTRY.map((p) => p.id));
|
|
61
159
|
const dynamic = [];
|
|
62
160
|
for (const pluginDir of PLUGIN_DIRS) {
|
|
63
|
-
const parent =
|
|
161
|
+
const parent = join2(repoPath, pluginDir);
|
|
64
162
|
if (!existsSync(parent)) continue;
|
|
65
163
|
let entries = [];
|
|
66
164
|
try {
|
|
@@ -69,10 +167,10 @@ function mergeDynamicPlugins(repoPath) {
|
|
|
69
167
|
continue;
|
|
70
168
|
}
|
|
71
169
|
for (const entry of entries) {
|
|
72
|
-
const pluginPath =
|
|
170
|
+
const pluginPath = join2(parent, entry);
|
|
73
171
|
if (!isDirectory(pluginPath)) continue;
|
|
74
172
|
if (entry === "install-helper") continue;
|
|
75
|
-
const initSh =
|
|
173
|
+
const initSh = join2(pluginPath, "init.sh");
|
|
76
174
|
if (!existsSync(initSh)) continue;
|
|
77
175
|
const pluginId = entry;
|
|
78
176
|
if (existingIds.has(pluginId)) continue;
|
|
@@ -133,39 +231,6 @@ import { join as join4 } from "path";
|
|
|
133
231
|
import { homedir } from "os";
|
|
134
232
|
import { join as join3 } from "path";
|
|
135
233
|
import { existsSync as existsSync2 } from "fs";
|
|
136
|
-
|
|
137
|
-
// src/utils/i18n.ts
|
|
138
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
139
|
-
import { join as join2, dirname as dirname2 } from "path";
|
|
140
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
141
|
-
var __filename2 = fileURLToPath2(import.meta.url);
|
|
142
|
-
var __dirname2 = dirname2(__filename2);
|
|
143
|
-
function loadLocale(locale) {
|
|
144
|
-
const localePath = join2(__dirname2, "locales", `${locale}.json`);
|
|
145
|
-
try {
|
|
146
|
-
const content = readFileSync2(localePath, "utf-8");
|
|
147
|
-
return JSON.parse(content);
|
|
148
|
-
} catch {
|
|
149
|
-
const fallbackPath = join2(__dirname2, "locales", "zh_CN.json");
|
|
150
|
-
try {
|
|
151
|
-
const content = readFileSync2(fallbackPath, "utf-8");
|
|
152
|
-
return JSON.parse(content);
|
|
153
|
-
} catch {
|
|
154
|
-
return {};
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
var currentLang = "zh_CN";
|
|
159
|
-
var messages = loadLocale("zh_CN");
|
|
160
|
-
function setLanguage(lang) {
|
|
161
|
-
currentLang = lang;
|
|
162
|
-
messages = loadLocale(lang);
|
|
163
|
-
}
|
|
164
|
-
function t(key) {
|
|
165
|
-
return messages[key] !== void 0 ? messages[key] : key;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// src/utils/paths.ts
|
|
169
234
|
var VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "copilot"];
|
|
170
235
|
var VALID_LEVELS = ["project", "global"];
|
|
171
236
|
function validateTool(tool) {
|
|
@@ -467,73 +532,32 @@ function verifyPluginFilesExist(configRoot, manifest, tool, level) {
|
|
|
467
532
|
return true;
|
|
468
533
|
}
|
|
469
534
|
|
|
470
|
-
// src/utils/
|
|
471
|
-
import
|
|
472
|
-
import
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
\\____/_/ \\_\\_| \\_|_| \\_|____/ \\___/ \\__|
|
|
491
|
-
`));
|
|
492
|
-
if (subtitle) {
|
|
493
|
-
console.log(chalk.bold(` ${subtitle}`));
|
|
494
|
-
console.log();
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
function getDisplayWidth(str) {
|
|
498
|
-
let width = 0;
|
|
499
|
-
for (const ch of str) {
|
|
500
|
-
const code = ch.codePointAt(0);
|
|
501
|
-
if (code >= 11904 && code <= 40959 || code >= 63744 && code <= 64255 || code >= 65072 && code <= 65103 || code >= 65280 && code <= 65519 || code >= 13312 && code <= 19903 || code >= 131072 && code <= 173791 || code >= 173824 && code <= 177983 || code >= 177984 && code <= 178207 || code >= 178208 && code <= 183983) {
|
|
502
|
-
width += 2;
|
|
503
|
-
} else {
|
|
504
|
-
width += 1;
|
|
535
|
+
// src/utils/config.ts
|
|
536
|
+
import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync4 } from "fs";
|
|
537
|
+
import { join as join6 } from "path";
|
|
538
|
+
import { homedir as homedir3 } from "os";
|
|
539
|
+
import { parse, stringify } from "yaml";
|
|
540
|
+
|
|
541
|
+
// src/utils/fs.ts
|
|
542
|
+
import { writeFileSync, renameSync, existsSync as existsSync5, unlinkSync } from "fs";
|
|
543
|
+
import { dirname as dirname3 } from "path";
|
|
544
|
+
function atomicWriteFileSync(filePath, data, encoding = "utf-8") {
|
|
545
|
+
const dir = dirname3(filePath);
|
|
546
|
+
if (!existsSync5(dir)) {
|
|
547
|
+
throw new Error(`Directory does not exist: ${dir}`);
|
|
548
|
+
}
|
|
549
|
+
const tmpPath = `${filePath}.tmp`;
|
|
550
|
+
writeFileSync(tmpPath, data, encoding);
|
|
551
|
+
if (existsSync5(filePath)) {
|
|
552
|
+
try {
|
|
553
|
+
unlinkSync(filePath);
|
|
554
|
+
} catch {
|
|
505
555
|
}
|
|
506
556
|
}
|
|
507
|
-
|
|
508
|
-
}
|
|
509
|
-
function printBoxTitle(title, width = 65) {
|
|
510
|
-
const border = "\u2550".repeat(width);
|
|
511
|
-
const displayWidth = getDisplayWidth(title);
|
|
512
|
-
const totalPadding = width - displayWidth;
|
|
513
|
-
const leftPadding = Math.floor(totalPadding / 2);
|
|
514
|
-
const rightPadding = totalPadding - leftPadding;
|
|
515
|
-
const paddedTitle = " ".repeat(Math.max(0, leftPadding)) + title + " ".repeat(Math.max(0, rightPadding));
|
|
516
|
-
console.log();
|
|
517
|
-
console.log(chalk.cyan.bold(` \u2554${border}\u2557`));
|
|
518
|
-
console.log(chalk.cyan.bold(` \u2551`) + chalk.cyan.bold(paddedTitle) + chalk.cyan.bold(`\u2551`));
|
|
519
|
-
console.log(chalk.cyan.bold(` \u255A${border}\u255D`));
|
|
520
|
-
console.log();
|
|
521
|
-
}
|
|
522
|
-
function showOperationHints(isCheckbox = false) {
|
|
523
|
-
if (isCheckbox) {
|
|
524
|
-
console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m ${t("hint_select_move")} | \x1B[36m${t("hint_select_space")}\x1B[0m ${t("hint_select_check")} | \x1B[36m\u23CE\x1B[0m ${t("hint_select_confirm")}\uFF08${t("hint_checkbox_suffix")}\uFF09
|
|
525
|
-
`);
|
|
526
|
-
} else {
|
|
527
|
-
console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m ${t("hint_select_move")} | \x1B[36m\u23CE\x1B[0m ${t("hint_select_confirm")}
|
|
528
|
-
`);
|
|
529
|
-
}
|
|
557
|
+
renameSync(tmpPath, filePath);
|
|
530
558
|
}
|
|
531
559
|
|
|
532
560
|
// src/utils/config.ts
|
|
533
|
-
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync4, writeFileSync } from "fs";
|
|
534
|
-
import { join as join6 } from "path";
|
|
535
|
-
import { homedir as homedir3 } from "os";
|
|
536
|
-
import { parse, stringify } from "yaml";
|
|
537
561
|
function getConfigDir() {
|
|
538
562
|
return join6(homedir3(), ".cannbot");
|
|
539
563
|
}
|
|
@@ -542,7 +566,7 @@ function getConfigPath() {
|
|
|
542
566
|
}
|
|
543
567
|
function readConfig() {
|
|
544
568
|
const configPath = getConfigPath();
|
|
545
|
-
if (!
|
|
569
|
+
if (!existsSync6(configPath)) {
|
|
546
570
|
return {
|
|
547
571
|
language: "zh_CN",
|
|
548
572
|
installedPlugins: []
|
|
@@ -559,6 +583,7 @@ function readConfig() {
|
|
|
559
583
|
installedPlugins: parsed.installedPlugins || []
|
|
560
584
|
};
|
|
561
585
|
} catch {
|
|
586
|
+
logger.warn(t("config_corrupted"));
|
|
562
587
|
return {
|
|
563
588
|
language: "zh_CN",
|
|
564
589
|
installedPlugins: []
|
|
@@ -567,12 +592,12 @@ function readConfig() {
|
|
|
567
592
|
}
|
|
568
593
|
function writeConfig(config) {
|
|
569
594
|
const configDir = getConfigDir();
|
|
570
|
-
if (!
|
|
595
|
+
if (!existsSync6(configDir)) {
|
|
571
596
|
mkdirSync(configDir, { recursive: true });
|
|
572
597
|
}
|
|
573
598
|
const configPath = getConfigPath();
|
|
574
599
|
const content = stringify(config);
|
|
575
|
-
|
|
600
|
+
atomicWriteFileSync(configPath, content);
|
|
576
601
|
}
|
|
577
602
|
function updateConfig(updates) {
|
|
578
603
|
const config = readConfig();
|
|
@@ -918,19 +943,19 @@ async function stepConfirm(tool, level, plugins) {
|
|
|
918
943
|
}
|
|
919
944
|
|
|
920
945
|
// src/core/repository.ts
|
|
921
|
-
import { existsSync as
|
|
922
|
-
import { join as join8, dirname as
|
|
946
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6 } from "fs";
|
|
947
|
+
import { join as join8, dirname as dirname5 } from "path";
|
|
923
948
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
924
949
|
import { execa as execa2 } from "execa";
|
|
925
950
|
import { parse as parseYaml3 } from "yaml";
|
|
926
951
|
|
|
927
952
|
// src/core/scanner.ts
|
|
928
|
-
import { existsSync as
|
|
929
|
-
import { join as join7, dirname as
|
|
953
|
+
import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
954
|
+
import { join as join7, dirname as dirname4 } from "path";
|
|
930
955
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
931
956
|
import { parse as parseYaml2 } from "yaml";
|
|
932
957
|
var __filename3 = fileURLToPath3(import.meta.url);
|
|
933
|
-
var __dirname3 =
|
|
958
|
+
var __dirname3 = dirname4(__filename3);
|
|
934
959
|
var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
|
|
935
960
|
"node_modules",
|
|
936
961
|
".git",
|
|
@@ -974,26 +999,26 @@ function scanSkills(repoPath) {
|
|
|
974
999
|
const seen = /* @__PURE__ */ new Set();
|
|
975
1000
|
for (const dir of SKILL_SCAN_DIRS) {
|
|
976
1001
|
const fullPath = join7(repoPath, dir);
|
|
977
|
-
if (!
|
|
1002
|
+
if (!existsSync7(fullPath)) continue;
|
|
978
1003
|
scanDirectory(fullPath, repoPath, dir, skills, seen);
|
|
979
1004
|
}
|
|
980
1005
|
for (const pluginDir of PLUGIN_SCAN_DIRS) {
|
|
981
1006
|
const pluginParent = join7(repoPath, pluginDir);
|
|
982
|
-
if (!
|
|
1007
|
+
if (!existsSync7(pluginParent)) continue;
|
|
983
1008
|
for (const plugin of safeReaddir(pluginParent)) {
|
|
984
1009
|
const pluginPath = join7(pluginParent, plugin);
|
|
985
1010
|
if (!isDirectory2(pluginPath)) continue;
|
|
986
1011
|
const skillsDir = join7(pluginPath, "skills");
|
|
987
|
-
if (
|
|
1012
|
+
if (existsSync7(skillsDir)) {
|
|
988
1013
|
scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
|
|
989
1014
|
}
|
|
990
1015
|
const skillDir = join7(pluginPath, "skill");
|
|
991
|
-
if (
|
|
1016
|
+
if (existsSync7(skillDir)) {
|
|
992
1017
|
scanDirectory(skillDir, repoPath, `${pluginDir}/${plugin}/skill`, skills, seen);
|
|
993
1018
|
}
|
|
994
1019
|
const rootSkillMd = join7(pluginPath, "SKILL.md");
|
|
995
1020
|
const initSh = join7(pluginPath, "init.sh");
|
|
996
|
-
if (
|
|
1021
|
+
if (existsSync7(rootSkillMd) && !existsSync7(initSh)) {
|
|
997
1022
|
const frontmatter = parseFrontmatter(rootSkillMd);
|
|
998
1023
|
if (frontmatter && !seen.has(frontmatter.name)) {
|
|
999
1024
|
seen.add(frontmatter.name);
|
|
@@ -1042,15 +1067,15 @@ function parseFrontmatter(filePath) {
|
|
|
1042
1067
|
function getCurrentCommit(repoPath) {
|
|
1043
1068
|
try {
|
|
1044
1069
|
const headFile = join7(repoPath, ".git", "HEAD");
|
|
1045
|
-
if (!
|
|
1070
|
+
if (!existsSync7(headFile)) return "unknown";
|
|
1046
1071
|
const headContent = readFileSync5(headFile, "utf-8").trim();
|
|
1047
1072
|
if (headContent.startsWith("ref: ")) {
|
|
1048
1073
|
const refPath = join7(repoPath, ".git", headContent.slice(5));
|
|
1049
|
-
if (
|
|
1074
|
+
if (existsSync7(refPath)) {
|
|
1050
1075
|
return readFileSync5(refPath, "utf-8").trim();
|
|
1051
1076
|
}
|
|
1052
1077
|
const packedRefsPath = join7(repoPath, ".git", "packed-refs");
|
|
1053
|
-
if (
|
|
1078
|
+
if (existsSync7(packedRefsPath)) {
|
|
1054
1079
|
const packedRefs = readFileSync5(packedRefsPath, "utf-8");
|
|
1055
1080
|
const refName = headContent.slice(5);
|
|
1056
1081
|
const lines = packedRefs.split("\n");
|
|
@@ -1069,7 +1094,7 @@ function getCurrentCommit(repoPath) {
|
|
|
1069
1094
|
function readScanCache() {
|
|
1070
1095
|
try {
|
|
1071
1096
|
const cachePath = getCachePath();
|
|
1072
|
-
if (!
|
|
1097
|
+
if (!existsSync7(cachePath)) return null;
|
|
1073
1098
|
const content = readFileSync5(cachePath, "utf-8");
|
|
1074
1099
|
const cache = JSON.parse(content);
|
|
1075
1100
|
if (!cache.skills || !cache.timestamp) return null;
|
|
@@ -1083,11 +1108,11 @@ function readScanCache() {
|
|
|
1083
1108
|
function writeScanCache(cache) {
|
|
1084
1109
|
try {
|
|
1085
1110
|
const cachePath = getCachePath();
|
|
1086
|
-
const cacheDir =
|
|
1087
|
-
if (!
|
|
1111
|
+
const cacheDir = dirname4(cachePath);
|
|
1112
|
+
if (!existsSync7(cacheDir)) {
|
|
1088
1113
|
mkdirSync2(cacheDir, { recursive: true });
|
|
1089
1114
|
}
|
|
1090
|
-
|
|
1115
|
+
atomicWriteFileSync(cachePath, JSON.stringify(cache, null, 2));
|
|
1091
1116
|
} catch {
|
|
1092
1117
|
}
|
|
1093
1118
|
}
|
|
@@ -1100,7 +1125,7 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
|
|
|
1100
1125
|
if (EXCLUDE_DIRS.has(entry)) continue;
|
|
1101
1126
|
if (!isDirectory2(fullPath)) continue;
|
|
1102
1127
|
const skillMd = join7(fullPath, "SKILL.md");
|
|
1103
|
-
if (
|
|
1128
|
+
if (existsSync7(skillMd)) {
|
|
1104
1129
|
const frontmatter = parseFrontmatter(skillMd);
|
|
1105
1130
|
if (frontmatter && !seen.has(frontmatter.name)) {
|
|
1106
1131
|
seen.add(frontmatter.name);
|
|
@@ -1368,7 +1393,7 @@ function getAllCategories() {
|
|
|
1368
1393
|
|
|
1369
1394
|
// src/core/repository.ts
|
|
1370
1395
|
var __filename4 = fileURLToPath4(import.meta.url);
|
|
1371
|
-
var __dirname4 =
|
|
1396
|
+
var __dirname4 = dirname5(__filename4);
|
|
1372
1397
|
function loadRepoUrl() {
|
|
1373
1398
|
if (process.env.CANNBOT_REPO_URL) {
|
|
1374
1399
|
return process.env.CANNBOT_REPO_URL;
|
|
@@ -1432,6 +1457,7 @@ var RepositoryManager = class {
|
|
|
1432
1457
|
try {
|
|
1433
1458
|
await execa2("git", ["pull", "--quiet"], { cwd: repoPath, timeout: 3e4 });
|
|
1434
1459
|
} catch {
|
|
1460
|
+
logger.warn(t("repo_pull_failed"));
|
|
1435
1461
|
}
|
|
1436
1462
|
mergeDynamicPlugins(repoPath);
|
|
1437
1463
|
}
|
|
@@ -1442,18 +1468,18 @@ var RepositoryManager = class {
|
|
|
1442
1468
|
return this.repoPath;
|
|
1443
1469
|
}
|
|
1444
1470
|
isValidRepo(path) {
|
|
1445
|
-
if (!
|
|
1471
|
+
if (!existsSync8(path)) return false;
|
|
1446
1472
|
const gitDir = join8(path, ".git");
|
|
1447
1473
|
const pluginsDir = join8(path, "plugins-official");
|
|
1448
|
-
return
|
|
1474
|
+
return existsSync8(gitDir) && existsSync8(pluginsDir);
|
|
1449
1475
|
}
|
|
1450
1476
|
async cloneRepo() {
|
|
1451
1477
|
const configDir = getCannbotConfigDir();
|
|
1452
|
-
if (!
|
|
1478
|
+
if (!existsSync8(configDir)) {
|
|
1453
1479
|
mkdirSync3(configDir, { recursive: true });
|
|
1454
1480
|
}
|
|
1455
1481
|
const targetPath = getCannbotRepoPath();
|
|
1456
|
-
if (
|
|
1482
|
+
if (existsSync8(targetPath)) {
|
|
1457
1483
|
if (this.isValidRepo(targetPath)) {
|
|
1458
1484
|
this.repoPath = targetPath;
|
|
1459
1485
|
return targetPath;
|
|
@@ -1479,12 +1505,12 @@ function createRepositoryManager(customPath) {
|
|
|
1479
1505
|
}
|
|
1480
1506
|
|
|
1481
1507
|
// src/core/installer.ts
|
|
1482
|
-
import { existsSync as
|
|
1508
|
+
import { existsSync as existsSync11 } from "fs";
|
|
1483
1509
|
import { join as join11 } from "path";
|
|
1484
1510
|
import { execa as execa3 } from "execa";
|
|
1485
1511
|
|
|
1486
1512
|
// src/core/record.ts
|
|
1487
|
-
import { existsSync as
|
|
1513
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, lstatSync, unlinkSync as unlinkSync2 } from "fs";
|
|
1488
1514
|
import { join as join9 } from "path";
|
|
1489
1515
|
function getInstallsDir() {
|
|
1490
1516
|
return join9(getCannbotConfigDir(), "installs");
|
|
@@ -1494,28 +1520,29 @@ function getRecordPath(pluginId) {
|
|
|
1494
1520
|
}
|
|
1495
1521
|
function readRecord(pluginId) {
|
|
1496
1522
|
const recordPath = getRecordPath(pluginId);
|
|
1497
|
-
if (!
|
|
1523
|
+
if (!existsSync9(recordPath)) {
|
|
1498
1524
|
return null;
|
|
1499
1525
|
}
|
|
1500
1526
|
try {
|
|
1501
1527
|
const content = readFileSync7(recordPath, "utf-8");
|
|
1502
1528
|
return JSON.parse(content);
|
|
1503
1529
|
} catch {
|
|
1530
|
+
logger.warn(t("record_corrupted").replace("{file}", recordPath));
|
|
1504
1531
|
return null;
|
|
1505
1532
|
}
|
|
1506
1533
|
}
|
|
1507
1534
|
function writeRecord(record) {
|
|
1508
1535
|
const installsDir = getInstallsDir();
|
|
1509
|
-
if (!
|
|
1536
|
+
if (!existsSync9(installsDir)) {
|
|
1510
1537
|
mkdirSync4(installsDir, { recursive: true });
|
|
1511
1538
|
}
|
|
1512
1539
|
const recordPath = getRecordPath(record.pluginId);
|
|
1513
|
-
|
|
1540
|
+
atomicWriteFileSync(recordPath, JSON.stringify(record, null, 2));
|
|
1514
1541
|
}
|
|
1515
1542
|
function deleteRecord(pluginId) {
|
|
1516
1543
|
const recordPath = getRecordPath(pluginId);
|
|
1517
|
-
if (
|
|
1518
|
-
|
|
1544
|
+
if (existsSync9(recordPath)) {
|
|
1545
|
+
unlinkSync2(recordPath);
|
|
1519
1546
|
}
|
|
1520
1547
|
}
|
|
1521
1548
|
function scanInstalledFiles(pluginId, displayName, tool, level, installPath, configRoot, manifest) {
|
|
@@ -1523,24 +1550,24 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
1523
1550
|
const directories = [];
|
|
1524
1551
|
if (manifest) {
|
|
1525
1552
|
const skillsDir = join9(configRoot, "skills");
|
|
1526
|
-
if (
|
|
1553
|
+
if (existsSync9(skillsDir)) {
|
|
1527
1554
|
directories.push(skillsDir);
|
|
1528
1555
|
for (const skillName of manifest.installed_skills || []) {
|
|
1529
1556
|
const skillPath = join9(skillsDir, skillName);
|
|
1530
|
-
if (
|
|
1557
|
+
if (existsSync9(skillPath) || isSymlink(skillPath)) {
|
|
1531
1558
|
files.push(skillPath);
|
|
1532
1559
|
}
|
|
1533
1560
|
}
|
|
1534
1561
|
}
|
|
1535
1562
|
const agentsDir = join9(configRoot, "agents");
|
|
1536
|
-
if (
|
|
1563
|
+
if (existsSync9(agentsDir)) {
|
|
1537
1564
|
directories.push(agentsDir);
|
|
1538
1565
|
for (const agentName of manifest.installed_agents || []) {
|
|
1539
1566
|
const agentPath = join9(agentsDir, agentName);
|
|
1540
1567
|
const agentPathMd = join9(agentsDir, agentName + ".md");
|
|
1541
|
-
if (
|
|
1568
|
+
if (existsSync9(agentPath) || isSymlink(agentPath)) {
|
|
1542
1569
|
files.push(agentPath);
|
|
1543
|
-
} else if (
|
|
1570
|
+
} else if (existsSync9(agentPathMd) || isSymlink(agentPathMd)) {
|
|
1544
1571
|
files.push(agentPathMd);
|
|
1545
1572
|
}
|
|
1546
1573
|
}
|
|
@@ -1551,16 +1578,16 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
|
|
|
1551
1578
|
files.push(workflowsLink);
|
|
1552
1579
|
}
|
|
1553
1580
|
const manifestPath = join9(configRoot, "cannbot-manifest.json");
|
|
1554
|
-
if (
|
|
1581
|
+
if (existsSync9(manifestPath)) {
|
|
1555
1582
|
files.push(manifestPath);
|
|
1556
1583
|
}
|
|
1557
1584
|
const pluginManifestPath = join9(configRoot, `${pluginId}-manifest.json`);
|
|
1558
|
-
if (
|
|
1585
|
+
if (existsSync9(pluginManifestPath)) {
|
|
1559
1586
|
files.push(pluginManifestPath);
|
|
1560
1587
|
}
|
|
1561
1588
|
const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
1562
1589
|
const configFilePath = level === "project" ? join9(installPath, configFileName) : join9(configRoot, configFileName);
|
|
1563
|
-
if (
|
|
1590
|
+
if (existsSync9(configFilePath)) {
|
|
1564
1591
|
files.push(configFilePath);
|
|
1565
1592
|
}
|
|
1566
1593
|
const repoLinks = ["asc-devkit", "pypto", "tilelang-ascend", "cann-recipes-infer", "cann-samples"];
|
|
@@ -1598,23 +1625,24 @@ function getSkillRecordPath() {
|
|
|
1598
1625
|
}
|
|
1599
1626
|
function readSkillRecord() {
|
|
1600
1627
|
const recordPath = getSkillRecordPath();
|
|
1601
|
-
if (!
|
|
1628
|
+
if (!existsSync9(recordPath)) {
|
|
1602
1629
|
return {};
|
|
1603
1630
|
}
|
|
1604
1631
|
try {
|
|
1605
1632
|
const content = readFileSync7(recordPath, "utf-8");
|
|
1606
1633
|
return JSON.parse(content);
|
|
1607
1634
|
} catch {
|
|
1635
|
+
logger.warn(t("skill_record_corrupted"));
|
|
1608
1636
|
return {};
|
|
1609
1637
|
}
|
|
1610
1638
|
}
|
|
1611
1639
|
function writeSkillRecord(record) {
|
|
1612
1640
|
const installsDir = getInstallsDir();
|
|
1613
|
-
if (!
|
|
1641
|
+
if (!existsSync9(installsDir)) {
|
|
1614
1642
|
mkdirSync4(installsDir, { recursive: true });
|
|
1615
1643
|
}
|
|
1616
1644
|
const recordPath = getSkillRecordPath();
|
|
1617
|
-
|
|
1645
|
+
atomicWriteFileSync(recordPath, JSON.stringify(record, null, 2));
|
|
1618
1646
|
}
|
|
1619
1647
|
function addSkillsToRecord(skillIds, tool, level, installPath) {
|
|
1620
1648
|
const record = readSkillRecord();
|
|
@@ -1655,12 +1683,12 @@ function getInstalledSkills(tool, level, installPath) {
|
|
|
1655
1683
|
const skillsDir = join9(configRoot, "skills");
|
|
1656
1684
|
return recordedSkills.filter((skillId) => {
|
|
1657
1685
|
const skillPath = join9(skillsDir, skillId);
|
|
1658
|
-
return
|
|
1686
|
+
return existsSync9(skillPath) || isSymlink(skillPath);
|
|
1659
1687
|
});
|
|
1660
1688
|
}
|
|
1661
1689
|
|
|
1662
1690
|
// src/core/backup.ts
|
|
1663
|
-
import { existsSync as
|
|
1691
|
+
import { existsSync as existsSync10, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
1664
1692
|
import { join as join10 } from "path";
|
|
1665
1693
|
function getAgentsFileName(tool) {
|
|
1666
1694
|
return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
@@ -1677,7 +1705,7 @@ function detectCurrentPlugin(configRoot, tool) {
|
|
|
1677
1705
|
}
|
|
1678
1706
|
}
|
|
1679
1707
|
const agentsFile = join10(configRoot, getAgentsFileName(tool));
|
|
1680
|
-
if (!
|
|
1708
|
+
if (!existsSync10(agentsFile)) {
|
|
1681
1709
|
return null;
|
|
1682
1710
|
}
|
|
1683
1711
|
const allRecords = readAllRecords();
|
|
@@ -1696,7 +1724,7 @@ function detectCurrentPlugin(configRoot, tool) {
|
|
|
1696
1724
|
}
|
|
1697
1725
|
function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
|
|
1698
1726
|
const agentsFile = join10(configRoot, getAgentsFileName(tool));
|
|
1699
|
-
if (!
|
|
1727
|
+
if (!existsSync10(agentsFile)) {
|
|
1700
1728
|
return null;
|
|
1701
1729
|
}
|
|
1702
1730
|
const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
|
|
@@ -1715,7 +1743,7 @@ function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
|
|
|
1715
1743
|
}
|
|
1716
1744
|
}
|
|
1717
1745
|
function findBackups(configRoot) {
|
|
1718
|
-
if (!
|
|
1746
|
+
if (!existsSync10(configRoot)) {
|
|
1719
1747
|
return [];
|
|
1720
1748
|
}
|
|
1721
1749
|
const files = readdirSync3(configRoot);
|
|
@@ -1753,8 +1781,8 @@ function restoreBackup(backupPath, configRoot, tool) {
|
|
|
1753
1781
|
}
|
|
1754
1782
|
function deleteBackup(backupPath) {
|
|
1755
1783
|
try {
|
|
1756
|
-
if (
|
|
1757
|
-
|
|
1784
|
+
if (existsSync10(backupPath)) {
|
|
1785
|
+
unlinkSync3(backupPath);
|
|
1758
1786
|
return true;
|
|
1759
1787
|
}
|
|
1760
1788
|
return false;
|
|
@@ -1846,7 +1874,7 @@ async function installPlugin(opts) {
|
|
|
1846
1874
|
};
|
|
1847
1875
|
}
|
|
1848
1876
|
const scriptPath = join11(opts.repoPath, plugin.dir, plugin.script);
|
|
1849
|
-
if (!
|
|
1877
|
+
if (!existsSync11(scriptPath)) {
|
|
1850
1878
|
return {
|
|
1851
1879
|
success: false,
|
|
1852
1880
|
pluginId: opts.pluginId,
|
|
@@ -1864,7 +1892,7 @@ async function installPlugin(opts) {
|
|
|
1864
1892
|
const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
|
|
1865
1893
|
const agentsFile = join11(configRoot, getAgentsFileName(opts.tool));
|
|
1866
1894
|
let backupInfo = null;
|
|
1867
|
-
if (
|
|
1895
|
+
if (existsSync11(agentsFile)) {
|
|
1868
1896
|
const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
|
|
1869
1897
|
if (currentPlugin && currentPlugin.pluginId !== opts.pluginId) {
|
|
1870
1898
|
let choice = "overwrite";
|
|
@@ -1943,6 +1971,7 @@ async function installPlugin(opts) {
|
|
|
1943
1971
|
}
|
|
1944
1972
|
writeRecord(record);
|
|
1945
1973
|
} catch {
|
|
1974
|
+
logger.warn(t("record_write_failed"));
|
|
1946
1975
|
}
|
|
1947
1976
|
return {
|
|
1948
1977
|
success: true,
|
|
@@ -1966,8 +1995,8 @@ async function installPlugin(opts) {
|
|
|
1966
1995
|
}
|
|
1967
1996
|
|
|
1968
1997
|
// src/core/skill-installer.ts
|
|
1969
|
-
import { existsSync as
|
|
1970
|
-
import { join as join12, dirname as
|
|
1998
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync4, readdirSync as readdirSync4, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
|
|
1999
|
+
import { join as join12, dirname as dirname6 } from "path";
|
|
1971
2000
|
import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
|
|
1972
2001
|
import chalk5 from "chalk";
|
|
1973
2002
|
import Table from "cli-table3";
|
|
@@ -1975,7 +2004,7 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
1975
2004
|
const configRoot = getConfigRoot(tool, level);
|
|
1976
2005
|
const skillsDir = join12(configRoot, "skills");
|
|
1977
2006
|
const installPath = level === "project" ? process.cwd() : configRoot;
|
|
1978
|
-
if (!
|
|
2007
|
+
if (!existsSync12(skillsDir)) {
|
|
1979
2008
|
mkdirSync5(skillsDir, { recursive: true });
|
|
1980
2009
|
}
|
|
1981
2010
|
const results = [];
|
|
@@ -1988,14 +2017,14 @@ async function installSkills(skillIds, tool, level, repoPath) {
|
|
|
1988
2017
|
}
|
|
1989
2018
|
const sourcePath = resolveSkillSourcePath(skill, repoPath);
|
|
1990
2019
|
const targetPath = join12(skillsDir, skillId);
|
|
1991
|
-
if (!
|
|
2020
|
+
if (!existsSync12(sourcePath)) {
|
|
1992
2021
|
results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
|
|
1993
2022
|
continue;
|
|
1994
2023
|
}
|
|
1995
2024
|
try {
|
|
1996
2025
|
const resolvedSource = realpathSync(sourcePath);
|
|
1997
|
-
if (
|
|
1998
|
-
|
|
2026
|
+
if (existsSync12(targetPath) || isSymlink2(targetPath)) {
|
|
2027
|
+
unlinkSync4(targetPath);
|
|
1999
2028
|
}
|
|
2000
2029
|
symlinkSync(resolvedSource, targetPath);
|
|
2001
2030
|
results.push({ skillId, success: true });
|
|
@@ -2018,8 +2047,8 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
2018
2047
|
for (const skillId of skillIds) {
|
|
2019
2048
|
const targetPath = join12(skillsDir, skillId);
|
|
2020
2049
|
try {
|
|
2021
|
-
if (
|
|
2022
|
-
|
|
2050
|
+
if (existsSync12(targetPath) || isSymlink2(targetPath)) {
|
|
2051
|
+
unlinkSync4(targetPath);
|
|
2023
2052
|
results.push({ skillId, success: true });
|
|
2024
2053
|
removedIds.push(skillId);
|
|
2025
2054
|
logger.step(` ${t("uninstall_remove_label")}: ${skillId}`);
|
|
@@ -2034,7 +2063,7 @@ async function uninstallSkills(skillIds, tool, level) {
|
|
|
2034
2063
|
if (removedIds.length > 0) {
|
|
2035
2064
|
removeSkillsFromRecord(removedIds, tool, level, installPath);
|
|
2036
2065
|
}
|
|
2037
|
-
if (
|
|
2066
|
+
if (existsSync12(skillsDir)) {
|
|
2038
2067
|
try {
|
|
2039
2068
|
const entries = readdirSync4(skillsDir);
|
|
2040
2069
|
if (entries.length === 0) {
|
|
@@ -2220,8 +2249,8 @@ function listAllSkills() {
|
|
|
2220
2249
|
function resolveSkillSourcePath(skill, repoPath) {
|
|
2221
2250
|
if (skill.filePath) {
|
|
2222
2251
|
const absPath = skill.filePath.startsWith("/") ? skill.filePath : join12(repoPath, skill.filePath);
|
|
2223
|
-
if (
|
|
2224
|
-
return
|
|
2252
|
+
if (existsSync12(absPath)) {
|
|
2253
|
+
return dirname6(absPath);
|
|
2225
2254
|
}
|
|
2226
2255
|
}
|
|
2227
2256
|
return join12(repoPath, skill.source, skill.id);
|
|
@@ -2323,13 +2352,13 @@ function printEnhancedSummary(results, tool, configRoot) {
|
|
|
2323
2352
|
}
|
|
2324
2353
|
|
|
2325
2354
|
// src/commands/init.ts
|
|
2326
|
-
import { existsSync as
|
|
2355
|
+
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
|
|
2327
2356
|
import { join as join13 } from "path";
|
|
2328
2357
|
var BACK2 = "__back__";
|
|
2329
2358
|
var CANCEL2 = "__cancel__";
|
|
2330
2359
|
async function initCommand() {
|
|
2331
2360
|
const cwd = process.cwd();
|
|
2332
|
-
if (
|
|
2361
|
+
if (existsSync13(join13(cwd, "package.json")) && (() => {
|
|
2333
2362
|
try {
|
|
2334
2363
|
const pkg = JSON.parse(readFileSync8(join13(cwd, "package.json"), "utf-8"));
|
|
2335
2364
|
return pkg.name === "@cannbot-ai/install-helper";
|
|
@@ -2557,7 +2586,7 @@ async function listCommand() {
|
|
|
2557
2586
|
|
|
2558
2587
|
// src/commands/doctor.ts
|
|
2559
2588
|
import chalk8 from "chalk";
|
|
2560
|
-
import { existsSync as
|
|
2589
|
+
import { existsSync as existsSync14, readdirSync as readdirSync5, lstatSync as lstatSync3, unlinkSync as unlinkSync5, mkdirSync as mkdirSync6 } from "fs";
|
|
2561
2590
|
import { join as join14 } from "path";
|
|
2562
2591
|
async function doctorCommand(options = {}) {
|
|
2563
2592
|
console.log();
|
|
@@ -2601,7 +2630,7 @@ async function doctorCommand(options = {}) {
|
|
|
2601
2630
|
const configRoot = getConfigRoot(primaryTool, "project");
|
|
2602
2631
|
const skillsDir = getSkillsDir(configRoot);
|
|
2603
2632
|
const agentsDir = getAgentsDir(configRoot);
|
|
2604
|
-
if (
|
|
2633
|
+
if (existsSync14(skillsDir)) {
|
|
2605
2634
|
const brokenLinks = checkBrokenLinks(skillsDir);
|
|
2606
2635
|
if (brokenLinks === 0) {
|
|
2607
2636
|
const count = readdirSync5(skillsDir).length;
|
|
@@ -2623,7 +2652,7 @@ async function doctorCommand(options = {}) {
|
|
|
2623
2652
|
console.log(chalk8.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: ${t("doctor_created").replace("{path}", skillsDir)}`);
|
|
2624
2653
|
}
|
|
2625
2654
|
}
|
|
2626
|
-
if (
|
|
2655
|
+
if (existsSync14(agentsDir)) {
|
|
2627
2656
|
const brokenLinks = checkBrokenLinks(agentsDir);
|
|
2628
2657
|
if (brokenLinks === 0) {
|
|
2629
2658
|
const count = readdirSync5(agentsDir).length;
|
|
@@ -2649,7 +2678,7 @@ async function doctorCommand(options = {}) {
|
|
|
2649
2678
|
console.log(chalk8.bold(` ${t("doctor_config")}`));
|
|
2650
2679
|
const configFile = getConfigFileName(primaryTool);
|
|
2651
2680
|
const configPath = join14(process.cwd(), configFile);
|
|
2652
|
-
if (
|
|
2681
|
+
if (existsSync14(configPath)) {
|
|
2653
2682
|
console.log(chalk8.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
|
|
2654
2683
|
} else {
|
|
2655
2684
|
console.log(chalk8.dim(" \u2014") + ` ${configFile} ${t("doctor_config_not_exist")}`);
|
|
@@ -2676,7 +2705,7 @@ function checkBrokenLinks(dir) {
|
|
|
2676
2705
|
try {
|
|
2677
2706
|
const stats = lstatSync3(fullPath);
|
|
2678
2707
|
if (stats.isSymbolicLink()) {
|
|
2679
|
-
if (!
|
|
2708
|
+
if (!existsSync14(fullPath)) {
|
|
2680
2709
|
broken++;
|
|
2681
2710
|
}
|
|
2682
2711
|
}
|
|
@@ -2697,8 +2726,8 @@ function fixBrokenLinks(dir) {
|
|
|
2697
2726
|
try {
|
|
2698
2727
|
const stats = lstatSync3(fullPath);
|
|
2699
2728
|
if (stats.isSymbolicLink()) {
|
|
2700
|
-
if (!
|
|
2701
|
-
|
|
2729
|
+
if (!existsSync14(fullPath)) {
|
|
2730
|
+
unlinkSync5(fullPath);
|
|
2702
2731
|
fixed++;
|
|
2703
2732
|
}
|
|
2704
2733
|
}
|
|
@@ -2772,7 +2801,10 @@ async function installCommand(names, options) {
|
|
|
2772
2801
|
tool2 = validateTool(options.tool);
|
|
2773
2802
|
} else {
|
|
2774
2803
|
const detected = await selectToolWithDetection();
|
|
2775
|
-
if (detected === "back" || detected === "cancel")
|
|
2804
|
+
if (detected === "back" || detected === "cancel") {
|
|
2805
|
+
logger.info(t("init_cancelled"));
|
|
2806
|
+
return;
|
|
2807
|
+
}
|
|
2776
2808
|
tool2 = detected;
|
|
2777
2809
|
}
|
|
2778
2810
|
const level2 = options.level ? validateLevel(options.level) : "project";
|
|
@@ -2821,7 +2853,10 @@ async function installCommand(names, options) {
|
|
|
2821
2853
|
tool2 = validateTool(options.tool);
|
|
2822
2854
|
} else {
|
|
2823
2855
|
const detected = await selectToolWithDetection();
|
|
2824
|
-
if (detected === "back" || detected === "cancel")
|
|
2856
|
+
if (detected === "back" || detected === "cancel") {
|
|
2857
|
+
logger.info(t("init_cancelled"));
|
|
2858
|
+
return;
|
|
2859
|
+
}
|
|
2825
2860
|
tool2 = detected;
|
|
2826
2861
|
}
|
|
2827
2862
|
const level2 = options.level ? validateLevel(options.level) : "project";
|
|
@@ -2832,11 +2867,17 @@ async function installCommand(names, options) {
|
|
|
2832
2867
|
const selectedSkills = await interactiveSkillSelect(tool2, level2);
|
|
2833
2868
|
if (selectedSkills === "back") {
|
|
2834
2869
|
const redetected = await selectToolWithDetection();
|
|
2835
|
-
if (redetected === "back" || redetected === "cancel")
|
|
2870
|
+
if (redetected === "back" || redetected === "cancel") {
|
|
2871
|
+
logger.info(t("init_cancelled"));
|
|
2872
|
+
return;
|
|
2873
|
+
}
|
|
2836
2874
|
tool2 = redetected;
|
|
2837
2875
|
break;
|
|
2838
2876
|
}
|
|
2839
|
-
if (selectedSkills === "cancel")
|
|
2877
|
+
if (selectedSkills === "cancel") {
|
|
2878
|
+
logger.info(t("init_cancelled"));
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2840
2881
|
if (selectedSkills.length === 0) {
|
|
2841
2882
|
logger.info(t("install_no_skill_selected"));
|
|
2842
2883
|
return;
|
|
@@ -2911,7 +2952,10 @@ async function installCommand(names, options) {
|
|
|
2911
2952
|
tool = validateTool(options.tool);
|
|
2912
2953
|
} else {
|
|
2913
2954
|
const detected = await selectToolWithDetection();
|
|
2914
|
-
if (detected === "back" || detected === "cancel")
|
|
2955
|
+
if (detected === "back" || detected === "cancel") {
|
|
2956
|
+
logger.info(t("init_cancelled"));
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2915
2959
|
tool = detected;
|
|
2916
2960
|
}
|
|
2917
2961
|
const level = options.level ? validateLevel(options.level) : "project";
|
|
@@ -3029,7 +3073,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
|
|
|
3029
3073
|
}
|
|
3030
3074
|
|
|
3031
3075
|
// src/commands/uninstall.ts
|
|
3032
|
-
import { existsSync as
|
|
3076
|
+
import { existsSync as existsSync15, unlinkSync as unlinkSync6, rmdirSync as rmdirSync2, readdirSync as readdirSync6, lstatSync as lstatSync4 } from "fs";
|
|
3033
3077
|
import { resolve } from "path";
|
|
3034
3078
|
import chalk11 from "chalk";
|
|
3035
3079
|
async function uninstallCommand(names, options) {
|
|
@@ -3071,8 +3115,8 @@ async function uninstallCommand(names, options) {
|
|
|
3071
3115
|
for (const filePath of record.files) {
|
|
3072
3116
|
if (!isSafePath(filePath)) continue;
|
|
3073
3117
|
try {
|
|
3074
|
-
if (
|
|
3075
|
-
|
|
3118
|
+
if (existsSync15(filePath) || isSymlink3(filePath)) {
|
|
3119
|
+
unlinkSync6(filePath);
|
|
3076
3120
|
const name = filePath.split("/").pop() || filePath;
|
|
3077
3121
|
logger.step(` ${t("uninstall_remove_label")}: ${name}`);
|
|
3078
3122
|
removedFiles++;
|
|
@@ -3086,7 +3130,7 @@ async function uninstallCommand(names, options) {
|
|
|
3086
3130
|
if (resolve(dirPath) === resolve(configRoot)) {
|
|
3087
3131
|
continue;
|
|
3088
3132
|
}
|
|
3089
|
-
if (
|
|
3133
|
+
if (existsSync15(dirPath)) {
|
|
3090
3134
|
const entries = readdirSync6(dirPath);
|
|
3091
3135
|
if (entries.length === 0) {
|
|
3092
3136
|
rmdirSync2(dirPath);
|
|
@@ -3157,7 +3201,10 @@ async function updateCommand(pluginNames, options) {
|
|
|
3157
3201
|
tool = validateTool(options.tool);
|
|
3158
3202
|
} else {
|
|
3159
3203
|
const detected = await selectToolWithDetection();
|
|
3160
|
-
if (detected === "back" || detected === "cancel")
|
|
3204
|
+
if (detected === "back" || detected === "cancel") {
|
|
3205
|
+
logger.info(t("init_cancelled"));
|
|
3206
|
+
return;
|
|
3207
|
+
}
|
|
3161
3208
|
tool = detected;
|
|
3162
3209
|
}
|
|
3163
3210
|
const level = options.level ? validateLevel(options.level) : "project";
|
|
@@ -3231,7 +3278,7 @@ async function updateCommand(pluginNames, options) {
|
|
|
3231
3278
|
|
|
3232
3279
|
// src/commands/info.ts
|
|
3233
3280
|
import chalk13 from "chalk";
|
|
3234
|
-
import { existsSync as
|
|
3281
|
+
import { existsSync as existsSync16, readdirSync as readdirSync7 } from "fs";
|
|
3235
3282
|
import { join as join15 } from "path";
|
|
3236
3283
|
async function infoCommand(pluginName) {
|
|
3237
3284
|
const plugin = findPlugin(pluginName);
|
|
@@ -3257,11 +3304,11 @@ async function infoCommand(pluginName) {
|
|
|
3257
3304
|
const repoManager = createRepositoryManager();
|
|
3258
3305
|
const repoPath = await repoManager.ensureRepo();
|
|
3259
3306
|
const quickstartPath = join15(repoPath, plugin.dir, "quickstart.md");
|
|
3260
|
-
if (
|
|
3307
|
+
if (existsSync16(quickstartPath)) {
|
|
3261
3308
|
console.log(` ${chalk13.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
|
|
3262
3309
|
}
|
|
3263
3310
|
const agentsDir = join15(repoPath, plugin.dir, "agents");
|
|
3264
|
-
if (
|
|
3311
|
+
if (existsSync16(agentsDir)) {
|
|
3265
3312
|
const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
|
|
3266
3313
|
if (agentFiles.length > 0) {
|
|
3267
3314
|
console.log();
|
|
@@ -3319,7 +3366,7 @@ function createCLI() {
|
|
|
3319
3366
|
setLanguage(config.language);
|
|
3320
3367
|
}
|
|
3321
3368
|
const program2 = new Command();
|
|
3322
|
-
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.
|
|
3369
|
+
program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.34");
|
|
3323
3370
|
program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
|
|
3324
3371
|
await initCommand();
|
|
3325
3372
|
});
|