grf-cli 1.0.0 → 1.0.3

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.
Files changed (104) hide show
  1. package/README.md +5 -5
  2. package/README.zh-CN.md +5 -5
  3. package/dist/cli.js +2 -14
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/add.d.ts +5 -0
  6. package/dist/commands/add.d.ts.map +1 -1
  7. package/dist/commands/add.js +15 -16
  8. package/dist/commands/add.js.map +1 -1
  9. package/dist/commands/clean.d.ts +5 -0
  10. package/dist/commands/clean.d.ts.map +1 -1
  11. package/dist/commands/clean.js +15 -33
  12. package/dist/commands/clean.js.map +1 -1
  13. package/dist/commands/config.d.ts +5 -0
  14. package/dist/commands/config.d.ts.map +1 -1
  15. package/dist/commands/config.js +19 -39
  16. package/dist/commands/config.js.map +1 -1
  17. package/dist/commands/index.d.ts +27 -0
  18. package/dist/commands/index.d.ts.map +1 -0
  19. package/dist/commands/index.js +52 -0
  20. package/dist/commands/index.js.map +1 -0
  21. package/dist/commands/list.d.ts +5 -0
  22. package/dist/commands/list.d.ts.map +1 -1
  23. package/dist/commands/list.js +27 -59
  24. package/dist/commands/list.js.map +1 -1
  25. package/dist/commands/load.d.ts +5 -0
  26. package/dist/commands/load.d.ts.map +1 -1
  27. package/dist/commands/load.js +23 -61
  28. package/dist/commands/load.js.map +1 -1
  29. package/dist/commands/unload.d.ts +6 -1
  30. package/dist/commands/unload.d.ts.map +1 -1
  31. package/dist/commands/unload.js +157 -162
  32. package/dist/commands/unload.js.map +1 -1
  33. package/dist/commands/update.d.ts +6 -1
  34. package/dist/commands/update.d.ts.map +1 -1
  35. package/dist/commands/update.js +66 -74
  36. package/dist/commands/update.js.map +1 -1
  37. package/dist/core/config-manager.d.ts +83 -0
  38. package/dist/core/config-manager.d.ts.map +1 -0
  39. package/dist/core/config-manager.js +170 -0
  40. package/dist/core/config-manager.js.map +1 -0
  41. package/dist/core/config.d.ts +22 -2
  42. package/dist/core/config.d.ts.map +1 -1
  43. package/dist/core/config.js +71 -35
  44. package/dist/core/config.js.map +1 -1
  45. package/dist/core/loading-state.d.ts +125 -0
  46. package/dist/core/loading-state.d.ts.map +1 -0
  47. package/dist/core/loading-state.js +212 -0
  48. package/dist/core/loading-state.js.map +1 -0
  49. package/dist/core/loading.d.ts +21 -26
  50. package/dist/core/loading.d.ts.map +1 -1
  51. package/dist/core/loading.js +124 -87
  52. package/dist/core/loading.js.map +1 -1
  53. package/dist/core/migration.d.ts +54 -0
  54. package/dist/core/migration.d.ts.map +1 -0
  55. package/dist/core/migration.js +279 -0
  56. package/dist/core/migration.js.map +1 -0
  57. package/dist/core/paths.d.ts +58 -0
  58. package/dist/core/paths.d.ts.map +1 -0
  59. package/dist/core/paths.js +103 -0
  60. package/dist/core/paths.js.map +1 -0
  61. package/dist/core/repos-index.d.ts +113 -0
  62. package/dist/core/repos-index.d.ts.map +1 -0
  63. package/dist/core/repos-index.js +206 -0
  64. package/dist/core/repos-index.js.map +1 -0
  65. package/dist/core/sync.d.ts.map +1 -1
  66. package/dist/core/sync.js +3 -3
  67. package/dist/core/sync.js.map +1 -1
  68. package/dist/ui/format.d.ts +159 -0
  69. package/dist/ui/format.d.ts.map +1 -0
  70. package/dist/ui/format.js +300 -0
  71. package/dist/ui/format.js.map +1 -0
  72. package/dist/ui/index.d.ts +9 -0
  73. package/dist/ui/index.d.ts.map +1 -0
  74. package/dist/ui/index.js +53 -0
  75. package/dist/ui/index.js.map +1 -0
  76. package/dist/ui/prompt.d.ts +94 -0
  77. package/dist/ui/prompt.d.ts.map +1 -0
  78. package/dist/ui/prompt.js +223 -0
  79. package/dist/ui/prompt.js.map +1 -0
  80. package/dist/ui/spinner.d.ts +99 -0
  81. package/dist/ui/spinner.d.ts.map +1 -0
  82. package/dist/ui/spinner.js +136 -0
  83. package/dist/ui/spinner.js.map +1 -0
  84. package/dist/ui/table.d.ts +142 -0
  85. package/dist/ui/table.d.ts.map +1 -0
  86. package/dist/ui/table.js +213 -0
  87. package/dist/ui/table.js.map +1 -0
  88. package/dist/utils/constants.d.ts +152 -0
  89. package/dist/utils/constants.d.ts.map +1 -0
  90. package/dist/utils/constants.js +160 -0
  91. package/dist/utils/constants.js.map +1 -0
  92. package/dist/utils/error.d.ts +109 -0
  93. package/dist/utils/error.d.ts.map +1 -0
  94. package/dist/utils/error.js +212 -0
  95. package/dist/utils/error.js.map +1 -0
  96. package/dist/utils/index.d.ts +8 -0
  97. package/dist/utils/index.d.ts.map +1 -0
  98. package/dist/utils/index.js +44 -0
  99. package/dist/utils/index.js.map +1 -0
  100. package/dist/utils/validation.d.ts +122 -0
  101. package/dist/utils/validation.d.ts.map +1 -0
  102. package/dist/utils/validation.js +248 -0
  103. package/dist/utils/validation.js.map +1 -0
  104. package/package.json +4 -4
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  /**
3
3
  * unload 命令
4
- * 移除当前项目中已加载的参考代码(use 命令的逆操作)
4
+ * 从当前项目中移除已加载的参考代码(use 命令的逆操作)
5
5
  */
