@zjex/git-workflow 0.3.10 → 0.4.1
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/CHANGELOG.md +470 -12
- package/README.md +8 -3
- package/ROADMAP.md +1 -1
- package/dist/index.js +229 -30
- package/docs/.vitepress/config.ts +111 -100
- package/docs/commands/branch.md +33 -12
- package/docs/commands/index.md +38 -33
- package/docs/commands/tag.md +71 -15
- package/docs/commands/update.md +79 -3
- package/docs/guide/api.md +607 -0
- package/docs/guide/contributing.md +441 -0
- package/docs/guide/development.md +295 -0
- package/docs/guide/team-collaboration.md +538 -0
- package/docs/guide/testing.md +461 -0
- package/package.json +3 -3
- package/scripts/generate-changelog-manual.js +135 -0
- package/src/commands/stash.ts +176 -7
- package/src/commands/tag.ts +120 -0
- package/src/index.ts +89 -72
- package/src/update-notifier.ts +1 -1
- package/tests/commands.test.ts +409 -0
- package/tests/stash.test.ts +161 -89
- package/tests/tag.test.ts +236 -0
- package/tests/update-notifier.test.ts +52 -0
- package/CODE_DOCUMENTATION.md +0 -169
- package/TESTING.md +0 -436
package/src/commands/stash.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { execSync } from "child_process";
|
|
1
|
+
import { execSync, spawn } from "child_process";
|
|
2
2
|
import { select, input } from "@inquirer/prompts";
|
|
3
3
|
import ora from "ora";
|
|
4
|
+
import boxen from "boxen";
|
|
4
5
|
import {
|
|
5
6
|
colors,
|
|
6
7
|
theme,
|
|
@@ -222,19 +223,187 @@ function applyStash(index: number, pop: boolean): void {
|
|
|
222
223
|
|
|
223
224
|
async function showDiff(index: number): Promise<void> {
|
|
224
225
|
try {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
226
|
+
// 获取差异内容(不使用颜色,我们自己格式化)
|
|
227
|
+
const diffOutput = execOutput(
|
|
228
|
+
`git stash show -p --no-color stash@{${index}}`
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
if (!diffOutput) {
|
|
232
|
+
console.log(colors.yellow("没有差异内容"));
|
|
233
|
+
await input({
|
|
234
|
+
message: colors.dim("按 Enter 返回菜单..."),
|
|
235
|
+
theme,
|
|
236
|
+
});
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 获取统计信息
|
|
241
|
+
const statsOutput = execOutput(`git stash show --stat stash@{${index}}`);
|
|
242
|
+
|
|
243
|
+
// 解析差异内容,按文件分组
|
|
244
|
+
const files = parseDiffByFile(diffOutput);
|
|
245
|
+
|
|
246
|
+
// 构建完整输出
|
|
247
|
+
let fullOutput = "";
|
|
248
|
+
|
|
249
|
+
// 添加统计信息
|
|
250
|
+
if (statsOutput) {
|
|
251
|
+
const statsBox = boxen(statsOutput, {
|
|
252
|
+
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
253
|
+
margin: { top: 0, bottom: 1, left: 0, right: 0 },
|
|
254
|
+
borderStyle: "double",
|
|
255
|
+
borderColor: "yellow",
|
|
256
|
+
title: `📊 Stash #${index} 统计`,
|
|
257
|
+
titleAlignment: "center",
|
|
258
|
+
});
|
|
259
|
+
fullOutput += statsBox + "\n";
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 为每个文件创建边框
|
|
263
|
+
for (const file of files) {
|
|
264
|
+
const fileContent = formatFileDiff(file);
|
|
265
|
+
const fileBox = boxen(fileContent, {
|
|
266
|
+
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
267
|
+
margin: { top: 0, bottom: 1, left: 0, right: 0 },
|
|
268
|
+
borderStyle: "round",
|
|
269
|
+
borderColor: "cyan",
|
|
270
|
+
title: `📄 ${file.path}`,
|
|
271
|
+
titleAlignment: "left",
|
|
272
|
+
});
|
|
273
|
+
fullOutput += fileBox + "\n";
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// 使用 less 分页器显示,等待用户退出
|
|
277
|
+
await startPager(fullOutput);
|
|
278
|
+
} catch (error) {
|
|
279
|
+
console.log(colors.red("无法显示差异"));
|
|
229
280
|
await input({
|
|
230
281
|
message: colors.dim("按 Enter 返回菜单..."),
|
|
231
282
|
theme,
|
|
232
283
|
});
|
|
233
|
-
} catch {
|
|
234
|
-
console.log(colors.red("无法显示差异"));
|
|
235
284
|
}
|
|
236
285
|
}
|
|
237
286
|
|
|
287
|
+
/**
|
|
288
|
+
* 解析差异内容,按文件分组
|
|
289
|
+
*/
|
|
290
|
+
interface FileDiff {
|
|
291
|
+
path: string;
|
|
292
|
+
lines: string[];
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function parseDiffByFile(diffOutput: string): FileDiff[] {
|
|
296
|
+
const files: FileDiff[] = [];
|
|
297
|
+
const lines = diffOutput.split("\n");
|
|
298
|
+
let currentFile: FileDiff | null = null;
|
|
299
|
+
|
|
300
|
+
for (const line of lines) {
|
|
301
|
+
// 检测文件头
|
|
302
|
+
if (line.startsWith("diff --git")) {
|
|
303
|
+
// 保存上一个文件
|
|
304
|
+
if (currentFile && currentFile.lines.length > 0) {
|
|
305
|
+
files.push(currentFile);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// 提取文件路径
|
|
309
|
+
const match = line.match(/diff --git a\/(.*?) b\/(.*?)$/);
|
|
310
|
+
const path = match ? match[2] : "unknown";
|
|
311
|
+
|
|
312
|
+
currentFile = { path, lines: [] };
|
|
313
|
+
} else if (currentFile) {
|
|
314
|
+
// 跳过 index 和 --- +++ 行
|
|
315
|
+
if (
|
|
316
|
+
line.startsWith("index ") ||
|
|
317
|
+
line.startsWith("--- ") ||
|
|
318
|
+
line.startsWith("+++ ")
|
|
319
|
+
) {
|
|
320
|
+
continue;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
currentFile.lines.push(line);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 保存最后一个文件
|
|
328
|
+
if (currentFile && currentFile.lines.length > 0) {
|
|
329
|
+
files.push(currentFile);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return files;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* 格式化文件差异内容
|
|
337
|
+
*/
|
|
338
|
+
function formatFileDiff(file: FileDiff): string {
|
|
339
|
+
const formattedLines: string[] = [];
|
|
340
|
+
|
|
341
|
+
for (const line of file.lines) {
|
|
342
|
+
if (line.startsWith("@@")) {
|
|
343
|
+
// 位置信息 - 使用蓝色
|
|
344
|
+
formattedLines.push(colors.blue(line));
|
|
345
|
+
} else if (line.startsWith("+")) {
|
|
346
|
+
// 新增行 - 使用绿色
|
|
347
|
+
formattedLines.push(colors.green(line));
|
|
348
|
+
} else if (line.startsWith("-")) {
|
|
349
|
+
// 删除行 - 使用红色
|
|
350
|
+
formattedLines.push(colors.red(line));
|
|
351
|
+
} else {
|
|
352
|
+
// 上下文行 - 使用灰色
|
|
353
|
+
formattedLines.push(colors.dim(line));
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return formattedLines.join("\n");
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* 启动分页器显示内容
|
|
362
|
+
*/
|
|
363
|
+
function startPager(content: string): Promise<void> {
|
|
364
|
+
return new Promise((resolve) => {
|
|
365
|
+
const pager = process.env.PAGER || "less";
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
// -R: 支持ANSI颜色代码
|
|
369
|
+
// -S: 不换行长行
|
|
370
|
+
// -F: 如果内容少于一屏则直接退出
|
|
371
|
+
// -X: 不清屏
|
|
372
|
+
// -i: 忽略大小写搜索
|
|
373
|
+
const pagerProcess = spawn(pager, ["-R", "-S", "-F", "-X", "-i"], {
|
|
374
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
375
|
+
env: { ...process.env, LESS: "-R -S -F -X -i" },
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// 处理 stdin 的 EPIPE 错误(当 less 提前退出时)
|
|
379
|
+
pagerProcess.stdin.on("error", (err: NodeJS.ErrnoException) => {
|
|
380
|
+
if (err.code !== "EPIPE") {
|
|
381
|
+
console.error(err);
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// 将内容写入分页器
|
|
386
|
+
pagerProcess.stdin.write(content);
|
|
387
|
+
pagerProcess.stdin.end();
|
|
388
|
+
|
|
389
|
+
// 等待分页器退出后返回菜单
|
|
390
|
+
pagerProcess.on("exit", () => {
|
|
391
|
+
resolve();
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
// 处理错误
|
|
395
|
+
pagerProcess.on("error", () => {
|
|
396
|
+
console.log(content);
|
|
397
|
+
resolve();
|
|
398
|
+
});
|
|
399
|
+
} catch (error) {
|
|
400
|
+
// 如果出错,直接输出内容
|
|
401
|
+
console.log(content);
|
|
402
|
+
resolve();
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
|
|
238
407
|
async function createBranchFromStash(index: number): Promise<void> {
|
|
239
408
|
const type = await select({
|
|
240
409
|
message: "选择分支类型:",
|
package/src/commands/tag.ts
CHANGED
|
@@ -624,3 +624,123 @@ export async function updateTag(): Promise<void> {
|
|
|
624
624
|
}
|
|
625
625
|
}
|
|
626
626
|
}
|
|
627
|
+
|
|
628
|
+
/**
|
|
629
|
+
* 清理无效标签(不包含数字的标签)
|
|
630
|
+
*/
|
|
631
|
+
export async function cleanInvalidTags(): Promise<void> {
|
|
632
|
+
const fetchSpinner = ora("正在获取 tags...").start();
|
|
633
|
+
exec("git fetch --tags", true);
|
|
634
|
+
fetchSpinner.stop();
|
|
635
|
+
|
|
636
|
+
divider();
|
|
637
|
+
|
|
638
|
+
// 获取所有标签
|
|
639
|
+
const allTags = execOutput("git tag -l").split("\n").filter(Boolean);
|
|
640
|
+
|
|
641
|
+
// 过滤出无效标签(不包含数字)
|
|
642
|
+
const invalidTags = allTags.filter((tag) => !/\d/.test(tag));
|
|
643
|
+
|
|
644
|
+
if (invalidTags.length === 0) {
|
|
645
|
+
console.log(colors.green("✅ 没有找到无效标签"));
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
console.log(colors.yellow(`❌ 找到 ${invalidTags.length} 个无效标签:`));
|
|
650
|
+
console.log("");
|
|
651
|
+
|
|
652
|
+
// 显示每个无效标签的详细信息
|
|
653
|
+
for (const tag of invalidTags) {
|
|
654
|
+
try {
|
|
655
|
+
const commitHash = execOutput(`git rev-list -n 1 "${tag}"`).trim();
|
|
656
|
+
const commitDate = execOutput(`git log -1 --format=%ai "${tag}"`).trim();
|
|
657
|
+
const commitMsg = execOutput(`git log -1 --format=%s "${tag}"`).trim();
|
|
658
|
+
|
|
659
|
+
console.log(colors.red(` 标签: ${tag}`));
|
|
660
|
+
console.log(colors.dim(` Commit: ${commitHash}`));
|
|
661
|
+
console.log(colors.dim(` 日期: ${commitDate}`));
|
|
662
|
+
console.log(colors.dim(` 消息: ${commitMsg}`));
|
|
663
|
+
console.log("");
|
|
664
|
+
} catch {
|
|
665
|
+
console.log(colors.red(` 标签: ${tag}`));
|
|
666
|
+
console.log(colors.dim(` (无法获取提交信息)`));
|
|
667
|
+
console.log("");
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
divider();
|
|
672
|
+
|
|
673
|
+
const shouldClean = await select({
|
|
674
|
+
message: "是否删除这些无效标签?",
|
|
675
|
+
choices: [
|
|
676
|
+
{ name: "是,删除所有无效标签", value: true },
|
|
677
|
+
{ name: "否,取消操作", value: false },
|
|
678
|
+
],
|
|
679
|
+
theme,
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
if (!shouldClean) {
|
|
683
|
+
console.log(colors.yellow("已取消"));
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
divider();
|
|
688
|
+
|
|
689
|
+
// 删除本地标签
|
|
690
|
+
const localSpinner = ora("正在删除本地无效标签...").start();
|
|
691
|
+
let localSuccess = 0;
|
|
692
|
+
let localFailed = 0;
|
|
693
|
+
|
|
694
|
+
for (const tag of invalidTags) {
|
|
695
|
+
try {
|
|
696
|
+
execSync(`git tag -d "${tag}"`, { stdio: "pipe" });
|
|
697
|
+
localSuccess++;
|
|
698
|
+
} catch {
|
|
699
|
+
localFailed++;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
if (localFailed === 0) {
|
|
704
|
+
localSpinner.succeed(`本地标签已删除: ${localSuccess} 个`);
|
|
705
|
+
} else {
|
|
706
|
+
localSpinner.warn(
|
|
707
|
+
`本地标签删除: 成功 ${localSuccess} 个,失败 ${localFailed} 个`
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// 询问是否删除远程标签
|
|
712
|
+
const deleteRemote = await select({
|
|
713
|
+
message: "是否同时删除远程的无效标签?",
|
|
714
|
+
choices: [
|
|
715
|
+
{ name: "是", value: true },
|
|
716
|
+
{ name: "否", value: false },
|
|
717
|
+
],
|
|
718
|
+
theme,
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
if (deleteRemote) {
|
|
722
|
+
const remoteSpinner = ora("正在删除远程无效标签...").start();
|
|
723
|
+
let remoteSuccess = 0;
|
|
724
|
+
let remoteFailed = 0;
|
|
725
|
+
|
|
726
|
+
for (const tag of invalidTags) {
|
|
727
|
+
try {
|
|
728
|
+
execSync(`git push origin --delete "${tag}"`, { stdio: "pipe" });
|
|
729
|
+
remoteSuccess++;
|
|
730
|
+
} catch {
|
|
731
|
+
remoteFailed++;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
if (remoteFailed === 0) {
|
|
736
|
+
remoteSpinner.succeed(`远程标签已删除: ${remoteSuccess} 个`);
|
|
737
|
+
} else {
|
|
738
|
+
remoteSpinner.warn(
|
|
739
|
+
`远程标签删除: 成功 ${remoteSuccess} 个,失败 ${remoteFailed} 个`
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
console.log("");
|
|
745
|
+
console.log(colors.green("✨ 清理完成!"));
|
|
746
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,7 +15,13 @@ import { select } from "@inquirer/prompts";
|
|
|
15
15
|
import { ExitPromptError } from "@inquirer/core";
|
|
16
16
|
import { checkGitRepo, theme, colors } from "./utils.js";
|
|
17
17
|
import { createBranch, deleteBranch } from "./commands/branch.js";
|
|
18
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
listTags,
|
|
20
|
+
createTag,
|
|
21
|
+
deleteTag,
|
|
22
|
+
updateTag,
|
|
23
|
+
cleanInvalidTags,
|
|
24
|
+
} from "./commands/tag.js";
|
|
19
25
|
import { release } from "./commands/release.js";
|
|
20
26
|
import { init } from "./commands/init.js";
|
|
21
27
|
import { stash } from "./commands/stash.js";
|
|
@@ -119,7 +125,7 @@ async function mainMenu(): Promise<void> {
|
|
|
119
125
|
value: "hotfix",
|
|
120
126
|
},
|
|
121
127
|
{
|
|
122
|
-
name: `[3] 🗑️ 删除分支 ${colors.dim("gw
|
|
128
|
+
name: `[3] 🗑️ 删除分支 ${colors.dim("gw brd")}`,
|
|
123
129
|
value: "delete",
|
|
124
130
|
},
|
|
125
131
|
{
|
|
@@ -143,15 +149,15 @@ async function mainMenu(): Promise<void> {
|
|
|
143
149
|
value: "tags",
|
|
144
150
|
},
|
|
145
151
|
{
|
|
146
|
-
name: `[9]
|
|
152
|
+
name: `[9] � 发布版本 ${colors.dim("gw r")}`,
|
|
147
153
|
value: "release",
|
|
148
154
|
},
|
|
149
155
|
{
|
|
150
|
-
name: `[a]
|
|
156
|
+
name: `[a] � 管理 stash ${colors.dim("gw s")}`,
|
|
151
157
|
value: "stash",
|
|
152
158
|
},
|
|
153
159
|
{
|
|
154
|
-
name: `[b]
|
|
160
|
+
name: `[b] � 查看日志 ${colors.dim("gw log")}`,
|
|
155
161
|
value: "log",
|
|
156
162
|
},
|
|
157
163
|
{
|
|
@@ -263,9 +269,8 @@ cli
|
|
|
263
269
|
});
|
|
264
270
|
|
|
265
271
|
cli
|
|
266
|
-
.command("
|
|
267
|
-
.alias("
|
|
268
|
-
.alias("d")
|
|
272
|
+
.command("br:del [branch]", "删除本地/远程分支")
|
|
273
|
+
.alias("brd")
|
|
269
274
|
.action(async (branch?: string) => {
|
|
270
275
|
await checkForUpdates(version, "@zjex/git-workflow");
|
|
271
276
|
checkGitRepo();
|
|
@@ -291,7 +296,7 @@ cli
|
|
|
291
296
|
});
|
|
292
297
|
|
|
293
298
|
cli
|
|
294
|
-
.command("tag:
|
|
299
|
+
.command("tag:del", "删除 tag")
|
|
295
300
|
.alias("td")
|
|
296
301
|
.action(async () => {
|
|
297
302
|
await checkForUpdates(version, "@zjex/git-workflow");
|
|
@@ -308,6 +313,15 @@ cli
|
|
|
308
313
|
return updateTag();
|
|
309
314
|
});
|
|
310
315
|
|
|
316
|
+
cli
|
|
317
|
+
.command("tag:clean", "清理无效 tag")
|
|
318
|
+
.alias("tc")
|
|
319
|
+
.action(async () => {
|
|
320
|
+
await checkForUpdates(version, "@zjex/git-workflow");
|
|
321
|
+
checkGitRepo();
|
|
322
|
+
return cleanInvalidTags();
|
|
323
|
+
});
|
|
324
|
+
|
|
311
325
|
cli
|
|
312
326
|
.command("release", "交互式选择版本号并更新 package.json")
|
|
313
327
|
.alias("r")
|
|
@@ -364,77 +378,80 @@ cli
|
|
|
364
378
|
return log(logOptions);
|
|
365
379
|
});
|
|
366
380
|
|
|
367
|
-
cli
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
381
|
+
cli
|
|
382
|
+
.command("clean", "清理缓存和临时文件")
|
|
383
|
+
.alias("cc")
|
|
384
|
+
.action(async () => {
|
|
385
|
+
const { clearUpdateCache } = await import("./update-notifier.js");
|
|
386
|
+
const { existsSync, unlinkSync, readdirSync } = await import("fs");
|
|
387
|
+
const { homedir, tmpdir } = await import("os");
|
|
388
|
+
const { join } = await import("path");
|
|
389
|
+
const { select } = await import("@inquirer/prompts");
|
|
390
|
+
|
|
391
|
+
let cleanedCount = 0;
|
|
392
|
+
let deletedGlobalConfig = false;
|
|
393
|
+
|
|
394
|
+
// 检查全局配置文件是否存在
|
|
395
|
+
const globalConfig = join(homedir(), ".gwrc.json");
|
|
396
|
+
const hasGlobalConfig = existsSync(globalConfig);
|
|
397
|
+
|
|
398
|
+
// 如果有全局配置文件,询问是否删除
|
|
399
|
+
if (hasGlobalConfig) {
|
|
400
|
+
const shouldDeleteConfig = await select({
|
|
401
|
+
message: "检测到全局配置文件,是否删除?",
|
|
402
|
+
choices: [
|
|
403
|
+
{ name: "否,保留配置文件", value: false },
|
|
404
|
+
{ name: "是,删除配置文件", value: true },
|
|
405
|
+
],
|
|
406
|
+
theme,
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
if (shouldDeleteConfig) {
|
|
410
|
+
try {
|
|
411
|
+
unlinkSync(globalConfig);
|
|
412
|
+
cleanedCount++;
|
|
413
|
+
deletedGlobalConfig = true;
|
|
414
|
+
} catch {
|
|
415
|
+
// 静默失败
|
|
416
|
+
}
|
|
399
417
|
}
|
|
400
418
|
}
|
|
401
|
-
}
|
|
402
419
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
420
|
+
// 1. 清理更新缓存
|
|
421
|
+
clearUpdateCache();
|
|
422
|
+
cleanedCount++;
|
|
423
|
+
|
|
424
|
+
// 2. 清理临时 commit 消息文件
|
|
425
|
+
try {
|
|
426
|
+
const tmpDir = tmpdir();
|
|
427
|
+
const files = readdirSync(tmpDir);
|
|
428
|
+
const gwTmpFiles = files.filter((f) => f.startsWith(".gw-commit-msg-"));
|
|
429
|
+
|
|
430
|
+
for (const file of gwTmpFiles) {
|
|
431
|
+
try {
|
|
432
|
+
unlinkSync(join(tmpDir, file));
|
|
433
|
+
cleanedCount++;
|
|
434
|
+
} catch {
|
|
435
|
+
// 静默失败
|
|
436
|
+
}
|
|
419
437
|
}
|
|
438
|
+
} catch {
|
|
439
|
+
// 静默失败
|
|
420
440
|
}
|
|
421
|
-
} catch {
|
|
422
|
-
// 静默失败
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
console.log("");
|
|
426
|
-
console.log(colors.green(`✔ 已清理 ${cleanedCount} 个文件`));
|
|
427
441
|
|
|
428
|
-
if (deletedGlobalConfig) {
|
|
429
442
|
console.log("");
|
|
430
|
-
console.log(colors.
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
443
|
+
console.log(colors.green(`✔ 已清理 ${cleanedCount} 个文件`));
|
|
444
|
+
|
|
445
|
+
if (deletedGlobalConfig) {
|
|
446
|
+
console.log("");
|
|
447
|
+
console.log(colors.yellow("⚠️ 全局配置文件已删除"));
|
|
448
|
+
console.log(
|
|
449
|
+
colors.dim(` 如需重新配置,请运行: ${colors.cyan("gw init")}`)
|
|
450
|
+
);
|
|
451
|
+
}
|
|
435
452
|
|
|
436
|
-
|
|
437
|
-
});
|
|
453
|
+
console.log("");
|
|
454
|
+
});
|
|
438
455
|
|
|
439
456
|
// 不使用 cac 的 version,手动处理 --version 和 --help
|
|
440
457
|
cli.option("-v, --version", "显示版本号");
|
package/src/update-notifier.ts
CHANGED
|
@@ -181,7 +181,7 @@ async function showUpdateMessage(
|
|
|
181
181
|
console.log(
|
|
182
182
|
boxen(message, {
|
|
183
183
|
padding: { top: 1, bottom: 1, left: 3, right: 3 },
|
|
184
|
-
margin: 1,
|
|
184
|
+
margin: { top: 0, bottom: 0, left: 1, right: 1 },
|
|
185
185
|
borderStyle: "round",
|
|
186
186
|
borderColor: "yellow",
|
|
187
187
|
align: "center",
|