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

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