6
6
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
7
  if (k2 === undefined) k2 = k;
@@ -41,67 +41,39 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
41
41
  };
42
42
  Object.defineProperty(exports, "__esModule", { value: true });
43
43
  exports.unloadCommand = void 0;
44
+ exports.registerUnloadCommand = registerUnloadCommand;
44
45
  const commander_1 = require("commander");
45
46
  const chalk_1 = __importDefault(require("chalk"));
46
- const ora_1 = __importDefault(require("ora"));
47
47
  const path_1 = __importDefault(require("path"));
48
- const readline = __importStar(require("readline"));
49
48
  const prompts_1 = require("@inquirer/prompts");
50
49
  const filesystem = __importStar(require("../core/filesystem.js"));
51
50
  const loading = __importStar(require("../core/loading.js"));
52
- const index_js_1 = require("../types/index.js");
53
- /** .gitreference 目录名 */
54
- const GITREFERENCE_DIR = ".gitreference";
51
+ const spinner_js_1 = require("../ui/spinner.js");
52
+ const prompt_js_1 = require("../ui/prompt.js");
53
+ const table_js_1 = require("../ui/table.js");
54
+ const error_js_1 = require("../utils/error.js");
55
+ const constants_js_1 = require("../utils/constants.js");
55
56
  /**
56
- * loading.json 获取所有已加载仓库的目标路径
57
- * @param projectRoot 项目根目录
58
- * @returns 由 gitreference 管理的路径列表
57
+ * 注册 unload 命令
58
+ * @param program Commander 程序实例
59
59
  */
