@zjex/git-workflow 0.2.5 → 0.2.7
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 +114 -4
- package/dist/index.js +519 -49
- package/package.json +2 -2
- package/src/ai-service.ts +350 -0
- package/src/commands/commit.ts +121 -36
- package/src/commands/init.ts +156 -9
- package/src/config.ts +9 -0
- package/src/index.ts +23 -1
- package/src/update-notifier.ts +25 -11
- package/test-ctrl-c.mjs +0 -32
- package/test-full-flow.mjs +0 -108
- package/test-update-flow.mjs +0 -98
package/src/commands/init.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, writeFileSync } from "fs";
|
|
2
|
-
import { select, input
|
|
2
|
+
import { select, input } from "@inquirer/prompts";
|
|
3
3
|
import { colors, theme, divider } from "../utils.js";
|
|
4
4
|
import type { GwConfig } from "../config.js";
|
|
5
5
|
|
|
@@ -22,9 +22,12 @@ const DEFAULT_COMMIT_EMOJIS = {
|
|
|
22
22
|
|
|
23
23
|
export async function init(): Promise<void> {
|
|
24
24
|
if (existsSync(CONFIG_FILE)) {
|
|
25
|
-
const overwrite = await
|
|
25
|
+
const overwrite = await select({
|
|
26
26
|
message: `${CONFIG_FILE} 已存在,是否覆盖?`,
|
|
27
|
-
|
|
27
|
+
choices: [
|
|
28
|
+
{ name: "否,取消", value: false },
|
|
29
|
+
{ name: "是,覆盖", value: true },
|
|
30
|
+
],
|
|
28
31
|
theme,
|
|
29
32
|
});
|
|
30
33
|
if (!overwrite) {
|
|
@@ -64,9 +67,12 @@ export async function init(): Promise<void> {
|
|
|
64
67
|
divider();
|
|
65
68
|
|
|
66
69
|
// ID 配置
|
|
67
|
-
const requireId = await
|
|
70
|
+
const requireId = await select({
|
|
68
71
|
message: "是否要求必填 ID (Story ID / Issue ID)?",
|
|
69
|
-
|
|
72
|
+
choices: [
|
|
73
|
+
{ name: "否", value: false },
|
|
74
|
+
{ name: "是", value: true },
|
|
75
|
+
],
|
|
70
76
|
theme,
|
|
71
77
|
});
|
|
72
78
|
if (requireId) config.requireId = true;
|
|
@@ -110,16 +116,22 @@ export async function init(): Promise<void> {
|
|
|
110
116
|
divider();
|
|
111
117
|
|
|
112
118
|
// Commit 配置
|
|
113
|
-
const autoStage = await
|
|
119
|
+
const autoStage = await select({
|
|
114
120
|
message: "Commit 时是否自动暂存所有更改?",
|
|
115
|
-
|
|
121
|
+
choices: [
|
|
122
|
+
{ name: "是", value: true },
|
|
123
|
+
{ name: "否", value: false },
|
|
124
|
+
],
|
|
116
125
|
theme,
|
|
117
126
|
});
|
|
118
127
|
if (!autoStage) config.autoStage = false;
|
|
119
128
|
|
|
120
|
-
const useEmoji = await
|
|
129
|
+
const useEmoji = await select({
|
|
121
130
|
message: "Commit 时是否使用 emoji?",
|
|
122
|
-
|
|
131
|
+
choices: [
|
|
132
|
+
{ name: "是", value: true },
|
|
133
|
+
{ name: "否", value: false },
|
|
134
|
+
],
|
|
123
135
|
theme,
|
|
124
136
|
});
|
|
125
137
|
if (!useEmoji) config.useEmoji = false;
|
|
@@ -129,6 +141,122 @@ export async function init(): Promise<void> {
|
|
|
129
141
|
|
|
130
142
|
divider();
|
|
131
143
|
|
|
144
|
+
// AI Commit 配置
|
|
145
|
+
console.log(
|
|
146
|
+
colors.dim("\nAI Commit 配置 (使用 AI 自动生成 commit message)\n")
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
const enableAI = await select({
|
|
150
|
+
message: "是否启用 AI Commit 功能?",
|
|
151
|
+
choices: [
|
|
152
|
+
{ name: "是(推荐)", value: true },
|
|
153
|
+
{ name: "否", value: false },
|
|
154
|
+
],
|
|
155
|
+
theme,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (enableAI) {
|
|
159
|
+
const aiProvider = await select({
|
|
160
|
+
message: "选择 AI 提供商:",
|
|
161
|
+
choices: [
|
|
162
|
+
{
|
|
163
|
+
name: "GitHub Models(免费,推荐)",
|
|
164
|
+
value: "github",
|
|
165
|
+
description: "使用 GitHub 账号,每天 150 次免费",
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: "Groq(免费)",
|
|
169
|
+
value: "groq",
|
|
170
|
+
description: "需要注册,每天 14,400 次免费",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "OpenAI(付费)",
|
|
174
|
+
value: "openai",
|
|
175
|
+
description: "需要付费 API key",
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "Claude(付费)",
|
|
179
|
+
value: "claude",
|
|
180
|
+
description: "需要付费 API key",
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: "Ollama(本地)",
|
|
184
|
+
value: "ollama",
|
|
185
|
+
description: "需要安装 Ollama",
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
theme,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const useBuiltinKey = await select({
|
|
192
|
+
message: "API Key 配置:",
|
|
193
|
+
choices: [
|
|
194
|
+
{
|
|
195
|
+
name: "使用内置 Key(开箱即用)",
|
|
196
|
+
value: true,
|
|
197
|
+
description: "使用工具内置的 API key,共享限额",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
name: "使用自己的 Key(推荐)",
|
|
201
|
+
value: false,
|
|
202
|
+
description: "配置自己的 API key,独享限额",
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
theme,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
let apiKey = "";
|
|
209
|
+
if (!useBuiltinKey) {
|
|
210
|
+
apiKey = await input({
|
|
211
|
+
message: `输入你的 ${
|
|
212
|
+
aiProvider === "github" ? "GitHub Token" : "API Key"
|
|
213
|
+
}:`,
|
|
214
|
+
validate: (value) => {
|
|
215
|
+
if (!value.trim()) return "API Key 不能为空";
|
|
216
|
+
return true;
|
|
217
|
+
},
|
|
218
|
+
theme,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const language = await select({
|
|
223
|
+
message: "生成的 commit message 语言:",
|
|
224
|
+
choices: [
|
|
225
|
+
{ name: "中文", value: "zh-CN" },
|
|
226
|
+
{ name: "English", value: "en-US" },
|
|
227
|
+
],
|
|
228
|
+
theme,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
config.aiCommit = {
|
|
232
|
+
enabled: true,
|
|
233
|
+
provider: aiProvider as
|
|
234
|
+
| "github"
|
|
235
|
+
| "groq"
|
|
236
|
+
| "openai"
|
|
237
|
+
| "claude"
|
|
238
|
+
| "ollama",
|
|
239
|
+
apiKey: apiKey || undefined,
|
|
240
|
+
language: language as "zh-CN" | "en-US",
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// 根据提供商设置默认模型
|
|
244
|
+
const defaultModels: Record<string, string> = {
|
|
245
|
+
github: "gpt-4o-mini",
|
|
246
|
+
groq: "llama-3.1-8b-instant",
|
|
247
|
+
openai: "gpt-4o-mini",
|
|
248
|
+
claude: "claude-3-haiku-20240307",
|
|
249
|
+
ollama: "qwen2.5-coder:7b",
|
|
250
|
+
};
|
|
251
|
+
config.aiCommit.model = defaultModels[aiProvider];
|
|
252
|
+
} else {
|
|
253
|
+
config.aiCommit = {
|
|
254
|
+
enabled: false,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
divider();
|
|
259
|
+
|
|
132
260
|
// 写入配置
|
|
133
261
|
const content = JSON.stringify(config, null, 2);
|
|
134
262
|
writeFileSync(CONFIG_FILE, content + "\n");
|
|
@@ -139,5 +267,24 @@ export async function init(): Promise<void> {
|
|
|
139
267
|
"\n提示: 可以在配置文件中修改 commitEmojis 来自定义各类型的 emoji"
|
|
140
268
|
)
|
|
141
269
|
);
|
|
270
|
+
|
|
271
|
+
if (config.aiCommit?.enabled) {
|
|
272
|
+
console.log(
|
|
273
|
+
colors.dim(
|
|
274
|
+
"提示: AI Commit 已启用,运行 'gw c' 时可以选择 AI 自动生成 commit message"
|
|
275
|
+
)
|
|
276
|
+
);
|
|
277
|
+
if (!config.aiCommit.apiKey) {
|
|
278
|
+
console.log(
|
|
279
|
+
colors.yellow(
|
|
280
|
+
"\n⚠️ 当前使用内置 API key,建议配置自己的 key 以获得更好的体验"
|
|
281
|
+
)
|
|
282
|
+
);
|
|
283
|
+
console.log(
|
|
284
|
+
colors.dim(" 获取方法: https://github.com/settings/tokens/new")
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
142
289
|
console.log(colors.dim("\n" + content));
|
|
143
290
|
}
|
package/src/config.ts
CHANGED
|
@@ -36,6 +36,15 @@ export interface GwConfig {
|
|
|
36
36
|
chore?: string;
|
|
37
37
|
revert?: string;
|
|
38
38
|
};
|
|
39
|
+
// AI commit 配置
|
|
40
|
+
aiCommit?: {
|
|
41
|
+
enabled?: boolean; // 是否启用 AI commit,默认 true
|
|
42
|
+
provider?: "github" | "groq" | "openai" | "claude" | "ollama"; // AI 提供商,默认 github
|
|
43
|
+
apiKey?: string; // API key,空则使用内置 key
|
|
44
|
+
model?: string; // 模型名称
|
|
45
|
+
language?: "zh-CN" | "en-US"; // 生成语言,默认 zh-CN
|
|
46
|
+
maxTokens?: number; // 最大 token 数,默认 200
|
|
47
|
+
};
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
const defaultConfig: GwConfig = {
|
package/src/index.ts
CHANGED
|
@@ -12,17 +12,39 @@ import { stash } from "./commands/stash.js";
|
|
|
12
12
|
import { commit } from "./commands/commit.js";
|
|
13
13
|
import { showHelp } from "./commands/help.js";
|
|
14
14
|
import { checkForUpdates } from "./update-notifier.js";
|
|
15
|
-
import { checkForUpdates } from "./update-notifier.js";
|
|
16
15
|
|
|
17
16
|
// 捕获 Ctrl+C 退出,静默处理
|
|
18
17
|
process.on("uncaughtException", (err) => {
|
|
19
18
|
if (err instanceof ExitPromptError) {
|
|
19
|
+
console.log(""); // 输出空行,让界面更整洁
|
|
20
20
|
process.exit(0);
|
|
21
21
|
}
|
|
22
22
|
console.error(err);
|
|
23
23
|
process.exit(1);
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
+
// 捕获未处理的 Promise 拒绝
|
|
27
|
+
process.on("unhandledRejection", (reason) => {
|
|
28
|
+
if (reason instanceof ExitPromptError) {
|
|
29
|
+
console.log("");
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
console.error("未处理的 Promise 拒绝:", reason);
|
|
33
|
+
process.exit(1);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// 捕获 SIGINT 信号 (Ctrl+C)
|
|
37
|
+
process.on("SIGINT", () => {
|
|
38
|
+
console.log("");
|
|
39
|
+
process.exit(0);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// 捕获 SIGTERM 信号
|
|
43
|
+
process.on("SIGTERM", () => {
|
|
44
|
+
console.log("");
|
|
45
|
+
process.exit(0);
|
|
46
|
+
});
|
|
47
|
+
|
|
26
48
|
declare const __VERSION__: string | undefined;
|
|
27
49
|
|
|
28
50
|
// 开发环境下从 package.json 读取版本号
|
package/src/update-notifier.ts
CHANGED
|
@@ -145,18 +145,18 @@ async function performUpdate(packageName: string): Promise<void> {
|
|
|
145
145
|
}).start();
|
|
146
146
|
|
|
147
147
|
try {
|
|
148
|
-
//
|
|
148
|
+
// 先卸载当前版本,确保干净安装
|
|
149
149
|
try {
|
|
150
|
-
execSync(
|
|
150
|
+
execSync(`npm uninstall -g ${packageName}`, {
|
|
151
151
|
encoding: "utf-8",
|
|
152
152
|
stdio: ["pipe", "pipe", "pipe"],
|
|
153
153
|
});
|
|
154
|
-
spinner.text = "
|
|
154
|
+
spinner.text = "正在安装新版本...";
|
|
155
155
|
} catch {
|
|
156
|
-
//
|
|
156
|
+
// 当前版本不存在,忽略错误
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
//
|
|
159
|
+
// 执行安装命令
|
|
160
160
|
execSync(`npm install -g ${packageName}`, {
|
|
161
161
|
encoding: "utf-8",
|
|
162
162
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -164,8 +164,26 @@ async function performUpdate(packageName: string): Promise<void> {
|
|
|
164
164
|
|
|
165
165
|
spinner.succeed(colors.green("更新成功!"));
|
|
166
166
|
console.log("");
|
|
167
|
-
console.log(
|
|
168
|
-
|
|
167
|
+
console.log(
|
|
168
|
+
boxen(
|
|
169
|
+
[
|
|
170
|
+
colors.bold("✨ 更新完成!"),
|
|
171
|
+
"",
|
|
172
|
+
colors.dim("请运行以下命令刷新并使用新版本:"),
|
|
173
|
+
"",
|
|
174
|
+
colors.yellow(" hash -r && gw --version"),
|
|
175
|
+
"",
|
|
176
|
+
colors.dim("或者重新打开终端"),
|
|
177
|
+
].join("\n"),
|
|
178
|
+
{
|
|
179
|
+
padding: 1,
|
|
180
|
+
margin: { top: 0, bottom: 1, left: 2, right: 2 },
|
|
181
|
+
borderStyle: "round",
|
|
182
|
+
borderColor: "green",
|
|
183
|
+
align: "left",
|
|
184
|
+
}
|
|
185
|
+
)
|
|
186
|
+
);
|
|
169
187
|
|
|
170
188
|
// 更新成功后退出,让用户重新运行
|
|
171
189
|
process.exit(0);
|
|
@@ -173,10 +191,6 @@ async function performUpdate(packageName: string): Promise<void> {
|
|
|
173
191
|
spinner.fail(colors.red("更新失败"));
|
|
174
192
|
console.log("");
|
|
175
193
|
console.log(colors.dim(" 你可以手动运行以下命令更新:"));
|
|
176
|
-
console.log(colors.yellow(" # 如果之前安装过旧版本,先卸载:"));
|
|
177
|
-
console.log(colors.cyan(" npm uninstall -g git-workflow"));
|
|
178
|
-
console.log("");
|
|
179
|
-
console.log(colors.yellow(" # 然后安装新版本:"));
|
|
180
194
|
console.log(colors.cyan(` npm install -g ${packageName}`));
|
|
181
195
|
console.log("");
|
|
182
196
|
}
|
package/test-ctrl-c.mjs
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { select } from "@inquirer/prompts";
|
|
4
|
-
import { ExitPromptError } from "@inquirer/core";
|
|
5
|
-
|
|
6
|
-
// 捕获 Ctrl+C 退出,静默处理
|
|
7
|
-
process.on("uncaughtException", (err) => {
|
|
8
|
-
if (err instanceof ExitPromptError) {
|
|
9
|
-
console.log("\n✓ Ctrl+C 被正确捕获,程序退出");
|
|
10
|
-
process.exit(0);
|
|
11
|
-
}
|
|
12
|
-
console.error("其他错误:", err);
|
|
13
|
-
process.exit(1);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
async function test() {
|
|
17
|
-
try {
|
|
18
|
-
const choice = await select({
|
|
19
|
-
message: "测试 Ctrl+C (按 Ctrl+C 退出):",
|
|
20
|
-
choices: [
|
|
21
|
-
{ name: "选项 1", value: "1" },
|
|
22
|
-
{ name: "选项 2", value: "2" },
|
|
23
|
-
],
|
|
24
|
-
});
|
|
25
|
-
console.log(`你选择了: ${choice}`);
|
|
26
|
-
} catch (error) {
|
|
27
|
-
console.log("\n在 catch 中捕获到错误,重新抛出...");
|
|
28
|
-
throw error;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
test();
|
package/test-full-flow.mjs
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import boxen from "boxen";
|
|
4
|
-
import { select } from "@inquirer/prompts";
|
|
5
|
-
import { ExitPromptError } from "@inquirer/core";
|
|
6
|
-
|
|
7
|
-
// 捕获 Ctrl+C 退出,静默处理
|
|
8
|
-
process.on("uncaughtException", (err) => {
|
|
9
|
-
if (err instanceof ExitPromptError) {
|
|
10
|
-
process.exit(0);
|
|
11
|
-
}
|
|
12
|
-
console.error(err);
|
|
13
|
-
process.exit(1);
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const colors = {
|
|
17
|
-
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
18
|
-
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
19
|
-
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
async function checkForUpdates() {
|
|
23
|
-
const current = "0.2.3";
|
|
24
|
-
const latest = "0.2.4";
|
|
25
|
-
const packageName = "@zjex/git-workflow";
|
|
26
|
-
|
|
27
|
-
const message = [
|
|
28
|
-
colors.bold("🎉 发现新版本可用!"),
|
|
29
|
-
"",
|
|
30
|
-
`${colors.dim(current)} → ${colors.green(colors.bold(latest))}`,
|
|
31
|
-
].join("\n");
|
|
32
|
-
|
|
33
|
-
console.log("");
|
|
34
|
-
console.log(
|
|
35
|
-
boxen(message, {
|
|
36
|
-
padding: 1,
|
|
37
|
-
margin: 1,
|
|
38
|
-
borderStyle: "round",
|
|
39
|
-
borderColor: "yellow",
|
|
40
|
-
align: "left",
|
|
41
|
-
})
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
const action = await select({
|
|
46
|
-
message: "你想做什么?",
|
|
47
|
-
choices: [
|
|
48
|
-
{
|
|
49
|
-
name: "🚀 立即更新",
|
|
50
|
-
value: "update",
|
|
51
|
-
description: `运行 npm install -g ${packageName}`,
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: "⏭️ 稍后更新,继续使用",
|
|
55
|
-
value: "continue",
|
|
56
|
-
description: "下次启动时会再次提示",
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
name: "🙈 跳过此版本 (24h 内不再提示)",
|
|
60
|
-
value: "dismiss",
|
|
61
|
-
description: "24 小时内不会再提示此版本",
|
|
62
|
-
},
|
|
63
|
-
],
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
if (action === "update") {
|
|
67
|
-
console.log("\n模拟更新中...\n");
|
|
68
|
-
process.exit(0);
|
|
69
|
-
} else if (action === "dismiss") {
|
|
70
|
-
console.log(colors.dim("\n已跳过此版本,24 小时内不再提示\n"));
|
|
71
|
-
}
|
|
72
|
-
} catch (error) {
|
|
73
|
-
// 用户按了 Ctrl+C,重新抛出让全局处理
|
|
74
|
-
console.log("");
|
|
75
|
-
throw error;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
async function mainMenu() {
|
|
80
|
-
// 先检查更新,等待完成
|
|
81
|
-
await checkForUpdates();
|
|
82
|
-
|
|
83
|
-
// 然后显示主菜单
|
|
84
|
-
console.log(
|
|
85
|
-
colors.green(`
|
|
86
|
-
███████╗ ██╗███████╗██╗ ██╗
|
|
87
|
-
╚══███╔╝ ██║██╔════╝╚██╗██╔╝
|
|
88
|
-
███╔╝ ██║█████╗ ╚███╔╝
|
|
89
|
-
███╔╝ ██ ██║██╔══╝ ██╔██╗
|
|
90
|
-
███████╗╚█████╔╝███████╗██╔╝ ██╗
|
|
91
|
-
╚══════╝ ╚════╝ ╚══════╝╚═╝ ╚═╝
|
|
92
|
-
`)
|
|
93
|
-
);
|
|
94
|
-
console.log(colors.dim(` git-workflow v0.2.4\n`));
|
|
95
|
-
|
|
96
|
-
const choice = await select({
|
|
97
|
-
message: "选择操作:",
|
|
98
|
-
choices: [
|
|
99
|
-
{ name: "[1] ✨ 创建 feature 分支 gw f", value: "1" },
|
|
100
|
-
{ name: "[2] 🐛 创建 hotfix 分支 gw h", value: "2" },
|
|
101
|
-
{ name: "[3] 🗑️ 删除分支 gw d", value: "3" },
|
|
102
|
-
],
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
console.log(`\n你选择了: ${choice}\n`);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
mainMenu();
|
package/test-update-flow.mjs
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import boxen from "boxen";
|
|
4
|
-
import { select } from "@inquirer/prompts";
|
|
5
|
-
import ora from "ora";
|
|
6
|
-
|
|
7
|
-
const colors = {
|
|
8
|
-
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
9
|
-
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
10
|
-
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
11
|
-
cyan: (s) => `\x1b[36m${s}\x1b[0m`,
|
|
12
|
-
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
13
|
-
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
14
|
-
reset: "\x1b[0m",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
async function testUpdateFlow() {
|
|
18
|
-
const current = "0.1.0";
|
|
19
|
-
const latest = "0.2.0";
|
|
20
|
-
const packageName = "@zjex/git-workflow";
|
|
21
|
-
|
|
22
|
-
// 1. 显示更新提示框
|
|
23
|
-
const message = [
|
|
24
|
-
colors.bold("🎉 发现新版本可用!"),
|
|
25
|
-
"",
|
|
26
|
-
`${colors.dim(current)} → ${colors.green(colors.bold(latest))}`,
|
|
27
|
-
].join("\n");
|
|
28
|
-
|
|
29
|
-
console.log("");
|
|
30
|
-
console.log(
|
|
31
|
-
boxen(message, {
|
|
32
|
-
padding: 1,
|
|
33
|
-
margin: 1,
|
|
34
|
-
borderStyle: "round",
|
|
35
|
-
borderColor: "yellow",
|
|
36
|
-
align: "left",
|
|
37
|
-
})
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
// 2. 交互式选择
|
|
41
|
-
try {
|
|
42
|
-
const action = await select({
|
|
43
|
-
message: "你想做什么?",
|
|
44
|
-
choices: [
|
|
45
|
-
{
|
|
46
|
-
name: "🚀 立即更新",
|
|
47
|
-
value: "update",
|
|
48
|
-
description: `运行 npm install -g ${packageName}`,
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
name: "⏭️ 稍后更新,继续使用",
|
|
52
|
-
value: "continue",
|
|
53
|
-
description: "下次启动时会再次提示",
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
name: "🙈 跳过此版本 (24h 内不再提示)",
|
|
57
|
-
value: "dismiss",
|
|
58
|
-
description: "24 小时内不会再提示此版本",
|
|
59
|
-
},
|
|
60
|
-
],
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
console.log("");
|
|
64
|
-
|
|
65
|
-
// 3. 根据选择执行操作
|
|
66
|
-
if (action === "update") {
|
|
67
|
-
// 模拟更新过程
|
|
68
|
-
const spinner = ora({
|
|
69
|
-
text: "正在更新...",
|
|
70
|
-
spinner: "dots",
|
|
71
|
-
}).start();
|
|
72
|
-
|
|
73
|
-
// 模拟卸载旧版本
|
|
74
|
-
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
75
|
-
spinner.text = "已卸载旧版本,正在安装新版本...";
|
|
76
|
-
|
|
77
|
-
// 模拟安装新版本
|
|
78
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
79
|
-
|
|
80
|
-
spinner.succeed(colors.green("更新成功!"));
|
|
81
|
-
console.log("");
|
|
82
|
-
console.log(colors.cyan(" 提示: 请重新运行命令以使用新版本"));
|
|
83
|
-
console.log("");
|
|
84
|
-
} else if (action === "continue") {
|
|
85
|
-
console.log(colors.cyan("继续使用当前版本..."));
|
|
86
|
-
console.log("");
|
|
87
|
-
} else if (action === "dismiss") {
|
|
88
|
-
console.log(colors.dim("已跳过此版本,24 小时内不再提示"));
|
|
89
|
-
console.log("");
|
|
90
|
-
}
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.log("");
|
|
93
|
-
console.log(colors.dim("已取消"));
|
|
94
|
-
console.log("");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
testUpdateFlow();
|