zen-gitsync 2.11.39 → 2.12.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE +190 -21
  2. package/README.md +695 -695
  3. package/index.js +25 -11
  4. package/package.json +2 -2
  5. package/scripts/convert-colors-to-vars.cjs +286 -272
  6. package/scripts/convert-fontsize-to-vars.cjs +221 -207
  7. package/scripts/convert-spacing-to-vars.cjs +256 -242
  8. package/scripts/convert-to-standard-vars.cjs +282 -268
  9. package/scripts/release.js +599 -585
  10. package/src/config.js +350 -336
  11. package/src/gitCommit.js +455 -440
  12. package/src/ui/public/assets/EditorView-CbqSI9nw.css +1 -0
  13. package/src/ui/public/assets/EditorView-GS5cmh99.js +21 -0
  14. package/src/ui/public/assets/SourceMapView-DyMK80hS.css +1 -0
  15. package/src/ui/public/assets/SourceMapView-_YRtzmZZ.js +3 -0
  16. package/src/ui/public/assets/index-ML5Y-5lO.css +1 -0
  17. package/src/ui/public/assets/index-yky0Sd13.js +73 -0
  18. package/src/ui/public/assets/{ts.worker-Dth06zuC.js → ts.worker-METxwbDZ.js} +1 -16
  19. package/src/ui/public/assets/{vendor-B1T2uxYO.js → vendor-DITsiaGj.js} +294 -287
  20. package/src/ui/public/assets/vendor-q83wvJns.css +1 -0
  21. package/src/ui/public/index.html +4 -4
  22. package/src/ui/server/.claude/codediff.txt +6 -0
  23. package/src/ui/server/index.js +410 -396
  24. package/src/ui/server/middleware/requestLogger.js +51 -37
  25. package/src/ui/server/routes/branchStatus.js +101 -87
  26. package/src/ui/server/routes/code.js +110 -96
  27. package/src/ui/server/routes/codeAnalysis.js +995 -981
  28. package/src/ui/server/routes/config.js +1172 -1158
  29. package/src/ui/server/routes/exec.js +272 -258
  30. package/src/ui/server/routes/fileOpen.js +279 -265
  31. package/src/ui/server/routes/fs.js +701 -699
  32. package/src/ui/server/routes/git/diff.js +352 -338
  33. package/src/ui/server/routes/git/diffUtils.js +128 -114
  34. package/src/ui/server/routes/git/stash.js +552 -538
  35. package/src/ui/server/routes/git/tags.js +172 -158
  36. package/src/ui/server/routes/git.js +190 -176
  37. package/src/ui/server/routes/gitOps.js +1179 -1165
  38. package/src/ui/server/routes/instances.js +38 -24
  39. package/src/ui/server/routes/npm.js +1023 -1009
  40. package/src/ui/server/routes/process.js +82 -68
  41. package/src/ui/server/routes/status.js +67 -53
  42. package/src/ui/server/routes/terminal.js +319 -305
  43. package/src/ui/server/socket/registerUiSocketHandlers.js +226 -212
  44. package/src/ui/server/utils/createSavePortToFile.js +46 -32
  45. package/src/ui/server/utils/instanceRegistry.js +270 -256
  46. package/src/ui/server/utils/pathGuard.js +155 -0
  47. package/src/ui/server/utils/pathGuard.test.js +138 -0
  48. package/src/ui/server/utils/randomStartPort.js +51 -37
  49. package/src/ui/server/utils/startServerOnAvailablePort.js +101 -87
  50. package/src/utils/index.js +1058 -1044
  51. package/src/ui/public/assets/devopicons-QN4QXivI.woff2 +0 -0
  52. package/src/ui/public/assets/file-icons-C0jOugUK.woff2 +0 -0
  53. package/src/ui/public/assets/fontawesome-B-jkhYfk.woff2 +0 -0
  54. package/src/ui/public/assets/index-BvVl-092.js +0 -95
  55. package/src/ui/public/assets/index-DXO3Lvqi.css +0 -1
  56. package/src/ui/public/assets/mfixx-CpAhKOZz.woff2 +0 -0
  57. package/src/ui/public/assets/octicons-CaZ_fok2.woff2 +0 -0
  58. package/src/ui/public/assets/vendor-hOO_r_AU.css +0 -1