60
- async function getGitreferenceManagedPaths(projectRoot) {
61
- const entries = await loading.getEntries(projectRoot);
62
- return entries.map((entry) => entry.targetPath);
63
- }
64
- /**
65
- * 填充字符串到指定宽度
66
- * @param str 原始字符串
67
- * @param width 目标宽度
68
- * @returns 填充后的字符串
69
- */
70
- function padEnd(str, width) {
71
- if (str.length >= width)
72
- return str;
73
- return str + " ".repeat(width - str.length);
74
- }
75
- /**
76
- * 确认提示
77
- * @param message 提示消息
78
- * @returns 用户是否确认
79
- */
80
- async function confirm(message) {
81
- const rl = readline.createInterface({
82
- input: process.stdin,
83
- output: process.stdout,
84
- });
85
- return new Promise((resolve) => {
86
- rl.question(`${message} (y/N) `, (answer) => {
87
- rl.close();
88
- resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
89
- });
90
- });
60
+ function registerUnloadCommand(program) {
61
+ program.addCommand(exports.unloadCommand);
91
62
  }
63
+ /** .gitreference 目录名(使用共享常量) */
64
+ const GITREFERENCE_DIR = constants_js_1.DIR_NAMES.GITREFERENCE;
92
65
  /**
93
66
  * 从 loading.json 获取所有已加载的仓库条目
94
- * @param projectRoot 项目根目录
95
67
  * @returns 加载条目列表
96
68
  */
97
- async function getLoadedEntries(projectRoot) {
98
- return await loading.getEntries(projectRoot);
69
+ async function getLoadedEntries() {
70
+ return await loading.getEntries();
99
71
  }
100
72
  /**
101
- * 递归扫描 .gitreference 目录,获取空目录列表
73
+ * 递归扫描 .gitreference 目录以获取空目录列表
102
74
  * @param baseDir .gitreference 目录的绝对路径
103
- * @param currentPath 当前扫描的相对路径
104
- * @param loadedPaths 已加载的路径列表(用于排除)
75
+ * @param currentPath 当前正在扫描的相对路径
76
+ * @param loadedPaths 已加载路径列表(用于排除)
105
77
  * @returns 空目录列表
106
78
  */
107
79
  async function scanEmptyDirs(baseDir, currentPath = "", loadedPaths = new Set()) {
@@ -160,7 +132,7 @@ function matchEntries(entries, name) {
160
132
  return entries.filter((entry) => {
161
133
  const repoName = entry.repoName.replace(/\\/g, "/");
162
134
  const targetPath = entry.targetPath.replace(/\\/g, "/");
163
- // 完整仓库名匹配: github.com/facebook/react
135
+ // 完整仓库名称匹配: github.com/facebook/react
164
136
  if (repoName === normalizedName) {
165
137
  return true;
166
138
  }
@@ -168,7 +140,7 @@ function matchEntries(entries, name) {
168
140
  if (targetPath === normalizedName) {
169
141
  return true;
170
142
  }
171
- // 仓库短名匹配: react -> 匹配所有名为 react 的仓库
143
+ // 短仓库名称匹配: react -> 匹配所有名为 react 的仓库
172
144
  const shortName = path_1.default.basename(repoName);
173
145
  if (shortName === normalizedName) {
174
146
  return true;
@@ -187,7 +159,7 @@ function matchEntries(entries, name) {
187
159
  /**
188
160
  * 递归删除空的父目录
189
161
  * @param dirPath 起始目录路径
190
- * @param stopAt 停止删除的目录(不会删除此目录)
162
+ * @param stopAt 停止的目录(不会删除此目录)
191
163
  * @param verbose 是否输出详细信息
192
164
  */
193
165
  async function removeEmptyParents(dirPath, stopAt, verbose = false) {
@@ -197,7 +169,7 @@ async function removeEmptyParents(dirPath, stopAt, verbose = false) {
197
169
  const entries = await filesystem.readDir(currentDir);
198
170
  if (entries.length === 0) {
199
171
  if (verbose) {
200
- console.log(chalk_1.default.gray(` 清理空目录: ${path_1.default.relative(stopAt, currentDir)}`));
172
+ console.log(chalk_1.default.gray(` Cleaning empty directory: ${path_1.default.relative(stopAt, currentDir)}`));
201
173
  }
202
174
  await filesystem.removeDir(currentDir);
203
175
  currentDir = path_1.default.dirname(currentDir);
@@ -233,7 +205,7 @@ async function cleanEmptyDirectories(gitrefDir, emptyDirs, verbose = false) {
233
205
  const entries = await filesystem.readDir(dir.absolutePath);
234
206
  if (entries.length === 0) {
235
207
  if (verbose) {
236
- console.log(chalk_1.default.gray(` 删除空目录: ${dir.fullPath.replace(/\\/g, "/")}`));
208
+ console.log(chalk_1.default.gray(` Removing empty directory: ${dir.fullPath.replace(/\\/g, "/")}`));
237
209
  }
238
210
  await filesystem.removeDir(dir.absolutePath);
239
211
  cleanedCount++;
@@ -249,24 +221,24 @@ async function cleanEmptyDirectories(gitrefDir, emptyDirs, verbose = false) {
249
221
  return cleanedCount;
250
222
  }
251
223
  /**
252
- * 交互式选择仓库条目
224
+ * 交互式仓库条目选择
253
225
  * @param matches 匹配的条目列表
254
226
  * @param name 用户输入的名称
255
227
  * @returns 用户选择的条目,如果取消则返回 null
256
228
  */
257
229
  async function selectEntry(matches, name) {
258
- console.log(chalk_1.default.yellow(`找到 ${matches.length} 个匹配 '${name}' 的参考代码:`));
230
+ console.log(chalk_1.default.yellow(`Found ${matches.length} reference code matching '${name}':`));
259
231
  console.log();
260
232
  try {
261
233
  const selected = await (0, prompts_1.select)({
262
- message: "请选择要删除的参考代码:",
234
+ message: "Select reference code to remove:",
263
235
  choices: [
264
236
  ...matches.map((match) => ({
265
237
  name: `${match.repoName} -> ${match.targetPath}`,
266
238
  value: match,
267
239
  })),
268
240
  {
269
- name: chalk_1.default.gray("取消"),
241
+ name: chalk_1.default.gray("Cancel"),
270
242
  value: null,
271
243
  },
272
244
  ],
@@ -279,20 +251,20 @@ async function selectEntry(matches, name) {
279
251
  }
280
252
  }
281
253
  /**
282
- * 详细模式下删除目录
254
+ * 在详细模式下删除目录
283
255
  * @param dirPath 要删除的目录路径
284
- * @param displayPath 显示用的路径
256
+ * @param displayPath 用于显示的路径
285
257
  * @param verbose 是否输出详细信息
286
258
  */
287
259
  async function removeDirVerbose(dirPath, displayPath, verbose) {
288
260
  if (verbose) {
289
- console.log(chalk_1.default.gray(` 删除目录: ${displayPath}`));
261
+ console.log(chalk_1.default.gray(` Removing directory: ${displayPath}`));
290
262
  }
291
263
  await filesystem.removeDir(dirPath);
292
264
  }
293
265
  /**
294
- * 清理 .gitignore 中的参考代码路径条目
295
- * @param targetPath 被删除的目标路径(相对于工作目录)
266
+ * .gitignore 中清理参考代码路径条目
267
+ * @param targetPath 已删除的目标路径(相对于工作目录)
296
268
  * @param gitreferenceDirExists .gitreference 目录是否仍然存在
297
269
  * @param verbose 是否输出详细信息
298
270
  */
@@ -301,11 +273,11 @@ async function cleanupGitignore(targetPath, gitreferenceDirExists, verbose = fal
301
273
  // 如果删除的是 .gitreference 目录下的内容
302
274
  if (targetPath.startsWith(".gitreference") ||
303
275
  targetPath.startsWith(GITREFERENCE_DIR)) {
304
- // 只有当 .gitreference 目录不存在或为空时,才移除 .gitignore 中的 .gitreference/ 条目
276
+ // 只有当目录不存在或为空时才从 .gitignore 中移除 .gitreference/ 条目
305
277
  if (!gitreferenceDirExists) {
306
278
  const removed = await filesystem.removeFromGitignore(cwd, ".gitreference/");
307
279
  if (removed && verbose) {
308
- console.log(chalk_1.default.gray(" 已从 .gitignore 中移除 .gitreference/"));
280
+ console.log(chalk_1.default.gray(" Removed .gitreference/ from .gitignore"));
309
281
  }
310
282
  }
311
283
  }
@@ -316,7 +288,7 @@ async function cleanupGitignore(targetPath, gitreferenceDirExists, verbose = fal
316
288
  : targetPath + "/";
317
289
  const removed = await filesystem.removeFromGitignore(cwd, gitignoreEntry);
318
290
  if (removed && verbose) {
319
- console.log(chalk_1.default.gray(` 已从 .gitignore 中移除 ${gitignoreEntry}`));
291
+ console.log(chalk_1.default.gray(` Removed ${gitignoreEntry} from .gitignore`));
320
292
  }
321
293
  }
322
294
  }
@@ -336,7 +308,7 @@ exports.unloadCommand = new commander_1.Command("unload")
336
308
  const cwd = process.cwd();
337
309
  const gitrefDir = path_1.default.join(cwd, GITREFERENCE_DIR);
338
310
  // 获取所有已加载的条目
339
- const loadedEntries = await getLoadedEntries(cwd);
311
+ const loadedEntries = await getLoadedEntries();
340
312
  // 检查 .gitreference 目录是否存在(用于空目录扫描)
341
313
  const gitrefDirExists = await filesystem.exists(gitrefDir);
342
314
  // 扫描空目录(仅当 .gitreference 目录存在时)
@@ -347,29 +319,29 @@ exports.unloadCommand = new commander_1.Command("unload")
347
319
  // 情况 0: --clean-empty 选项,清理空目录
348
320
  if (options.cleanEmpty) {
349
321
  if (emptyDirs.length === 0) {
350
- console.log(chalk_1.default.green("没有需要清理的空目录。"));
322
+ console.log(chalk_1.default.green("No empty directories to clean."));
351
323
  return;
352
324
  }
353
- console.log(`发现 ${chalk_1.default.bold(emptyDirs.length)} 个空目录:`);
325
+ console.log(`Found ${chalk_1.default.bold(emptyDirs.length)} empty directories:`);
354
326
  for (const dir of emptyDirs) {
355
327
  console.log(` - ${dir.fullPath.replace(/\\/g, "/")}`);
356
328
  }
357
329
  console.log();
358
330
  // dry-run 模式
359
331
  if (options.dryRun) {
360
- console.log(chalk_1.default.yellow("(试运行模式,未执行实际删除)"));
332
+ console.log(chalk_1.default.yellow("(Dry run mode, no actual deletion)"));
361
333
  return;
362
334
  }
363
335
  // 确认删除
364
336
  if (!options.force) {
365
- const confirmed = await confirm("确定要清理这些空目录吗?");
337
+ const confirmed = await (0, prompt_js_1.confirm)("Are you sure you want to clean these empty directories?");
366
338
  if (!confirmed) {
367
- console.log(chalk_1.default.yellow("操作已取消。"));
339
+ console.log(chalk_1.default.yellow("Operation cancelled."));
368
340
  return;
369
341
  }
370
342
  }
371
343
  // 执行清理
372
- const spinner = (0, ora_1.default)("正在清理空目录...").start();
344
+ const spinner = (0, spinner_js_1.startSpinner)("Cleaning empty directories...");
373
345
  try {
374
346
  const cleanedCount = await cleanEmptyDirectories(gitrefDir, emptyDirs, options.verbose);
375
347
  // 检查 .gitreference 目录是否为空
@@ -378,7 +350,7 @@ exports.unloadCommand = new commander_1.Command("unload")
378
350
  const remaining = await filesystem.readDir(gitrefDir);
379
351
  if (remaining.length === 0) {
380
352
  if (options.verbose) {
381
- console.log(chalk_1.default.gray(` 删除空的 .gitreference 目录`));
353
+ console.log(chalk_1.default.gray(` Removing empty .gitreference directory`));
382
354
  }
383
355
  await filesystem.removeDir(gitrefDir);
384
356
  }
@@ -388,13 +360,13 @@ exports.unloadCommand = new commander_1.Command("unload")
388
360
  }
389
361
  }
390
362
  const elapsed = Date.now() - startTime;
391
- spinner.succeed(chalk_1.default.green(`已清理 ${cleanedCount} 个空目录!`));
363
+ spinner.succeed(chalk_1.default.green(`Cleaned ${cleanedCount} empty directories!`));
392
364
  if (options.verbose) {
393
- console.log(chalk_1.default.gray(` 耗时: ${elapsed}ms`));
365
+ console.log(chalk_1.default.gray(` Time elapsed: ${elapsed}ms`));
394
366
  }
395
367
  }
396
368
  catch (error) {
397
- spinner.fail(chalk_1.default.red("清理失败"));
369
+ spinner.fail(chalk_1.default.red("Cleanup failed"));
398
370
  throw error;
399
371
  }
400
372
  return;
@@ -402,20 +374,20 @@ exports.unloadCommand = new commander_1.Command("unload")
402
374
  // 情况 1: --list 选项,列出所有已加载的参考代码
403
375
  if (options.list) {
404
376
  if (loadedEntries.length === 0 && emptyDirs.length === 0) {
405
- console.log(chalk_1.default.yellow("当前项目中没有已加载的参考代码。"));
377
+ console.log(chalk_1.default.yellow("No loaded reference code in current project."));
406
378
  return;
407
379
  }
408
380
  if (loadedEntries.length > 0) {
409
- console.log(chalk_1.default.bold(`📦 当前项目中已加载的参考代码 (${loadedEntries.length})`));
381
+ console.log(chalk_1.default.bold(`📦 Loaded reference code in current project (${loadedEntries.length})`));
410
382
  console.log();
411
383
  // 表头
412
384
  const COL_NAME = 35;
413
385
  const COL_PATH = 30;
414
386
  const COL_COMMIT = 10;
415
387
  console.log(chalk_1.default.gray(" " +
416
- padEnd("REPO", COL_NAME) +
417
- padEnd("PATH", COL_PATH) +
418
- padEnd("COMMIT", COL_COMMIT)));
388
+ (0, table_js_1.padEnd)("REPO", COL_NAME) +
389
+ (0, table_js_1.padEnd)("PATH", COL_PATH) +
390
+ (0, table_js_1.padEnd)("COMMIT", COL_COMMIT)));
419
391
  // 条目列表
420
392
  for (const entry of loadedEntries) {
421
393
  const repoName = entry.repoName.replace(/\\/g, "/");
@@ -424,51 +396,51 @@ exports.unloadCommand = new commander_1.Command("unload")
424
396
  ? entry.commitId.substring(0, 7)
425
397
  : "-";
426
398
  console.log(" " +
427
- padEnd(repoName, COL_NAME) +
428
- padEnd(targetPath, COL_PATH) +
429
- padEnd(commitShort, COL_COMMIT));
399
+ (0, table_js_1.padEnd)(repoName, COL_NAME) +
400
+ (0, table_js_1.padEnd)(targetPath, COL_PATH) +
401
+ (0, table_js_1.padEnd)(commitShort, COL_COMMIT));
430
402
  }
431
403
  console.log();
432
- // 详细模式下显示更多信息
404
+ // 在详细模式下显示更多信息
433
405
  if (options.verbose) {
434
- console.log(chalk_1.default.gray("详细信息:"));
406
+ console.log(chalk_1.default.gray("Details:"));
435
407
  for (const entry of loadedEntries) {
436
408
  console.log(chalk_1.default.gray(` - ${entry.repoName}`));
437
409
  console.log(chalk_1.default.gray(` ID: ${entry.id}`));
438
410
  console.log(chalk_1.default.gray(` URL: ${entry.repoUrl}`));
439
- console.log(chalk_1.default.gray(` 路径: ${entry.targetPath}`));
411
+ console.log(chalk_1.default.gray(` Path: ${entry.targetPath}`));
440
412
  console.log(chalk_1.default.gray(` Commit: ${entry.commitId}`));
441
413
  if (entry.branch) {
442
- console.log(chalk_1.default.gray(` 分支: ${entry.branch}`));
414
+ console.log(chalk_1.default.gray(` Branch: ${entry.branch}`));
443
415
  }
444
416
  if (entry.subdir) {
445
- console.log(chalk_1.default.gray(` 子目录: ${entry.subdir}`));
417
+ console.log(chalk_1.default.gray(` Subdir: ${entry.subdir}`));
446
418
  }
447
- console.log(chalk_1.default.gray(` 加载时间: ${entry.loadedAt}`));
419
+ console.log(chalk_1.default.gray(` Loaded at: ${entry.loadedAt}`));
448
420
  if (entry.updatedAt) {
449
- console.log(chalk_1.default.gray(` 更新时间: ${entry.updatedAt}`));
421
+ console.log(chalk_1.default.gray(` Updated at: ${entry.updatedAt}`));
450
422
  }
451
423
  }
452
424
  console.log();
453
425
  }
454
426
  }
455
427
  else {
456
- console.log(chalk_1.default.yellow("当前项目中没有已加载的参考代码。"));
428
+ console.log(chalk_1.default.yellow("No loaded reference code in current project."));
457
429
  console.log();
458
430
  }
459
431
  // 显示空目录提示
460
432
  if (emptyDirs.length > 0) {
461
- console.log(chalk_1.default.yellow(`⚠️ 发现 ${emptyDirs.length} 个空目录结构`));
433
+ console.log(chalk_1.default.yellow(`⚠️ Found ${emptyDirs.length} empty directory structures`));
462
434
  if (options.verbose) {
463
435
  for (const dir of emptyDirs) {
464
436
  console.log(chalk_1.default.gray(` - ${dir.fullPath.replace(/\\/g, "/")}`));
465
437
  }
466
438
  }
467
- console.log(chalk_1.default.gray(` 使用 'grf unload --clean-empty' 清理空目录`));
439
+ console.log(chalk_1.default.gray(` Use 'grf unload --clean-empty' to clean empty directories`));
468
440
  console.log();
469
441
  }
470
442
  if (loadedEntries.length > 0) {
471
- console.log(chalk_1.default.gray(`💡 使用 'grf unload <name>' 移除指定的参考代码`));
443
+ console.log(chalk_1.default.gray(`💡 Use 'grf unload <name>' to remove specific reference code`));
472
444
  }
473
445
  return;
474
446
  }
@@ -476,9 +448,9 @@ exports.unloadCommand = new commander_1.Command("unload")
476
448
  if (options.all) {
477
449
  // 如果没有已加载的条目
478
450
  if (loadedEntries.length === 0) {
479
- console.log(chalk_1.default.yellow("没有找到需要删除的参考代码。"));
451
+ console.log(chalk_1.default.yellow("No reference code found to delete."));
480
452
  console.log();
481
- console.log(chalk_1.default.gray("💡 提示: loading.json 中没有记录任何已加载的参考代码。"));
453
+ console.log(chalk_1.default.gray("💡 Hint: No loaded reference code recorded in loading.json."));
482
454
  return;
483
455
  }
484
456
  const pathsToDelete = [];
@@ -492,40 +464,64 @@ exports.unloadCommand = new commander_1.Command("unload")
492
464
  });
493
465
  }
494
466
  // 显示将要删除的内容
495
- console.log(`将要删除 ${chalk_1.default.bold(loadedEntries.length)} 个参考代码:`);
467
+ console.log(`Will delete ${chalk_1.default.bold(loadedEntries.length)} reference code:`);
496
468
  for (const pathInfo of pathsToDelete) {
497
- const status = pathInfo.exists ? "" : chalk_1.default.gray(" (路径不存在)");
469
+ const status = pathInfo.exists
470
+ ? ""
471
+ : chalk_1.default.gray(" (path does not exist)");
498
472
  console.log(` - ${pathInfo.entry.repoName} -> ${pathInfo.entry.targetPath}${status}`);
499
473
  }
500
474
  console.log();
501
475
  // dry-run 模式
502
476
  if (options.dryRun) {
503
- console.log(chalk_1.default.yellow("(试运行模式,未执行实际删除)"));
477
+ console.log(chalk_1.default.yellow("(Dry run mode, no actual deletion)"));
504
478
  return;
505
479
  }
506
480
  // 确认删除
507
481
  if (!options.force) {
508
- const confirmed = await confirm("确定要删除吗?");
482
+ const confirmed = await (0, prompt_js_1.confirm)("Are you sure you want to delete?");
509
483
  if (!confirmed) {
510
- console.log(chalk_1.default.yellow("操作已取消。"));
484
+ console.log(chalk_1.default.yellow("Operation cancelled."));
511
485
  return;
512
486
  }
513
487
  }
514
488
  // 执行删除
515
- const spinner = (0, ora_1.default)("正在删除参考代码...").start();
489
+ const spinner = (0, spinner_js_1.startSpinner)("Removing reference code...");
516
490
  try {
517
491
  let deletedCount = 0;
518
492
  for (const pathInfo of pathsToDelete) {
519
493
  if (options.verbose) {
520
494
  spinner.stop();
521
- console.log(chalk_1.default.gray(` 删除: ${pathInfo.entry.targetPath}`));
495
+ console.log(chalk_1.default.gray(` Removing: ${pathInfo.entry.targetPath}`));
522
496
  spinner.start();
523
497
  }
524
498
  // 删除实际文件/目录(如果存在)
525
499
  if (pathInfo.exists) {
526
500
  await filesystem.removeDir(pathInfo.absolutePath);
501
+ // 递归删除空的父目录
502
+ if (pathInfo.entry.targetPath.startsWith(".gitreference/") ||
503
+ pathInfo.entry.targetPath.startsWith(GITREFERENCE_DIR + "/")) {
504
+ // 在 .gitreference 下,清理到 gitrefDir 为止
505
+ if (options.verbose) {
506
+ spinner.stop();
507
+ }
508
+ await removeEmptyParents(pathInfo.absolutePath, gitrefDir, options.verbose);
509
+ if (options.verbose) {
510
+ spinner.start();
511
+ }
512
+ }
513
+ else {
514
+ // 自定义路径,清理到工作目录为止
515
+ if (options.verbose) {
516
+ spinner.stop();
517
+ }
518
+ await removeEmptyParents(pathInfo.absolutePath, cwd, options.verbose);
519
+ if (options.verbose) {
520
+ spinner.start();
521
+ }
522
+ }
527
523
  }
528
- // 清理 .gitignore 中对应的条目
524
+ // .gitignore 中清理对应条目
529
525
  const gitignoreEntry = pathInfo.entry.targetPath.endsWith("/")
530
526
  ? pathInfo.entry.targetPath
531
527
  : pathInfo.entry.targetPath + "/";
@@ -533,21 +529,21 @@ exports.unloadCommand = new commander_1.Command("unload")
533
529
  deletedCount++;
534
530
  }
535
531
  // 清空 loading.json
536
- await loading.clearAllEntries(cwd);
532
+ await loading.clearAllEntries();
537
533
  // 检查 .gitreference 目录是否为空
538
534
  if (!options.keepEmpty && gitrefDirExists) {
539
535
  try {
540
536
  const remaining = await filesystem.readDir(gitrefDir);
541
- // 只剩下 loading.json 或为空时删除整个目录
537
+ // 当只剩 loading.json 或为空时删除整个目录
542
538
  if (remaining.length === 0 ||
543
539
  (remaining.length === 1 && remaining[0] === "loading.json")) {
544
540
  if (options.verbose) {
545
541
  spinner.stop();
546
- console.log(chalk_1.default.gray(` 删除 .gitreference 目录`));
542
+ console.log(chalk_1.default.gray(` Removing .gitreference directory`));
547
543
  spinner.start();
548
544
  }
549
545
  await filesystem.removeDir(gitrefDir);
550
- // 移除 .gitignore 中的 .gitreference/ 条目
546
+ // .gitignore 中移除 .gitreference/ 条目
551
547
  await filesystem.removeFromGitignore(cwd, ".gitreference/");
552
548
  }
553
549
  }
@@ -556,44 +552,44 @@ exports.unloadCommand = new commander_1.Command("unload")
556
552
  }
557
553
  }
558
554
  const elapsed = Date.now() - startTime;
559
- spinner.succeed(chalk_1.default.green(`已删除 ${deletedCount} 个参考代码!`));
555
+ spinner.succeed(chalk_1.default.green(`Deleted ${deletedCount} reference code!`));
560
556
  if (options.verbose) {
561
- console.log(chalk_1.default.gray(` 耗时: ${elapsed}ms`));
557
+ console.log(chalk_1.default.gray(` Time elapsed: ${elapsed}ms`));
562
558
  }
563
559
  }
564
560
  catch (error) {
565
- spinner.fail(chalk_1.default.red("删除失败"));
561
+ spinner.fail(chalk_1.default.red("Deletion failed"));
566
562
  throw error;
567
563
  }
568
564
  return;
569
565
  }
570
- // 情况 3: 指定仓库名称,删除指定的参考代码
566
+ // 情况 3: 指定了仓库名称,删除特定参考代码
571
567
  if (name) {
572
568
  // 匹配条目
573
569
  const matches = matchEntries(loadedEntries, name);
574
570
  if (matches.length === 0) {
575
- console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} 未找到匹配的参考代码: ${name}`));
571
+ console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} No matching reference code found: ${name}`));
576
572
  console.log();
577
- console.log(`使用 '${chalk_1.default.cyan("grf unload --list")}' 查看所有已加载的参考代码。`);
573
+ console.log(`Use '${chalk_1.default.cyan("grf unload --list")}' to see all loaded reference code.`);
578
574
  process.exit(1);
579
575
  }
580
576
  let targetEntry;
581
577
  if (matches.length > 1) {
582
- // 如果使用了 --force 选项,仍然报错要求精确指定
578
+ // 如果使用了 --force 选项,仍然需要精确指定
583
579
  if (options.force) {
584
- console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} 找到多个匹配的参考代码:`));
580
+ console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} Found multiple matching reference code:`));
585
581
  console.log();
586
582
  for (const match of matches) {
587
583
  console.log(` - ${match.repoName} -> ${match.targetPath}`);
588
584
  }
589
585
  console.log();
590
- console.log(`请使用完整路径精确指定要删除的参考代码。`);
586
+ console.log(`Please use full path to specify exactly which reference code to delete.`);
591
587
  process.exit(1);
592
588
  }
593
589
  // 交互式选择
594
590
  const selected = await selectEntry(matches, name);
595
591
  if (!selected) {
596
- console.log(chalk_1.default.yellow("操作已取消。"));
592
+ console.log(chalk_1.default.yellow("Operation cancelled."));
597
593
  return;
598
594
  }
599
595
  targetEntry = selected;
@@ -607,46 +603,47 @@ exports.unloadCommand = new commander_1.Command("unload")
607
603
  const absolutePath = path_1.default.resolve(cwd, targetEntry.targetPath);
608
604
  const pathExists = await filesystem.exists(absolutePath);
609
605
  // 显示将要删除的内容
610
- console.log(`将要删除: ${chalk_1.default.cyan(displayName)}`);
611
- console.log(` 目标路径: ${chalk_1.default.gray(displayPath)}`);
606
+ console.log(`Will delete: ${chalk_1.default.cyan(displayName)}`);
607
+ console.log(` Target path: ${chalk_1.default.gray(displayPath)}`);
612
608
  if (!pathExists) {
613
- console.log(chalk_1.default.yellow(` (注意: 目标路径不存在,将仅从 loading.json 中移除记录)`));
609
+ console.log(chalk_1.default.yellow(` (Note: Target path does not exist, will only remove record from loading.json)`));
614
610
  }
615
611
  if (options.verbose) {
616
- console.log(` 绝对路径: ${chalk_1.default.gray(absolutePath)}`);
612
+ console.log(` Absolute path: ${chalk_1.default.gray(absolutePath)}`);
617
613
  console.log(` Commit: ${chalk_1.default.gray(targetEntry.commitId)}`);
618
614
  if (targetEntry.branch) {
619
- console.log(` 分支: ${chalk_1.default.gray(targetEntry.branch)}`);
615
+ console.log(` Branch: ${chalk_1.default.gray(targetEntry.branch)}`);
620
616
  }
621
617
  }
622
618
  console.log();
623
619
  // dry-run 模式
624
620
  if (options.dryRun) {
625
- console.log(chalk_1.default.yellow("(试运行模式,未执行实际删除)"));
621
+ console.log(chalk_1.default.yellow("(Dry run mode, no actual deletion)"));
626
622
  return;
627
623
  }
628
624
  // 确认删除
629
625
  if (!options.force) {
630
- const confirmed = await confirm(`确定要删除 '${displayName}' 吗?`);
626
+ const confirmed = await (0, prompt_js_1.confirm)(`Are you sure you want to delete '${displayName}'?`);
631
627
  if (!confirmed) {
632
- console.log(chalk_1.default.yellow("操作已取消。"));
628
+ console.log(chalk_1.default.yellow("Operation cancelled."));
633
629
  return;
634
630
  }
635
631
  }
636
632
  // 执行删除
637
- const spinner = (0, ora_1.default)("正在删除参考代码...").start();
633
+ const spinner = (0, spinner_js_1.startSpinner)("Removing reference code...");
638
634
  try {
639
635
  // 删除实际文件/目录(如果存在)
640
636
  if (pathExists) {
641
637
  if (options.verbose) {
642
638
  spinner.stop();
643
- console.log(chalk_1.default.gray(` 删除目录: ${displayPath}`));
639
+ console.log(chalk_1.default.gray(` Removing directory: ${displayPath}`));
644
640
  spinner.start();
645
641
  }
646
642
  await filesystem.removeDir(absolutePath);
647
- // 递归删除空的父目录(仅当在 .gitreference 目录下时)
643
+ // 递归删除空的父目录
648
644
  if (targetEntry.targetPath.startsWith(".gitreference/") ||
649
645
  targetEntry.targetPath.startsWith(GITREFERENCE_DIR + "/")) {
646
+ // 在 .gitreference 下,清理到 gitrefDir 为止
650
647
  if (options.verbose) {
651
648
  spinner.stop();
652
649
  }
@@ -655,36 +652,46 @@ exports.unloadCommand = new commander_1.Command("unload")
655
652
  spinner.start();
656
653
  }
657
654
  }
655
+ else {
656
+ // 自定义路径,清理到工作目录为止
657
+ if (options.verbose) {
658
+ spinner.stop();
659
+ }
660
+ await removeEmptyParents(absolutePath, cwd, options.verbose);
661
+ if (options.verbose) {
662
+ spinner.start();
663
+ }
664
+ }
658
665
  }
659
- // 从 loading.json 移除条目
660
- await loading.removeEntry(targetEntry.id, cwd);
661
- // 清理 .gitignore 中对应的条目
666
+ // 从 loading.json 中移除条目
667
+ await loading.removeEntry(targetEntry.id);
668
+ // .gitignore 中清理对应条目
662
669
  const gitignoreEntry = targetEntry.targetPath.endsWith("/")
663
670
  ? targetEntry.targetPath
664
671
  : targetEntry.targetPath + "/";
665
672
  const gitignoreRemoved = await filesystem.removeFromGitignore(cwd, gitignoreEntry);
666
673
  if (gitignoreRemoved && options.verbose) {
667
674
  spinner.stop();
668
- console.log(chalk_1.default.gray(` 已从 .gitignore 中移除 ${gitignoreEntry}`));
675
+ console.log(chalk_1.default.gray(` Removed ${gitignoreEntry} from .gitignore`));
669
676
  spinner.start();
670
677
  }
671
678
  // 检查 .gitreference 目录是否为空
672
679
  if (!options.keepEmpty && gitrefDirExists) {
673
680
  try {
674
681
  const remaining = await filesystem.readDir(gitrefDir);
675
- // 只剩下 loading.json 或为空时删除整个目录
682
+ // 当只剩 loading.json 或为空时删除整个目录
676
683
  if (remaining.length === 0 ||
677
684
  (remaining.length === 1 && remaining[0] === "loading.json")) {
678
685
  // 检查 loading.json 是否还有其他条目
679
- const remainingEntries = await loading.getEntries(cwd);
686
+ const remainingEntries = await loading.getEntries();
680
687
  if (remainingEntries.length === 0) {
681
688
  if (options.verbose) {
682
689
  spinner.stop();
683
- console.log(chalk_1.default.gray(` 删除空的 .gitreference 目录`));
690
+ console.log(chalk_1.default.gray(` Removing empty .gitreference directory`));
684
691
  spinner.start();
685
692
  }
686
693
  await filesystem.removeDir(gitrefDir);
687
- // 移除 .gitignore 中的 .gitreference/ 条目
694
+ // .gitignore 中移除 .gitreference/ 条目
688
695
  await filesystem.removeFromGitignore(cwd, ".gitreference/");
689
696
  }
690
697
  }
@@ -694,45 +701,33 @@ exports.unloadCommand = new commander_1.Command("unload")
694
701
  }
695
702
  }
696
703
  const elapsed = Date.now() - startTime;
697
- spinner.succeed(chalk_1.default.green("参考代码已移除!"));
704
+ spinner.succeed(chalk_1.default.green("Reference code removed!"));
698
705
  console.log();
699
- console.log(` ${chalk_1.default.gray("仓库:")} ${displayName}`);
700
- console.log(` ${chalk_1.default.gray("路径:")} ${displayPath}`);
706
+ console.log(` ${chalk_1.default.gray("Repository:")} ${displayName}`);
707
+ console.log(` ${chalk_1.default.gray("Path:")} ${displayPath}`);
701
708
  if (options.verbose) {
702
- console.log(chalk_1.default.gray(` 耗时: ${elapsed}ms`));
709
+ console.log(chalk_1.default.gray(` Time elapsed: ${elapsed}ms`));
703
710
  }
704
711
  }
705
712
  catch (error) {
706
- spinner.fail(chalk_1.default.red("删除失败"));
713
+ spinner.fail(chalk_1.default.red("Deletion failed"));
707
714
  throw error;
708
715
  }
709
716
  return;
710
717
  }
711
- // 情况 4: 没有指定名称也没有 --all 或 --list,显示使用说明
712
- console.log(chalk_1.default.yellow("未指定要移除的参考代码。"));
718
+ // 情况 4: 未指定名称、--all 或 --list,显示用法
719
+ console.log(chalk_1.default.yellow("No reference code specified to remove."));
713
720
  console.log();
714
- console.log("用法:");
715
- console.log(` ${chalk_1.default.cyan("grf unload <name>")} 移除指定的参考代码`);
716
- console.log(` ${chalk_1.default.cyan("grf unload --all")} 移除所有参考代码`);
717
- console.log(` ${chalk_1.default.cyan("grf unload --list")} 列出所有已加载的参考代码`);
718
- console.log(` ${chalk_1.default.cyan("grf unload --clean-empty")} 清理空目录结构`);
721
+ console.log("Usage:");
722
+ console.log(` ${chalk_1.default.cyan("grf unload <name>")} Remove specific reference code`);
723
+ console.log(` ${chalk_1.default.cyan("grf unload --all")} Remove all reference code`);
724
+ console.log(` ${chalk_1.default.cyan("grf unload --list")} List all loaded reference code`);
725
+ console.log(` ${chalk_1.default.cyan("grf unload --clean-empty")} Clean empty directory structures`);
719
726
  console.log();
720
- console.log(`使用 '${chalk_1.default.cyan("grf unload --list")}' 查看所有已加载的参考代码。`);
727
+ console.log(`Use '${chalk_1.default.cyan("grf unload --list")}' to see all loaded reference code.`);
721
728
  }
722
729
  catch (error) {
723
- if (error instanceof index_js_1.GrfError) {
724
- console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} ${error.message}`));
725
- if (error.code === index_js_1.ErrorCode.FS_PERMISSION_DENIED) {
726
- console.error(chalk_1.default.gray(` 权限被拒绝,请检查文件权限。`));
727
- }
728
- }
729
- else if (error instanceof Error) {
730
- console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} ${error.message}`));
731
- }
732
- else {
733
- console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} 发生未知错误`));
734
- }
735
- process.exit(1);
730
+ (0, error_js_1.handleError)(error, { exit: true });
736
731
  }
737
732
  });
738
733
  //# sourceMappingURL=unload.js.map