@cannbot-ai/install-helper 0.0.2-beta.34 → 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,13 +12,13 @@ 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 as readFileSync2, existsSync, statSync } from "fs";
15
+ import { readdirSync, readFileSync as readFileSync2, existsSync } from "fs";
16
16
  import { join as join2, dirname as dirname2 } from "path";
17
17
  import { fileURLToPath as fileURLToPath2 } from "url";
18
18
  import { parse as parseYaml } from "yaml";
19
19
 
20
20
  // src/utils/logger.ts
21
- import chalk from "chalk";
21
+ import chalk2 from "chalk";
22
22
  import ora from "ora";
23
23
 
24
24
  // src/utils/i18n.ts
@@ -52,20 +52,95 @@ function t(key) {
52
52
  return messages[key] !== void 0 ? messages[key] : key;
53
53
  }
54
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
+
55
130
  // src/utils/logger.ts
56
131
  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)),
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)),
62
137
  blank: () => console.log()
63
138
  };
64
139
  function createSpinner(text) {
65
140
  return ora({ text, color: "cyan" });
66
141
  }
67
142
  function printBanner(subtitle) {
68
- console.log(chalk.cyan(`
143
+ console.log(chalk2.cyan(`
69
144
  ____ _ _ _ _ _ ____ _
70
145
  / ___| / \\ | \\ | | \\ | | __ ) ___ | |_
71
146
  | | / _ \\ | \\| | \\| | _ \\ / _ \\| __|
@@ -73,22 +148,10 @@ function printBanner(subtitle) {
73
148
  \\____/_/ \\_\\_| \\_|_| \\_|____/ \\___/ \\__|
74
149
  `));
75
150
  if (subtitle) {
76
- console.log(chalk.bold(` ${subtitle}`));
151
+ console.log(chalk2.bold(` ${subtitle}`));
77
152
  console.log();
78
153
  }
79
154
  }
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
155
  function printBoxTitle(title, width = 65) {
93
156
  const border = "\u2550".repeat(width);
94
157
  const displayWidth = getDisplayWidth(title);
@@ -97,9 +160,9 @@ function printBoxTitle(title, width = 65) {
97
160
  const rightPadding = totalPadding - leftPadding;
98
161
  const paddedTitle = " ".repeat(Math.max(0, leftPadding)) + title + " ".repeat(Math.max(0, rightPadding));
99
162
  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`));
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`));
103
166
  console.log();
104
167
  }
105
168
  function showOperationHints(isCheckbox = false) {
@@ -112,6 +175,23 @@ function showOperationHints(isCheckbox = false) {
112
175
  }
113
176
  }
114
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
+
115
195
  // src/core/registry.ts
116
196
  var __filename2 = fileURLToPath2(import.meta.url);
117
197
  var __dirname2 = dirname2(__filename2);
@@ -193,13 +273,6 @@ function mergeDynamicPlugins(repoPath) {
193
273
  );
194
274
  }
195
275
  }
196
- function isDirectory(path) {
197
- try {
198
- return statSync(path).isDirectory();
199
- } catch {
200
- return false;
201
- }
202
- }
203
276
  function findPlugin(query) {
204
277
  const normalized = query.toLowerCase().trim();
205
278
  const exactMatch = PLUGIN_REGISTRY.find(
@@ -431,7 +504,7 @@ function getToolDisplayName(tool) {
431
504
  return names[tool];
432
505
  }
433
506
  function getAllTools() {
434
- return ["opencode", "claude", "trae", "cursor", "copilot"];
507
+ return VALID_TOOLS;
435
508
  }
436
509
 
437
510
  // src/core/manifest.ts
@@ -474,7 +547,7 @@ function readAllManifests(configRoot) {
474
547
  function scanInstalled() {
475
548
  const plugins = getAllPlugins();
476
549
  const installed = [];
477
- const tools = ["opencode", "claude", "trae", "cursor", "copilot"];
550
+ const tools = VALID_TOOLS;
478
551
  const levels = ["project", "global"];
479
552
  for (const tool of tools) {
480
553
  for (const level of levels) {
@@ -535,7 +608,6 @@ function verifyPluginFilesExist(configRoot, manifest, tool, level) {
535
608
  // src/utils/config.ts
536
609
  import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync4 } from "fs";
537
610
  import { join as join6 } from "path";
538
- import { homedir as homedir3 } from "os";
539
611
  import { parse, stringify } from "yaml";
540
612
 
541
613
  // src/utils/fs.ts
@@ -559,7 +631,7 @@ function atomicWriteFileSync(filePath, data, encoding = "utf-8") {
559
631
 
560
632
  // src/utils/config.ts
561
633
  function getConfigDir() {
562
- return join6(homedir3(), ".cannbot");
634
+ return getCannbotConfigDir();
563
635
  }
564
636
  function getConfigPath() {
565
637
  return join6(getConfigDir(), "config.yaml");
@@ -620,84 +692,11 @@ function removeInstalledPlugin(pluginId) {
620
692
  writeConfig(config);
621
693
  }
622
694
 
623
- // src/ui/theme.ts
624
- import chalk2 from "chalk";
625
- var selectTheme = {
626
- helpMode: "never"
627
- };
628
- function isCJK(code) {
629
- 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;
630
- }
631
- function isEmoji(code) {
632
- return code >= 127744 && code <= 129791 || code >= 9728 && code <= 10175;
633
- }
634
- function getDisplayWidth2(str) {
635
- let width = 0;
636
- for (const ch of str) {
637
- const code = ch.codePointAt(0);
638
- if (isCJK(code) || isEmoji(code)) {
639
- width += 2;
640
- } else {
641
- width += 1;
642
- }
643
- }
644
- return width;
645
- }
646
- function wrapDescription(text) {
647
- const prefix = " \u{1F4A1} ";
648
- const indent = " ";
649
- const cols = process.stdout.columns || 120;
650
- const maxLen = Math.max(20, cols - getDisplayWidth2(prefix) - 2);
651
- const tokens = [];
652
- let i = 0;
653
- while (i < text.length) {
654
- const code = text[i].codePointAt(0);
655
- if (isCJK(code)) {
656
- tokens.push({ text: text[i], width: 2 });
657
- i++;
658
- } else {
659
- let j = i;
660
- while (j < text.length) {
661
- const c = text[j].codePointAt(0);
662
- if (isCJK(c)) break;
663
- j++;
664
- }
665
- const word = text.slice(i, j);
666
- tokens.push({ text: word, width: getDisplayWidth2(word) });
667
- i = j;
668
- }
669
- }
670
- const lines = [];
671
- let line = "";
672
- let lineWidth = 0;
673
- for (const token of tokens) {
674
- if (lineWidth + token.width > maxLen && line) {
675
- lines.push(line.trimEnd());
676
- line = token.text;
677
- lineWidth = token.width;
678
- } else {
679
- line += token.text;
680
- lineWidth += token.width;
681
- }
682
- }
683
- if (line) lines.push(line.trimEnd());
684
- return lines.map((l, i2) => chalk2.cyan(i2 === 0 ? prefix + l : indent + l)).join("\n");
685
- }
686
- var checkboxTheme = {
687
- icon: {
688
- checked: "\x1B[32m\u2611\x1B[22m",
689
- unchecked: "\u2610",
690
- cursor: "\u276F"
691
- },
692
- helpMode: "never",
693
- style: {
694
- description: (text) => wrapDescription(text)
695
- }
696
- };
697
-
698
- // src/ui/wizard.ts
695
+ // src/utils/constants.ts
699
696
  var BACK = "__back__";
700
697
  var CANCEL = "__cancel__";
698
+
699
+ // src/ui/wizard.ts
701
700
  async function selectToolWithDetection() {
702
701
  const config = readConfig();
703
702
  logger.blank();
@@ -781,7 +780,7 @@ async function stepTool(detectedTools, lastTool) {
781
780
  if (detectedTools.length === 0) {
782
781
  logger.error(t("error_tool_not_found"));
783
782
  const choices2 = [
784
- ...["opencode", "claude", "trae", "cursor", "copilot"].map((tool) => ({
783
+ ...VALID_TOOLS.map((tool) => ({
785
784
  name: `> ${getToolDisplayName(tool)}`,
786
785
  value: tool
787
786
  })),
@@ -950,7 +949,7 @@ import { execa as execa2 } from "execa";
950
949
  import { parse as parseYaml3 } from "yaml";
951
950
 
952
951
  // src/core/scanner.ts
953
- import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2, mkdirSync as mkdirSync2 } from "fs";
952
+ import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync5, mkdirSync as mkdirSync2 } from "fs";
954
953
  import { join as join7, dirname as dirname4 } from "path";
955
954
  import { fileURLToPath as fileURLToPath3 } from "url";
956
955
  import { parse as parseYaml2 } from "yaml";
@@ -1007,7 +1006,7 @@ function scanSkills(repoPath) {
1007
1006
  if (!existsSync7(pluginParent)) continue;
1008
1007
  for (const plugin of safeReaddir(pluginParent)) {
1009
1008
  const pluginPath = join7(pluginParent, plugin);
1010
- if (!isDirectory2(pluginPath)) continue;
1009
+ if (!isDirectory(pluginPath)) continue;
1011
1010
  const skillsDir = join7(pluginPath, "skills");
1012
1011
  if (existsSync7(skillsDir)) {
1013
1012
  scanDirectory(skillsDir, repoPath, `${pluginDir}/${plugin}/skills`, skills, seen);
@@ -1123,7 +1122,7 @@ function scanDirectory(dirPath, repoPath, sourcePrefix, skills, seen) {
1123
1122
  for (const entry of safeReaddir(dirPath)) {
1124
1123
  const fullPath = join7(dirPath, entry);
1125
1124
  if (EXCLUDE_DIRS.has(entry)) continue;
1126
- if (!isDirectory2(fullPath)) continue;
1125
+ if (!isDirectory(fullPath)) continue;
1127
1126
  const skillMd = join7(fullPath, "SKILL.md");
1128
1127
  if (existsSync7(skillMd)) {
1129
1128
  const frontmatter = parseFrontmatter(skillMd);
@@ -1148,29 +1147,22 @@ function safeReaddir(dir) {
1148
1147
  return [];
1149
1148
  }
1150
1149
  }
1151
- function isDirectory2(path) {
1152
- try {
1153
- return statSync2(path).isDirectory();
1154
- } catch {
1155
- return false;
1156
- }
1157
- }
1158
1150
 
1159
1151
  // src/core/skill-registry.ts
1160
1152
  var CATEGORY_DEFS = [
1161
- { id: "knowledge", name: "\u77E5\u8BC6\u4E0E\u53C2\u8003" },
1162
- { id: "env-tools", name: "\u73AF\u5883\u4E0E\u5DE5\u5177" },
1163
- { id: "debug", name: "\u8C03\u8BD5\u4E0E\u8BCA\u65AD" },
1164
- { id: "testing", name: "\u6D4B\u8BD5\u4E0E\u8D28\u91CF" },
1165
- { id: "ascendc", name: "AscendC \u5F00\u53D1" },
1166
- { id: "pypto", name: "PyPTO \u5F00\u53D1" },
1167
- { id: "tilelang", name: "TileLang \u5F00\u53D1" },
1168
- { id: "triton", name: "Triton \u5F00\u53D1" },
1169
- { id: "model", name: "\u6A21\u578B\u63A8\u7406\u4F18\u5316" },
1170
- { id: "runtime", name: "Runtime \u8FC1\u79FB" },
1171
- { id: "graph", name: "\u56FE\u6A21\u5F0F" },
1172
- { id: "platform", name: "\u5E73\u53F0\u5DE5\u5177" },
1173
- { 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" }
1174
1166
  ];
1175
1167
  var dynamicSkills = [];
1176
1168
  var initialized = false;
@@ -1380,9 +1372,10 @@ function getAllSkills() {
1380
1372
  }
1381
1373
  function getAllCategories() {
1382
1374
  const skills = getActiveSkills();
1375
+ const isEn = t("list_name") === "Name";
1383
1376
  return CATEGORY_DEFS.map((def) => ({
1384
1377
  id: def.id,
1385
- name: def.name,
1378
+ name: isEn ? def.nameEn : def.name,
1386
1379
  skills: skills.filter((s) => {
1387
1380
  const catId = CATEGORY_MAP[s.id];
1388
1381
  if (catId) return catId === def.id;
@@ -1510,7 +1503,7 @@ import { join as join11 } from "path";
1510
1503
  import { execa as execa3 } from "execa";
1511
1504
 
1512
1505
  // src/core/record.ts
1513
- import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, lstatSync, unlinkSync as unlinkSync2 } from "fs";
1506
+ import { existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
1514
1507
  import { join as join9 } from "path";
1515
1508
  function getInstallsDir() {
1516
1509
  return join9(getCannbotConfigDir(), "installs");
@@ -1613,13 +1606,6 @@ function scanInstalledFiles(pluginId, displayName, tool, level, installPath, con
1613
1606
  directories
1614
1607
  };
1615
1608
  }
1616
- function isSymlink(path) {
1617
- try {
1618
- return lstatSync(path).isSymbolicLink();
1619
- } catch {
1620
- return false;
1621
- }
1622
- }
1623
1609
  function getSkillRecordPath() {
1624
1610
  return join9(getInstallsDir(), "skills.json");
1625
1611
  }
@@ -1690,9 +1676,6 @@ function getInstalledSkills(tool, level, installPath) {
1690
1676
  // src/core/backup.ts
1691
1677
  import { existsSync as existsSync10, copyFileSync, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
1692
1678
  import { join as join10 } from "path";
1693
- function getAgentsFileName(tool) {
1694
- return tool === "claude" ? "CLAUDE.md" : "AGENTS.md";
1695
- }
1696
1679
  function detectCurrentPlugin(configRoot, tool) {
1697
1680
  const manifest = readManifest(configRoot);
1698
1681
  if (manifest?.team) {
@@ -1801,20 +1784,9 @@ function formatTimestamp(date) {
1801
1784
  }
1802
1785
  function readAllRecords() {
1803
1786
  const records = [];
1804
- const plugins = [
1805
- "ops-direct-invoke",
1806
- "ops-direct-invoke-flash",
1807
- "ops-registry-invoke",
1808
- "pypto-op-orchestrator",
1809
- "triton-op-generator",
1810
- "tilelang-op-orchestrator",
1811
- "model-infer-optimize",
1812
- "catlass-op-generator",
1813
- "ops-code-reviewer",
1814
- "torch-compile"
1815
- ];
1816
- for (const pluginId of plugins) {
1817
- const record = readRecord(pluginId);
1787
+ const plugins = getAllPlugins();
1788
+ for (const plugin of plugins) {
1789
+ const record = readRecord(plugin.id);
1818
1790
  if (record) {
1819
1791
  records.push(record);
1820
1792
  }
@@ -1869,7 +1841,7 @@ async function installPlugin(opts) {
1869
1841
  pluginId: opts.pluginId,
1870
1842
  skillsCount: 0,
1871
1843
  agentsCount: 0,
1872
- errors: [`Plugin not found: ${opts.pluginId}`],
1844
+ errors: [t("error_plugin_not_found") + ": " + opts.pluginId],
1873
1845
  warnings: []
1874
1846
  };
1875
1847
  }
@@ -1880,7 +1852,7 @@ async function installPlugin(opts) {
1880
1852
  pluginId: opts.pluginId,
1881
1853
  skillsCount: 0,
1882
1854
  agentsCount: 0,
1883
- errors: [`Script not found: ${scriptPath}`],
1855
+ errors: [t("error_script_not_found").replace("{path}", scriptPath)],
1884
1856
  warnings: []
1885
1857
  };
1886
1858
  }
@@ -1890,7 +1862,7 @@ async function installPlugin(opts) {
1890
1862
  }
1891
1863
  const cwd = opts.installPath || process.cwd();
1892
1864
  const configRoot = getConfigRoot(opts.tool, opts.level, opts.installPath);
1893
- const agentsFile = join11(configRoot, getAgentsFileName(opts.tool));
1865
+ const agentsFile = join11(configRoot, getAgentsFileName2(opts.tool));
1894
1866
  let backupInfo = null;
1895
1867
  if (existsSync11(agentsFile)) {
1896
1868
  const currentPlugin = detectCurrentPlugin(configRoot, opts.tool);
@@ -1982,7 +1954,7 @@ async function installPlugin(opts) {
1982
1954
  warnings: []
1983
1955
  };
1984
1956
  } catch (error) {
1985
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1957
+ const errorMessage = error instanceof Error ? error.message : t("error_unknown");
1986
1958
  return {
1987
1959
  success: false,
1988
1960
  pluginId: opts.pluginId,
@@ -1995,7 +1967,7 @@ async function installPlugin(opts) {
1995
1967
  }
1996
1968
 
1997
1969
  // src/core/skill-installer.ts
1998
- import { existsSync as existsSync12, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync4, readdirSync as readdirSync4, rmdirSync, realpathSync, lstatSync as lstatSync2 } from "fs";
1970
+ import { existsSync as existsSync12, mkdirSync as mkdirSync5, symlinkSync, unlinkSync as unlinkSync4, readdirSync as readdirSync4, rmdirSync, realpathSync } from "fs";
1999
1971
  import { join as join12, dirname as dirname6 } from "path";
2000
1972
  import { select as select3, checkbox as checkbox2, Separator as Separator2 } from "@inquirer/prompts";
2001
1973
  import chalk5 from "chalk";
@@ -2012,25 +1984,25 @@ async function installSkills(skillIds, tool, level, repoPath) {
2012
1984
  for (const skillId of skillIds) {
2013
1985
  const skill = findSkill(skillId);
2014
1986
  if (!skill) {
2015
- results.push({ skillId, success: false, error: "Skill not found in registry" });
1987
+ results.push({ skillId, success: false, error: t("error_skill_not_found") });
2016
1988
  continue;
2017
1989
  }
2018
1990
  const sourcePath = resolveSkillSourcePath(skill, repoPath);
2019
1991
  const targetPath = join12(skillsDir, skillId);
2020
1992
  if (!existsSync12(sourcePath)) {
2021
- results.push({ skillId, success: false, error: `Source not found: ${sourcePath}` });
1993
+ results.push({ skillId, success: false, error: t("error_source_not_found").replace("{path}", sourcePath) });
2022
1994
  continue;
2023
1995
  }
2024
1996
  try {
2025
1997
  const resolvedSource = realpathSync(sourcePath);
2026
- if (existsSync12(targetPath) || isSymlink2(targetPath)) {
1998
+ if (existsSync12(targetPath) || isSymlink(targetPath)) {
2027
1999
  unlinkSync4(targetPath);
2028
2000
  }
2029
2001
  symlinkSync(resolvedSource, targetPath);
2030
2002
  results.push({ skillId, success: true });
2031
2003
  installedIds.push(skillId);
2032
2004
  } catch (error) {
2033
- 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") });
2034
2006
  }
2035
2007
  }
2036
2008
  if (installedIds.length > 0) {
@@ -2047,17 +2019,17 @@ async function uninstallSkills(skillIds, tool, level) {
2047
2019
  for (const skillId of skillIds) {
2048
2020
  const targetPath = join12(skillsDir, skillId);
2049
2021
  try {
2050
- if (existsSync12(targetPath) || isSymlink2(targetPath)) {
2022
+ if (existsSync12(targetPath) || isSymlink(targetPath)) {
2051
2023
  unlinkSync4(targetPath);
2052
2024
  results.push({ skillId, success: true });
2053
2025
  removedIds.push(skillId);
2054
2026
  logger.step(` ${t("uninstall_remove_label")}: ${skillId}`);
2055
2027
  } else {
2056
- results.push({ skillId, success: false, error: "Not installed" });
2028
+ results.push({ skillId, success: false, error: t("error_not_installed") });
2057
2029
  logger.warn(`${skillId} ${t("uninstall_skill_not_installed")}`);
2058
2030
  }
2059
2031
  } catch (error) {
2060
- 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") });
2061
2033
  }
2062
2034
  }
2063
2035
  if (removedIds.length > 0) {
@@ -2079,8 +2051,6 @@ var SELECT_ALL = "__select_all__";
2079
2051
  var SELECT_ALL_CATEGORY = "__select_all_category__";
2080
2052
  var CONTINUE_SELECT = "__continue_select__";
2081
2053
  async function interactiveSkillSelect(tool, level) {
2082
- const BACK3 = "__back__";
2083
- const CANCEL3 = "__cancel__";
2084
2054
  const categories = getAllCategories();
2085
2055
  const allSkillIds = getAllSkills().map((s) => s.id);
2086
2056
  let accumulated = [];
@@ -2103,8 +2073,8 @@ async function interactiveSkillSelect(tool, level) {
2103
2073
  })),
2104
2074
  new Separator2("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
2105
2075
  ...accumulated.length > 0 ? [{ name: `>> ${t("skill_confirm_install_count").replace("{count}", String(accumulated.length))}`, value: "install" }] : [],
2106
- { name: "<- " + t("wizard_back"), value: BACK3 },
2107
- { name: "x " + t("wizard_cancel"), value: CANCEL3 }
2076
+ { name: "<- " + t("wizard_back"), value: BACK },
2077
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
2108
2078
  ];
2109
2079
  showOperationHints();
2110
2080
  selectedCategoryId = await select3({
@@ -2114,8 +2084,8 @@ async function interactiveSkillSelect(tool, level) {
2114
2084
  theme: selectTheme,
2115
2085
  pageSize: 15
2116
2086
  });
2117
- if (selectedCategoryId === BACK3) return "back";
2118
- if (selectedCategoryId === CANCEL3) return "cancel";
2087
+ if (selectedCategoryId === BACK) return "back";
2088
+ if (selectedCategoryId === CANCEL) return "cancel";
2119
2089
  if (selectedCategoryId === SELECT_ALL) {
2120
2090
  return allSkillIds;
2121
2091
  }
@@ -2255,13 +2225,6 @@ function resolveSkillSourcePath(skill, repoPath) {
2255
2225
  }
2256
2226
  return join12(repoPath, skill.source, skill.id);
2257
2227
  }
2258
- function isSymlink2(path) {
2259
- try {
2260
- return lstatSync2(path).isSymbolicLink();
2261
- } catch {
2262
- return false;
2263
- }
2264
- }
2265
2228
 
2266
2229
  // src/ui/display.ts
2267
2230
  import chalk6 from "chalk";
@@ -2354,8 +2317,6 @@ function printEnhancedSummary(results, tool, configRoot) {
2354
2317
  // src/commands/init.ts
2355
2318
  import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
2356
2319
  import { join as join13 } from "path";
2357
- var BACK2 = "__back__";
2358
- var CANCEL2 = "__cancel__";
2359
2320
  async function initCommand() {
2360
2321
  const cwd = process.cwd();
2361
2322
  if (existsSync13(join13(cwd, "package.json")) && (() => {
@@ -2414,7 +2375,6 @@ async function initCommand() {
2414
2375
  }
2415
2376
  async function selectMode() {
2416
2377
  printBoxTitle(t("wizard_select_mode_title"));
2417
- const CANCEL3 = "__cancel__";
2418
2378
  const choices = [
2419
2379
  {
2420
2380
  name: `> ${t("wizard_mode_plugin")} \u2014 ${t("wizard_mode_plugin_desc")}`,
@@ -2425,7 +2385,7 @@ async function selectMode() {
2425
2385
  value: "skill"
2426
2386
  },
2427
2387
  new Separator3("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"),
2428
- { name: "x " + t("wizard_cancel"), value: CANCEL3 }
2388
+ { name: "x " + t("wizard_cancel"), value: CANCEL }
2429
2389
  ];
2430
2390
  showOperationHints();
2431
2391
  const result = await select4({
@@ -2434,7 +2394,7 @@ async function selectMode() {
2434
2394
  loop: false,
2435
2395
  theme: selectTheme
2436
2396
  });
2437
- if (result === CANCEL3) return null;
2397
+ if (result === CANCEL) return null;
2438
2398
  return result;
2439
2399
  }
2440
2400
  async function pluginInstallFlow() {
@@ -2511,11 +2471,11 @@ async function skillInstallFlow() {
2511
2471
  }
2512
2472
  case 1: {
2513
2473
  const result = await stepLevel();
2514
- if (result === BACK2) {
2474
+ if (result === BACK) {
2515
2475
  step = 0;
2516
2476
  break;
2517
2477
  }
2518
- if (result === CANCEL2) {
2478
+ if (result === CANCEL) {
2519
2479
  logger.info(t("init_cancelled"));
2520
2480
  return "done";
2521
2481
  }
@@ -2586,13 +2546,12 @@ async function listCommand() {
2586
2546
 
2587
2547
  // src/commands/doctor.ts
2588
2548
  import chalk8 from "chalk";
2589
- import { existsSync as existsSync14, readdirSync as readdirSync5, lstatSync as lstatSync3, unlinkSync as unlinkSync5, mkdirSync as mkdirSync6 } from "fs";
2549
+ import { existsSync as existsSync14, readdirSync as readdirSync5, lstatSync as lstatSync2, unlinkSync as unlinkSync5, mkdirSync as mkdirSync6 } from "fs";
2590
2550
  import { join as join14 } from "path";
2591
2551
  async function doctorCommand(options = {}) {
2592
2552
  console.log();
2593
2553
  console.log(chalk8.bold(` ${t("doctor_title")}`));
2594
2554
  console.log(chalk8.dim(" " + "\u2500".repeat(46)));
2595
- let errors = 0;
2596
2555
  let warnings = 0;
2597
2556
  let fixes = 0;
2598
2557
  console.log();
@@ -2687,11 +2646,11 @@ async function doctorCommand(options = {}) {
2687
2646
  console.log(chalk8.dim(" " + "\u2500".repeat(46)));
2688
2647
  if (options.fix && fixes > 0) {
2689
2648
  console.log(
2690
- ` ${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))}`
2691
2650
  );
2692
2651
  } else {
2693
2652
  console.log(
2694
- ` ${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))}`
2695
2654
  );
2696
2655
  }
2697
2656
  console.log();
@@ -2703,7 +2662,7 @@ function checkBrokenLinks(dir) {
2703
2662
  for (const entry of entries) {
2704
2663
  const fullPath = join14(dir, entry);
2705
2664
  try {
2706
- const stats = lstatSync3(fullPath);
2665
+ const stats = lstatSync2(fullPath);
2707
2666
  if (stats.isSymbolicLink()) {
2708
2667
  if (!existsSync14(fullPath)) {
2709
2668
  broken++;
@@ -2724,7 +2683,7 @@ function fixBrokenLinks(dir) {
2724
2683
  for (const entry of entries) {
2725
2684
  const fullPath = join14(dir, entry);
2726
2685
  try {
2727
- const stats = lstatSync3(fullPath);
2686
+ const stats = lstatSync2(fullPath);
2728
2687
  if (stats.isSymbolicLink()) {
2729
2688
  if (!existsSync14(fullPath)) {
2730
2689
  unlinkSync5(fullPath);
@@ -2742,7 +2701,6 @@ function fixBrokenLinks(dir) {
2742
2701
  // src/commands/status.ts
2743
2702
  import chalk9 from "chalk";
2744
2703
  async function statusCommand() {
2745
- const plugins = getAllPlugins();
2746
2704
  const installed = scanInstalled();
2747
2705
  const installedMap = new Map(installed.map((p) => [p.id, p]));
2748
2706
  console.log();
@@ -3073,7 +3031,7 @@ async function installPlugins(pluginIds, tool, level, repoPath, installPath, yes
3073
3031
  }
3074
3032
 
3075
3033
  // src/commands/uninstall.ts
3076
- import { existsSync as existsSync15, unlinkSync as unlinkSync6, 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";
3077
3035
  import { resolve } from "path";
3078
3036
  import chalk11 from "chalk";
3079
3037
  async function uninstallCommand(names, options) {
@@ -3115,7 +3073,7 @@ async function uninstallCommand(names, options) {
3115
3073
  for (const filePath of record.files) {
3116
3074
  if (!isSafePath(filePath)) continue;
3117
3075
  try {
3118
- if (existsSync15(filePath) || isSymlink3(filePath)) {
3076
+ if (existsSync15(filePath) || isSymlink(filePath)) {
3119
3077
  unlinkSync6(filePath);
3120
3078
  const name = filePath.split("/").pop() || filePath;
3121
3079
  logger.step(` ${t("uninstall_remove_label")}: ${name}`);
@@ -3163,7 +3121,7 @@ async function uninstallCommand(names, options) {
3163
3121
  }
3164
3122
  const totalRemoved = removedFiles + removedDirs;
3165
3123
  if (totalRemoved > 0) {
3166
- 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)));
3167
3125
  } else {
3168
3126
  logger.warn(`${plugin.displayName}${t("uninstall_files_gone")}`);
3169
3127
  }
@@ -3185,13 +3143,6 @@ async function uninstallCommand(names, options) {
3185
3143
  logger.blank();
3186
3144
  }
3187
3145
  }
3188
- function isSymlink3(path) {
3189
- try {
3190
- return lstatSync4(path).isSymbolicLink();
3191
- } catch {
3192
- return false;
3193
- }
3194
- }
3195
3146
 
3196
3147
  // src/commands/update.ts
3197
3148
  import chalk12 from "chalk";
@@ -3360,13 +3311,27 @@ async function langCommand(action, value) {
3360
3311
  }
3361
3312
 
3362
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
+ }
3363
3328
  function createCLI() {
3364
3329
  const config = readConfig();
3365
3330
  if (config.language) {
3366
3331
  setLanguage(config.language);
3367
3332
  }
3368
3333
  const program2 = new Command();
3369
- program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version("0.0.2-beta.34");
3334
+ program2.name("install-helper").description("CANNBot Install Helper - Interactive installer for CANN operator development skills").version(readVersion());
3370
3335
  program2.command("init", { isDefault: false }).description("Run interactive installation wizard").action(async () => {
3371
3336
  await initCommand();
3372
3337
  });