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.
- package/README.md +5 -5
- package/README.zh-CN.md +5 -5
- package/dist/cli.js +2 -14
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +5 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +15 -16
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/clean.d.ts +5 -0
- package/dist/commands/clean.d.ts.map +1 -1
- package/dist/commands/clean.js +15 -33
- package/dist/commands/clean.js.map +1 -1
- package/dist/commands/config.d.ts +5 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +19 -39
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/index.d.ts +27 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +52 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/list.d.ts +5 -0
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +27 -59
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/load.d.ts +5 -0
- package/dist/commands/load.d.ts.map +1 -1
- package/dist/commands/load.js +23 -61
- package/dist/commands/load.js.map +1 -1
- package/dist/commands/unload.d.ts +6 -1
- package/dist/commands/unload.d.ts.map +1 -1
- package/dist/commands/unload.js +157 -162
- package/dist/commands/unload.js.map +1 -1
- package/dist/commands/update.d.ts +6 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +66 -74
- package/dist/commands/update.js.map +1 -1
- package/dist/core/config-manager.d.ts +83 -0
- package/dist/core/config-manager.d.ts.map +1 -0
- package/dist/core/config-manager.js +170 -0
- package/dist/core/config-manager.js.map +1 -0
- package/dist/core/config.d.ts +22 -2
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +71 -35
- package/dist/core/config.js.map +1 -1
- package/dist/core/loading-state.d.ts +125 -0
- package/dist/core/loading-state.d.ts.map +1 -0
- package/dist/core/loading-state.js +212 -0
- package/dist/core/loading-state.js.map +1 -0
- package/dist/core/loading.d.ts +21 -26
- package/dist/core/loading.d.ts.map +1 -1
- package/dist/core/loading.js +124 -87
- package/dist/core/loading.js.map +1 -1
- package/dist/core/migration.d.ts +54 -0
- package/dist/core/migration.d.ts.map +1 -0
- package/dist/core/migration.js +279 -0
- package/dist/core/migration.js.map +1 -0
- package/dist/core/paths.d.ts +58 -0
- package/dist/core/paths.d.ts.map +1 -0
- package/dist/core/paths.js +103 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/repos-index.d.ts +113 -0
- package/dist/core/repos-index.d.ts.map +1 -0
- package/dist/core/repos-index.js +206 -0
- package/dist/core/repos-index.js.map +1 -0
- package/dist/core/sync.d.ts.map +1 -1
- package/dist/core/sync.js +3 -3
- package/dist/core/sync.js.map +1 -1
- package/dist/ui/format.d.ts +159 -0
- package/dist/ui/format.d.ts.map +1 -0
- package/dist/ui/format.js +300 -0
- package/dist/ui/format.js.map +1 -0
- package/dist/ui/index.d.ts +9 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +53 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/prompt.d.ts +94 -0
- package/dist/ui/prompt.d.ts.map +1 -0
- package/dist/ui/prompt.js +223 -0
- package/dist/ui/prompt.js.map +1 -0
- package/dist/ui/spinner.d.ts +99 -0
- package/dist/ui/spinner.d.ts.map +1 -0
- package/dist/ui/spinner.js +136 -0
- package/dist/ui/spinner.js.map +1 -0
- package/dist/ui/table.d.ts +142 -0
- package/dist/ui/table.d.ts.map +1 -0
- package/dist/ui/table.js +213 -0
- package/dist/ui/table.js.map +1 -0
- package/dist/utils/constants.d.ts +152 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +160 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/error.d.ts +109 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +212 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +44 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/validation.d.ts +122 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +248 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +4 -4
package/dist/commands/unload.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
3
|
* unload 命令
|
|
4
|
-
*
|
|
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
|
|
53
|
-
|
|
54
|
-
const
|
|
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
|
-
*
|
|
57
|
-
* @param
|
|
58
|
-
* @returns 由 gitreference 管理的路径列表
|
|
57
|
+
* 注册 unload 命令
|
|
58
|
+
* @param program Commander 程序实例
|
|
59
59
|
*/
|
|
60
|
-
|
|
61
|
-
|
|
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(
|
|
98
|
-
return await loading.getEntries(
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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(`
|
|
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(`
|
|
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(
|
|
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(`
|
|
261
|
+
console.log(chalk_1.default.gray(` Removing directory: ${displayPath}`));
|
|
290
262
|
}
|
|
291
263
|
await filesystem.removeDir(dirPath);
|
|
292
264
|
}
|
|
293
265
|
/**
|
|
294
|
-
*
|
|
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
|
-
//
|
|
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("
|
|
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(`
|
|
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(
|
|
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(
|
|
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,
|
|
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(`
|
|
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(
|
|
363
|
+
spinner.succeed(chalk_1.default.green(`Cleaned ${cleanedCount} empty directories!`));
|
|
392
364
|
if (options.verbose) {
|
|
393
|
-
console.log(chalk_1.default.gray(`
|
|
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(`📦
|
|
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(`
|
|
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(`
|
|
414
|
+
console.log(chalk_1.default.gray(` Branch: ${entry.branch}`));
|
|
443
415
|
}
|
|
444
416
|
if (entry.subdir) {
|
|
445
|
-
console.log(chalk_1.default.gray(`
|
|
417
|
+
console.log(chalk_1.default.gray(` Subdir: ${entry.subdir}`));
|
|
446
418
|
}
|
|
447
|
-
console.log(chalk_1.default.gray(`
|
|
419
|
+
console.log(chalk_1.default.gray(` Loaded at: ${entry.loadedAt}`));
|
|
448
420
|
if (entry.updatedAt) {
|
|
449
|
-
console.log(chalk_1.default.gray(`
|
|
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(`⚠️
|
|
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(`
|
|
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(`💡
|
|
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("💡
|
|
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(
|
|
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
|
|
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,
|
|
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(`
|
|
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
|
-
//
|
|
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(
|
|
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
|
-
//
|
|
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(`
|
|
542
|
+
console.log(chalk_1.default.gray(` Removing .gitreference directory`));
|
|
547
543
|
spinner.start();
|
|
548
544
|
}
|
|
549
545
|
await filesystem.removeDir(gitrefDir);
|
|
550
|
-
//
|
|
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(
|
|
555
|
+
spinner.succeed(chalk_1.default.green(`Deleted ${deletedCount} reference code!`));
|
|
560
556
|
if (options.verbose) {
|
|
561
|
-
console.log(chalk_1.default.gray(`
|
|
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("✗")}
|
|
571
|
+
console.error(chalk_1.default.red(`${chalk_1.default.bold("✗")} No matching reference code found: ${name}`));
|
|
576
572
|
console.log();
|
|
577
|
-
console.log(
|
|
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(
|
|
611
|
-
console.log(`
|
|
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(` (
|
|
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(`
|
|
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(`
|
|
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(
|
|
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,
|
|
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(`
|
|
639
|
+
console.log(chalk_1.default.gray(` Removing directory: ${displayPath}`));
|
|
644
640
|
spinner.start();
|
|
645
641
|
}
|
|
646
642
|
await filesystem.removeDir(absolutePath);
|
|
647
|
-
//
|
|
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
|
|
661
|
-
//
|
|
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(`
|
|
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
|
-
//
|
|
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(
|
|
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(`
|
|
690
|
+
console.log(chalk_1.default.gray(` Removing empty .gitreference directory`));
|
|
684
691
|
spinner.start();
|
|
685
692
|
}
|
|
686
693
|
await filesystem.removeDir(gitrefDir);
|
|
687
|
-
//
|
|
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("
|
|
700
|
-
console.log(` ${chalk_1.default.gray("
|
|
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(`
|
|
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:
|
|
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(
|
|
727
|
+
console.log(`Use '${chalk_1.default.cyan("grf unload --list")}' to see all loaded reference code.`);
|
|
721
728
|
}
|
|
722
729
|
catch (error) {
|
|
723
|
-
|
|
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
|