@zjex/git-workflow 0.2.19 → 0.2.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,31 +1,16 @@
1
1
  #!/usr/bin/env -S node --no-warnings=ExperimentalWarning
2
-
3
- // src/index.ts
4
- import { cac } from "cac";
5
- import { select as select8 } from "@inquirer/prompts";
6
- import { ExitPromptError } from "@inquirer/core";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
7
11
 
8
12
  // src/utils.ts
9
13
  import { execSync } from "child_process";
10
- var colors = {
11
- red: (s) => `\x1B[31m${s}\x1B[0m`,
12
- green: (s) => `\x1B[32m${s}\x1B[0m`,
13
- yellow: (s) => `\x1B[33m${s}\x1B[0m`,
14
- cyan: (s) => `\x1B[36m${s}\x1B[0m`,
15
- dim: (s) => `\x1B[2m${s}\x1B[0m`,
16
- bold: (s) => `\x1B[1m${s}\x1B[0m`,
17
- reset: "\x1B[0m"
18
- };
19
- var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
20
- var theme = {
21
- helpMode: "always",
22
- style: {
23
- keysHelpTip: (keys) => {
24
- const tips = keys.map(([key, label]) => `${key} ${label}`).join(" \u2022 ");
25
- return `\x1B[2m${tips} \u2022 Ctrl+C quit\x1B[0m`;
26
- }
27
- }
28
- };
29
14
  function exec(cmd, silent = false) {
30
15
  try {
31
16
  const options = {
@@ -66,13 +51,267 @@ function getMainBranch() {
66
51
  function divider() {
67
52
  console.log(colors.dim("\u2500".repeat(40)));
68
53
  }
54
+ var colors, TODAY, theme;
55
+ var init_utils = __esm({
56
+ "src/utils.ts"() {
57
+ "use strict";
58
+ colors = {
59
+ red: (s) => `\x1B[31m${s}\x1B[0m`,
60
+ green: (s) => `\x1B[32m${s}\x1B[0m`,
61
+ yellow: (s) => `\x1B[33m${s}\x1B[0m`,
62
+ cyan: (s) => `\x1B[36m${s}\x1B[0m`,
63
+ dim: (s) => `\x1B[2m${s}\x1B[0m`,
64
+ bold: (s) => `\x1B[1m${s}\x1B[0m`,
65
+ reset: "\x1B[0m"
66
+ };
67
+ TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10).replace(/-/g, "");
68
+ theme = {
69
+ helpMode: "always",
70
+ style: {
71
+ keysHelpTip: (keys) => {
72
+ const tips = keys.map(([key, label]) => `${key} ${label}`).join(" \u2022 ");
73
+ return `\x1B[2m${tips} \u2022 Ctrl+C quit\x1B[0m`;
74
+ }
75
+ }
76
+ };
77
+ }
78
+ });
79
+
80
+ // src/update-notifier.ts
81
+ var update_notifier_exports = {};
82
+ __export(update_notifier_exports, {
83
+ checkForUpdates: () => checkForUpdates,
84
+ clearUpdateCache: () => clearUpdateCache
85
+ });
86
+ import { execSync as execSync6 } from "child_process";
87
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, unlinkSync } from "fs";
88
+ import { homedir as homedir3 } from "os";
89
+ import { join as join3 } from "path";
90
+ import boxen from "boxen";
91
+ import { select as select7 } from "@inquirer/prompts";
92
+ import ora5 from "ora";
93
+ import semver from "semver";
94
+ async function checkForUpdates(currentVersion, packageName = "@zjex/git-workflow", interactive = false) {
95
+ try {
96
+ const cache = readCache();
97
+ const now = Date.now();
98
+ if (cache?.latestVersion && cache.checkedVersion === currentVersion) {
99
+ if (cache.lastDismiss && now - cache.lastDismiss < DISMISS_INTERVAL) {
100
+ backgroundCheck(currentVersion, packageName);
101
+ return;
102
+ }
103
+ if (semver.gt(cache.latestVersion, currentVersion)) {
104
+ if (interactive) {
105
+ const action = await showUpdateMessage(
106
+ currentVersion,
107
+ cache.latestVersion,
108
+ packageName
109
+ );
110
+ if (action === "update") {
111
+ await performUpdate(packageName);
112
+ } else if (action === "dismiss") {
113
+ writeCache({ ...cache, lastDismiss: now });
114
+ }
115
+ } else {
116
+ showSimpleNotification(currentVersion, cache.latestVersion);
117
+ }
118
+ }
119
+ }
120
+ backgroundCheck(currentVersion, packageName);
121
+ } catch (error) {
122
+ if (error?.constructor?.name === "ExitPromptError") {
123
+ throw error;
124
+ }
125
+ }
126
+ }
127
+ function backgroundCheck(currentVersion, packageName) {
128
+ const cache = readCache();
129
+ const now = Date.now();
130
+ if (cache?.lastCheck && now - cache.lastCheck < CHECK_INTERVAL) {
131
+ return;
132
+ }
133
+ Promise.resolve().then(async () => {
134
+ try {
135
+ const latestVersion = await getLatestVersion(packageName);
136
+ if (latestVersion) {
137
+ writeCache({
138
+ ...cache,
139
+ lastCheck: now,
140
+ latestVersion,
141
+ checkedVersion: currentVersion
142
+ });
143
+ }
144
+ } catch {
145
+ }
146
+ });
147
+ }
148
+ async function getLatestVersion(packageName) {
149
+ try {
150
+ const result = execSync6(`npm view ${packageName} version`, {
151
+ encoding: "utf-8",
152
+ timeout: 3e3,
153
+ stdio: ["pipe", "pipe", "ignore"]
154
+ // 忽略 stderr
155
+ });
156
+ return result.trim();
157
+ } catch {
158
+ return null;
159
+ }
160
+ }
161
+ function showSimpleNotification(current, latest) {
162
+ const message = `${colors.yellow("\u{1F389} \u53D1\u73B0\u65B0\u7248\u672C")} ${colors.dim(
163
+ current
164
+ )} \u2192 ${colors.green(latest)} ${colors.dim("\u8FD0\u884C")} ${colors.cyan(
165
+ "gw update"
166
+ )} ${colors.dim("\u66F4\u65B0")}`;
167
+ console.log("");
168
+ console.log(
169
+ boxen(message, {
170
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
171
+ margin: { top: 0, bottom: 1, left: 0, right: 0 },
172
+ borderStyle: "round",
173
+ borderColor: "yellow",
174
+ align: "center"
175
+ })
176
+ );
177
+ }
178
+ async function showUpdateMessage(current, latest, packageName) {
179
+ const message = [
180
+ colors.yellow(colors.bold("\u{1F389} \u53D1\u73B0\u65B0\u7248\u672C\uFF01")),
181
+ "",
182
+ `${colors.dim(current)} \u2192 ${colors.green(colors.bold(latest))}`
183
+ ].join("\n");
184
+ console.log("");
185
+ console.log(
186
+ boxen(message, {
187
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
188
+ margin: 1,
189
+ borderStyle: "round",
190
+ borderColor: "yellow",
191
+ align: "center",
192
+ width: 40
193
+ })
194
+ );
195
+ try {
196
+ const action = await select7({
197
+ message: "\u4F60\u60F3\u505A\u4EC0\u4E48\uFF1F",
198
+ choices: [
199
+ {
200
+ name: "\u{1F680} \u7ACB\u5373\u66F4\u65B0",
201
+ value: "update",
202
+ description: `\u8FD0\u884C npm install -g ${packageName}`
203
+ },
204
+ {
205
+ name: "\u23ED\uFE0F \u7A0D\u540E\u66F4\u65B0\uFF0C\u7EE7\u7EED\u4F7F\u7528",
206
+ value: "continue",
207
+ description: "\u4E0B\u6B21\u542F\u52A8\u65F6\u4F1A\u518D\u6B21\u63D0\u793A"
208
+ },
209
+ {
210
+ name: "\u{1F648} \u8DF3\u8FC7\u6B64\u7248\u672C (24h \u5185\u4E0D\u518D\u63D0\u793A)",
211
+ value: "dismiss",
212
+ description: "24 \u5C0F\u65F6\u5185\u4E0D\u4F1A\u518D\u63D0\u793A\u6B64\u7248\u672C"
213
+ }
214
+ ]
215
+ });
216
+ return action;
217
+ } catch (error) {
218
+ console.log("");
219
+ throw error;
220
+ }
221
+ }
222
+ async function performUpdate(packageName) {
223
+ console.log("");
224
+ const spinner = ora5({
225
+ text: "\u6B63\u5728\u66F4\u65B0...",
226
+ spinner: "dots"
227
+ }).start();
228
+ try {
229
+ execSync6(`npm install -g ${packageName}@latest`, {
230
+ encoding: "utf-8",
231
+ stdio: ["pipe", "pipe", "pipe"]
232
+ });
233
+ spinner.succeed(colors.green("\u66F4\u65B0\u6210\u529F\uFF01"));
234
+ clearUpdateCache();
235
+ console.log("");
236
+ console.log(
237
+ boxen(
238
+ [
239
+ colors.green(colors.bold("\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01")),
240
+ "",
241
+ colors.dim("\u8BF7\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u4F7F\u7528\u65B0\u7248\u672C")
242
+ ].join("\n"),
243
+ {
244
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
245
+ margin: { top: 0, bottom: 1, left: 2, right: 2 },
246
+ borderStyle: "round",
247
+ borderColor: "green",
248
+ align: "center",
249
+ width: 40
250
+ }
251
+ )
252
+ );
253
+ process.exit(0);
254
+ } catch (error) {
255
+ spinner.fail(colors.red("\u66F4\u65B0\u5931\u8D25"));
256
+ console.log("");
257
+ console.log(colors.dim(" \u4F60\u53EF\u4EE5\u624B\u52A8\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0:"));
258
+ console.log(colors.cyan(` npm install -g ${packageName}@latest`));
259
+ console.log("");
260
+ }
261
+ }
262
+ function clearUpdateCache() {
263
+ try {
264
+ const cacheFile = join3(homedir3(), CACHE_FILE);
265
+ if (existsSync3(cacheFile)) {
266
+ unlinkSync(cacheFile);
267
+ }
268
+ } catch {
269
+ }
270
+ }
271
+ function readCache() {
272
+ try {
273
+ const cacheFile = join3(homedir3(), CACHE_FILE);
274
+ if (!existsSync3(cacheFile)) {
275
+ return null;
276
+ }
277
+ const content = readFileSync3(cacheFile, "utf-8");
278
+ return JSON.parse(content);
279
+ } catch {
280
+ return null;
281
+ }
282
+ }
283
+ function writeCache(cache) {
284
+ try {
285
+ const cacheFile = join3(homedir3(), CACHE_FILE);
286
+ writeFileSync3(cacheFile, JSON.stringify(cache), "utf-8");
287
+ } catch {
288
+ }
289
+ }
290
+ var CHECK_INTERVAL, DISMISS_INTERVAL, CACHE_FILE;
291
+ var init_update_notifier = __esm({
292
+ "src/update-notifier.ts"() {
293
+ "use strict";
294
+ init_utils();
295
+ CHECK_INTERVAL = 1e3 * 60 * 60 * 4;
296
+ DISMISS_INTERVAL = 1e3 * 60 * 60 * 24;
297
+ CACHE_FILE = ".gw-update-check";
298
+ }
299
+ });
300
+
301
+ // src/index.ts
302
+ init_utils();
303
+ import { cac } from "cac";
304
+ import { select as select8 } from "@inquirer/prompts";
305
+ import { ExitPromptError } from "@inquirer/core";
69
306
 
70
307
  // src/commands/branch.ts
308
+ init_utils();
71
309
  import { execSync as execSync2 } from "child_process";
72
310
  import { select, input } from "@inquirer/prompts";
73
311
  import ora from "ora";
74
312
 
75
313
  // src/config.ts
314
+ init_utils();
76
315
  import { existsSync, readFileSync } from "fs";
77
316
  import { join } from "path";
78
317
  import { homedir } from "os";
@@ -392,6 +631,7 @@ async function deleteBranch(branchArg) {
392
631
  }
393
632
 
394
633
  // src/commands/tag.ts
634
+ init_utils();
395
635
  import { execSync as execSync3 } from "child_process";
396
636
  import { select as select2, input as input2 } from "@inquirer/prompts";
397
637
  import ora2 from "ora";
@@ -790,6 +1030,7 @@ async function updateTag() {
790
1030
  }
791
1031
 
792
1032
  // src/commands/release.ts
1033
+ init_utils();
793
1034
  import { readFileSync as readFileSync2, writeFileSync } from "fs";
794
1035
  import { select as select3 } from "@inquirer/prompts";
795
1036
  function getPackageVersion() {
@@ -888,6 +1129,7 @@ async function release() {
888
1129
  }
889
1130
 
890
1131
  // src/commands/init.ts
1132
+ init_utils();
891
1133
  import { existsSync as existsSync2, writeFileSync as writeFileSync2 } from "fs";
892
1134
  import { join as join2 } from "path";
893
1135
  import { homedir as homedir2 } from "os";
@@ -1172,6 +1414,7 @@ async function init() {
1172
1414
  }
1173
1415
 
1174
1416
  // src/commands/stash.ts
1417
+ init_utils();
1175
1418
  import { execSync as execSync4 } from "child_process";
1176
1419
  import { select as select5, input as input4 } from "@inquirer/prompts";
1177
1420
  import ora3 from "ora";
@@ -1406,11 +1649,13 @@ async function dropStash(index) {
1406
1649
  }
1407
1650
 
1408
1651
  // src/commands/commit.ts
1652
+ init_utils();
1409
1653
  import { execSync as execSync5 } from "child_process";
1410
1654
  import { select as select6, input as input5, checkbox } from "@inquirer/prompts";
1411
1655
  import ora4 from "ora";
1412
1656
 
1413
1657
  // src/ai-service.ts
1658
+ init_utils();
1414
1659
  var AI_PROVIDERS = {
1415
1660
  github: {
1416
1661
  name: "GitHub Models",
@@ -1890,6 +2135,7 @@ ${issues}`;
1890
2135
  }
1891
2136
 
1892
2137
  // src/commands/help.ts
2138
+ init_utils();
1893
2139
  function showHelp() {
1894
2140
  return `
1895
2141
  \u5206\u652F\u547D\u4EE4:
@@ -1932,6 +2178,9 @@ Tag \u547D\u4EE4:
1932
2178
  gw update \u68C0\u67E5\u5E76\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C
1933
2179
  gw upt \u540C\u4E0A (\u522B\u540D)
1934
2180
 
2181
+ \u6E05\u7406\u547D\u4EE4:
2182
+ gw clean \u6E05\u7406\u7F13\u5B58\u6587\u4EF6
2183
+
1935
2184
  Stash \u547D\u4EE4:
1936
2185
  gw stash \u4EA4\u4E92\u5F0F\u7BA1\u7406 stash
1937
2186
  gw s \u540C\u4E0A (\u522B\u540D)
@@ -1962,160 +2211,28 @@ Commit \u547D\u4EE4:
1962
2211
  `;
1963
2212
  }
1964
2213
 
1965
- // src/update-notifier.ts
1966
- import { execSync as execSync6 } from "child_process";
1967
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3 } from "fs";
1968
- import { homedir as homedir3 } from "os";
1969
- import { join as join3 } from "path";
1970
- import boxen from "boxen";
1971
- import { select as select7 } from "@inquirer/prompts";
1972
- import ora5 from "ora";
1973
- var DISMISS_INTERVAL = 1e3 * 60 * 60 * 24;
1974
- var CACHE_FILE = ".gw-update-check";
1975
- async function checkForUpdates(currentVersion, packageName = "@zjex/git-workflow") {
1976
- try {
1977
- const cache = readCache();
1978
- const now = Date.now();
1979
- if (cache?.lastDismiss && now - cache.lastDismiss < DISMISS_INTERVAL) {
1980
- return;
1981
- }
1982
- const latestVersion = await getLatestVersion(packageName);
1983
- if (latestVersion && latestVersion !== currentVersion) {
1984
- const action = await showUpdateMessage(
1985
- currentVersion,
1986
- latestVersion,
1987
- packageName
1988
- );
1989
- if (action === "update") {
1990
- await performUpdate(packageName);
1991
- } else if (action === "dismiss") {
1992
- writeCache({ lastDismiss: now, latestVersion });
1993
- }
1994
- }
1995
- } catch (error) {
1996
- if (error?.constructor?.name === "ExitPromptError") {
1997
- throw error;
1998
- }
1999
- }
2000
- }
2001
- async function getLatestVersion(packageName) {
2002
- try {
2003
- const result = execSync6(`npm view ${packageName} version`, {
2004
- encoding: "utf-8",
2005
- timeout: 3e3,
2006
- stdio: ["pipe", "pipe", "ignore"]
2007
- // 忽略 stderr
2008
- });
2009
- return result.trim();
2010
- } catch {
2011
- return null;
2012
- }
2013
- }
2014
- async function showUpdateMessage(current, latest, packageName) {
2015
- const message = [
2016
- colors.bold("\uFFFD \u53D1\u73B0\u65B0\u7248\u65B0\u672C\u53EF\u7528\uFF01"),
2017
- "",
2018
- `${colors.dim(current)} \u2192 ${colors.green(colors.bold(latest))}`
2019
- ].join("\n");
2020
- console.log("");
2021
- console.log(
2022
- boxen(message, {
2023
- padding: 1,
2024
- margin: 1,
2025
- borderStyle: "round",
2026
- borderColor: "yellow",
2027
- align: "left"
2028
- })
2029
- );
2030
- try {
2031
- const action = await select7({
2032
- message: "\u4F60\u60F3\u505A\u4EC0\u4E48\uFF1F",
2033
- choices: [
2034
- {
2035
- name: "\u{1F680} \u7ACB\u5373\u66F4\u65B0",
2036
- value: "update",
2037
- description: `\u8FD0\u884C npm install -g ${packageName}`
2038
- },
2039
- {
2040
- name: "\u23ED\uFE0F \u7A0D\u540E\u66F4\u65B0\uFF0C\u7EE7\u7EED\u4F7F\u7528",
2041
- value: "continue",
2042
- description: "\u4E0B\u6B21\u542F\u52A8\u65F6\u4F1A\u518D\u6B21\u63D0\u793A"
2043
- },
2044
- {
2045
- name: "\u{1F648} \u8DF3\u8FC7\u6B64\u7248\u672C (24h \u5185\u4E0D\u518D\u63D0\u793A)",
2046
- value: "dismiss",
2047
- description: "24 \u5C0F\u65F6\u5185\u4E0D\u4F1A\u518D\u63D0\u793A\u6B64\u7248\u672C"
2048
- }
2049
- ]
2050
- });
2051
- return action;
2052
- } catch (error) {
2053
- console.log("");
2054
- throw error;
2055
- }
2056
- }
2057
- async function performUpdate(packageName) {
2058
- console.log("");
2059
- const spinner = ora5({
2060
- text: "\u6B63\u5728\u66F4\u65B0...",
2061
- spinner: "dots"
2062
- }).start();
2063
- try {
2064
- execSync6(`npm install -g ${packageName}@latest`, {
2065
- encoding: "utf-8",
2066
- stdio: ["pipe", "pipe", "pipe"]
2067
- });
2068
- spinner.succeed(colors.green("\u66F4\u65B0\u6210\u529F\uFF01"));
2069
- console.log("");
2070
- console.log(
2071
- boxen(
2072
- [
2073
- colors.bold("\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01"),
2074
- "",
2075
- colors.dim("\u8BF7\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u4F7F\u7528\u65B0\u7248\u672C")
2076
- ].join("\n"),
2077
- {
2078
- padding: 1,
2079
- margin: { top: 0, bottom: 1, left: 2, right: 2 },
2080
- borderStyle: "round",
2081
- borderColor: "green",
2082
- align: "left"
2083
- }
2084
- )
2085
- );
2086
- process.exit(0);
2087
- } catch (error) {
2088
- spinner.fail(colors.red("\u66F4\u65B0\u5931\u8D25"));
2089
- console.log("");
2090
- console.log(colors.dim(" \u4F60\u53EF\u4EE5\u624B\u52A8\u8FD0\u884C\u4EE5\u4E0B\u547D\u4EE4\u66F4\u65B0:"));
2091
- console.log(colors.cyan(` npm install -g ${packageName}@latest`));
2092
- console.log("");
2093
- }
2094
- }
2095
- function readCache() {
2096
- try {
2097
- const cacheFile = join3(homedir3(), CACHE_FILE);
2098
- if (!existsSync3(cacheFile)) {
2099
- return null;
2100
- }
2101
- const content = readFileSync3(cacheFile, "utf-8");
2102
- return JSON.parse(content);
2103
- } catch {
2104
- return null;
2105
- }
2106
- }
2107
- function writeCache(cache) {
2108
- try {
2109
- const cacheFile = join3(homedir3(), CACHE_FILE);
2110
- writeFileSync3(cacheFile, JSON.stringify(cache), "utf-8");
2111
- } catch {
2112
- }
2113
- }
2214
+ // src/index.ts
2215
+ init_update_notifier();
2114
2216
 
2115
2217
  // src/commands/update.ts
2218
+ init_utils();
2116
2219
  import { execSync as execSync7 } from "child_process";
2117
2220
  import ora6 from "ora";
2118
2221
  import boxen2 from "boxen";
2222
+ import semver2 from "semver";
2223
+ import { existsSync as existsSync4, unlinkSync as unlinkSync2 } from "fs";
2224
+ import { homedir as homedir4 } from "os";
2225
+ import { join as join4 } from "path";
2226
+ var CACHE_FILE2 = ".gw-update-check";
2227
+ function clearUpdateCache2() {
2228
+ try {
2229
+ const cacheFile = join4(homedir4(), CACHE_FILE2);
2230
+ if (existsSync4(cacheFile)) {
2231
+ unlinkSync2(cacheFile);
2232
+ }
2233
+ } catch {
2234
+ }
2235
+ }
2119
2236
  async function getLatestVersion2(packageName) {
2120
2237
  try {
2121
2238
  const result = execSync7(`npm view ${packageName} version`, {
@@ -2142,11 +2259,11 @@ async function update(currentVersion) {
2142
2259
  return;
2143
2260
  }
2144
2261
  spinner.stop();
2145
- if (latestVersion === currentVersion) {
2262
+ if (semver2.gte(currentVersion, latestVersion)) {
2146
2263
  console.log(
2147
2264
  boxen2(
2148
2265
  [
2149
- colors.bold("\u2705 \u5DF2\u662F\u6700\u65B0\u7248\u672C"),
2266
+ colors.green(colors.bold("\u2705 \u5DF2\u662F\u6700\u65B0\u7248\u672C")),
2150
2267
  "",
2151
2268
  `\u5F53\u524D\u7248\u672C: ${colors.green(currentVersion)}`
2152
2269
  ].join("\n"),
@@ -2161,21 +2278,29 @@ async function update(currentVersion) {
2161
2278
  );
2162
2279
  return;
2163
2280
  }
2281
+ const versionText = `${currentVersion} \u2192 ${latestVersion}`;
2282
+ const maxWidth = Math.max(
2283
+ "\u{1F389} \u53D1\u73B0\u65B0\u7248\u672C\uFF01".length,
2284
+ versionText.length,
2285
+ "\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01".length,
2286
+ "\u8BF7\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u4F7F\u7528\u65B0\u7248\u672C".length
2287
+ );
2164
2288
  console.log(
2165
2289
  boxen2(
2166
2290
  [
2167
- colors.bold("\u{1F389} \u53D1\u73B0\u65B0\u7248\u672C\uFF01"),
2291
+ colors.yellow(colors.bold("\u{1F389} \u53D1\u73B0\u65B0\u7248\u672C\uFF01")),
2168
2292
  "",
2169
2293
  `${colors.dim(currentVersion)} \u2192 ${colors.green(
2170
2294
  colors.bold(latestVersion)
2171
2295
  )}`
2172
2296
  ].join("\n"),
2173
2297
  {
2174
- padding: 1,
2298
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
2175
2299
  margin: { top: 0, bottom: 1, left: 2, right: 2 },
2176
2300
  borderStyle: "round",
2177
2301
  borderColor: "yellow",
2178
- align: "left"
2302
+ align: "center",
2303
+ width: 40
2179
2304
  }
2180
2305
  )
2181
2306
  );
@@ -2185,20 +2310,22 @@ async function update(currentVersion) {
2185
2310
  stdio: ["pipe", "pipe", "pipe"]
2186
2311
  });
2187
2312
  updateSpinner.succeed(colors.green("\u66F4\u65B0\u6210\u529F\uFF01"));
2313
+ clearUpdateCache2();
2188
2314
  console.log("");
2189
2315
  console.log(
2190
2316
  boxen2(
2191
2317
  [
2192
- colors.bold("\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01"),
2318
+ colors.green(colors.bold("\u2728 \u66F4\u65B0\u5B8C\u6210\uFF01")),
2193
2319
  "",
2194
2320
  colors.dim("\u8BF7\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u4F7F\u7528\u65B0\u7248\u672C")
2195
2321
  ].join("\n"),
2196
2322
  {
2197
- padding: 1,
2323
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
2198
2324
  margin: { top: 0, bottom: 1, left: 2, right: 2 },
2199
2325
  borderStyle: "round",
2200
2326
  borderColor: "green",
2201
- align: "left"
2327
+ align: "center",
2328
+ width: 40
2202
2329
  }
2203
2330
  )
2204
2331
  );
@@ -2238,7 +2365,7 @@ process.on("SIGTERM", () => {
2238
2365
  console.log("");
2239
2366
  process.exit(0);
2240
2367
  });
2241
- var version = true ? "0.2.19" : "0.0.0-dev";
2368
+ var version = true ? "0.2.20" : "0.0.0-dev";
2242
2369
  async function mainMenu() {
2243
2370
  console.log(
2244
2371
  colors.green(`
@@ -2357,7 +2484,7 @@ async function mainMenu() {
2357
2484
  }
2358
2485
  var cli = cac("gw");
2359
2486
  cli.command("", "\u663E\u793A\u4EA4\u4E92\u5F0F\u83DC\u5355").action(async () => {
2360
- await checkForUpdates(version, "@zjex/git-workflow");
2487
+ await checkForUpdates(version, "@zjex/git-workflow", true);
2361
2488
  return mainMenu();
2362
2489
  });
2363
2490
  cli.command("feature", "\u521B\u5EFA feature \u5206\u652F").alias("feat").alias("f").option("--base <branch>", "\u6307\u5B9A\u57FA\u7840\u5206\u652F").action(async (options) => {
@@ -2416,6 +2543,13 @@ cli.command("commit", "\u4EA4\u4E92\u5F0F\u63D0\u4EA4 (Conventional Commits + Gi
2416
2543
  cli.command("update", "\u68C0\u67E5\u5E76\u66F4\u65B0\u5230\u6700\u65B0\u7248\u672C").alias("upt").action(async () => {
2417
2544
  return update(version);
2418
2545
  });
2546
+ cli.command("clean", "\u6E05\u7406\u7F13\u5B58\u6587\u4EF6").action(async () => {
2547
+ const { clearUpdateCache: clearUpdateCache3 } = await Promise.resolve().then(() => (init_update_notifier(), update_notifier_exports));
2548
+ clearUpdateCache3();
2549
+ console.log("");
2550
+ console.log(colors.green("\u2714 \u7F13\u5B58\u5DF2\u6E05\u7406"));
2551
+ console.log("");
2552
+ });
2419
2553
  cli.help((sections) => {
2420
2554
  sections.push({
2421
2555
  body: showHelp()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zjex/git-workflow",
3
- "version": "0.2.19",
3
+ "version": "0.2.20",
4
4
  "description": "🚀 极简的 Git 工作流 CLI 工具,让分支管理和版本发布变得轻松愉快",
5
5
  "type": "module",
6
6
  "bin": {
@@ -42,10 +42,12 @@
42
42
  "@inquirer/prompts": "^7.0.0",
43
43
  "boxen": "^8.0.1",
44
44
  "cac": "^6.7.14",
45
- "ora": "^9.0.0"
45
+ "ora": "^9.0.0",
46
+ "semver": "^7.7.3"
46
47
  },
47
48
  "devDependencies": {
48
49
  "@types/node": "^25.0.3",
50
+ "@types/semver": "^7.7.1",
49
51
  "changelogen": "^0.6.2",
50
52
  "husky": "^9.1.7",
51
53
  "tsup": "^8.5.1",
@@ -42,6 +42,9 @@ Tag 命令:
42
42
  gw update 检查并更新到最新版本
43
43
  gw upt 同上 (别名)
44
44
 
45
+ 清理命令:
46
+ gw clean 清理缓存文件
47
+
45
48
  Stash 命令:
46
49
  gw stash 交互式管理 stash
47
50
  gw s 同上 (别名)
@@ -1,8 +1,28 @@
1
1
  import { execSync } from "child_process";
2
2
  import ora from "ora";
3
3
  import boxen from "boxen";
4
+ import semver from "semver";
5
+ import { existsSync, unlinkSync } from "fs";
6
+ import { homedir } from "os";
7
+ import { join } from "path";
4
8
  import { colors } from "../utils.js";
5
9
 
10
+ const CACHE_FILE = ".gw-update-check";
11
+
12
+ /**
13
+ * 清理更新缓存文件
14
+ */
15
+ function clearUpdateCache(): void {
16
+ try {
17
+ const cacheFile = join(homedir(), CACHE_FILE);
18
+ if (existsSync(cacheFile)) {
19
+ unlinkSync(cacheFile);
20
+ }
21
+ } catch {
22
+ // 静默失败
23
+ }
24
+ }
25
+
6
26
  /**
7
27
  * 获取 npm 上的最新版本
8
28
  */
@@ -42,11 +62,12 @@ export async function update(currentVersion: string): Promise<void> {
42
62
 
43
63
  spinner.stop();
44
64
 
45
- if (latestVersion === currentVersion) {
65
+ // 使用 semver 比较版本
66
+ if (semver.gte(currentVersion, latestVersion)) {
46
67
  console.log(
47
68
  boxen(
48
69
  [
49
- colors.bold("✅ 已是最新版本"),
70
+ colors.green(colors.bold("✅ 已是最新版本")),
50
71
  "",
51
72
  `当前版本: ${colors.green(currentVersion)}`,
52
73
  ].join("\n"),
@@ -63,21 +84,30 @@ export async function update(currentVersion: string): Promise<void> {
63
84
  }
64
85
 
65
86
  // 有新版本
87
+ const versionText = `${currentVersion} → ${latestVersion}`;
88
+ const maxWidth = Math.max(
89
+ "🎉 发现新版本!".length,
90
+ versionText.length,
91
+ "✨ 更新完成!".length,
92
+ "请重新打开终端使用新版本".length
93
+ );
94
+
66
95
  console.log(
67
96
  boxen(
68
97
  [
69
- colors.bold("🎉 发现新版本!"),
98
+ colors.yellow(colors.bold("🎉 发现新版本!")),
70
99
  "",
71
100
  `${colors.dim(currentVersion)} → ${colors.green(
72
101
  colors.bold(latestVersion)
73
102
  )}`,
74
103
  ].join("\n"),
75
104
  {
76
- padding: 1,
105
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
77
106
  margin: { top: 0, bottom: 1, left: 2, right: 2 },
78
107
  borderStyle: "round",
79
108
  borderColor: "yellow",
80
- align: "left",
109
+ align: "center",
110
+ width: 40,
81
111
  }
82
112
  )
83
113
  );
@@ -91,20 +121,25 @@ export async function update(currentVersion: string): Promise<void> {
91
121
  });
92
122
 
93
123
  updateSpinner.succeed(colors.green("更新成功!"));
124
+
125
+ // 清理缓存文件
126
+ clearUpdateCache();
127
+
94
128
  console.log("");
95
129
  console.log(
96
130
  boxen(
97
131
  [
98
- colors.bold("✨ 更新完成!"),
132
+ colors.green(colors.bold("✨ 更新完成!")),
99
133
  "",
100
134
  colors.dim("请重新打开终端使用新版本"),
101
135
  ].join("\n"),
102
136
  {
103
- padding: 1,
137
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
104
138
  margin: { top: 0, bottom: 1, left: 2, right: 2 },
105
139
  borderStyle: "round",
106
140
  borderColor: "green",
107
- align: "left",
141
+ align: "center",
142
+ width: 40,
108
143
  }
109
144
  )
110
145
  );
package/src/index.ts CHANGED
@@ -178,7 +178,7 @@ const cli = cac("gw");
178
178
 
179
179
  // 默认命令 - 显示交互式菜单
180
180
  cli.command("", "显示交互式菜单").action(async () => {
181
- await checkForUpdates(version, "@zjex/git-workflow");
181
+ await checkForUpdates(version, "@zjex/git-workflow", true);
182
182
  return mainMenu();
183
183
  });
184
184
 
@@ -290,6 +290,14 @@ cli
290
290
  return update(version);
291
291
  });
292
292
 
293
+ cli.command("clean", "清理缓存文件").action(async () => {
294
+ const { clearUpdateCache } = await import("./update-notifier.js");
295
+ clearUpdateCache();
296
+ console.log("");
297
+ console.log(colors.green("✔ 缓存已清理"));
298
+ console.log("");
299
+ });
300
+
293
301
  cli.help((sections) => {
294
302
  sections.push({
295
303
  body: showHelp(),
@@ -1,57 +1,72 @@
1
1
  import { execSync } from "child_process";
2
- import { readFileSync, writeFileSync, existsSync } from "fs";
2
+ import { readFileSync, writeFileSync, existsSync, unlinkSync } from "fs";
3
3
  import { homedir } from "os";
4
4
  import { join } from "path";
5
5
  import boxen from "boxen";
6
6
  import { select } from "@inquirer/prompts";
7
7
  import ora from "ora";
8
+ import semver from "semver";
8
9
  import { colors } from "./utils.js";
9
10
 
11
+ const CHECK_INTERVAL = 1000 * 60 * 60 * 4; // 4 小时检查一次
10
12
  const DISMISS_INTERVAL = 1000 * 60 * 60 * 24; // 24 小时后再次提示
11
13
  const CACHE_FILE = ".gw-update-check";
12
14
 
13
15
  interface UpdateCache {
16
+ lastCheck?: number; // 上次检查更新的时间
14
17
  lastDismiss?: number; // 用户上次关闭提示的时间
15
- latestVersion?: string;
18
+ latestVersion?: string; // 最新版本号
19
+ checkedVersion?: string; // 检查时的当前版本
16
20
  }
17
21
 
18
22
  /**
19
- * 检查是否有新版本
23
+ * 检查是否有新版本(异步静默检查)
24
+ * @param currentVersion 当前版本
25
+ * @param packageName 包名
26
+ * @param interactive 是否交互式(true: 显示完整提示并可选择更新,false: 只显示简单提示)
20
27
  */
21
28
  export async function checkForUpdates(
22
29
  currentVersion: string,
23
- packageName: string = "@zjex/git-workflow"
30
+ packageName: string = "@zjex/git-workflow",
31
+ interactive: boolean = false
24
32
  ): Promise<void> {
25
33
  try {
26
- // 读取缓存
27
34
  const cache = readCache();
28
35
  const now = Date.now();
29
36
 
30
- // 如果用户在 24 小时内关闭过提示,跳过
31
- if (cache?.lastDismiss && now - cache.lastDismiss < DISMISS_INTERVAL) {
32
- return;
33
- }
37
+ // 1. 先检查缓存中是否有新版本需要提示
38
+ if (cache?.latestVersion && cache.checkedVersion === currentVersion) {
39
+ // 如果用户在 24 小时内关闭过提示,跳过
40
+ if (cache.lastDismiss && now - cache.lastDismiss < DISMISS_INTERVAL) {
41
+ // 继续后台检查(不阻塞)
42
+ backgroundCheck(currentVersion, packageName);
43
+ return;
44
+ }
45
+
46
+ // 使用 semver 比较版本
47
+ if (semver.gt(cache.latestVersion, currentVersion)) {
48
+ if (interactive) {
49
+ // 交互式模式:显示完整提示,可选择更新
50
+ const action = await showUpdateMessage(
51
+ currentVersion,
52
+ cache.latestVersion,
53
+ packageName
54
+ );
34
55
 
35
- // 获取最新版本
36
- const latestVersion = await getLatestVersion(packageName);
37
-
38
- // 如果有新版本,显示提示
39
- if (latestVersion && latestVersion !== currentVersion) {
40
- const action = await showUpdateMessage(
41
- currentVersion,
42
- latestVersion,
43
- packageName
44
- );
45
-
46
- if (action === "update") {
47
- // 用户选择立即更新
48
- await performUpdate(packageName);
49
- } else if (action === "dismiss") {
50
- // 用户选择跳过,记录时间
51
- writeCache({ lastDismiss: now, latestVersion });
56
+ if (action === "update") {
57
+ await performUpdate(packageName);
58
+ } else if (action === "dismiss") {
59
+ writeCache({ ...cache, lastDismiss: now });
60
+ }
61
+ } else {
62
+ // 非交互式模式:只显示简单提示
63
+ showSimpleNotification(currentVersion, cache.latestVersion);
64
+ }
52
65
  }
53
- // action === "continue" 时直接继续,不记录
54
66
  }
67
+
68
+ // 2. 后台异步检查更新(不阻塞当前命令)
69
+ backgroundCheck(currentVersion, packageName);
55
70
  } catch (error) {
56
71
  // 如果是用户按 Ctrl+C,重新抛出让全局处理
57
72
  if (error?.constructor?.name === "ExitPromptError") {
@@ -61,6 +76,37 @@ export async function checkForUpdates(
61
76
  }
62
77
  }
63
78
 
79
+ /**
80
+ * 后台异步检查更新(不阻塞)
81
+ */
82
+ function backgroundCheck(currentVersion: string, packageName: string): void {
83
+ const cache = readCache();
84
+ const now = Date.now();
85
+
86
+ // 如果距离上次检查不到 4 小时,跳过
87
+ if (cache?.lastCheck && now - cache.lastCheck < CHECK_INTERVAL) {
88
+ return;
89
+ }
90
+
91
+ // 使用 Promise 异步执行,不阻塞当前命令
92
+ Promise.resolve().then(async () => {
93
+ try {
94
+ const latestVersion = await getLatestVersion(packageName);
95
+
96
+ if (latestVersion) {
97
+ writeCache({
98
+ ...cache,
99
+ lastCheck: now,
100
+ latestVersion,
101
+ checkedVersion: currentVersion,
102
+ });
103
+ }
104
+ } catch {
105
+ // 静默失败
106
+ }
107
+ });
108
+ }
109
+
64
110
  /**
65
111
  * 获取 npm 上的最新版本
66
112
  */
@@ -78,7 +124,29 @@ async function getLatestVersion(packageName: string): Promise<string | null> {
78
124
  }
79
125
 
80
126
  /**
81
- * 显示更新提示消息并让用户选择
127
+ * 显示简单的更新通知(非交互式,不阻塞)
128
+ */
129
+ function showSimpleNotification(current: string, latest: string): void {
130
+ const message = `${colors.yellow("🎉 发现新版本")} ${colors.dim(
131
+ current
132
+ )} → ${colors.green(latest)} ${colors.dim("运行")} ${colors.cyan(
133
+ "gw update"
134
+ )} ${colors.dim("更新")}`;
135
+
136
+ console.log("");
137
+ console.log(
138
+ boxen(message, {
139
+ padding: { top: 0, bottom: 0, left: 2, right: 2 },
140
+ margin: { top: 0, bottom: 1, left: 0, right: 0 },
141
+ borderStyle: "round",
142
+ borderColor: "yellow",
143
+ align: "center",
144
+ })
145
+ );
146
+ }
147
+
148
+ /**
149
+ * 显示更新提示消息并让用户选择(交互式)
82
150
  * @returns "update" | "continue" | "dismiss"
83
151
  */
84
152
  async function showUpdateMessage(
@@ -87,7 +155,7 @@ async function showUpdateMessage(
87
155
  packageName: string
88
156
  ): Promise<"update" | "continue" | "dismiss"> {
89
157
  const message = [
90
- colors.bold(" 发现新版新本可用!"),
158
+ colors.yellow(colors.bold("🎉 发现新版本!")),
91
159
  "",
92
160
  `${colors.dim(current)} → ${colors.green(colors.bold(latest))}`,
93
161
  ].join("\n");
@@ -95,11 +163,12 @@ async function showUpdateMessage(
95
163
  console.log("");
96
164
  console.log(
97
165
  boxen(message, {
98
- padding: 1,
166
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
99
167
  margin: 1,
100
168
  borderStyle: "round",
101
169
  borderColor: "yellow",
102
- align: "left",
170
+ align: "center",
171
+ width: 40,
103
172
  })
104
173
  );
105
174
 
@@ -152,20 +221,25 @@ async function performUpdate(packageName: string): Promise<void> {
152
221
  });
153
222
 
154
223
  spinner.succeed(colors.green("更新成功!"));
224
+
225
+ // 清理缓存文件
226
+ clearUpdateCache();
227
+
155
228
  console.log("");
156
229
  console.log(
157
230
  boxen(
158
231
  [
159
- colors.bold("✨ 更新完成!"),
232
+ colors.green(colors.bold("✨ 更新完成!")),
160
233
  "",
161
234
  colors.dim("请重新打开终端使用新版本"),
162
235
  ].join("\n"),
163
236
  {
164
- padding: 1,
237
+ padding: { top: 1, bottom: 1, left: 3, right: 3 },
165
238
  margin: { top: 0, bottom: 1, left: 2, right: 2 },
166
239
  borderStyle: "round",
167
240
  borderColor: "green",
168
- align: "left",
241
+ align: "center",
242
+ width: 40,
169
243
  }
170
244
  )
171
245
  );
@@ -181,6 +255,20 @@ async function performUpdate(packageName: string): Promise<void> {
181
255
  }
182
256
  }
183
257
 
258
+ /**
259
+ * 清理更新缓存文件
260
+ */
261
+ export function clearUpdateCache(): void {
262
+ try {
263
+ const cacheFile = join(homedir(), CACHE_FILE);
264
+ if (existsSync(cacheFile)) {
265
+ unlinkSync(cacheFile);
266
+ }
267
+ } catch {
268
+ // 静默失败
269
+ }
270
+ }
271
+
184
272
  /**
185
273
  * 读取缓存
186
274
  */