@@ -1,585 +1,599 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * 发布前准备工作
5
- * 1. 更新版本号(最后一位加1)
6
- * 2. 构建前端项目
7
- * 3. 提交更改到git
8
- * 4. 发布到npm
9
- */
10
-
11
- import fs from 'fs';
12
- import path from 'path';
13
- import { fileURLToPath } from 'url';
14
- import { execSync } from 'child_process';
15
- import chalk from 'chalk';
16
- import readline from 'readline/promises';
17
-
18
- // 获取项目根目录
19
- const __filename = fileURLToPath(import.meta.url);
20
- const __dirname = path.dirname(__filename);
21
- const rootDir = path.resolve(__dirname, '..');
22
-
23
- // 创建readline接口函数
24
- function createReadlineInterface() {
25
- return readline.createInterface({
26
- input: process.stdin,
27
- output: process.stdout
28
- });
29
- }
30
-
31
- // 读取package.json
32
- const packageJsonPath = path.join(rootDir, 'package.json');
33
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
34
-
35
- // 尝试终止可能正在运行的Git进程
36
- function terminateGitProcesses() {
37
- console.log(chalk.yellow('尝试终止可能正在运行的Git进程...'));
38
-
39
- try {
40
- // 在Windows上
41
- if (process.platform === 'win32') {
42
- try {
43
- execSync('taskkill /f /im git.exe /t', { stdio: 'ignore' });
44
- console.log(chalk.green('已终止Git进程'));
45
- } catch (e) {
46
- // 可能没有正在运行的进程,忽略错误
47
- console.log(chalk.gray('没有找到正在运行的Git进程'));
48
- }
49
- }
50
- // 在Linux/MacOS上
51
- else {
52
- try {
53
- execSync("pkill -f 'git' || true", { stdio: 'ignore' });
54
- console.log(chalk.green('已终止Git进程'));
55
- } catch (e) {
56
- // 忽略错误
57
- console.log(chalk.gray('没有找到正在运行的Git进程'));
58
- }
59
- }
60
-
61
- // 等待进程终止
62
- console.log(chalk.gray('等待进程终止...'));
63
- execSync('sleep 2 || ping -n 3 127.0.0.1 > nul', { stdio: 'ignore' });
64
- } catch (error) {
65
- console.log(chalk.yellow('终止Git进程失败,但将继续尝试清理锁文件'));
66
- }
67
- }
68
-
69
- // 询问是否继续执行
70
- async function askContinue(message) {
71
- const rl = createReadlineInterface();
72
-
73
- try {
74
- const answer = await rl.question(message);
75
- // 如果是空字符串(直接回车)或者是"y",都返回true
76
- return answer.toLowerCase() === 'y' || answer.trim() === '';
77
- } finally {
78
- rl.close();
79
- }
80
- }
81
-
82
- // 检查并清理Git锁文件
83
- async function checkAndCleanGitLocks() {
84
- console.log(chalk.gray('检查Git锁文件...'));
85
-
86
- const gitDir = path.join(rootDir, '.git');
87
-
88
- // 可能的锁文件列表
89
- const lockFiles = [
90
- path.join(gitDir, 'index.lock'),
91
- path.join(gitDir, 'HEAD.lock'),
92
- path.join(gitDir, 'config.lock'),
93
- path.join(gitDir, 'refs', 'heads', '*.lock'),
94
- path.join(gitDir, 'packed-refs.lock')
95
- ];
96
-
97
- // 检查并清理每个锁文件
98
- let foundLocks = false;
99
- let hasBusyLocks = false;
100
-
101
- lockFiles.forEach(lockPattern => {
102
- // 处理通配符模式
103
- if (lockPattern.includes('*')) {
104
- const baseDir = path.dirname(lockPattern);
105
- const pattern = path.basename(lockPattern);
106
-
107
- try {
108
- // 确保目录存在
109
- if (fs.existsSync(baseDir)) {
110
- const files = fs.readdirSync(baseDir);
111
- files.forEach(file => {
112
- if (file.endsWith('.lock')) {
113
- const lockPath = path.join(baseDir, file);
114
- foundLocks = true;
115
- console.log(chalk.yellow(`发现Git锁文件: ${lockPath}`));
116
-
117
- try {
118
- fs.unlinkSync(lockPath);
119
- console.log(chalk.green(`成功删除Git锁文件: ${lockPath}`));
120
- } catch (error) {
121
- hasBusyLocks = true;
122
- console.error(chalk.red(`无法删除Git锁文件 ${lockPath}:`), error);
123
- console.log(chalk.yellow('文件可能正被进程使用,尝试终止Git进程后重试'));
124
- }
125
- }
126
- });
127
- }
128
- } catch (error) {
129
- console.log(chalk.gray(`无法检查目录 ${baseDir}: ${error.message}`));
130
- }
131
- } else {
132
- // 直接检查具体路径
133
- if (fs.existsSync(lockPattern)) {
134
- foundLocks = true;
135
- console.log(chalk.yellow(`发现Git锁文件: ${lockPattern}`));
136
-
137
- try {
138
- fs.unlinkSync(lockPattern);
139
- console.log(chalk.green(`成功删除Git锁文件: ${lockPattern}`));
140
- } catch (error) {
141
- hasBusyLocks = true;
142
- console.error(chalk.red(`无法删除Git锁文件 ${lockPattern}:`), error);
143
- console.log(chalk.yellow('文件可能正被进程使用,尝试终止Git进程后重试'));
144
- }
145
- }
146
- }
147
- });
148
-
149
- if (hasBusyLocks) {
150
- // 尝试终止Git进程
151
- terminateGitProcesses();
152
-
153
- // 再次尝试删除锁文件
154
- let stillHasBusyLocks = false;
155
-
156
- lockFiles.forEach(lockPattern => {
157
- if (!lockPattern.includes('*') && fs.existsSync(lockPattern)) {
158
- try {
159
- fs.unlinkSync(lockPattern);
160
- console.log(chalk.green(`成功删除Git锁文件: ${lockPattern}`));
161
- } catch (error) {
162
- stillHasBusyLocks = true;
163
- console.error(chalk.red(`仍然无法删除Git锁文件 ${lockPattern}`));
164
- }
165
- }
166
- });
167
-
168
- if (stillHasBusyLocks) {
169
- console.log(chalk.yellow('警告:一些Git锁文件无法删除。建议:'));
170
- console.log(chalk.yellow('1. 关闭所有可能使用Git的应用程序'));
171
- console.log(chalk.yellow('2. 手动删除上述锁文件'));
172
- console.log(chalk.yellow('3. 重新运行发布脚本'));
173
-
174
- // 询问是否要继续
175
- const shouldContinue = await askContinue(chalk.yellow('是否尝试继续执行?(Y/n): '));
176
-
177
- if (!shouldContinue) {
178
- console.log(chalk.yellow('用户选择终止发布过程'));
179
- process.exit(1);
180
- }
181
-
182
- console.log(chalk.yellow('尝试继续执行,但可能会失败...'));
183
- }
184
- } else if (!foundLocks) {
185
- console.log(chalk.gray('未发现Git锁文件,继续执行...'));
186
- }
187
-
188
- // 等待一下,确保文件系统操作完成
189
- execSync('sleep 1 || ping -n 2 127.0.0.1 > nul', { stdio: 'ignore' });
190
- }
191
-
192
- // 检查发布环境
193
- async function checkEnvironment() {
194
- console.log(chalk.blue('=== 检查发布环境 ==='));
195
-
196
- try {
197
- // 检查Git是否可用
198
- execSync('git --version', { stdio: 'ignore' });
199
-
200
- // 检查是否在Git仓库中
201
- execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
202
-
203
- // 清理可能的Git锁文件
204
- await checkAndCleanGitLocks();
205
-
206
- // 检查当前分支
207
- const currentBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
208
- console.log(chalk.gray(`当前Git分支: ${currentBranch}`));
209
-
210
- // 如果不在主分支上,询问是否继续
211
- if (currentBranch !== 'main' && currentBranch !== 'master') {
212
- const rl = createReadlineInterface();
213
-
214
- try {
215
- const answer = await rl.question(chalk.yellow(`当前不在主分支上,是否继续在 ${currentBranch} 分支上发布? (Y/n): `));
216
- if (answer.toLowerCase() === 'n') {
217
- throw '用户选择取消发布';
218
- }
219
- } finally {
220
- rl.close();
221
- }
222
- }
223
-
224
- // 检查工作区是否干净
225
- try {
226
- execSync('git diff --quiet && git diff --staged --quiet', { stdio: 'ignore' });
227
- console.log(chalk.green('Git工作区干净'));
228
- } catch (e) {
229
- console.log(chalk.yellow('Git工作区有未提交的更改'));
230
-
231
- // 显示未提交的更改
232
- console.log(chalk.gray('\n未提交的更改:'));
233
- execSync('git status -s', { stdio: 'inherit' });
234
- console.log(''); // 空行
235
-
236
- const rl = createReadlineInterface();
237
-
238
- try {
239
- const answer = await rl.question(chalk.yellow('有未提交的更改,是否继续发布? (Y/n): '));
240
- if (answer.toLowerCase() === 'n') {
241
- throw '用户选择取消发布';
242
- }
243
- } finally {
244
- rl.close();
245
- }
246
- }
247
-
248
- console.log(chalk.green('环境检查通过'));
249
- } catch (error) {
250
- if (error === '用户选择取消发布') {
251
- console.log(chalk.yellow('发布已取消'));
252
- process.exit(0);
253
- }
254
-
255
- console.error(chalk.red('环境检查失败:'), error);
256
- process.exit(1);
257
- }
258
- }
259
-
260
- // TSC 类型检查
261
- async function runTypeCheck() {
262
- console.log(chalk.blue('\n=== TypeScript 类型检查 ==='));
263
-
264
- const frontendDir = path.join(rootDir, 'src', 'ui', 'client');
265
- if (!fs.existsSync(frontendDir)) {
266
- console.log(chalk.yellow('前端项目目录不存在,跳过 TSC 检查'));
267
- return;
268
- }
269
-
270
- try {
271
- console.log(chalk.gray('执行 tsc --noEmit...'));
272
- execSync('npx tsc --noEmit', { cwd: frontendDir, stdio: 'inherit' });
273
- console.log(chalk.green('TSC 类型检查通过'));
274
- } catch (error) {
275
- console.error(chalk.red('TSC 类型检查失败,请修复以上错误后重新发布'));
276
- process.exit(1);
277
- }
278
- }
279
-
280
- // 更新版本号
281
- function updateVersion() {
282
- console.log(chalk.blue('=== 更新版本号 ==='));
283
-
284
- const currentVersion = packageJson.version;
285
- console.log(chalk.gray(`当前版本: ${currentVersion}`));
286
-
287
- // 拆分版本号
288
- const versionParts = currentVersion.split('.');
289
-
290
- // 递增最后一位版本号
291
- const lastPart = parseInt(versionParts[versionParts.length - 1], 10);
292
- versionParts[versionParts.length - 1] = (lastPart + 1).toString();
293
-
294
- // 重组版本号
295
- const newVersion = versionParts.join('.');
296
- packageJson.version = newVersion;
297
-
298
- // 写回package.json
299
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
300
-
301
- console.log(chalk.green(`版本号已更新: ${currentVersion} -> ${newVersion}`));
302
- return newVersion;
303
- }
304
-
305
- // 构建前端项目
306
- async function buildFrontend() {
307
- console.log(chalk.blue('\n=== 构建前端项目 ==='));
308
-
309
- try {
310
- // 检查前端项目目录是否存在
311
- const frontendDir = path.join(rootDir, 'src', 'ui', 'client');
312
- if (!fs.existsSync(frontendDir)) {
313
- console.log(chalk.yellow('前端项目目录不存在,跳过构建'));
314
- return;
315
- }
316
-
317
- // 检查前端依赖是否安装
318
- console.log(chalk.gray('检查前端依赖...'));
319
- const nodeModulesPath = path.join(frontendDir, 'node_modules');
320
- if (!fs.existsSync(nodeModulesPath)) {
321
- console.log(chalk.yellow('未找到前端依赖,开始安装...'));
322
- execSync('cd ./src/ui/client && npm install', { stdio: 'inherit' });
323
- console.log(chalk.green('前端依赖安装完成'));
324
- }
325
-
326
- // 安装Node.js类型定义(如果需要)
327
- try {
328
- const typesNodePath = path.join(nodeModulesPath, '@types', 'node');
329
- if (!fs.existsSync(typesNodePath)) {
330
- console.log(chalk.yellow('安装Node.js类型定义...'));
331
- execSync('cd ./src/ui/client && npm install --save-dev @types/node', { stdio: 'inherit' });
332
- }
333
- } catch (error) {
334
- console.log(chalk.yellow('安装Node.js类型定义失败,继续构建...'));
335
- }
336
-
337
- // 更新tsconfig.app.json以包含node类型(如果需要)
338
- try {
339
- const tsconfigAppPath = path.join(frontendDir, 'tsconfig.app.json');
340
- if (fs.existsSync(tsconfigAppPath)) {
341
- const tsconfig = JSON.parse(fs.readFileSync(tsconfigAppPath, 'utf8'));
342
- let needsUpdate = false;
343
-
344
- if (!tsconfig.compilerOptions) {
345
- tsconfig.compilerOptions = {};
346
- needsUpdate = true;
347
- }
348
-
349
- if (!tsconfig.compilerOptions.types) {
350
- tsconfig.compilerOptions.types = ['node'];
351
- needsUpdate = true;
352
- } else if (!tsconfig.compilerOptions.types.includes('node')) {
353
- tsconfig.compilerOptions.types.push('node');
354
- needsUpdate = true;
355
- }
356
-
357
- if (needsUpdate) {
358
- console.log(chalk.yellow('更新tsconfig.app.json以包含Node.js类型...'));
359
- fs.writeFileSync(tsconfigAppPath, JSON.stringify(tsconfig, null, 2), 'utf8');
360
- }
361
- }
362
- } catch (error) {
363
- console.log(`error ==>`, error)
364
- console.log(chalk.yellow('更新tsconfig失败,继续构建...'));
365
- }
366
-
367
- // 执行构建命令
368
- console.log(chalk.gray('执行构建命令...'));
369
- execSync('cd ./src/ui/client && npm run build', { stdio: 'inherit' });
370
- console.log(chalk.green('前端项目构建完成'));
371
- } catch (error) {
372
- console.error(chalk.red('前端项目构建失败:'), error);
373
-
374
- // 询问用户是否继续发布过程
375
- console.log(chalk.yellow('\n前端构建失败,但您可以选择继续发布过程。'));
376
- const rl = createReadlineInterface();
377
-
378
- try {
379
- const answer = await rl.question(chalk.yellow('是否继续发布流程?(Y/n): '));
380
- if (answer.toLowerCase() === 'n') {
381
- console.log(chalk.red('发布流程已取消'));
382
- process.exit(1);
383
- }
384
- console.log(chalk.yellow('继续发布流程...'));
385
- } finally {
386
- rl.close();
387
- }
388
- }
389
- }
390
-
391
- // 提交更改到git
392
- async function commitChanges(version) {
393
- console.log(chalk.blue('\n=== 提交更改到Git ==='));
394
-
395
- try {
396
- // 检查并清理可能的Git锁文件
397
- await checkAndCleanGitLocks();
398
-
399
- // 创建提交信息,包含版本号
400
- const commitMessage = `chore: 发布版本 v${version}`;
401
-
402
- // 禁用Git钩子以确保没有其他脚本干扰
403
- console.log(chalk.gray('临时禁用Git钩子...'));
404
- const gitHooksDir = path.join(rootDir, '.git', 'hooks');
405
- let renamedHooks = [];
406
-
407
- console.log(chalk.gray('添加更改文件...'));
408
- // 使用--force参数,避免可能的锁文件问题,但排除node_modules目录
409
- execSync('git add .', { stdio: 'inherit' });
410
-
411
- // 等待一下,确保文件系统同步
412
- console.log(chalk.gray('等待文件系统同步...'));
413
- execSync('sleep 1 || ping -n 2 127.0.0.1 > nul', { stdio: 'ignore' });
414
-
415
- console.log(chalk.gray('提交更改...'));
416
-
417
- // 尝试提交,如果失败则重试
418
- let committed = false;
419
- let attempts = 0;
420
- const maxAttempts = 3;
421
-
422
- while (!committed && attempts < maxAttempts) {
423
- attempts++;
424
-
425
- try {
426
- // 检查并清理Git锁文件
427
- if (attempts > 1) {
428
- await checkAndCleanGitLocks();
429
- console.log(chalk.yellow(`重试提交 (${attempts}/${maxAttempts})...`));
430
- // 稍等更长时间
431
- execSync('sleep 2 || ping -n 3 127.0.0.1 > nul', { stdio: 'ignore' });
432
- }
433
-
434
- // 使用--no-verify参数跳过钩子,避免可能的挂起
435
- execSync(`git commit --no-verify -m "${commitMessage}"`, { stdio: 'inherit' });
436
- committed = true;
437
- } catch (error) {
438
- if (attempts >= maxAttempts) {
439
- throw error; // 重试次数用完,抛出错误
440
- }
441
- console.log(chalk.yellow(`提交失败,将在2秒后重试...`));
442
- // 等待2秒后重试
443
- execSync('sleep 2 || ping -n 3 127.0.0.1 > nul', { stdio: 'ignore' });
444
- }
445
- }
446
-
447
- console.log(chalk.green(`更改已提交到Git,提交信息: "${commitMessage}"`));
448
-
449
- // 创建版本标签
450
- console.log(chalk.gray('创建版本标签...'));
451
- execSync(`git tag v${version}`, { stdio: 'inherit' });
452
- console.log(chalk.green(`已创建标签: v${version}`));
453
-
454
- // 默认推送到远程(注释掉确认提示)
455
- // const rl = createReadlineInterface();
456
-
457
- try {
458
- // const answer = await rl.question(chalk.yellow('是否推送代码和标签到远程仓库? (Y/n): '));
459
-
460
- // if (answer.toLowerCase() !== 'n') {
461
- try {
462
- // 获取当前分支
463
- const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
464
-
465
- console.log(chalk.gray(`推送代码到远程仓库,分支: ${branch}...`));
466
- execSync(`git push origin ${branch}`, { stdio: 'inherit' });
467
-
468
- console.log(chalk.gray('推送标签到远程仓库...'));
469
- execSync('git push origin --tags', { stdio: 'inherit' });
470
-
471
- console.log(chalk.green('代码和标签已成功推送到远程仓库'));
472
- } catch (pushError) {
473
- console.error(chalk.red('推送到远程仓库失败:'), pushError);
474
- // 继续发布过程,不终止
475
- }
476
- // } else {
477
- // console.log(chalk.yellow('跳过推送到远程仓库'));
478
- // }
479
- } finally {
480
- // rl.close();
481
-
482
- // 恢复Git钩子
483
- if (renamedHooks.length > 0) {
484
- console.log(chalk.gray('恢复Git钩子...'));
485
- for (const hook of renamedHooks) {
486
- try {
487
- fs.renameSync(hook.disabled, hook.original);
488
- } catch (e) {
489
- console.log(chalk.yellow(`无法恢复Git钩子: ${path.basename(hook.original)}`));
490
- }
491
- }
492
- console.log(chalk.gray(`已恢复 ${renamedHooks.length} 个Git钩子`));
493
- }
494
- }
495
- } catch (error) {
496
- console.error(chalk.red('Git提交失败:'), error);
497
- process.exit(1);
498
- }
499
- }
500
-
501
- // 发布到NPM
502
- async function publishToNpm() {
503
- console.log(chalk.blue('\n=== 发布到NPM ==='));
504
-
505
- // 默认发布到NPM(注释掉确认提示)
506
- // const rl = createReadlineInterface();
507
-
508
- try {
509
- // 等待用户确认
510
- // const answer = await rl.question(chalk.yellow('是否发布到NPM? (Y/n): '));
511
-
512
- // if (answer.toLowerCase() === 'n') {
513
- // console.log(chalk.yellow('跳过发布到NPM'));
514
- // return;
515
- // }
516
-
517
- // 执行npm发布
518
- console.log(chalk.gray('执行npm发布...'));
519
- try {
520
- execSync('npm publish --registry=https://registry.npmjs.org/', { stdio: 'inherit' });
521
- console.log(chalk.green('已成功发布到NPM'));
522
-
523
- // 发布成功后执行更新和查看命令
524
- console.log(chalk.blue('\n=== 发布后操作 ==='));
525
-
526
- try {
527
- console.log(chalk.gray('执行 npm run update:g...'));
528
- execSync('npm run update:g', { stdio: 'inherit' });
529
- console.log(chalk.green('✅ update:g 执行完成'));
530
- } catch (error) {
531
- console.error(chalk.red('❌ update:g 执行失败:'), error.message);
532
- }
533
-
534
- try {
535
- console.log(chalk.gray('执行 npm run npm:ls:g...'));
536
- execSync('npm run npm:ls:g', { stdio: 'inherit' });
537
- console.log(chalk.green('✅ npm:ls:g 执行完成'));
538
- } catch (error) {
539
- console.error(chalk.red('❌ npm:ls:g 执行失败:'), error.message);
540
- }
541
-
542
- } catch (error) {
543
- console.error(chalk.red('发布到NPM失败:'), error);
544
- throw error;
545
- }
546
- } finally {
547
- // rl.close();
548
- }
549
- }
550
-
551
- // 主流程
552
- async function main() {
553
- console.log(chalk.cyan('\n🚀 开始发布流程...\n'));
554
-
555
- try {
556
- // 1. 检查环境
557
- await checkEnvironment();
558
-
559
- // 2. TSC 类型检查
560
- await runTypeCheck();
561
-
562
- // 3. 更新版本号
563
- const newVersion = updateVersion();
564
-
565
- // 4. 构建前端项目
566
- await buildFrontend();
567
-
568
- // 5. 提交更改到Git
569
- await commitChanges(newVersion);
570
-
571
- // 6. 发布到NPM
572
- await publishToNpm();
573
-
574
- console.log(chalk.green('\n🎉 发布完成!'));
575
- } catch (error) {
576
- console.error(chalk.red('\n❌ 发布失败:'), error);
577
- process.exit(1);
578
- }
579
- }
580
-
581
- // 启动流程
582
- main().catch(error => {
583
- console.error(chalk.red('\n❌ 未捕获的错误:'), error);
584
- process.exit(1);
585
- });
1
+ #!/usr/bin/env node
2
+ // Copyright 2026 xz333221
3
+ //
4
+ // Licensed under the Apache License, Version 2.0 (the "License");
5
+ // you may not use this file except in compliance with the License.
6
+ // You may obtain a copy of the License at
7
+ //
8
+ // http://www.apache.org/licenses/LICENSE-2.0
9
+ //
10
+ // Unless required by applicable law or agreed to in writing, software
11
+ // distributed under the License is distributed on an "AS IS" BASIS,
12
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ // See the License for the specific language governing permissions and
14
+ // limitations under the License.
15
+ //
16
+
17
+ /**
18
+ * 发布前准备工作
19
+ * 1. 更新版本号(最后一位加1)
20
+ * 2. 构建前端项目
21
+ * 3. 提交更改到git
22
+ * 4. 发布到npm
23
+ */
24
+
25
+ import fs from 'fs';
26
+ import path from 'path';
27
+ import { fileURLToPath } from 'url';
28
+ import { execSync } from 'child_process';
29
+ import chalk from 'chalk';
30
+ import readline from 'readline/promises';
31
+
32
+ // 获取项目根目录
33
+ const __filename = fileURLToPath(import.meta.url);
34
+ const __dirname = path.dirname(__filename);
35
+ const rootDir = path.resolve(__dirname, '..');
36
+
37
+ // 创建readline接口函数
38
+ function createReadlineInterface() {
39
+ return readline.createInterface({
40
+ input: process.stdin,
41
+ output: process.stdout
42
+ });
43
+ }
44
+
45
+ // 读取package.json
46
+ const packageJsonPath = path.join(rootDir, 'package.json');
47
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
48
+
49
+ // 尝试终止可能正在运行的Git进程
50
+ function terminateGitProcesses() {
51
+ console.log(chalk.yellow('尝试终止可能正在运行的Git进程...'));
52
+
53
+ try {
54
+ // 在Windows上
55
+ if (process.platform === 'win32') {
56
+ try {
57
+ execSync('taskkill /f /im git.exe /t', { stdio: 'ignore' });
58
+ console.log(chalk.green('已终止Git进程'));
59
+ } catch (e) {
60
+ // 可能没有正在运行的进程,忽略错误
61
+ console.log(chalk.gray('没有找到正在运行的Git进程'));
62
+ }
63
+ }
64
+ // 在Linux/MacOS上
65
+ else {
66
+ try {
67
+ execSync("pkill -f 'git' || true", { stdio: 'ignore' });
68
+ console.log(chalk.green('已终止Git进程'));
69
+ } catch (e) {
70
+ // 忽略错误
71
+ console.log(chalk.gray('没有找到正在运行的Git进程'));
72
+ }
73
+ }
74
+
75
+ // 等待进程终止
76
+ console.log(chalk.gray('等待进程终止...'));
77
+ execSync('sleep 2 || ping -n 3 127.0.0.1 > nul', { stdio: 'ignore' });
78
+ } catch (error) {
79
+ console.log(chalk.yellow('终止Git进程失败,但将继续尝试清理锁文件'));
80
+ }
81
+ }
82
+
83
+ // 询问是否继续执行
84
+ async function askContinue(message) {
85
+ const rl = createReadlineInterface();
86
+
87
+ try {
88
+ const answer = await rl.question(message);
89
+ // 如果是空字符串(直接回车)或者是"y",都返回true
90
+ return answer.toLowerCase() === 'y' || answer.trim() === '';
91
+ } finally {
92
+ rl.close();
93
+ }
94
+ }
95
+
96
+ // 检查并清理Git锁文件
97
+ async function checkAndCleanGitLocks() {
98
+ console.log(chalk.gray('检查Git锁文件...'));
99
+
100
+ const gitDir = path.join(rootDir, '.git');
101
+
102
+ // 可能的锁文件列表
103
+ const lockFiles = [
104
+ path.join(gitDir, 'index.lock'),
105
+ path.join(gitDir, 'HEAD.lock'),
106
+ path.join(gitDir, 'config.lock'),
107
+ path.join(gitDir, 'refs', 'heads', '*.lock'),
108
+ path.join(gitDir, 'packed-refs.lock')
109
+ ];
110
+
111
+ // 检查并清理每个锁文件
112
+ let foundLocks = false;
113
+ let hasBusyLocks = false;
114
+
115
+ lockFiles.forEach(lockPattern => {
116
+ // 处理通配符模式
117
+ if (lockPattern.includes('*')) {
118
+ const baseDir = path.dirname(lockPattern);
119
+ const pattern = path.basename(lockPattern);
120
+
121
+ try {
122
+ // 确保目录存在
123
+ if (fs.existsSync(baseDir)) {
124
+ const files = fs.readdirSync(baseDir);
125
+ files.forEach(file => {
126
+ if (file.endsWith('.lock')) {
127
+ const lockPath = path.join(baseDir, file);
128
+ foundLocks = true;
129
+ console.log(chalk.yellow(`发现Git锁文件: ${lockPath}`));
130
+
131
+ try {
132
+ fs.unlinkSync(lockPath);
133
+ console.log(chalk.green(`成功删除Git锁文件: ${lockPath}`));
134
+ } catch (error) {
135
+ hasBusyLocks = true;
136
+ console.error(chalk.red(`无法删除Git锁文件 ${lockPath}:`), error);
137
+ console.log(chalk.yellow('文件可能正被进程使用,尝试终止Git进程后重试'));
138
+ }
139
+ }
140
+ });
141
+ }
142
+ } catch (error) {
143
+ console.log(chalk.gray(`无法检查目录 ${baseDir}: ${error.message}`));
144
+ }
145
+ } else {
146
+ // 直接检查具体路径
147
+ if (fs.existsSync(lockPattern)) {
148
+ foundLocks = true;
149
+ console.log(chalk.yellow(`发现Git锁文件: ${lockPattern}`));
150
+
151
+ try {
152
+ fs.unlinkSync(lockPattern);
153
+ console.log(chalk.green(`成功删除Git锁文件: ${lockPattern}`));
154
+ } catch (error) {
155
+ hasBusyLocks = true;
156
+ console.error(chalk.red(`无法删除Git锁文件 ${lockPattern}:`), error);
157
+ console.log(chalk.yellow('文件可能正被进程使用,尝试终止Git进程后重试'));
158
+ }
159
+ }
160
+ }
161
+ });
162
+
163
+ if (hasBusyLocks) {
164
+ // 尝试终止Git进程
165
+ terminateGitProcesses();
166
+
167
+ // 再次尝试删除锁文件
168
+ let stillHasBusyLocks = false;
169
+
170
+ lockFiles.forEach(lockPattern => {
171
+ if (!lockPattern.includes('*') && fs.existsSync(lockPattern)) {
172
+ try {
173
+ fs.unlinkSync(lockPattern);
174
+ console.log(chalk.green(`成功删除Git锁文件: ${lockPattern}`));
175
+ } catch (error) {
176
+ stillHasBusyLocks = true;
177
+ console.error(chalk.red(`仍然无法删除Git锁文件 ${lockPattern}`));
178
+ }
179
+ }
180
+ });
181
+
182
+ if (stillHasBusyLocks) {
183
+ console.log(chalk.yellow('警告:一些Git锁文件无法删除。建议:'));
184
+ console.log(chalk.yellow('1. 关闭所有可能使用Git的应用程序'));
185
+ console.log(chalk.yellow('2. 手动删除上述锁文件'));
186
+ console.log(chalk.yellow('3. 重新运行发布脚本'));
187
+
188
+ // 询问是否要继续
189
+ const shouldContinue = await askContinue(chalk.yellow('是否尝试继续执行?(Y/n): '));
190
+
191
+ if (!shouldContinue) {
192
+ console.log(chalk.yellow('用户选择终止发布过程'));
193
+ process.exit(1);
194
+ }
195
+
196
+ console.log(chalk.yellow('尝试继续执行,但可能会失败...'));
197
+ }
198
+ } else if (!foundLocks) {
199
+ console.log(chalk.gray('未发现Git锁文件,继续执行...'));
200
+ }
201
+
202
+ // 等待一下,确保文件系统操作完成
203
+ execSync('sleep 1 || ping -n 2 127.0.0.1 > nul', { stdio: 'ignore' });
204
+ }
205
+
206
+ // 检查发布环境
207
+ async function checkEnvironment() {
208
+ console.log(chalk.blue('=== 检查发布环境 ==='));
209
+
210
+ try {
211
+ // 检查Git是否可用
212
+ execSync('git --version', { stdio: 'ignore' });
213
+
214
+ // 检查是否在Git仓库中
215
+ execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
216
+
217
+ // 清理可能的Git锁文件
218
+ await checkAndCleanGitLocks();
219
+
220
+ // 检查当前分支
221
+ const currentBranch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
222
+ console.log(chalk.gray(`当前Git分支: ${currentBranch}`));
223
+
224
+ // 如果不在主分支上,询问是否继续
225
+ if (currentBranch !== 'main' && currentBranch !== 'master') {
226
+ const rl = createReadlineInterface();
227
+
228
+ try {
229
+ const answer = await rl.question(chalk.yellow(`当前不在主分支上,是否继续在 ${currentBranch} 分支上发布? (Y/n): `));
230
+ if (answer.toLowerCase() === 'n') {
231
+ throw '用户选择取消发布';
232
+ }
233
+ } finally {
234
+ rl.close();
235
+ }
236
+ }
237
+
238
+ // 检查工作区是否干净
239
+ try {
240
+ execSync('git diff --quiet && git diff --staged --quiet', { stdio: 'ignore' });
241
+ console.log(chalk.green('Git工作区干净'));
242
+ } catch (e) {
243
+ console.log(chalk.yellow('Git工作区有未提交的更改'));
244
+
245
+ // 显示未提交的更改
246
+ console.log(chalk.gray('\n未提交的更改:'));
247
+ execSync('git status -s', { stdio: 'inherit' });
248
+ console.log(''); // 空行
249
+
250
+ const rl = createReadlineInterface();
251
+
252
+ try {
253
+ const answer = await rl.question(chalk.yellow('有未提交的更改,是否继续发布? (Y/n): '));
254
+ if (answer.toLowerCase() === 'n') {
255
+ throw '用户选择取消发布';
256
+ }
257
+ } finally {
258
+ rl.close();
259
+ }
260
+ }
261
+
262
+ console.log(chalk.green('环境检查通过'));
263
+ } catch (error) {
264
+ if (error === '用户选择取消发布') {
265
+ console.log(chalk.yellow('发布已取消'));
266
+ process.exit(0);
267
+ }
268
+
269
+ console.error(chalk.red('环境检查失败:'), error);
270
+ process.exit(1);
271
+ }
272
+ }
273
+
274
+ // TSC 类型检查
275
+ async function runTypeCheck() {
276
+ console.log(chalk.blue('\n=== TypeScript 类型检查 ==='));
277
+
278
+ const frontendDir = path.join(rootDir, 'src', 'ui', 'client');
279
+ if (!fs.existsSync(frontendDir)) {
280
+ console.log(chalk.yellow('前端项目目录不存在,跳过 TSC 检查'));
281
+ return;
282
+ }
283
+
284
+ try {
285
+ console.log(chalk.gray('执行 tsc --noEmit...'));
286
+ execSync('npx tsc --noEmit', { cwd: frontendDir, stdio: 'inherit' });
287
+ console.log(chalk.green('TSC 类型检查通过'));
288
+ } catch (error) {
289
+ console.error(chalk.red('TSC 类型检查失败,请修复以上错误后重新发布'));
290
+ process.exit(1);
291
+ }
292
+ }
293
+
294
+ // 更新版本号
295
+ function updateVersion() {
296
+ console.log(chalk.blue('=== 更新版本号 ==='));
297
+
298
+ const currentVersion = packageJson.version;
299
+ console.log(chalk.gray(`当前版本: ${currentVersion}`));
300
+
301
+ // 拆分版本号
302
+ const versionParts = currentVersion.split('.');
303
+
304
+ // 递增最后一位版本号
305
+ const lastPart = parseInt(versionParts[versionParts.length - 1], 10);
306
+ versionParts[versionParts.length - 1] = (lastPart + 1).toString();
307
+
308
+ // 重组版本号
309
+ const newVersion = versionParts.join('.');
310
+ packageJson.version = newVersion;
311
+
312
+ // 写回package.json
313
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n', 'utf8');
314
+
315
+ console.log(chalk.green(`版本号已更新: ${currentVersion} -> ${newVersion}`));
316
+ return newVersion;
317
+ }
318
+
319
+ // 构建前端项目
320
+ async function buildFrontend() {
321
+ console.log(chalk.blue('\n=== 构建前端项目 ==='));
322
+
323
+ try {
324
+ // 检查前端项目目录是否存在
325
+ const frontendDir = path.join(rootDir, 'src', 'ui', 'client');
326
+ if (!fs.existsSync(frontendDir)) {
327
+ console.log(chalk.yellow('前端项目目录不存在,跳过构建'));
328
+ return;
329
+ }
330
+
331
+ // 检查前端依赖是否安装
332
+ console.log(chalk.gray('检查前端依赖...'));
333
+ const nodeModulesPath = path.join(frontendDir, 'node_modules');
334
+ if (!fs.existsSync(nodeModulesPath)) {
335
+ console.log(chalk.yellow('未找到前端依赖,开始安装...'));
336
+ execSync('cd ./src/ui/client && npm install', { stdio: 'inherit' });
337
+ console.log(chalk.green('前端依赖安装完成'));
338
+ }
339
+
340
+ // 安装Node.js类型定义(如果需要)
341
+ try {
342
+ const typesNodePath = path.join(nodeModulesPath, '@types', 'node');
343
+ if (!fs.existsSync(typesNodePath)) {
344
+ console.log(chalk.yellow('安装Node.js类型定义...'));
345
+ execSync('cd ./src/ui/client && npm install --save-dev @types/node', { stdio: 'inherit' });
346
+ }
347
+ } catch (error) {
348
+ console.log(chalk.yellow('安装Node.js类型定义失败,继续构建...'));
349
+ }
350
+
351
+ // 更新tsconfig.app.json以包含node类型(如果需要)
352
+ try {
353
+ const tsconfigAppPath = path.join(frontendDir, 'tsconfig.app.json');
354
+ if (fs.existsSync(tsconfigAppPath)) {
355
+ const tsconfig = JSON.parse(fs.readFileSync(tsconfigAppPath, 'utf8'));
356
+ let needsUpdate = false;
357
+
358
+ if (!tsconfig.compilerOptions) {
359
+ tsconfig.compilerOptions = {};
360
+ needsUpdate = true;
361
+ }
362
+
363
+ if (!tsconfig.compilerOptions.types) {
364
+ tsconfig.compilerOptions.types = ['node'];
365
+ needsUpdate = true;
366
+ } else if (!tsconfig.compilerOptions.types.includes('node')) {
367
+ tsconfig.compilerOptions.types.push('node');
368
+ needsUpdate = true;
369
+ }
370
+
371
+ if (needsUpdate) {
372
+ console.log(chalk.yellow('更新tsconfig.app.json以包含Node.js类型...'));
373
+ fs.writeFileSync(tsconfigAppPath, JSON.stringify(tsconfig, null, 2), 'utf8');
374
+ }
375
+ }
376
+ } catch (error) {
377
+ console.log(`error ==>`, error)
378
+ console.log(chalk.yellow('更新tsconfig失败,继续构建...'));
379
+ }
380
+
381
+ // 执行构建命令
382
+ console.log(chalk.gray('执行构建命令...'));
383
+ execSync('cd ./src/ui/client && npm run build', { stdio: 'inherit' });
384
+ console.log(chalk.green('前端项目构建完成'));
385
+ } catch (error) {
386
+ console.error(chalk.red('前端项目构建失败:'), error);
387
+
388
+ // 询问用户是否继续发布过程
389
+ console.log(chalk.yellow('\n前端构建失败,但您可以选择继续发布过程。'));
390
+ const rl = createReadlineInterface();
391
+
392
+ try {
393
+ const answer = await rl.question(chalk.yellow('是否继续发布流程?(Y/n): '));
394
+ if (answer.toLowerCase() === 'n') {
395
+ console.log(chalk.red('发布流程已取消'));
396
+ process.exit(1);
397
+ }
398
+ console.log(chalk.yellow('继续发布流程...'));
399
+ } finally {
400
+ rl.close();
401
+ }
402
+ }
403
+ }
404
+
405
+ // 提交更改到git
406
+ async function commitChanges(version) {
407
+ console.log(chalk.blue('\n=== 提交更改到Git ==='));
408
+
409
+ try {
410
+ // 检查并清理可能的Git锁文件
411
+ await checkAndCleanGitLocks();
412
+
413
+ // 创建提交信息,包含版本号
414
+ const commitMessage = `chore: 发布版本 v${version}`;
415
+
416
+ // 禁用Git钩子以确保没有其他脚本干扰
417
+ console.log(chalk.gray('临时禁用Git钩子...'));
418
+ const gitHooksDir = path.join(rootDir, '.git', 'hooks');
419
+ let renamedHooks = [];
420
+
421
+ console.log(chalk.gray('添加更改文件...'));
422
+ // 使用--force参数,避免可能的锁文件问题,但排除node_modules目录
423
+ execSync('git add .', { stdio: 'inherit' });
424
+
425
+ // 等待一下,确保文件系统同步
426
+ console.log(chalk.gray('等待文件系统同步...'));
427
+ execSync('sleep 1 || ping -n 2 127.0.0.1 > nul', { stdio: 'ignore' });
428
+
429
+ console.log(chalk.gray('提交更改...'));
430
+
431
+ // 尝试提交,如果失败则重试
432
+ let committed = false;
433
+ let attempts = 0;
434
+ const maxAttempts = 3;
435
+
436
+ while (!committed && attempts < maxAttempts) {
437
+ attempts++;
438
+
439
+ try {
440
+ // 检查并清理Git锁文件
441
+ if (attempts > 1) {
442
+ await checkAndCleanGitLocks();
443
+ console.log(chalk.yellow(`重试提交 (${attempts}/${maxAttempts})...`));
444
+ // 稍等更长时间
445
+ execSync('sleep 2 || ping -n 3 127.0.0.1 > nul', { stdio: 'ignore' });
446
+ }
447
+
448
+ // 使用--no-verify参数跳过钩子,避免可能的挂起
449
+ execSync(`git commit --no-verify -m "${commitMessage}"`, { stdio: 'inherit' });
450
+ committed = true;
451
+ } catch (error) {
452
+ if (attempts >= maxAttempts) {
453
+ throw error; // 重试次数用完,抛出错误
454
+ }
455
+ console.log(chalk.yellow(`提交失败,将在2秒后重试...`));
456
+ // 等待2秒后重试
457
+ execSync('sleep 2 || ping -n 3 127.0.0.1 > nul', { stdio: 'ignore' });
458
+ }
459
+ }
460
+
461
+ console.log(chalk.green(`更改已提交到Git,提交信息: "${commitMessage}"`));
462
+
463
+ // 创建版本标签
464
+ console.log(chalk.gray('创建版本标签...'));
465
+ execSync(`git tag v${version}`, { stdio: 'inherit' });
466
+ console.log(chalk.green(`已创建标签: v${version}`));
467
+
468
+ // 默认推送到远程(注释掉确认提示)
469
+ // const rl = createReadlineInterface();
470
+
471
+ try {
472
+ // const answer = await rl.question(chalk.yellow('是否推送代码和标签到远程仓库? (Y/n): '));
473
+
474
+ // if (answer.toLowerCase() !== 'n') {
475
+ try {
476
+ // 获取当前分支
477
+ const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
478
+
479
+ console.log(chalk.gray(`推送代码到远程仓库,分支: ${branch}...`));
480
+ execSync(`git push origin ${branch}`, { stdio: 'inherit' });
481
+
482
+ console.log(chalk.gray('推送标签到远程仓库...'));
483
+ execSync('git push origin --tags', { stdio: 'inherit' });
484
+
485
+ console.log(chalk.green('代码和标签已成功推送到远程仓库'));
486
+ } catch (pushError) {
487
+ console.error(chalk.red('推送到远程仓库失败:'), pushError);
488
+ // 继续发布过程,不终止
489
+ }
490
+ // } else {
491
+ // console.log(chalk.yellow('跳过推送到远程仓库'));
492
+ // }
493
+ } finally {
494
+ // rl.close();
495
+
496
+ // 恢复Git钩子
497
+ if (renamedHooks.length > 0) {
498
+ console.log(chalk.gray('恢复Git钩子...'));
499
+ for (const hook of renamedHooks) {
500
+ try {
501
+ fs.renameSync(hook.disabled, hook.original);
502
+ } catch (e) {
503
+ console.log(chalk.yellow(`无法恢复Git钩子: ${path.basename(hook.original)}`));
504
+ }
505
+ }
506
+ console.log(chalk.gray(`已恢复 ${renamedHooks.length} 个Git钩子`));
507
+ }
508
+ }
509
+ } catch (error) {
510
+ console.error(chalk.red('Git提交失败:'), error);
511
+ process.exit(1);
512
+ }
513
+ }
514
+
515
+ // 发布到NPM
516
+ async function publishToNpm() {
517
+ console.log(chalk.blue('\n=== 发布到NPM ==='));
518
+
519
+ // 默认发布到NPM(注释掉确认提示)
520
+ // const rl = createReadlineInterface();
521
+
522
+ try {
523
+ // 等待用户确认
524
+ // const answer = await rl.question(chalk.yellow('是否发布到NPM? (Y/n): '));
525
+
526
+ // if (answer.toLowerCase() === 'n') {
527
+ // console.log(chalk.yellow('跳过发布到NPM'));
528
+ // return;
529
+ // }
530
+
531
+ // 执行npm发布
532
+ console.log(chalk.gray('执行npm发布...'));
533
+ try {
534
+ execSync('npm publish --registry=https://registry.npmjs.org/', { stdio: 'inherit' });
535
+ console.log(chalk.green('已成功发布到NPM'));
536
+
537
+ // 发布成功后执行更新和查看命令
538
+ console.log(chalk.blue('\n=== 发布后操作 ==='));
539
+
540
+ try {
541
+ console.log(chalk.gray('执行 npm run update:g...'));
542
+ execSync('npm run update:g', { stdio: 'inherit' });
543
+ console.log(chalk.green('✅ update:g 执行完成'));
544
+ } catch (error) {
545
+ console.error(chalk.red('❌ update:g 执行失败:'), error.message);
546
+ }
547
+
548
+ try {
549
+ console.log(chalk.gray('执行 npm run npm:ls:g...'));
550
+ execSync('npm run npm:ls:g', { stdio: 'inherit' });
551
+ console.log(chalk.green('✅ npm:ls:g 执行完成'));
552
+ } catch (error) {
553
+ console.error(chalk.red(' npm:ls:g 执行失败:'), error.message);
554
+ }
555
+
556
+ } catch (error) {
557
+ console.error(chalk.red('发布到NPM失败:'), error);
558
+ throw error;
559
+ }
560
+ } finally {
561
+ // rl.close();
562
+ }
563
+ }
564
+
565
+ // 主流程
566
+ async function main() {
567
+ console.log(chalk.cyan('\n🚀 开始发布流程...\n'));
568
+
569
+ try {
570
+ // 1. 检查环境
571
+ await checkEnvironment();
572
+
573
+ // 2. TSC 类型检查
574
+ await runTypeCheck();
575
+
576
+ // 3. 更新版本号
577
+ const newVersion = updateVersion();
578
+
579
+ // 4. 构建前端项目
580
+ await buildFrontend();
581
+
582
+ // 5. 提交更改到Git
583
+ await commitChanges(newVersion);
584
+
585
+ // 6. 发布到NPM
586
+ await publishToNpm();
587
+
588
+ console.log(chalk.green('\n🎉 发布完成!'));
589
+ } catch (error) {
590
+ console.error(chalk.red('\n❌ 发布失败:'), error);
591
+ process.exit(1);
592
+ }
593
+ }
594
+
595
+ // 启动流程
596
+ main().catch(error => {
597
+ console.error(chalk.red('\n❌ 未捕获的错误:'), error);
598
+ process.exit(1);
599
+ });