@cannbot-ai/install-helper 0.0.2-beta.33 → 0.0.2-beta.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -12,18 +12,195 @@ 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 } 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 chalk2 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/ui/theme.ts
56
+ import chalk from "chalk";
57
+ var selectTheme = {
58
+ helpMode: "never"
59
+ };
60
+ function isCJK(code) {
61
+ return 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;
62
+ }
63
+ function isEmoji(code) {
64
+ return code >= 127744 && code <= 129791 || code >= 9728 && code <= 10175;
65
+ }
66
+ function getDisplayWidth(str) {
67
+ let width = 0;
68
+ for (const ch of str) {
69
+ const code = ch.codePointAt(0);
70
+ if (isCJK(code) || isEmoji(code)) {
71
+ width += 2;
72
+ } else {
73
+ width += 1;
74
+ }
75
+ }
76
+ return width;
77
+ }
78
+ function wrapDescription(text) {
79
+ const prefix = " \u{1F4A1} ";
80
+ const indent = " ";
81
+ const cols = process.stdout.columns || 120;
82
+ const maxLen = Math.max(20, cols - getDisplayWidth(prefix) - 2);
83
+ const tokens = [];
84
+ let i = 0;
85
+ while (i < text.length) {
86
+ const code = text[i].codePointAt(0);
87
+ if (isCJK(code)) {
88
+ tokens.push({ text: text[i], width: 2 });
89
+ i++;
90
+ } else {
91
+ let j = i;
92
+ while (j < text.length) {
93
+ const c = text[j].codePointAt(0);
94
+ if (isCJK(c)) break;
95
+ j++;
96
+ }
97
+ const word = text.slice(i, j);
98
+ tokens.push({ text: word, width: getDisplayWidth(word) });
99
+ i = j;
100
+ }
101
+ }
102
+ const lines = [];
103
+ let line = "";
104
+ let lineWidth = 0;
105
+ for (const token of tokens) {
106
+ if (lineWidth + token.width > maxLen && line) {
107
+ lines.push(line.trimEnd());
108
+ line = token.text;
109
+ lineWidth = token.width;
110
+ } else {
111
+ line += token.text;
112
+ lineWidth += token.width;
113
+ }
114
+ }
115
+ if (line) lines.push(line.trimEnd());
116
+ return lines.map((l, i2) => chalk.cyan(i2 === 0 ? prefix + l : indent + l)).join("\n");
117
+ }
118
+ var checkboxTheme = {
119
+ icon: {
120
+ checked: "\x1B[32m\u2611\x1B[22m",
121
+ unchecked: "\u2610",
122
+ cursor: "\u276F"
123
+ },
124
+ helpMode: "never",
125
+ style: {
126
+ description: (text) => wrapDescription(text)
127
+ }
128
+ };
129
+
130
+ // src/utils/logger.ts
131
+ var logger = {
132
+ success: (msg) => console.log(chalk2.green("\u2713") + " " + msg),
133
+ error: (msg) => console.log(chalk2.red("\u2717") + " " + msg),
134
+ warn: (msg) => console.log(chalk2.yellow("\u26A0") + " " + msg),
135
+ info: (msg) => console.log(chalk2.cyan("\u2192") + " " + msg),
136
+ step: (msg) => console.log(chalk2.dim(msg)),
137
+ blank: () => console.log()
138
+ };
139
+ function createSpinner(text) {
140
+ return ora({ text, color: "cyan" });
141
+ }
142
+ function printBanner(subtitle) {
143
+ console.log(chalk2.cyan(`
144
+ ____ _ _ _ _ _ ____ _
145
+ / ___| / \\ | \\ | | \\ | | __ ) ___ | |_
146
+ | | / _ \\ | \\| | \\| | _ \\ / _ \\| __|
147
+ | |___ / ___ \\| |\\ | |\\ | |_) | (_) | |_
148
+ \\____/_/ \\_\\_| \\_|_| \\_|____/ \\___/ \\__|
149
+ `));
150
+ if (subtitle) {
151
+ console.log(chalk2.bold(` ${subtitle}`));
152
+ console.log();
153
+ }
154
+ }
155
+ function printBoxTitle(title, width = 65) {
156
+ const border = "\u2550".repeat(width);
157
+ const displayWidth = getDisplayWidth(title);
158
+ const totalPadding = width - displayWidth;
159
+ const leftPadding = Math.floor(totalPadding / 2);
160
+ const rightPadding = totalPadding - leftPadding;
161
+ const paddedTitle = " ".repeat(Math.max(0, leftPadding)) + title + " ".repeat(Math.max(0, rightPadding));
162
+ console.log();
163
+ console.log(chalk2.cyan.bold(` \u2554${border}\u2557`));
164
+ console.log(chalk2.cyan.bold(` \u2551`) + chalk2.cyan.bold(paddedTitle) + chalk2.cyan.bold(`\u2551`));
165
+ console.log(chalk2.cyan.bold(` \u255A${border}\u255D`));
166
+ console.log();
167
+ }
168
+ function showOperationHints(isCheckbox = false) {
169
+ if (isCheckbox) {
170
+ 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
171
+ `);
172
+ } else {
173
+ console.log(` \u{1F4A1} \x1B[36m\u2191\u2193\x1B[0m ${t("hint_select_move")} | \x1B[36m\u23CE\x1B[0m ${t("hint_select_confirm")}
174
+ `);
175
+ }
176
+ }
177
+
178
+ // src/utils/fs-helpers.ts
179
+ import { lstatSync, statSync } from "fs";
180
+ function isSymlink(path) {
181
+ try {
182
+ return lstatSync(path).isSymbolicLink();
183
+ } catch {
184
+ return false;
185
+ }
186
+ }
187
+ function isDirectory(path) {
188
+ try {
189
+ return statSync(path).isDirectory();
190
+ } catch {
191
+ return false;
192
+ }
193
+ }
194
+
195
+ // src/core/registry.ts
196
+ var __filename2 = fileURLToPath2(import.meta.url);
197
+ var __dirname2 = dirname2(__filename2);
21
198
  function loadPluginsFromYaml() {
22
- const pluginsDir = join(__dirname, "plugins.d");
23
- const defaultsPath = join(pluginsDir, "_defaults.yml");
199
+ const pluginsDir = join2(__dirname2, "plugins.d");
200
+ const defaultsPath = join2(pluginsDir, "_defaults.yml");
24
201
  let defaults = {};
25
202
  try {
26
- defaults = parseYaml(readFileSync(defaultsPath, "utf-8")) || {};
203
+ defaults = parseYaml(readFileSync2(defaultsPath, "utf-8")) || {};
27
204
  } catch {
28
205
  }
29
206
  const plugins = [];
@@ -31,7 +208,7 @@ function loadPluginsFromYaml() {
31
208
  for (const file of readdirSync(pluginsDir)) {
32
209
  if (file.startsWith("_") || !file.endsWith(".yml")) continue;
33
210
  try {
34
- const content = parseYaml(readFileSync(join(pluginsDir, file), "utf-8"));
211
+ const content = parseYaml(readFileSync2(join2(pluginsDir, file), "utf-8"));
35
212
  if (!content || !content.id) continue;
36
213
  plugins.push({
37
214
  id: content.id,
@@ -44,6 +221,7 @@ function loadPluginsFromYaml() {
44
221
  description: content.description || ""
45
222
  });
46
223
  } catch {
224
+ logger.warn(t("plugin_yaml_error").replace("{file}", file));
47
225
  }
48
226
  }
49
227
  } catch {
@@ -60,7 +238,7 @@ function mergeDynamicPlugins(repoPath) {
60
238
  const existingIds = new Set(PLUGIN_REGISTRY.map((p) => p.id));
61
239
  const dynamic = [];
62
240
  for (const pluginDir of PLUGIN_DIRS) {
63
- const parent = join(repoPath, pluginDir);
241
+ const parent = join2(repoPath, pluginDir);
64
242
  if (!existsSync(parent)) continue;
65
243
  let entries = [];
66
244
  try {
@@ -69,10 +247,10 @@ function mergeDynamicPlugins(repoPath) {
69
247
  continue;
70
248
  }
71
249
  for (const entry of entries) {
72
- const pluginPath = join(parent, entry);
250
+ const pluginPath = join2(parent, entry);
73
251
  if (!isDirectory(pluginPath)) continue;
74
252
  if (entry === "install-helper") continue;
75
- const initSh = join(pluginPath, "init.sh");
253
+ const initSh = join2(pluginPath, "init.sh");
76
254
  if (!existsSync(initSh)) continue;
77
255
  const pluginId = entry;
78
256
  if (existingIds.has(pluginId)) continue;
@@ -95,13 +273,6 @@ function mergeDynamicPlugins(repoPath) {
95
273
  );
96
274
  }
97
275
  }
98
- function isDirectory(path) {
99
- try {
100
- return statSync(path).isDirectory();
101
- } catch {
102
- return false;
103
- }
104
- }
105
276
  function findPlugin(query) {
106
277
  const normalized = query.toLowerCase().trim();
107
278
  const exactMatch = PLUGIN_REGISTRY.find(
@@ -133,39 +304,6 @@ import { join as join4 } from "path";
133
304
  import { homedir } from "os";
134
305
  import { join as join3 } from "path";
135
306
  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
307
  var VALID_TOOLS = ["opencode", "claude", "trae", "cursor", "copilot"];
170
308
  var VALID_LEVELS = ["project", "global"];
171
309
  function validateTool(tool) {
@@ -366,7 +504,7 @@ function getToolDisplayName(tool) {
366
504
  return names[tool];
367
505
  }
368
506
  function getAllTools() {
369
- return ["opencode", "claude", "trae", "cursor", "copilot"];
507
+ return VALID_TOOLS;
370
508
  }
371
509
 
372
510
  // src/core/manifest.ts
@@ -409,7 +547,7 @@ function readAllManifests(configRoot) {
409
547
  function scanInstalled() {
410
548
  const plugins = getAllPlugins();
411
549
  const installed = [];
412
- const tools = ["opencode", "claude", "trae", "cursor", "copilot"];
550
+ const tools = VALID_TOOLS;
413
551
  const levels = ["project", "global"];
414
552
  for (const tool of tools) {
415
553
  for (const level of levels) {
@@ -467,82 +605,40 @@ function verifyPluginFilesExist(configRoot, manifest, tool, level) {
467
605
  return true;
468
606
  }
469
607
 
470
- // src/utils/logger.ts
471
- import chalk from "chalk";
472
- import ora from "ora";
473
- var logger = {
474
- success: (msg) => console.log(chalk.green("\u2713") + " " + msg),
475
- error: (msg) => console.log(chalk.red("\u2717") + " " + msg),
476
- warn: (msg) => console.log(chalk.yellow("\u26A0") + " " + msg),
477
- info: (msg) => console.log(chalk.cyan("\u2192") + " " + msg),
478
- step: (msg) => console.log(chalk.dim(msg)),
479
- blank: () => console.log()
480
- };
481
- function createSpinner(text) {
482
- return ora({ text, color: "cyan" });
483
- }
484
- function printBanner(subtitle) {
485
- console.log(chalk.cyan(`
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;
608
+ // src/utils/config.ts
609
+ import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync4 } from "fs";
610
+ import { join as join6 } from "path";
611
+ import { parse, stringify } from "yaml";
612
+
613
+ // src/utils/fs.ts
614
+ import { writeFileSync, renameSync, existsSync as existsSync5, unlinkSync } from "fs";
615
+ import { dirname as dirname3 } from "path";
616
+ function atomicWriteFileSync(filePath, data, encoding = "utf-8") {
617
+ const dir = dirname3(filePath);
618
+ if (!existsSync5(dir)) {
619
+ throw new Error(`Directory does not exist: ${dir}`);
620
+ }
621
+ const tmpPath = `${filePath}.tmp`;
622
+ writeFileSync(tmpPath, data, encoding);
623
+ if (existsSync5(filePath)) {
624
+ try {
625
+ unlinkSync(filePath);
626
+ } catch {
505
627
  }
506
628
  }
507
- return width;
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
- }
629
+ renameSync(tmpPath, filePath);
530
630
  }
531
631
 
532
632
  // 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
633
  function getConfigDir() {
538
- return join6(homedir3(), ".cannbot");
634
+ return getCannbotConfigDir();
539
635
  }
540
636
  function getConfigPath() {
541
637
  return join6(getConfigDir(), "config.yaml");
542
638
  }
543
639
  function readConfig() {
544
640
  const configPath = getConfigPath();
545
- if (!existsSync5(configPath)) {
641
+ if (!existsSync6(configPath)) {
546
642
  return {
547
643
  language: "zh_CN",
548
644
  installedPlugins: []
@@ -559,6 +655,7 @@ function readConfig() {
559
655
  installedPlugins: parsed.installedPlugins || []
560
656
  };
561
657
  } catch {
658
+ logger.warn(t("config_corrupted"));
562
659
  return {
563
660
  language: "zh_CN",
564
661
  installedPlugins: []
@@ -567,12 +664,12 @@ function readConfig() {
567
664
  }
568
665
  function writeConfig(config) {
569
666
  const configDir = getConfigDir();
570
- if (!existsSync5(configDir)) {
667
+ if (!existsSync6(configDir)) {
571
668
  mkdirSync(configDir, { recursive: true });
572
669
  }
573
670
  const configPath = getConfigPath();
574
671
  const content = stringify(config);
575
- writeFileSync(configPath, content, "utf-8");
672
+ atomicWriteFileSync(configPath, content);
576
673
  }
577
674
  function updateConfig(updates) {
578
675
  const config = readConfig();
@@ -595,84 +692,11 @@ function removeInstalledPlugin(pluginId) {
595
692
  writeConfig(config);
596
693
  }
597
694
 
598
- // src/ui/theme.ts
599
- import chalk2 from "chalk";
600
- var selectTheme = {
601
- helpMode: "never"
602
- };
603
- function isCJK(code) {
604
- return 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;
605
- }
606
- function isEmoji(code) {
607
- return code >= 127744 && code <= 129791 || code >= 9728 && code <= 10175;
608
- }
609
- function getDisplayWidth2(str) {
610
- let width = 0;
611
- for (const ch of str) {
612
- const code = ch.codePointAt(0);
613
- if (isCJK(code) || isEmoji(code)) {
614
- width += 2;
615
- } else {
616
- width += 1;
617
- }
618
- }
619
- return width;
620
- }
621
- function wrapDescription(text) {
622
- const prefix = " \u{1F4A1} ";
623
- const indent = " ";
624
- const cols = process.stdout.columns || 120;
625
- const maxLen = Math.max(20, cols - getDisplayWidth2(prefix) - 2);
626
- const tokens = [];
627
- let i = 0;
628
- while (i < text.length) {
629
- const code = text[i].codePointAt(0);
630
- if (isCJK(code)) {
631
- tokens.push({ text: text[i], width: 2 });
632
- i++;
633
- } else {
634
- let j = i;
635
- while (j < text.length) {
636
- const c = text[j].codePointAt(0);
637
- if (isCJK(c)) break;
638
- j++;
639
- }
640
- const word = text.slice(i, j);
641
- tokens.push({ text: word, width: getDisplayWidth2(word) });
642
- i = j;
643
- }
644
- }
645
- const lines = [];
646
- let line = "";
647
- let lineWidth = 0;
648
- for (const token of tokens) {
649
- if (lineWidth + token.width > maxLen && line) {
650
- lines.push(line.trimEnd());
651
- line = token.text;
652
- lineWidth = token.width;
653
- } else {
654
- line += token.text;
655
- lineWidth += token.width;
656
- }
657
- }
658
- if (line) lines.push(line.trimEnd());
659
- return lines.map((l, i2) => chalk2.cyan(i2 === 0 ? prefix + l : indent + l)).join("\n");
660
- }
661
- var checkboxTheme = {
662
- icon: {
663
- checked: "\x1B[32m\u2611\x1B[22m",
664
- unchecked: "\u2610",
665
- cursor: "\u276F"
666
- },
667
- helpMode: "never",
668
- style: {
669
- description: (text) => wrapDescription(text)
670
- }
671
- };
672
-
673
- // src/ui/wizard.ts
695
+ // src/utils/constants.ts
674
696
  var BACK = "__back__";
675
697
  var CANCEL = "__cancel__";
698
+
699
+ // src/ui/wizard.ts
676
700
  async function selectToolWithDetection() {
677
701
  const config = readConfig();
678
702
  logger.blank();
@@ -756,7 +780,7 @@ async function stepTool(detectedTools, lastTool) {
756
780
  if (detectedTools.length === 0) {
757
781
  logger.error(t("error_tool_not_found"));
758
782
  const choices2 = [
759
- ...["opencode", "claude", "trae", "cursor", "copilot"].map((tool) => ({
783
+ ...VALID_TOOLS.map((tool) => ({
760
784
  name: `> ${getToolDisplayName(tool)}`,
761
785
  value: tool
762
786
  })),
@@ -918,19 +942,19 @@ async function stepConfirm(tool, level, plugins) {
918
942
  }
919
943
 
920
944
  // src/core/repository.ts
921
- import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync6 } from "fs";
922
- import { join as join8, dirname as dirname4 } from "path";
945
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6 } from "fs";
946
+ import { join as join8, dirname as dirname5 } from "path";
923
947
  import { fileURLToPath as fileURLToPath4 } from "url";
924
948
  import { execa as execa2 } from "execa";
925
949
  import { parse as parseYaml3 } from "yaml";
926
950
 
927
951
  // src/core/scanner.ts
928
- import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
929
- import { join as join7, dirname as dirname3 } from "path";
952
+ import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync5, mkdirSync as mkdirSync2 } from "fs";
953
+ import { join as join7, dirname as dirname4 } from "path";
930
954
  import { fileURLToPath as fileURLToPath3 } from "url";
931
955
  import { parse as parseYaml2 } from "yaml";
932
956
  var __filename3 = fileURLToPath3(import.meta.url);
933
- var __dirname3 = dirname3(__filename3);
957
+ var __dirname3 = dirname4(__filename3);
934
958
  var EXCLUDE_DIRS = /* @__PURE__ */ new Set([
935
959
  "node_modules",
936
960
  ".git",
@@ -974,26 +998,26 @@ function scanSkills(repoPath) {
974
998
  const seen = /* @__PURE__ */ new Set();
975
999
  for (const dir of SKILL_SCAN_DIRS) {
976
1000
  const fullPath = join7(repoPath, dir);
977
- if (!existsSync6(fullPath)) continue;
1001
+ if (!existsSync7(fullPath)) continue;
978
1002
  scanDirectory(fullPath, repoPath, dir, skills, seen);
979
1003
  }
980
1004
  for (const pluginDir of PLUGIN_SCAN_DIRS) {
981
1005
  const pluginParent = join7(repoPath, pluginDir);
982
- if (!existsSync6(pluginParent)) continue;
1006
+ if (!existsSync7(pluginParent)) continue;
983
1007
  for (const plugin of safeReaddir(pluginParent)) {
984
1008
  const pluginPath = join7(pluginParent, plugin);
985
- if (!isDirectory2(pluginPath)) continue;
1009
+ if (!isDirectory(pluginPath)) continue;
986
1010
  const skillsDir = join7(pluginPath, "skills");
987
- if (existsSync6(skillsDir)) {
1011
+ if (existsSync7(skillsDir)) {
988
1012
  scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
989
1013
  }
990
1014
  const skillDir = join7(pluginPath, "skill");
991
- if (existsSync6(skillDir)) {
1015
+ if (existsSync7(skillDir)) {
992
1016
  scanDirectory(skillDir, repoPath, `${pluginDir}/${plugin}/skill`, skills, seen);
993
1017
  }
994
1018
  const rootSkillMd = join7(pluginPath, "SKILL.md");
995
1019
  const initSh = join7(pluginPath, "init.sh");
996
- if (existsSync6(rootSkillMd) && !existsSync6(initSh)) {
1020
+ if (existsSync7(rootSkillMd) && !existsSync7(initSh)) {
997
1021
  const frontmatter = parseFrontmatter(rootSkillMd);
998
1022
  if (frontmatter && !seen.has(frontmatter.name)) {
999
1023
  seen.add(frontmatter.name);
@@ -1042,15 +1066,15 @@ function parseFrontmatter(filePath) {
1042
1066
  function getCurrentCommit(repoPath) {
1043
1067
  try {
1044
1068
  const headFile = join7(repoPath, ".git", "HEAD");
1045
- if (!existsSync6(headFile)) return "unknown";
1069
+ if (!existsSync7(headFile)) return "unknown";
1046
1070
  const headContent = readFileSync5(headFile, "utf-8").trim();
1047
1071
  if (headContent.startsWith("ref: ")) {
1048
1072
  const refPath = join7(repoPath, ".git", headContent.slice(5));
1049
- if (existsSync6(refPath)) {
1073
+ if (existsSync7(refPath)) {
1050
1074
  return readFileSync5(refPath, "utf-8").trim();
1051
1075
  }
1052
1076
  const packedRefsPath = join7(repoPath, ".git", "packed-refs");
1053
- if (existsSync6(packedRefsPath)) {
1077
+ if (existsSync7(packedRefsPath)) {
1054
1078
  const packedRefs = readFileSync5(packedRefsPath, "utf-8");
1055
1079
  const refName = headContent.slice(5);
1056
1080
  const lines = packedRefs.split("\n");
@@ -1069,7 +1093,7 @@ function getCurrentCommit(repoPath) {
1069
1093
  function readScanCache() {
1070
1094
  try {
1071
1095
  const cachePath = getCachePath();
1072
- if (!existsSync6(cachePath)) return null;
1096
+ if (!existsSync7(cachePath)) return null;
1073
1097
  const content = readFileSync5(cachePath, "utf-8");
1074
1098
  const cache = JSON.parse(content);
1075
1099
  if (!cache.skills || !cache.timestamp) return null;
@@ -1083,11 +1107,11 @@ function readScanCache() {
1083
1107
  function writeScanCache(cache) {
1084
1108
  try {
1085
1109
  const cachePath = getCachePath();
1086
- const cacheDir = dirname3(cachePath);
1087
- if (!existsSync6(cacheDir)) {
1110
+ const cacheDir = dirname4(cachePath);
1111
+ if (!existsSync7(cacheDir)) {
1088
1112
  mkdirSync2(cacheDir, { recursive: true });
1089
1113
  }
1090
- writeFileSync2(cachePath, JSON.stringify(cache, null, 2));
1114
+ atomicWriteFileSync(cachePath, JSON.stringify(cache, null, 2));
1091
1115
  } catch {
1092
1116
  }
1093
1117
  }
@@ -1098,9 +1122,9 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1098
1122
  for (const entry of safeReaddir(dirPath)) {
1099
1123
  const fullPath = join7(dirPath, entry);
1100
1124
  if (EXCLUDE_DIRS.has(entry)) continue;
1101
- if (!isDirectory2(fullPath)) continue;
1125
+ if (!isDirectory(fullPath)) continue;
1102
1126
  const skillMd = join7(fullPath, "SKILL.md");
1103
- if (existsSync6(skillMd)) {
1127
+ if (existsSync7(skillMd)) {
1104
1128
  const frontmatter = parseFrontmatter(skillMd);
1105
1129
  if (frontmatter && !seen.has(frontmatter.name)) {
1106
1130
  seen.add(frontmatter.name);
@@ -1123,29 +1147,22 @@ function safeReaddir(dir) {
1123
1147
  return [];
1124
1148
  }
1125
1149
  }
1126
- function isDirectory2(path) {
1127
- try {
1128
- return statSync2(path).isDirectory();
1129
- } catch {
1130
- return false;
1131
- }
1132
- }
1133
1150
 
1134
1151
  // src/core/skill-registry.ts
1135
1152
  var CATEGORY_DEFS = [
1136
- { id: "knowledge", name: "\u77E5\u8BC6\u4E0E\u53C2\u8003" },
1137
- { id: "env-tools", name: "\u73AF\u5883\u4E0E\u5DE5\u5177" },
1138
- { id: "debug", name: "\u8C03\u8BD5\u4E0E\u8BCA\u65AD" },
1139
- { id: "testing", name: "\u6D4B\u8BD5\u4E0E\u8D28\u91CF" },
1140
- { id: "ascendc", name: "AscendC \u5F00\u53D1" },
1141
- { id: "pypto", name: "PyPTO \u5F00\u53D1" },
1142
- { id: "tilelang", name: "TileLang \u5F00\u53D1" },
1143
- { id: "triton", name: "Triton \u5F00\u53D1" },
1144
- { id: "model", name: "\u6A21\u578B\u63A8\u7406\u4F18\u5316" },
1145
- { id: "runtime", name: "Runtime \u8FC1\u79FB" },
1146
- { id: "graph", name: "\u56FE\u6A21\u5F0F" },
1147
- { id: "platform", name: "\u5E73\u53F0\u5DE5\u5177" },
1148
- { id: "other", name: "\u5176\u4ED6 Skills" }
1153
+ { id: "knowledge", name: "\u77E5\u8BC6\u4E0E\u53C2\u8003", nameEn: "Knowledge & Reference" },
1154
+ { id: "env-tools", name: "\u73AF\u5883\u4E0E\u5DE5\u5177", nameEn: "Environment & Tools" },
1155
+ { id: "debug", name: "\u8C03\u8BD5\u4E0E\u8BCA\u65AD", nameEn: "Debug & Diagnostics" },
1156
+ { id: "testing", name: "\u6D4B\u8BD5\u4E0E\u8D28\u91CF", nameEn: "Testing & Quality" },
1157
+ { id: "ascendc", name: "AscendC \u5F00\u53D1", nameEn: "AscendC Development" },
1158
+ { id: "pypto", name: "PyPTO \u5F00\u53D1", nameEn: "PyPTO Development" },
1159
+ { id: "tilelang", name: "TileLang \u5F00\u53D1", nameEn: "TileLang Development" },
1160
+ { id: "triton", name: "Triton \u5F00\u53D1", nameEn: "Triton Development" },
1161
+ { id: "model", name: "\u6A21\u578B\u63A8\u7406\u4F18\u5316", nameEn: "Model Inference Optimization" },
1162
+ { id: "runtime", name: "Runtime \u8FC1\u79FB", nameEn: "Runtime Migration" },
1163
+ { id: "graph", name: "\u56FE\u6A21\u5F0F", nameEn: "Graph Mode" },
1164
+ { id: "platform", name: "\u5E73\u53F0\u5DE5\u5177", nameEn: "Platform Tools" },
1165
+ { id: "other", name: "\u5176\u4ED6 Skills", nameEn: "Other Skills" }
1149
1166
  ];
1150
1167
  var dynamicSkills = [];
1151
1168
  var initialized = false;
@@ -1355,9 +1372,10 @@ function getAllSkills() {
1355
1372
  }
1356
1373
  function getAllCategories() {
1357
1374
  const skills = getActiveSkills();
1375
+ const isEn = t("list_name") === "Name";
1358
1376
  return CATEGORY_DEFS.map((def) => ({
1359
1377
  id: def.id,
1360
- name: def.name,
1378
+ name: isEn ? def.nameEn : def.name,
1361
1379
  skills: skills.filter((s) => {
1362
1380
  const catId = CATEGORY_MAP[s.id];
1363
1381
  if (catId) return catId === def.id;
@@ -1368,7 +1386,7 @@ function getAllCategories() {
1368
1386
 
1369
1387
  // src/core/repository.ts
1370
1388
  var __filename4 = fileURLToPath4(import.meta.url);
1371
- var __dirname4 = dirname4(__filename4);
1389
+ var __dirname4 = dirname5(__filename4);
1372
1390
  function loadRepoUrl() {
1373
1391
  if (process.env.CANNBOT_REPO_URL) {
1374
1392
  return process.env.CANNBOT_REPO_URL;
@@ -1432,6 +1450,7 @@ var RepositoryManager = class {
1432
1450
  try {
1433
1451
  await execa2("git", ["pull", "--quiet"], { cwd: repoPath, timeout: 3e4 });
1434
1452
  } catch {
1453
+ logger.warn(t("repo_pull_failed"));
1435
1454
  }
1436
1455
  mergeDynamicPlugins(repoPath);
1437
1456
  }
@@ -1442,18 +1461,18 @@ var RepositoryManager = class {
1442
1461
  return this.repoPath;
1443
1462
  }
1444
1463
  isValidRepo(path) {
1445
- if (!existsSync7(path)) return false;
1464
+ if (!existsSync8(path)) return false;
1446
1465
  const gitDir = join8(path, ".git");
1447
1466
  const pluginsDir = join8(path, "plugins-official");
1448
- return existsSync7(gitDir) && existsSync7(pluginsDir);
1467
+ return existsSync8(gitDir) && existsSync8(pluginsDir);
1449
1468
  }
1450
1469
  async cloneRepo() {
1451
1470
  const configDir = getCannbotConfigDir();
1452
- if (!existsSync7(configDir)) {
1471
+ if (!existsSync8(configDir)) {
1453
1472
  mkdirSync3(configDir, { recursive: true });
1454
1473
  }
1455
1474
  const targetPath = getCannbotRepoPath();
1456
- if (existsSync7(targetPath)) {
1475
+ if (existsSync8(targetPath)) {
1457
1476
  if (this.isValidRepo(targetPath)) {
1458
1477
  this.repoPath = targetPath;
1459
1478
  return targetPath;
@@ -1479,12 +1498,12 @@ function createRepositoryManager(customPath) {
1479
1498
  }
1480
1499
 
1481
1500
  // src/core/installer.ts
1482
- import { existsSync as existsSync10 } from "fs";
1501
+ import { existsSync as existsSync11 } from "fs";
1483
1502
  import { join as join11 } from "path";
1484
1503
  import { execa as execa3 } from "execa";
1485
1504
 
1486
1505
  // src/core/record.ts
1487
- import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, lstatSync, unlinkSync } from "fs";
1506
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
1488
1507
  import { join as join9 } from "path";
1489
1508
  function getInstallsDir() {
1490
1509
  return join9(getCannbotConfigDir(), "installs");
@@ -1494,28 +1513,29 @@ function getRecordPath(pluginId) {
1494
1513
  }
1495
1514
  function readRecord(pluginId) {
1496
1515
  const recordPath = getRecordPath(pluginId);
1497
- if (!existsSync8(recordPath)) {
1516
+ if (!existsSync9(recordPath)) {
1498
1517
  return null;
1499
1518
  }
1500
1519
  try {
1501
1520
  const content = readFileSync7(recordPath, "utf-8");
1502
1521
  return JSON.parse(content);
1503
1522
  } catch {
1523
+ logger.warn(t("record_corrupted").replace("{file}", recordPath));
1504
1524
  return null;
1505
1525
  }
1506
1526
  }
1507
1527
  function writeRecord(record) {
1508
1528
  const installsDir = getInstallsDir();
1509
- if (!existsSync8(installsDir)) {
1529
+ if (!existsSync9(installsDir)) {
1510
1530
  mkdirSync4(installsDir, { recursive: true });
1511
1531
  }
1512
1532
  const recordPath = getRecordPath(record.pluginId);
1513
- writeFileSync4(recordPath, JSON.stringify(record, null, 2), "utf-8");
1533
+ atomicWriteFileSync(recordPath, JSON.stringify(record, null, 2));
1514
1534
  }
1515
1535
  function deleteRecord(pluginId) {
1516
1536
  const recordPath = getRecordPath(pluginId);
1517
- if (existsSync8(recordPath)) {
1518
- unlinkSync(recordPath);
1537
+ if (existsSync9(recordPath)) {
1538
+ unlinkSync2(recordPath);
1519
1539
  }
1520
1540
  }
1521
1541
  function scanInstalledFiles(pluginId, displayName, tool, level, installPath, configRoot, manifest) {
@@ -1523,24 +1543,24 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1523
1543
  const directories = [];
1524
1544
  if (manifest) {
1525
1545
  const skillsDir = join9(configRoot, "skills");
1526
- if (existsSync8(skillsDir)) {
1546
+ if (existsSync9(skillsDir)) {
1527
1547
  directories.push(skillsDir);
1528
1548
  for (const skillName of manifest.installed_skills || []) {
1529
1549
  const skillPath = join9(skillsDir, skillName);
1530
- if (existsSync8(skillPath) || isSymlink(skillPath)) {
1550
+ if (existsSync9(skillPath) || isSymlink(skillPath)) {
1531
1551
  files.push(skillPath);
1532
1552
  }
1533
1553
  }
1534
1554
  }
1535
1555
  const agentsDir = join9(configRoot, "agents");
1536
- if (existsSync8(agentsDir)) {
1556
+ if (existsSync9(agentsDir)) {
1537
1557
  directories.push(agentsDir);
1538
1558
  for (const agentName of manifest.installed_agents || []) {
1539
1559
  const agentPath = join9(agentsDir, agentName);
1540
1560
  const agentPathMd = join9(agentsDir, agentName + ".md");
1541
- if (existsSync8(agentPath) || isSymlink(agentPath)) {
1561
+ if (existsSync9(agentPath) || isSymlink(agentPath)) {
1542
1562
  files.push(agentPath);
1543
- } else if (existsSync8(agentPathMd) || isSymlink(agentPathMd)) {
1563
+ } else if (existsSync9(agentPathMd) || isSymlink(agentPathMd)) {
1544
1564
  files.push(agentPathMd);
1545
1565
  }
1546
1566
  }
@@ -1551,16 +1571,16 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1551
1571
  files.push(workflowsLink);
1552
1572
  }
1553
1573
  const manifestPath = join9(configRoot, "cannbot-manifest.json");
1554
- if (existsSync8(manifestPath)) {
1574
+ if (existsSync9(manifestPath)) {
1555
1575
  files.push(manifestPath);
1556
1576
  }
1557
1577
  const pluginManifestPath = join9(configRoot, `${pluginId}-manifest.json`);
1558
- if (existsSync8(pluginManifestPath)) {
1578
+ if (existsSync9(pluginManifestPath)) {
1559
1579
  files.push(pluginManifestPath);
1560
1580
  }
1561
1581
  const configFileName = tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1562
1582
  const configFilePath = level === "project" ? join9(installPath, configFileName) : join9(configRoot, configFileName);
1563
- if (existsSync8(configFilePath)) {
1583
+ if (existsSync9(configFilePath)) {
1564
1584
  files.push(configFilePath);
1565
1585
  }
1566
1586
  const repoLinks = ["asc-devkit", "pypto", "tilelang-ascend", "cann-recipes-infer", "cann-samples"];
@@ -1586,35 +1606,29 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1586
1606
  directories
1587
1607
  };
1588
1608
  }
1589
- function isSymlink(path) {
1590
- try {
1591
- return lstatSync(path).isSymbolicLink();
1592
- } catch {
1593
- return false;
1594
- }
1595
- }
1596
1609
  function getSkillRecordPath() {
1597
1610
  return join9(getInstallsDir(), "skills.json");
1598
1611
  }
1599
1612
  function readSkillRecord() {
1600
1613
  const recordPath = getSkillRecordPath();
1601
- if (!existsSync8(recordPath)) {
1614
+ if (!existsSync9(recordPath)) {
1602
1615
  return {};
1603
1616
  }
1604
1617
  try {
1605
1618
  const content = readFileSync7(recordPath, "utf-8");
1606
1619
  return JSON.parse(content);
1607
1620
  } catch {
1621
+ logger.warn(t("skill_record_corrupted"));
1608
1622
  return {};
1609
1623
  }
1610
1624
  }
1611
1625
  function writeSkillRecord(record) {
1612
1626
  const installsDir = getInstallsDir();
1613
- if (!existsSync8(installsDir)) {
1627
+ if (!existsSync9(installsDir)) {
1614
1628
  mkdirSync4(installsDir, { recursive: true });
1615
1629
  }
1616
1630
  const recordPath = getSkillRecordPath();
1617
- writeFileSync4(recordPath, JSON.stringify(record, null, 2), "utf-8");
1631
+ atomicWriteFileSync(recordPath, JSON.stringify(record, null, 2));
1618
1632
  }
1619
1633
  function addSkillsToRecord(skillIds, tool, level, installPath) {
1620
1634
  const record = readSkillRecord();
@@ -1655,16 +1669,13 @@ function getInstalledSkills(tool, level, installPath) {
1655
1669
  const skillsDir = join9(configRoot, "skills");
1656
1670
  return recordedSkills.filter((skillId) => {
1657
1671
  const skillPath = join9(skillsDir, skillId);
1658
- return existsSync8(skillPath) || isSymlink(skillPath);
1672
+ return existsSync9(skillPath) || isSymlink(skillPath);
1659
1673
  });
1660
1674
  }
1661
1675
 
1662
1676
  // src/core/backup.ts
1663
- import { existsSync as existsSync9, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
1677
+ import { existsSync as existsSync10, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
1664
1678
  import { join as join10 } from "path";
1665
- function getAgentsFileName(tool) {
1666
- return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1667
- }
1668
1679
  function detectCurrentPlugin(configRoot, tool) {
1669
1680
  const manifest = readManifest(configRoot);
1670
1681
  if (manifest?.team) {
@@ -1677,7 +1688,7 @@ function detectCurrentPlugin(configRoot, tool) {
1677
1688
  }
1678
1689
  }
1679
1690
  const agentsFile = join10(configRoot, getAgentsFileName(tool));
1680
- if (!existsSync9(agentsFile)) {
1691
+ if (!existsSync10(agentsFile)) {
1681
1692
  return null;
1682
1693
  }
1683
1694
  const allRecords = readAllRecords();
@@ -1696,7 +1707,7 @@ function detectCurrentPlugin(configRoot, tool) {
1696
1707
  }
1697
1708
  function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
1698
1709
  const agentsFile = join10(configRoot, getAgentsFileName(tool));
1699
- if (!existsSync9(agentsFile)) {
1710
+ if (!existsSync10(agentsFile)) {
1700
1711
  return null;
1701
1712
  }
1702
1713
  const timestamp = formatTimestamp(/* @__PURE__ */ new Date());
@@ -1715,7 +1726,7 @@ function createBackup(configRoot, tool, fromPluginId, fromPluginName) {
1715
1726
  }
1716
1727
  }
1717
1728
  function findBackups(configRoot) {
1718
- if (!existsSync9(configRoot)) {
1729
+ if (!existsSync10(configRoot)) {
1719
1730
  return [];
1720
1731
  }
1721
1732
  const files = readdirSync3(configRoot);
@@ -1753,8 +1764,8 @@ function restoreBackup(backupPath, configRoot, tool) {
1753
1764
  }
1754
1765
  function deleteBackup(backupPath) {
1755
1766
  try {
1756
- if (existsSync9(backupPath)) {
1757
- unlinkSync2(backupPath);
1767
+ if (existsSync10(backupPath)) {
1768
+ unlinkSync3(backupPath);
1758
1769
  return true;
1759
1770
  }
1760
1771
  return false;
@@ -1773,20 +1784,9 @@ function formatTimestamp(date) {
1773
1784
  }
1774
1785
  function readAllRecords() {
1775
1786
  const records = [];
1776
- const plugins = [
1777
- "ops-direct-invoke",
1778
- "ops-direct-invoke-flash",
1779
- "ops-registry-invoke",
1780
- "pypto-op-orchestrator",
1781
- "triton-op-generator",
1782
- "tilelang-op-orchestrator",
1783
- "model-infer-optimize",
1784
- "catlass-op-generator",
1785
- "ops-code-reviewer",
1786
- "torch-compile"
1787
- ];
1788
- for (const pluginId of plugins) {
1789
- const record = readRecord(pluginId);
1787
+ const plugins = getAllPlugins();
1788
+ for (const plugin of plugins) {
1789
+ const record = readRecord(plugin.id);
1790
1790
  if (record) {
1791
1791
  records.push(record);
1792
1792
  }
@@ -1841,18 +1841,18 @@ async function installPlugin(opts) {
1841
1841
  pluginId: opts.pluginId,
1842
1842
  skillsCount: 0,
1843
1843
  agentsCount: 0,
1844
- errors: [`Plugin not found: ${opts.pluginId}`],
1844
+ errors: [t("error_plugin_not_found") + ": " + opts.pluginId],
1845
1845
  warnings: []
1846
1846
  };
1847
1847
  }
1848
1848
  const scriptPath = join11(opts.repoPath, plugin.dir, plugin.script);
1849
- if (!existsSync10(scriptPath)) {
1849
+ if (!existsSync11(scriptPath)) {
1850
1850
  return {
1851
1851
  success: false,
1852
1852
  pluginId: opts.pluginId,
1853
1853
  skillsCount: 0,
1854
1854
  agentsCount: 0,
1855
- errors: [`Script not found: ${scriptPath}`],
1855
+ errors: [t("error_script_not_found").replace("{path}", scriptPath)],
1856
1856
  warnings: []
1857
1857
  };
1858
1858
  }
@@ -1862,9 +1862,9 @@ async function installPlugin(opts) {
1862
1862
  }
1863
1863
  const cwd = opts.installPath || process.cwd();
1864
1864
  const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
1865
- const agentsFile = join11(configRoot, getAgentsFileName(opts.tool));
1865
+ const agentsFile = join11(configRoot, getAgentsFileName2(opts.tool));
1866
1866
  let backupInfo = null;
1867
- if (existsSync10(agentsFile)) {
1867
+ if (existsSync11(agentsFile)) {
1868
1868
  const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
1869
1869
  if (currentPlugin && currentPlugin.pluginId !== opts.pluginId) {
1870
1870
  let choice = "overwrite";
@@ -1943,6 +1943,7 @@ async function installPlugin(opts) {
1943
1943
  }
1944
1944
  writeRecord(record);
1945
1945
  } catch {
1946
+ logger.warn(t("record_write_failed"));
1946
1947
  }
1947
1948
  return {
1948
1949
  success: true,
@@ -1953,7 +1954,7 @@ async function installPlugin(opts) {
1953
1954
  warnings: []
1954
1955
  };
1955
1956
  } catch (error) {
1956
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1957
+ const errorMessage = error instanceof Error ? error.message : t("error_unknown");
1957
1958
  return {
1958
1959
  success: false,
1959
1960
  pluginId: opts.pluginId,
@@ -1966,8 +1967,8 @@ async function installPlugin(opts) {
1966
1967
  }
1967
1968
 
1968
1969
  // src/core/skill-installer.ts
1969
- import { existsSync as existsSync11, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync3, readdirSync as readdirSync4, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
1970
- import { join as join12, dirname as dirname5 } from "path";
1970
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync4, readdirSync as readdirSync4, rmdirSync, realpathSync } from "fs";
1971
+ import { join as join12, dirname as dirname6 } from "path";
1971
1972
  import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
1972
1973
  import chalk5 from "chalk";
1973
1974
  import Table from "cli-table3";
@@ -1975,7 +1976,7 @@ async function installSkills(skillIds, tool, level, repoPath) {
1975
1976
  const configRoot = getConfigRoot(tool, level);
1976
1977
  const skillsDir = join12(configRoot, "skills");
1977
1978
  const installPath = level === "project" ? process.cwd() : configRoot;
1978
- if (!existsSync11(skillsDir)) {
1979
+ if (!existsSync12(skillsDir)) {
1979
1980
  mkdirSync5(skillsDir, { recursive: true });
1980
1981
  }
1981
1982
  const results = [];
@@ -1983,25 +1984,25 @@ async function installSkills(skillIds, tool, level, repoPath) {
1983
1984
  for (const skillId of skillIds) {
1984
1985
  const skill = findSkill(skillId);
1985
1986
  if (!skill) {
1986
- results.push({ skillId, success: false, error: "Skill not found in registry" });
1987
+ results.push({ skillId, success: false, error: t("error_skill_not_found") });
1987
1988
  continue;
1988
1989
  }
1989
1990
  const sourcePath = resolveSkillSourcePath(skill, repoPath);
1990
1991
  const targetPath = join12(skillsDir, skillId);
1991
- if (!existsSync11(sourcePath)) {
1992
- results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
1992
+ if (!existsSync12(sourcePath)) {
1993
+ results.push({ skillId, success: false, error: t("error_source_not_found").replace("{path}", sourcePath) });
1993
1994
  continue;
1994
1995
  }
1995
1996
  try {
1996
1997
  const resolvedSource = realpathSync(sourcePath);
1997
- if (existsSync11(targetPath) || isSymlink2(targetPath)) {
1998
- unlinkSync3(targetPath);
1998
+ if (existsSync12(targetPath) || isSymlink(targetPath)) {
1999
+ unlinkSync4(targetPath);
1999
2000
  }
2000
2001
  symlinkSync(resolvedSource, targetPath);
2001
2002
  results.push({ skillId, success: true });
2002
2003
  installedIds.push(skillId);
2003
2004
  } catch (error) {
2004
- results.push({ skillId, success: false, error: error instanceof Error ? error.message : "Unknown error" });
2005
+ results.push({ skillId, success: false, error: error instanceof Error ? error.message : t("error_unknown") });
2005
2006
  }
2006
2007
  }
2007
2008
  if (installedIds.length > 0) {
@@ -2018,23 +2019,23 @@ async function uninstallSkills(skillIds, tool, level) {
2018
2019
  for (const skillId of skillIds) {
2019
2020
  const targetPath = join12(skillsDir, skillId);
2020
2021
  try {
2021
- if (existsSync11(targetPath) || isSymlink2(targetPath)) {
2022
- unlinkSync3(targetPath);
2022
+ if (existsSync12(targetPath) || isSymlink(targetPath)) {
2023
+ unlinkSync4(targetPath);
2023
2024
  results.push({ skillId, success: true });
2024
2025
  removedIds.push(skillId);
2025
2026
  logger.step(` ${t("uninstall_remove_label")}: ${skillId}`);
2026
2027
  } else {
2027
- results.push({ skillId, success: false, error: "Not installed" });
2028
+ results.push({ skillId, success: false, error: t("error_not_installed") });
2028
2029
  logger.warn(`${skillId} ${t("uninstall_skill_not_installed")}`);
2029
2030
  }
2030
2031
  } catch (error) {
2031
- results.push({ skillId, success: false, error: error instanceof Error ? error.message : "Unknown error" });
2032
+ results.push({ skillId, success: false, error: error instanceof Error ? error.message : t("error_unknown") });
2032
2033
  }
2033
2034
  }
2034
2035
  if (removedIds.length > 0) {
2035
2036
  removeSkillsFromRecord(removedIds, tool, level, installPath);
2036
2037
  }
2037
- if (existsSync11(skillsDir)) {
2038
+ if (existsSync12(skillsDir)) {
2038
2039
  try {
2039
2040
  const entries = readdirSync4(skillsDir);
2040
2041
  if (entries.length === 0) {
@@ -2050,8 +2051,6 @@ var SELECT_ALL = "__select_all__";
2050
2051
  var SELECT_ALL_CATEGORY = "__select_all_category__";
2051
2052
  var CONTINUE_SELECT = "__continue_select__";
2052
2053
  async function interactiveSkillSelect(tool, level) {
2053
- const BACK3 = "__back__";
2054
- const CANCEL3 = "__cancel__";
2055
2054
  const categories = getAllCategories();
2056
2055
  const allSkillIds = getAllSkills().map((s) => s.id);
2057
2056
  let accumulated = [];
@@ -2074,8 +2073,8 @@ async function interactiveSkillSelect(tool, level) {
2074
2073
  })),
2075
2074
  new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
2076
2075
  ...accumulated.length > 0 ? [{ name: `>> ${t("skill_confirm_install_count").replace("{count}", String(accumulated.length))}`, value: "install" }] : [],
2077
- { name: "<- " + t("wizard_back"), value: BACK3 },
2078
- { name: "x " + t("wizard_cancel"), value: CANCEL3 }
2076
+ { name: "<- " + t("wizard_back"), value: BACK },
2077
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
2079
2078
  ];
2080
2079
  showOperationHints();
2081
2080
  selectedCategoryId = await select3({
@@ -2085,8 +2084,8 @@ async function interactiveSkillSelect(tool, level) {
2085
2084
  theme: selectTheme,
2086
2085
  pageSize: 15
2087
2086
  });
2088
- if (selectedCategoryId === BACK3) return "back";
2089
- if (selectedCategoryId === CANCEL3) return "cancel";
2087
+ if (selectedCategoryId === BACK) return "back";
2088
+ if (selectedCategoryId === CANCEL) return "cancel";
2090
2089
  if (selectedCategoryId === SELECT_ALL) {
2091
2090
  return allSkillIds;
2092
2091
  }
@@ -2220,19 +2219,12 @@ function listAllSkills() {
2220
2219
  function resolveSkillSourcePath(skill, repoPath) {
2221
2220
  if (skill.filePath) {
2222
2221
  const absPath = skill.filePath.startsWith("/") ? skill.filePath : join12(repoPath, skill.filePath);
2223
- if (existsSync11(absPath)) {
2224
- return dirname5(absPath);
2222
+ if (existsSync12(absPath)) {
2223
+ return dirname6(absPath);
2225
2224
  }
2226
2225
  }
2227
2226
  return join12(repoPath, skill.source, skill.id);
2228
2227
  }
2229
- function isSymlink2(path) {
2230
- try {
2231
- return lstatSync2(path).isSymbolicLink();
2232
- } catch {
2233
- return false;
2234
- }
2235
- }
2236
2228
 
2237
2229
  // src/ui/display.ts
2238
2230
  import chalk6 from "chalk";
@@ -2323,13 +2315,11 @@ function printEnhancedSummary(results, tool, configRoot) {
2323
2315
  }
2324
2316
 
2325
2317
  // src/commands/init.ts
2326
- import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
2318
+ import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
2327
2319
  import { join as join13 } from "path";
2328
- var BACK2 = "__back__";
2329
- var CANCEL2 = "__cancel__";
2330
2320
  async function initCommand() {
2331
2321
  const cwd = process.cwd();
2332
- if (existsSync12(join13(cwd, "package.json")) && (() => {
2322
+ if (existsSync13(join13(cwd, "package.json")) && (() => {
2333
2323
  try {
2334
2324
  const pkg = JSON.parse(readFileSync8(join13(cwd, "package.json"), "utf-8"));
2335
2325
  return pkg.name === "@cannbot-ai/install-helper";
@@ -2385,7 +2375,6 @@ async function initCommand() {
2385
2375
  }
2386
2376
  async function selectMode() {
2387
2377
  printBoxTitle(t("wizard_select_mode_title"));
2388
- const CANCEL3 = "__cancel__";
2389
2378
  const choices = [
2390
2379
  {
2391
2380
  name: `> ${t("wizard_mode_plugin")} \u2014 ${t("wizard_mode_plugin_desc")}`,
@@ -2396,7 +2385,7 @@ async function selectMode() {
2396
2385
  value: "skill"
2397
2386
  },
2398
2387
  new Separator3("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
2399
- { name: "x " + t("wizard_cancel"), value: CANCEL3 }
2388
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
2400
2389
  ];
2401
2390
  showOperationHints();
2402
2391
  const result = await select4({
@@ -2405,7 +2394,7 @@ async function selectMode() {
2405
2394
  loop: false,
2406
2395
  theme: selectTheme
2407
2396
  });
2408
- if (result === CANCEL3) return null;
2397
+ if (result === CANCEL) return null;
2409
2398
  return result;
2410
2399
  }
2411
2400
  async function pluginInstallFlow() {
@@ -2482,11 +2471,11 @@ async function skillInstallFlow() {
2482
2471
  }
2483
2472
  case 1: {
2484
2473
  const result = await stepLevel();
2485
- if (result === BACK2) {
2474
+ if (result === BACK) {
2486
2475
  step = 0;
2487
2476
  break;
2488
2477
  }
2489
- if (result === CANCEL2) {
2478
+ if (result === CANCEL) {
2490
2479
  logger.info(t("init_cancelled"));
2491
2480
  return "done";
2492
2481
  }
@@ -2557,13 +2546,12 @@ async function listCommand() {
2557
2546
 
2558
2547
  // src/commands/doctor.ts
2559
2548
  import chalk8 from "chalk";
2560
- import { existsSync as existsSync13, readdirSync as readdirSync5, lstatSync as lstatSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6 } from "fs";
2549
+ import { existsSync as existsSync14, readdirSync as readdirSync5, lstatSync as lstatSync2, unlinkSync as unlinkSync5, mkdirSync as mkdirSync6 } from "fs";
2561
2550
  import { join as join14 } from "path";
2562
2551
  async function doctorCommand(options = {}) {
2563
2552
  console.log();
2564
2553
  console.log(chalk8.bold(` ${t("doctor_title")}`));
2565
2554
  console.log(chalk8.dim(" " + "\u2500".repeat(46)));
2566
- let errors = 0;
2567
2555
  let warnings = 0;
2568
2556
  let fixes = 0;
2569
2557
  console.log();
@@ -2601,7 +2589,7 @@ async function doctorCommand(options = {}) {
2601
2589
  const configRoot = getConfigRoot(primaryTool, "project");
2602
2590
  const skillsDir = getSkillsDir(configRoot);
2603
2591
  const agentsDir = getAgentsDir(configRoot);
2604
- if (existsSync13(skillsDir)) {
2592
+ if (existsSync14(skillsDir)) {
2605
2593
  const brokenLinks = checkBrokenLinks(skillsDir);
2606
2594
  if (brokenLinks === 0) {
2607
2595
  const count = readdirSync5(skillsDir).length;
@@ -2623,7 +2611,7 @@ async function doctorCommand(options = {}) {
2623
2611
  console.log(chalk8.green(" \u2713") + ` ${t("doctor_fix_rebuilding")}: ${t("doctor_created").replace("{path}", skillsDir)}`);
2624
2612
  }
2625
2613
  }
2626
- if (existsSync13(agentsDir)) {
2614
+ if (existsSync14(agentsDir)) {
2627
2615
  const brokenLinks = checkBrokenLinks(agentsDir);
2628
2616
  if (brokenLinks === 0) {
2629
2617
  const count = readdirSync5(agentsDir).length;
@@ -2649,7 +2637,7 @@ async function doctorCommand(options = {}) {
2649
2637
  console.log(chalk8.bold(` ${t("doctor_config")}`));
2650
2638
  const configFile = getConfigFileName(primaryTool);
2651
2639
  const configPath = join14(process.cwd(), configFile);
2652
- if (existsSync13(configPath)) {
2640
+ if (existsSync14(configPath)) {
2653
2641
  console.log(chalk8.green(" \u2713") + ` ${configFile} ${t("doctor_config_exists")}`);
2654
2642
  } else {
2655
2643
  console.log(chalk8.dim(" \u2014") + ` ${configFile} ${t("doctor_config_not_exist")}`);
@@ -2658,11 +2646,11 @@ async function doctorCommand(options = {}) {
2658
2646
  console.log(chalk8.dim(" " + "\u2500".repeat(46)));
2659
2647
  if (options.fix && fixes > 0) {
2660
2648
  console.log(
2661
- ` ${t("doctor_result")}: ${t("doctor_result_with_fix").replace("{warnings}", String(warnings)).replace("{errors}", String(errors)).replace("{fixes}", String(fixes))}`
2649
+ ` ${t("doctor_result")}: ${t("doctor_result_with_fix").replace("{warnings}", String(warnings)).replace("{fixes}", String(fixes))}`
2662
2650
  );
2663
2651
  } else {
2664
2652
  console.log(
2665
- ` ${t("doctor_result")}: ${t("doctor_result_without_fix").replace("{warnings}", String(warnings)).replace("{errors}", String(errors))}`
2653
+ ` ${t("doctor_result")}: ${t("doctor_result_without_fix").replace("{warnings}", String(warnings))}`
2666
2654
  );
2667
2655
  }
2668
2656
  console.log();
@@ -2674,9 +2662,9 @@ function checkBrokenLinks(dir) {
2674
2662
  for (const entry of entries) {
2675
2663
  const fullPath = join14(dir, entry);
2676
2664
  try {
2677
- const stats = lstatSync3(fullPath);
2665
+ const stats = lstatSync2(fullPath);
2678
2666
  if (stats.isSymbolicLink()) {
2679
- if (!existsSync13(fullPath)) {
2667
+ if (!existsSync14(fullPath)) {
2680
2668
  broken++;
2681
2669
  }
2682
2670
  }
@@ -2695,10 +2683,10 @@ function fixBrokenLinks(dir) {
2695
2683
  for (const entry of entries) {
2696
2684
  const fullPath = join14(dir, entry);
2697
2685
  try {
2698
- const stats = lstatSync3(fullPath);
2686
+ const stats = lstatSync2(fullPath);
2699
2687
  if (stats.isSymbolicLink()) {
2700
- if (!existsSync13(fullPath)) {
2701
- unlinkSync4(fullPath);
2688
+ if (!existsSync14(fullPath)) {
2689
+ unlinkSync5(fullPath);
2702
2690
  fixed++;
2703
2691
  }
2704
2692
  }
@@ -2713,7 +2701,6 @@ function fixBrokenLinks(dir) {
2713
2701
  // src/commands/status.ts
2714
2702
  import chalk9 from "chalk";
2715
2703
  async function statusCommand() {
2716
- const plugins = getAllPlugins();
2717
2704
  const installed = scanInstalled();
2718
2705
  const installedMap = new Map(installed.map((p) => [p.id, p]));
2719
2706
  console.log();
@@ -2772,7 +2759,10 @@ async function installCommand(names, options) {
2772
2759
  tool2 = validateTool(options.tool);
2773
2760
  } else {
2774
2761
  const detected = await selectToolWithDetection();
2775
- if (detected === "back" || detected === "cancel") return;
2762
+ if (detected === "back" || detected === "cancel") {
2763
+ logger.info(t("init_cancelled"));
2764
+ return;
2765
+ }
2776
2766
  tool2 = detected;
2777
2767
  }
2778
2768
  const level2 = options.level ? validateLevel(options.level) : "project";
@@ -2821,7 +2811,10 @@ async function installCommand(names, options) {
2821
2811
  tool2 = validateTool(options.tool);
2822
2812
  } else {
2823
2813
  const detected = await selectToolWithDetection();
2824
- if (detected === "back" || detected === "cancel") return;
2814
+ if (detected === "back" || detected === "cancel") {
2815
+ logger.info(t("init_cancelled"));
2816
+ return;
2817
+ }
2825
2818
  tool2 = detected;
2826
2819
  }
2827
2820
  const level2 = options.level ? validateLevel(options.level) : "project";
@@ -2832,11 +2825,17 @@ async function installCommand(names, options) {
2832
2825
  const selectedSkills = await interactiveSkillSelect(tool2, level2);
2833
2826
  if (selectedSkills === "back") {
2834
2827
  const redetected = await selectToolWithDetection();
2835
- if (redetected === "back" || redetected === "cancel") return;
2828
+ if (redetected === "back" || redetected === "cancel") {
2829
+ logger.info(t("init_cancelled"));
2830
+ return;
2831
+ }
2836
2832
  tool2 = redetected;
2837
2833
  break;
2838
2834
  }
2839
- if (selectedSkills === "cancel") return;
2835
+ if (selectedSkills === "cancel") {
2836
+ logger.info(t("init_cancelled"));
2837
+ return;
2838
+ }
2840
2839
  if (selectedSkills.length === 0) {
2841
2840
  logger.info(t("install_no_skill_selected"));
2842
2841
  return;
@@ -2911,7 +2910,10 @@ async function installCommand(names, options) {
2911
2910
  tool = validateTool(options.tool);
2912
2911
  } else {
2913
2912
  const detected = await selectToolWithDetection();
2914
- if (detected === "back" || detected === "cancel") return;
2913
+ if (detected === "back" || detected === "cancel") {
2914
+ logger.info(t("init_cancelled"));
2915
+ return;
2916
+ }
2915
2917
  tool = detected;
2916
2918
  }
2917
2919
  const level = options.level ? validateLevel(options.level) : "project";
@@ -3029,7 +3031,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
3029
3031
  }
3030
3032
 
3031
3033
  // src/commands/uninstall.ts
3032
- import { existsSync as existsSync14, unlinkSync as unlinkSync5, rmdirSync as rmdirSync2, readdirSync as readdirSync6, lstatSync as lstatSync4 } from "fs";
3034
+ import { existsSync as existsSync15, unlinkSync as unlinkSync6, rmdirSync as rmdirSync2, readdirSync as readdirSync6 } from "fs";
3033
3035
  import { resolve } from "path";
3034
3036
  import chalk11 from "chalk";
3035
3037
  async function uninstallCommand(names, options) {
@@ -3071,8 +3073,8 @@ async function uninstallCommand(names, options) {
3071
3073
  for (const filePath of record.files) {
3072
3074
  if (!isSafePath(filePath)) continue;
3073
3075
  try {
3074
- if (existsSync14(filePath) || isSymlink3(filePath)) {
3075
- unlinkSync5(filePath);
3076
+ if (existsSync15(filePath) || isSymlink(filePath)) {
3077
+ unlinkSync6(filePath);
3076
3078
  const name = filePath.split("/").pop() || filePath;
3077
3079
  logger.step(` ${t("uninstall_remove_label")}: ${name}`);
3078
3080
  removedFiles++;
@@ -3086,7 +3088,7 @@ async function uninstallCommand(names, options) {
3086
3088
  if (resolve(dirPath) === resolve(configRoot)) {
3087
3089
  continue;
3088
3090
  }
3089
- if (existsSync14(dirPath)) {
3091
+ if (existsSync15(dirPath)) {
3090
3092
  const entries = readdirSync6(dirPath);
3091
3093
  if (entries.length === 0) {
3092
3094
  rmdirSync2(dirPath);
@@ -3119,7 +3121,7 @@ async function uninstallCommand(names, options) {
3119
3121
  }
3120
3122
  const totalRemoved = removedFiles + removedDirs;
3121
3123
  if (totalRemoved > 0) {
3122
- logger.success(`${t("uninstall_removed")} ${plugin.displayName}\uFF08${t("uninstall_remove_file_format").replace("{count}", String(removedFiles))}\uFF0C${t("uninstall_remove_dir_format").replace("{count}", String(removedDirs))}\uFF09`);
3124
+ logger.success(t("uninstall_summary_format").replace("{name}", plugin.displayName).replace("{files}", String(removedFiles)).replace("{dirs}", String(removedDirs)));
3123
3125
  } else {
3124
3126
  logger.warn(`${plugin.displayName}${t("uninstall_files_gone")}`);
3125
3127
  }
@@ -3141,13 +3143,6 @@ async function uninstallCommand(names, options) {
3141
3143
  logger.blank();
3142
3144
  }
3143
3145
  }
3144
- function isSymlink3(path) {
3145
- try {
3146
- return lstatSync4(path).isSymbolicLink();
3147
- } catch {
3148
- return false;
3149
- }
3150
- }
3151
3146
 
3152
3147
  // src/commands/update.ts
3153
3148
  import chalk12 from "chalk";
@@ -3157,7 +3152,10 @@ async function updateCommand(pluginNames, options) {
3157
3152
  tool = validateTool(options.tool);
3158
3153
  } else {
3159
3154
  const detected = await selectToolWithDetection();
3160
- if (detected === "back" || detected === "cancel") return;
3155
+ if (detected === "back" || detected === "cancel") {
3156
+ logger.info(t("init_cancelled"));
3157
+ return;
3158
+ }
3161
3159
  tool = detected;
3162
3160
  }
3163
3161
  const level = options.level ? validateLevel(options.level) : "project";
@@ -3231,7 +3229,7 @@ async function updateCommand(pluginNames, options) {
3231
3229
 
3232
3230
  // src/commands/info.ts
3233
3231
  import chalk13 from "chalk";
3234
- import { existsSync as existsSync15, readdirSync as readdirSync7 } from "fs";
3232
+ import { existsSync as existsSync16, readdirSync as readdirSync7 } from "fs";
3235
3233
  import { join as join15 } from "path";
3236
3234
  async function infoCommand(pluginName) {
3237
3235
  const plugin = findPlugin(pluginName);
@@ -3257,11 +3255,11 @@ async function infoCommand(pluginName) {
3257
3255
  const repoManager = createRepositoryManager();
3258
3256
  const repoPath = await repoManager.ensureRepo();
3259
3257
  const quickstartPath = join15(repoPath, plugin.dir, "quickstart.md");
3260
- if (existsSync15(quickstartPath)) {
3258
+ if (existsSync16(quickstartPath)) {
3261
3259
  console.log(` ${chalk13.dim(t("info_quickstart") + ":")} ${quickstartPath}`);
3262
3260
  }
3263
3261
  const agentsDir = join15(repoPath, plugin.dir, "agents");
3264
- if (existsSync15(agentsDir)) {
3262
+ if (existsSync16(agentsDir)) {
3265
3263
  const agentFiles = readdirSync7(agentsDir).filter((f) => f.endsWith(".md"));
3266
3264
  if (agentFiles.length > 0) {
3267
3265
  console.log();
@@ -3313,13 +3311,27 @@ async function langCommand(action, value) {
3313
3311
  }
3314
3312
 
3315
3313
  // src/cli.ts
3314
+ import { readFileSync as readFileSync9 } from "fs";
3315
+ import { fileURLToPath as fileURLToPath5 } from "url";
3316
+ import { dirname as dirname7, join as join16 } from "path";
3317
+ function readVersion() {
3318
+ try {
3319
+ const __filename5 = fileURLToPath5(import.meta.url);
3320
+ const __dirname5 = dirname7(__filename5);
3321
+ const pkgPath = join16(__dirname5, "..", "package.json");
3322
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
3323
+ return pkg.version || "0.0.0";
3324
+ } catch {
3325
+ return "0.0.0";
3326
+ }
3327
+ }
3316
3328
  function createCLI() {
3317
3329
  const config = readConfig();
3318
3330
  if (config.language) {
3319
3331
  setLanguage(config.language);
3320
3332
  }
3321
3333
  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.33");
3334
+ program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version(readVersion());
3323
3335
  program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
3324
3336
  await initCommand();
3325
3337
  });