bun-push 0.1.9 → 0.2.0

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/cli.cjs ADDED
@@ -0,0 +1,1537 @@
1
+ #!/usr/bin/env node
2
+ //#region rolldown:runtime
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+
24
+ //#endregion
25
+ const ora = __toESM(require("ora"));
26
+ const chalk = __toESM(require("chalk"));
27
+ const fs = __toESM(require("fs"));
28
+ const path = __toESM(require("path"));
29
+ const prompts = __toESM(require("prompts"));
30
+ const semver = __toESM(require("semver"));
31
+ const child_process = __toESM(require("child_process"));
32
+ const figlet = __toESM(require("figlet"));
33
+
34
+ //#region src/i18n/locales/zh.ts
35
+ /**
36
+ * 中文语言包
37
+ */
38
+ var zh_default = {
39
+ common: {
40
+ yes: "是",
41
+ no: "否",
42
+ skip: "跳过",
43
+ cancel: "取消",
44
+ confirm: "确认",
45
+ error: "错误",
46
+ success: "成功"
47
+ },
48
+ package: {
49
+ selectPackage: "请选择要发布的包",
50
+ selectedPackage: "已选择包"
51
+ },
52
+ changelog: {
53
+ input: "请输入 changelog(单行输入,支持多次输入,输入空行结束)",
54
+ singleLineHint: "支持多次单行输入,输入空行结束。如果输入为空,将使用默认的版本升级记录",
55
+ empty: "changelog 不能为空",
56
+ generate: "是否生成 CHANGELOG.md 文件?",
57
+ usingDefault: "使用默认 changelog:版本升级记录",
58
+ defaultContent: "升级版本号: {currentVersion} → {newVersion}"
59
+ },
60
+ version: {
61
+ selectType: "选择版本类型",
62
+ currentVersion: "当前版本",
63
+ finalVersion: "最终版本",
64
+ customVersion: "自定义版本号",
65
+ customVersionDesc: "手动输入版本号",
66
+ inputVersion: "请输入版本号",
67
+ example: "示例",
68
+ versionEmpty: "版本号不能为空",
69
+ patch: "补丁版本 - 修复 bug",
70
+ minor: "次版本 - 新功能,向后兼容",
71
+ major: "主版本 - 破坏性变更",
72
+ invalid: "无效的版本号",
73
+ invalidWithVersion: "无效的版本号: {version}",
74
+ cannotGenerate: "无法生成下一个版本号",
75
+ unsupportedType: "不支持的发布类型",
76
+ unsupportedTypeWithType: "不支持的发布类型: {type}",
77
+ versionFormat: "{current} -> {next}"
78
+ },
79
+ script: {
80
+ select: "请选择要执行的脚本(通常是 build)",
81
+ noScripts: "该包没有 scripts",
82
+ running: "执行脚本",
83
+ success: "脚本执行成功",
84
+ failed: "脚本执行失败",
85
+ notFound: "脚本不存在",
86
+ notFoundWithName: "脚本 \"{name}\" 不存在",
87
+ executionFailed: "脚本执行失败,退出码: {exitCode}"
88
+ },
89
+ git: {
90
+ pushTag: "是否推送 git tag?",
91
+ createTagFailed: "创建 git tag 失败,退出码: {exitCode}",
92
+ pushTagFailed: "推送 git tag 失败,退出码: {exitCode}"
93
+ },
94
+ registry: {
95
+ input: "请输入 npm registry 地址",
96
+ empty: "registry 地址不能为空",
97
+ invalid: "请输入有效的 URL"
98
+ },
99
+ publish: {
100
+ preview: "发布配置预览",
101
+ packageName: "包名",
102
+ currentVersion: "当前版本",
103
+ newVersion: "新版本",
104
+ tag: "Tag",
105
+ changelog: "Changelog",
106
+ registry: "Registry",
107
+ pushTag: "推送 Tag",
108
+ generateChangelog: "生成 Changelog",
109
+ script: "执行脚本",
110
+ confirm: "确认发布?",
111
+ publishing: "正在发布到 npm...",
112
+ success: "发布成功!",
113
+ failed: "发布失败",
114
+ cancelled: "已取消发布",
115
+ error: "发布过程中出现错误",
116
+ generalError: "错误",
117
+ npmPublishFailed: "npm 发布失败,退出码: {exitCode}",
118
+ npmNotLoggedIn: "未登录到 npm registry: {registry},请先运行 'npm login --registry {registry}' 登录",
119
+ npmAuthCheckFailed: "检查 npm 登录状态失败 (registry: {registry}): {error}",
120
+ needOtp: "是否需要输入 npm 发布的一次性代码(OTP)?",
121
+ inputOtp: "请输入一次性代码(OTP)",
122
+ otpEmpty: "一次性代码不能为空",
123
+ otpInvalid: "一次性代码必须是 6 位数字",
124
+ otp: "一次性代码(OTP)",
125
+ rollingBack: "发布失败,正在回滚修改...",
126
+ rollbackComplete: "回滚完成",
127
+ rollbackFailed: "回滚失败,请手动恢复版本号和 changelog:"
128
+ },
129
+ success: {
130
+ title: "发布成功!",
131
+ packageName: "包名",
132
+ version: "版本",
133
+ registry: "Registry",
134
+ thanks: "感谢使用 lib-push!"
135
+ },
136
+ changelogTypes: {
137
+ added: "新增",
138
+ changed: "变更",
139
+ deprecated: "废弃",
140
+ removed: "移除",
141
+ fixed: "修复",
142
+ security: "安全"
143
+ },
144
+ workspace: {
145
+ packageJsonNotFound: "未找到 package.json 文件",
146
+ workspacesConfigInvalid: "workspaces 配置无效",
147
+ packageNotFound: "未找到要发布的包",
148
+ packageNotFoundByPath: "未找到路径为 {path} 的包",
149
+ monorepoRequiresPath: "monorepo 模式下必须指定 packagePath 或使用 CLI 模式"
150
+ }
151
+ };
152
+
153
+ //#endregion
154
+ //#region src/i18n/locales/en.ts
155
+ /**
156
+ * English language pack
157
+ */
158
+ var en_default = {
159
+ common: {
160
+ yes: "Yes",
161
+ no: "No",
162
+ skip: "Skip",
163
+ cancel: "Cancel",
164
+ confirm: "Confirm",
165
+ error: "Error",
166
+ success: "Success"
167
+ },
168
+ package: {
169
+ selectPackage: "Select package to publish",
170
+ selectedPackage: "Selected package"
171
+ },
172
+ changelog: {
173
+ input: "Enter changelog (single line input, supports multiple inputs, press Enter to finish)",
174
+ singleLineHint: "Supports multiple single-line inputs, press Enter to finish. If input is empty, default version upgrade record will be used",
175
+ empty: "changelog cannot be empty",
176
+ generate: "Generate CHANGELOG.md file?",
177
+ usingDefault: "Using default changelog: version upgrade record",
178
+ defaultContent: "Upgrade version: {currentVersion} → {newVersion}"
179
+ },
180
+ version: {
181
+ selectType: "Select version type",
182
+ currentVersion: "Current version",
183
+ finalVersion: "Final version",
184
+ customVersion: "Custom version",
185
+ customVersionDesc: "Enter version manually",
186
+ inputVersion: "Enter version number",
187
+ example: "Example",
188
+ versionEmpty: "Version cannot be empty",
189
+ patch: "Patch version - Bug fixes",
190
+ minor: "Minor version - New features, backward compatible",
191
+ major: "Major version - Breaking changes",
192
+ invalid: "Invalid version number",
193
+ invalidWithVersion: "Invalid version number: {version}",
194
+ cannotGenerate: "Cannot generate next version",
195
+ unsupportedType: "Unsupported release type",
196
+ unsupportedTypeWithType: "Unsupported release type: {type}",
197
+ versionFormat: "{current} -> {next}"
198
+ },
199
+ script: {
200
+ select: "Select script to run (usually build)",
201
+ noScripts: "This package has no scripts",
202
+ running: "Running script",
203
+ success: "Script executed successfully",
204
+ failed: "Script execution failed",
205
+ notFound: "Script not found",
206
+ notFoundWithName: "Script \"{name}\" not found",
207
+ executionFailed: "Script execution failed, exit code: {exitCode}"
208
+ },
209
+ git: {
210
+ pushTag: "Push git tag?",
211
+ createTagFailed: "Failed to create git tag, exit code: {exitCode}",
212
+ pushTagFailed: "Failed to push git tag, exit code: {exitCode}"
213
+ },
214
+ registry: {
215
+ input: "Enter npm registry address",
216
+ empty: "Registry address cannot be empty",
217
+ invalid: "Please enter a valid URL"
218
+ },
219
+ publish: {
220
+ preview: "Publish configuration preview",
221
+ packageName: "Package name",
222
+ currentVersion: "Current version",
223
+ newVersion: "New version",
224
+ tag: "Tag",
225
+ changelog: "Changelog",
226
+ registry: "Registry",
227
+ pushTag: "Push Tag",
228
+ generateChangelog: "Generate Changelog",
229
+ script: "Script",
230
+ confirm: "Confirm publish?",
231
+ publishing: "Publishing to npm...",
232
+ success: "Published successfully!",
233
+ failed: "Publish failed",
234
+ cancelled: "Publish cancelled",
235
+ error: "Error during publish",
236
+ generalError: "Error",
237
+ npmPublishFailed: "npm publish failed, exit code: {exitCode}",
238
+ npmNotLoggedIn: "Not logged in to npm registry: {registry}, please run 'npm login --registry {registry}' first",
239
+ npmAuthCheckFailed: "Failed to check npm login status (registry: {registry}): {error}",
240
+ needOtp: "Do you need to enter npm publish one-time code (OTP)?",
241
+ inputOtp: "Enter one-time code (OTP)",
242
+ otpEmpty: "One-time code cannot be empty",
243
+ otpInvalid: "One-time code must be 6 digits",
244
+ otp: "One-time code (OTP)",
245
+ rollingBack: "Publish failed, rolling back changes...",
246
+ rollbackComplete: "Rollback completed",
247
+ rollbackFailed: "Rollback failed, please manually restore version and changelog:"
248
+ },
249
+ success: {
250
+ title: "Published successfully!",
251
+ packageName: "Package name",
252
+ version: "Version",
253
+ registry: "Registry",
254
+ thanks: "Thanks for using lib-push!"
255
+ },
256
+ changelogTypes: {
257
+ added: "Added",
258
+ changed: "Changed",
259
+ deprecated: "Deprecated",
260
+ removed: "Removed",
261
+ fixed: "Fixed",
262
+ security: "Security"
263
+ },
264
+ workspace: {
265
+ packageJsonNotFound: "package.json file not found",
266
+ workspacesConfigInvalid: "workspaces configuration is invalid",
267
+ packageNotFound: "Package not found",
268
+ packageNotFoundByPath: "Package not found at path: {path}",
269
+ monorepoRequiresPath: "In monorepo mode, packagePath must be specified or use CLI mode"
270
+ }
271
+ };
272
+
273
+ //#endregion
274
+ //#region src/i18n/locales/ja.ts
275
+ /**
276
+ * 日本語言語パック
277
+ */
278
+ var ja_default = {
279
+ common: {
280
+ yes: "はい",
281
+ no: "いいえ",
282
+ skip: "スキップ",
283
+ cancel: "キャンセル",
284
+ confirm: "確認",
285
+ error: "エラー",
286
+ success: "成功"
287
+ },
288
+ package: {
289
+ selectPackage: "公開するパッケージを選択してください",
290
+ selectedPackage: "選択されたパッケージ"
291
+ },
292
+ changelog: {
293
+ input: "changelogを入力してください(1行入力、複数回入力対応、Enterキーで終了)",
294
+ singleLineHint: "複数回の1行入力をサポート、Enterキーで終了。入力が空の場合、デフォルトのバージョンアップグレード記録が使用されます",
295
+ empty: "changelogは空にできません",
296
+ generate: "CHANGELOG.mdファイルを生成しますか?",
297
+ usingDefault: "デフォルトのchangelogを使用:バージョンアップグレード記録",
298
+ defaultContent: "バージョンアップグレード: {currentVersion} → {newVersion}"
299
+ },
300
+ version: {
301
+ selectType: "バージョンタイプを選択",
302
+ currentVersion: "現在のバージョン",
303
+ finalVersion: "最終バージョン",
304
+ customVersion: "カスタムバージョン",
305
+ customVersionDesc: "バージョンを手動で入力",
306
+ inputVersion: "バージョン番号を入力してください",
307
+ example: "例",
308
+ versionEmpty: "バージョンは空にできません",
309
+ patch: "パッチバージョン - バグ修正",
310
+ minor: "マイナーバージョン - 新機能、後方互換",
311
+ major: "メジャーバージョン - 破壊的変更",
312
+ invalid: "無効なバージョン番号",
313
+ invalidWithVersion: "無効なバージョン番号: {version}",
314
+ cannotGenerate: "次のバージョンを生成できません",
315
+ unsupportedType: "サポートされていないリリースタイプ",
316
+ unsupportedTypeWithType: "サポートされていないリリースタイプ: {type}",
317
+ versionFormat: "{current} -> {next}"
318
+ },
319
+ script: {
320
+ select: "実行するスクリプトを選択してください(通常はbuild)",
321
+ noScripts: "このパッケージにはスクリプトがありません",
322
+ running: "スクリプトを実行中",
323
+ success: "スクリプトの実行に成功しました",
324
+ failed: "スクリプトの実行に失敗しました",
325
+ notFound: "スクリプトが見つかりません",
326
+ notFoundWithName: "スクリプト \"{name}\" が見つかりません",
327
+ executionFailed: "スクリプトの実行に失敗しました、終了コード: {exitCode}"
328
+ },
329
+ git: {
330
+ pushTag: "git tagをプッシュしますか?",
331
+ createTagFailed: "git tagの作成に失敗しました、終了コード: {exitCode}",
332
+ pushTagFailed: "git tagのプッシュに失敗しました、終了コード: {exitCode}"
333
+ },
334
+ registry: {
335
+ input: "npm registryアドレスを入力してください",
336
+ empty: "registryアドレスは空にできません",
337
+ invalid: "有効なURLを入力してください"
338
+ },
339
+ publish: {
340
+ preview: "公開設定プレビュー",
341
+ packageName: "パッケージ名",
342
+ currentVersion: "現在のバージョン",
343
+ newVersion: "新しいバージョン",
344
+ tag: "Tag",
345
+ changelog: "Changelog",
346
+ registry: "Registry",
347
+ pushTag: "Tagをプッシュ",
348
+ generateChangelog: "Changelogを生成",
349
+ script: "スクリプト",
350
+ confirm: "公開を確認しますか?",
351
+ publishing: "npmに公開中...",
352
+ success: "公開に成功しました!",
353
+ failed: "公開に失敗しました",
354
+ cancelled: "公開がキャンセルされました",
355
+ error: "公開中にエラーが発生しました",
356
+ generalError: "エラー",
357
+ npmPublishFailed: "npm公開に失敗しました、終了コード: {exitCode}",
358
+ npmNotLoggedIn: "npm registry にログインしていません: {registry},先に 'npm login --registry {registry}' を実行してください",
359
+ npmAuthCheckFailed: "npm ログイン状態の確認に失敗しました (registry: {registry}): {error}",
360
+ needOtp: "npm公開のワンタイムコード(OTP)を入力する必要がありますか?",
361
+ inputOtp: "ワンタイムコード(OTP)を入力してください",
362
+ otpEmpty: "ワンタイムコードは空にできません",
363
+ otpInvalid: "ワンタイムコードは6桁の数字である必要があります",
364
+ otp: "ワンタイムコード(OTP)",
365
+ rollingBack: "公開に失敗しました、変更をロールバック中...",
366
+ rollbackComplete: "ロールバックが完了しました",
367
+ rollbackFailed: "ロールバックに失敗しました、バージョンとchangelogを手動で復元してください:"
368
+ },
369
+ success: {
370
+ title: "公開に成功しました!",
371
+ packageName: "パッケージ名",
372
+ version: "バージョン",
373
+ registry: "Registry",
374
+ thanks: "lib-pushをご利用いただきありがとうございます!"
375
+ },
376
+ changelogTypes: {
377
+ added: "追加",
378
+ changed: "変更",
379
+ deprecated: "非推奨",
380
+ removed: "削除",
381
+ fixed: "修正",
382
+ security: "セキュリティ"
383
+ },
384
+ workspace: {
385
+ packageJsonNotFound: "package.jsonファイルが見つかりません",
386
+ workspacesConfigInvalid: "workspaces設定が無効です",
387
+ packageNotFound: "パッケージが見つかりません",
388
+ packageNotFoundByPath: "パス {path} にパッケージが見つかりません",
389
+ monorepoRequiresPath: "monorepoモードでは、packagePathを指定するかCLIモードを使用する必要があります"
390
+ }
391
+ };
392
+
393
+ //#endregion
394
+ //#region src/i18n/locales/ko.ts
395
+ /**
396
+ * 한국어 언어 팩
397
+ */
398
+ var ko_default = {
399
+ common: {
400
+ yes: "예",
401
+ no: "아니오",
402
+ skip: "건너뛰기",
403
+ cancel: "취소",
404
+ confirm: "확인",
405
+ error: "오류",
406
+ success: "성공"
407
+ },
408
+ package: {
409
+ selectPackage: "게시할 패키지를 선택하세요",
410
+ selectedPackage: "선택된 패키지"
411
+ },
412
+ changelog: {
413
+ input: "changelog를 입력하세요 (한 줄 입력, 여러 번 입력 지원, Enter 키로 종료)",
414
+ singleLineHint: "여러 번의 한 줄 입력을 지원하며, Enter 키로 종료합니다. 입력이 비어 있으면 기본 버전 업그레이드 기록이 사용됩니다",
415
+ empty: "changelog는 비어 있을 수 없습니다",
416
+ generate: "CHANGELOG.md 파일을 생성하시겠습니까?",
417
+ usingDefault: "기본 changelog 사용: 버전 업그레이드 기록",
418
+ defaultContent: "버전 업그레이드: {currentVersion} → {newVersion}"
419
+ },
420
+ version: {
421
+ selectType: "버전 유형 선택",
422
+ currentVersion: "현재 버전",
423
+ finalVersion: "최종 버전",
424
+ customVersion: "사용자 정의 버전",
425
+ customVersionDesc: "버전을 수동으로 입력",
426
+ inputVersion: "버전 번호를 입력하세요",
427
+ example: "예",
428
+ versionEmpty: "버전은 비어 있을 수 없습니다",
429
+ patch: "패치 버전 - 버그 수정",
430
+ minor: "마이너 버전 - 새 기능, 하위 호환",
431
+ major: "메이저 버전 - 주요 변경 사항",
432
+ invalid: "유효하지 않은 버전 번호",
433
+ invalidWithVersion: "유효하지 않은 버전 번호: {version}",
434
+ cannotGenerate: "다음 버전을 생성할 수 없습니다",
435
+ unsupportedType: "지원되지 않는 릴리스 유형",
436
+ unsupportedTypeWithType: "지원되지 않는 릴리스 유형: {type}",
437
+ versionFormat: "{current} -> {next}"
438
+ },
439
+ script: {
440
+ select: "실행할 스크립트를 선택하세요 (보통 build)",
441
+ noScripts: "이 패키지에는 스크립트가 없습니다",
442
+ running: "스크립트 실행 중",
443
+ success: "스크립트 실행 성공",
444
+ failed: "스크립트 실행 실패",
445
+ notFound: "스크립트를 찾을 수 없습니다",
446
+ notFoundWithName: "스크립트 \"{name}\"를 찾을 수 없습니다",
447
+ executionFailed: "스크립트 실행 실패, 종료 코드: {exitCode}"
448
+ },
449
+ git: {
450
+ pushTag: "git tag를 푸시하시겠습니까?",
451
+ createTagFailed: "git tag 생성 실패, 종료 코드: {exitCode}",
452
+ pushTagFailed: "git tag 푸시 실패, 종료 코드: {exitCode}"
453
+ },
454
+ registry: {
455
+ input: "npm registry 주소를 입력하세요",
456
+ empty: "registry 주소는 비어 있을 수 없습니다",
457
+ invalid: "유효한 URL을 입력하세요"
458
+ },
459
+ publish: {
460
+ preview: "게시 구성 미리보기",
461
+ packageName: "패키지 이름",
462
+ currentVersion: "현재 버전",
463
+ newVersion: "새 버전",
464
+ tag: "Tag",
465
+ changelog: "Changelog",
466
+ registry: "Registry",
467
+ pushTag: "Tag 푸시",
468
+ generateChangelog: "Changelog 생성",
469
+ script: "스크립트",
470
+ confirm: "게시를 확인하시겠습니까?",
471
+ publishing: "npm에 게시 중...",
472
+ success: "게시 성공!",
473
+ failed: "게시 실패",
474
+ cancelled: "게시 취소됨",
475
+ error: "게시 중 오류 발생",
476
+ generalError: "오류",
477
+ npmPublishFailed: "npm 게시 실패, 종료 코드: {exitCode}",
478
+ npmNotLoggedIn: "npm registry에 로그인하지 않았습니다: {registry},먼저 'npm login --registry {registry}'를 실행하세요",
479
+ npmAuthCheckFailed: "npm 로그인 상태 확인 실패 (registry: {registry}): {error}",
480
+ needOtp: "npm 게시 일회용 코드(OTP)를 입력해야 합니까?",
481
+ inputOtp: "일회용 코드(OTP)를 입력하세요",
482
+ otpEmpty: "일회용 코드는 비어 있을 수 없습니다",
483
+ otpInvalid: "일회용 코드는 6자리 숫자여야 합니다",
484
+ otp: "일회용 코드(OTP)",
485
+ rollingBack: "게시 실패, 변경 사항 롤백 중...",
486
+ rollbackComplete: "롤백 완료",
487
+ rollbackFailed: "롤백 실패, 버전과 changelog를 수동으로 복원하세요:"
488
+ },
489
+ success: {
490
+ title: "게시 성공!",
491
+ packageName: "패키지 이름",
492
+ version: "버전",
493
+ registry: "Registry",
494
+ thanks: "lib-push를 사용해 주셔서 감사합니다!"
495
+ },
496
+ changelogTypes: {
497
+ added: "추가됨",
498
+ changed: "변경됨",
499
+ deprecated: "사용 중단됨",
500
+ removed: "제거됨",
501
+ fixed: "수정됨",
502
+ security: "보안"
503
+ },
504
+ workspace: {
505
+ packageJsonNotFound: "package.json 파일을 찾을 수 없습니다",
506
+ workspacesConfigInvalid: "workspaces 구성이 유효하지 않습니다",
507
+ packageNotFound: "패키지를 찾을 수 없습니다",
508
+ packageNotFoundByPath: "경로 {path}에서 패키지를 찾을 수 없습니다",
509
+ monorepoRequiresPath: "monorepo 모드에서는 packagePath를 지정하거나 CLI 모드를 사용해야 합니다"
510
+ }
511
+ };
512
+
513
+ //#endregion
514
+ //#region src/i18n/index.ts
515
+ const SUPPORTED_LANGUAGES = [
516
+ "zh",
517
+ "en",
518
+ "ja",
519
+ "ko"
520
+ ];
521
+ const translations = {
522
+ zh: zh_default,
523
+ en: en_default,
524
+ ja: ja_default,
525
+ ko: ko_default
526
+ };
527
+ let currentLanguage = "zh";
528
+ /**
529
+ * 检测系统语言
530
+ */
531
+ function detectLanguage() {
532
+ const envLang = process.env.LANG || process.env.LANGUAGE || process.env.LC_ALL || process.env.LC_MESSAGES || "";
533
+ if (envLang) {
534
+ const langMatch = envLang.match(/(?:^|_|-)(zh|en|ja|ko)(?:[._-]|$)/i);
535
+ if (langMatch) {
536
+ const lang = langMatch[1].toLowerCase();
537
+ if (SUPPORTED_LANGUAGES.includes(lang)) return lang;
538
+ }
539
+ }
540
+ try {
541
+ const locale = Intl.DateTimeFormat().resolvedOptions().locale;
542
+ const lang = locale.split("-")[0].toLowerCase();
543
+ if (SUPPORTED_LANGUAGES.includes(lang)) return lang;
544
+ } catch {}
545
+ try {
546
+ const collator = new Intl.Collator();
547
+ const locale = collator.resolvedOptions().locale;
548
+ const lang = locale.split("-")[0].toLowerCase();
549
+ if (SUPPORTED_LANGUAGES.includes(lang)) return lang;
550
+ } catch {}
551
+ return "zh";
552
+ }
553
+ /**
554
+ * 初始化语言(自动检测)
555
+ */
556
+ function initLanguage() {
557
+ const envLang = process.env.LIB_PUSH_LANG;
558
+ if (envLang && SUPPORTED_LANGUAGES.includes(envLang)) {
559
+ currentLanguage = envLang;
560
+ return;
561
+ }
562
+ currentLanguage = detectLanguage();
563
+ }
564
+ /**
565
+ * 翻译函数
566
+ * @param key 翻译键
567
+ * @param params 参数对象,用于替换占位符 {key}
568
+ */
569
+ function t(key, params) {
570
+ const keys = key.split(".");
571
+ let value = translations[currentLanguage];
572
+ for (const k of keys) if (value && typeof value === "object" && k in value) value = value[k];
573
+ else if (currentLanguage !== "zh") {
574
+ value = translations.zh;
575
+ for (const k2 of keys) if (value && typeof value === "object" && k2 in value) value = value[k2];
576
+ else return key;
577
+ } else return key;
578
+ let result = typeof value === "string" ? value : key;
579
+ if (params) for (const [paramKey, paramValue] of Object.entries(params)) result = result.replace(new RegExp(`\\{${paramKey}\\}`, "g"), String(paramValue));
580
+ return result;
581
+ }
582
+ initLanguage();
583
+
584
+ //#endregion
585
+ //#region src/utils/workspace.ts
586
+ /**
587
+ * 读取 package.json 文件
588
+ */
589
+ function readPackageJson(path$1) {
590
+ const packageJsonPath = (0, path.join)(path$1, "package.json");
591
+ if (!(0, fs.existsSync)(packageJsonPath)) return null;
592
+ try {
593
+ const content = (0, fs.readFileSync)(packageJsonPath, "utf-8");
594
+ return JSON.parse(content);
595
+ } catch {
596
+ return null;
597
+ }
598
+ }
599
+ /**
600
+ * 检查是否是 monorepo 项目
601
+ */
602
+ function isMonorepo(packageJson) {
603
+ if (packageJson.workspaces && Array.isArray(packageJson.workspaces)) return true;
604
+ if (packageJson.workspaces?.packages && Array.isArray(packageJson.workspaces.packages)) return true;
605
+ return false;
606
+ }
607
+ /**
608
+ * 解析 workspace 模式
609
+ */
610
+ function parseWorkspacePatterns(workspaces) {
611
+ if (Array.isArray(workspaces)) return workspaces;
612
+ if (workspaces?.packages) return workspaces.packages;
613
+ return [];
614
+ }
615
+ /**
616
+ * 匹配包路径是否满足 workspace 模式
617
+ */
618
+ function matchesPattern(path$1, pattern) {
619
+ const regex = pattern.replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/\//g, "\\/");
620
+ return new RegExp(`^${regex}$`).test(path$1);
621
+ }
622
+ /**
623
+ * 扫描目录下的包
624
+ */
625
+ function scanPackages(rootPath, patterns, found = []) {
626
+ const rootPackageJson = readPackageJson(rootPath);
627
+ if (!rootPackageJson) return found;
628
+ function scanDirectory(dir, depth = 0) {
629
+ if (depth > 10) return;
630
+ try {
631
+ const entries = (0, fs.readdirSync)(dir);
632
+ for (const entry of entries) {
633
+ const fullPath = (0, path.join)(dir, entry);
634
+ const relativePath = fullPath.startsWith(rootPath) ? fullPath.slice(rootPath.length).replace(/^[/\\]/, "") : fullPath;
635
+ if (entry.startsWith(".") || entry === "node_modules") continue;
636
+ const stat = (0, fs.statSync)(fullPath);
637
+ if (stat.isDirectory()) {
638
+ const matches = patterns.some((pattern) => matchesPattern(relativePath, pattern));
639
+ if (matches) {
640
+ const packageJson = readPackageJson(fullPath);
641
+ if (packageJson && packageJson.name) found.push({
642
+ name: packageJson.name,
643
+ version: packageJson.version || "0.0.0",
644
+ path: fullPath,
645
+ packageJson
646
+ });
647
+ } else scanDirectory(fullPath, depth + 1);
648
+ }
649
+ }
650
+ } catch (error) {}
651
+ }
652
+ scanDirectory(rootPath);
653
+ return found;
654
+ }
655
+ /**
656
+ * 获取 workspace 信息
657
+ */
658
+ function getWorkspaceInfo(workingDir = process.cwd()) {
659
+ const rootPath = (0, path.resolve)(workingDir);
660
+ const rootPackageJson = readPackageJson(rootPath);
661
+ if (!rootPackageJson) throw new Error(t("workspace.packageJsonNotFound"));
662
+ const isMonorepoProject = isMonorepo(rootPackageJson);
663
+ if (!isMonorepoProject) return {
664
+ isMonorepo: false,
665
+ packages: [{
666
+ name: rootPackageJson.name || "unknown",
667
+ version: rootPackageJson.version || "0.0.0",
668
+ path: rootPath,
669
+ packageJson: rootPackageJson
670
+ }],
671
+ rootPackageJson,
672
+ rootPath
673
+ };
674
+ const workspaceConfig = rootPackageJson.workspaces;
675
+ const patterns = parseWorkspacePatterns(workspaceConfig);
676
+ if (patterns.length === 0) throw new Error(t("workspace.workspacesConfigInvalid"));
677
+ const packages = scanPackages(rootPath, patterns);
678
+ if (packages.length === 0 && rootPackageJson.name) packages.push({
679
+ name: rootPackageJson.name,
680
+ version: rootPackageJson.version || "0.0.0",
681
+ path: rootPath,
682
+ packageJson: rootPackageJson
683
+ });
684
+ return {
685
+ isMonorepo: true,
686
+ packages,
687
+ rootPackageJson,
688
+ rootPath
689
+ };
690
+ }
691
+
692
+ //#endregion
693
+ //#region src/utils/version.ts
694
+ const RELEASE_TYPES = [
695
+ "patch",
696
+ "minor",
697
+ "major"
698
+ ];
699
+ /**
700
+ * 生成下一个版本号
701
+ */
702
+ function getNextVersion(currentVersion, releaseType = "patch") {
703
+ if (!semver.default.valid(currentVersion)) throw new Error(t("version.invalidWithVersion", { version: currentVersion }));
704
+ const nextVersion = semver.default.inc(currentVersion, releaseType);
705
+ if (!nextVersion) throw new Error(t("version.cannotGenerate"));
706
+ return nextVersion;
707
+ }
708
+ /**
709
+ * 验证版本号格式
710
+ * 只接受标准的语义化版本号格式:major.minor.patch
711
+ * 不接受预发布版本(如 1.0.0-alpha)和构建元数据(如 1.0.0+20130313)
712
+ */
713
+ function isValidVersion(version) {
714
+ if (!version || typeof version !== "string") return false;
715
+ const trimmed = version.trim();
716
+ if (!trimmed) return false;
717
+ const standardVersionPattern = /^\d+\.\d+\.\d+$/;
718
+ if (!standardVersionPattern.test(trimmed)) return false;
719
+ const valid = semver.default.valid(trimmed);
720
+ if (!valid) return false;
721
+ return valid === trimmed;
722
+ }
723
+ /**
724
+ * 生成 git tag 名称
725
+ */
726
+ function generateTag(packageName, version) {
727
+ const nameWithoutScope = packageName.replace(/^@[^/]+\//, "");
728
+ return `${nameWithoutScope}@${version}`;
729
+ }
730
+ /**
731
+ * 获取发布类型的描述
732
+ */
733
+ function getReleaseTypeDescription(type) {
734
+ const descriptions = {
735
+ patch: t("version.patch"),
736
+ minor: t("version.minor"),
737
+ major: t("version.major")
738
+ };
739
+ return descriptions[type];
740
+ }
741
+
742
+ //#endregion
743
+ //#region src/utils/scripts.ts
744
+ /**
745
+ * 获取包的所有 scripts
746
+ */
747
+ function getPackageScripts(packageInfo) {
748
+ const scripts = packageInfo.packageJson.scripts;
749
+ if (!scripts || typeof scripts !== "object") return [];
750
+ return Object.keys(scripts);
751
+ }
752
+ /**
753
+ * 执行脚本
754
+ * 检测包管理器(npm 或 bun)并执行脚本
755
+ */
756
+ async function runScript(packageInfo, scriptName) {
757
+ const scripts = packageInfo.packageJson.scripts;
758
+ if (!scripts || !scripts[scriptName]) throw new Error(t("script.notFoundWithName", { name: scriptName }));
759
+ const hasPackageLock = (0, fs.existsSync)((0, path.join)(packageInfo.path, "package-lock.json"));
760
+ const hasBunLock = (0, fs.existsSync)((0, path.join)(packageInfo.path, "bun.lockb"));
761
+ const packageManager = hasBunLock && !hasPackageLock ? "bun" : "npm";
762
+ const command = packageManager === "bun" ? [
763
+ "bun",
764
+ "run",
765
+ scriptName
766
+ ] : [
767
+ "npm",
768
+ "run",
769
+ scriptName
770
+ ];
771
+ return new Promise((resolve$1, reject) => {
772
+ const proc = (0, child_process.spawn)(command[0], command.slice(1), {
773
+ cwd: packageInfo.path,
774
+ stdio: "inherit",
775
+ shell: process.platform === "win32"
776
+ });
777
+ proc.on("close", (exitCode) => {
778
+ if (exitCode !== 0) reject(new Error(t("script.executionFailed", { exitCode: exitCode || 0 })));
779
+ else resolve$1();
780
+ });
781
+ proc.on("error", (error) => {
782
+ reject(error);
783
+ });
784
+ });
785
+ }
786
+
787
+ //#endregion
788
+ //#region src/prompts.ts
789
+ /**
790
+ * 选择要发布的包(monorepo 模式)
791
+ */
792
+ async function selectPackage(packages) {
793
+ if (packages.length === 1) return packages[0];
794
+ const { value } = await (0, prompts.default)({
795
+ type: "select",
796
+ name: "value",
797
+ message: t("package.selectPackage"),
798
+ choices: packages.map((pkg) => ({
799
+ title: `${pkg.name} (${pkg.version})`,
800
+ value: pkg,
801
+ description: pkg.path
802
+ }))
803
+ });
804
+ if (!value) process.exit(0);
805
+ return value;
806
+ }
807
+ /**
808
+ * 生成默认的 changelog 内容
809
+ */
810
+ function generateDefaultChangelog(packageName, currentVersion, newVersion) {
811
+ return t("changelog.defaultContent", {
812
+ packageName,
813
+ currentVersion,
814
+ newVersion
815
+ });
816
+ }
817
+ /**
818
+ * 输入 changelog(单行输入,支持多次输入)
819
+ * 如果用户输入为空或空格,将使用默认的版本升级记录
820
+ */
821
+ async function inputChangelog(packageName, currentVersion, newVersion) {
822
+ const { createInterface } = await import("readline");
823
+ const rl = createInterface({
824
+ input: process.stdin,
825
+ output: process.stdout
826
+ });
827
+ console.log(chalk.default.cyan(t("changelog.input")));
828
+ console.log(chalk.default.gray(t("changelog.singleLineHint")));
829
+ const lines = [];
830
+ let lineNumber = 1;
831
+ return new Promise((resolve$1) => {
832
+ const promptLine = () => {
833
+ rl.setPrompt(chalk.default.gray(`[${lineNumber}] `));
834
+ rl.prompt();
835
+ };
836
+ promptLine();
837
+ rl.on("line", (line) => {
838
+ const trimmed = line.trim();
839
+ if (trimmed === "" && lines.length > 0) {
840
+ rl.close();
841
+ return;
842
+ }
843
+ if (trimmed === "" && lines.length === 0) {
844
+ rl.close();
845
+ return;
846
+ }
847
+ if (trimmed !== "") {
848
+ lines.push(trimmed);
849
+ lineNumber++;
850
+ promptLine();
851
+ }
852
+ });
853
+ rl.on("close", () => {
854
+ const result = lines.join("\n").trim();
855
+ if (!result) {
856
+ const defaultChangelog = generateDefaultChangelog(packageName, currentVersion, newVersion);
857
+ console.log(chalk.default.yellow(t("changelog.usingDefault")));
858
+ resolve$1(defaultChangelog);
859
+ return;
860
+ }
861
+ resolve$1(result);
862
+ });
863
+ rl.on("SIGINT", () => {
864
+ rl.close();
865
+ process.exit(0);
866
+ });
867
+ });
868
+ }
869
+ /**
870
+ * 确认是否生成 changelog 文件
871
+ */
872
+ async function confirmGenerateChangelog() {
873
+ const { value } = await (0, prompts.default)({
874
+ type: "confirm",
875
+ name: "value",
876
+ message: t("changelog.generate"),
877
+ initial: true
878
+ });
879
+ if (value === void 0) process.exit(0);
880
+ return value;
881
+ }
882
+ /**
883
+ * 选择版本类型并生成版本号
884
+ */
885
+ async function selectVersion(currentVersion) {
886
+ const choices = RELEASE_TYPES.map((type) => {
887
+ const nextVersion = getNextVersion(currentVersion, type);
888
+ return {
889
+ title: getReleaseTypeDescription(type),
890
+ value: type,
891
+ description: `${t("version.currentVersion")}: ${chalk.default.cyan(currentVersion)} → ${t("version.finalVersion")}: ${chalk.default.bold.green(nextVersion)}`
892
+ };
893
+ });
894
+ choices.push({
895
+ title: t("version.customVersion"),
896
+ value: "custom",
897
+ description: t("version.customVersionDesc")
898
+ });
899
+ const { value: releaseType } = await (0, prompts.default)({
900
+ type: "select",
901
+ name: "value",
902
+ message: `${t("version.currentVersion")}: ${chalk.default.cyan(currentVersion)} | ${t("version.selectType")}`,
903
+ choices
904
+ });
905
+ if (!releaseType) process.exit(0);
906
+ if (releaseType === "custom") {
907
+ const { value: customVersion } = await (0, prompts.default)({
908
+ type: "text",
909
+ name: "value",
910
+ message: `${t("version.inputVersion")} ${chalk.default.gray(`(${t("version.example")}: 1.0.0-beta.1)`)}`,
911
+ validate: (input) => {
912
+ const trimmed = input.trim();
913
+ if (!trimmed) return t("version.versionEmpty");
914
+ if (!isValidVersion(trimmed)) return t("version.invalidWithVersion", { version: trimmed });
915
+ return true;
916
+ }
917
+ });
918
+ if (!customVersion) process.exit(0);
919
+ const trimmedVersion = customVersion.trim();
920
+ if (!isValidVersion(trimmedVersion)) throw new Error(t("version.invalidWithVersion", { version: trimmedVersion }));
921
+ return {
922
+ version: trimmedVersion,
923
+ releaseType: "custom"
924
+ };
925
+ }
926
+ if (RELEASE_TYPES.includes(releaseType)) return {
927
+ version: getNextVersion(currentVersion, releaseType),
928
+ releaseType
929
+ };
930
+ throw new Error(t("version.unsupportedTypeWithType", { type: releaseType }));
931
+ }
932
+ /**
933
+ * 选择要执行的脚本
934
+ */
935
+ async function selectScript(packageInfo) {
936
+ const scripts = getPackageScripts(packageInfo);
937
+ if (scripts.length === 0) return void 0;
938
+ const choices = scripts.map((script) => ({
939
+ title: script,
940
+ value: script
941
+ }));
942
+ choices.push({
943
+ title: t("common.skip"),
944
+ value: "skip"
945
+ });
946
+ const { value: answer } = await (0, prompts.default)({
947
+ type: "select",
948
+ name: "value",
949
+ message: t("script.select"),
950
+ choices
951
+ });
952
+ if (!answer) process.exit(0);
953
+ return answer === "skip" ? void 0 : answer;
954
+ }
955
+ /**
956
+ * 确认是否推送 git tag
957
+ */
958
+ async function confirmPushTag() {
959
+ const { value } = await (0, prompts.default)({
960
+ type: "confirm",
961
+ name: "value",
962
+ message: t("git.pushTag"),
963
+ initial: true
964
+ });
965
+ if (value === void 0) process.exit(0);
966
+ return value;
967
+ }
968
+ /**
969
+ * 确认是否需要输入 npm OTP
970
+ */
971
+ async function confirmOtp() {
972
+ const { value: needOtp } = await (0, prompts.default)({
973
+ type: "confirm",
974
+ name: "value",
975
+ message: t("publish.needOtp"),
976
+ initial: false
977
+ });
978
+ if (needOtp === void 0) process.exit(0);
979
+ if (!needOtp) return void 0;
980
+ const { value: otp } = await (0, prompts.default)({
981
+ type: "text",
982
+ name: "value",
983
+ message: t("publish.inputOtp"),
984
+ validate: (input) => {
985
+ const trimmed = input.trim();
986
+ if (!trimmed) return t("publish.otpEmpty");
987
+ if (!/^\d{6}$/.test(trimmed)) return t("publish.otpInvalid");
988
+ return true;
989
+ }
990
+ });
991
+ if (!otp) process.exit(0);
992
+ return otp.trim();
993
+ }
994
+ /**
995
+ * 确认 npm registry 地址
996
+ */
997
+ async function confirmRegistry() {
998
+ const { value } = await (0, prompts.default)({
999
+ type: "text",
1000
+ name: "value",
1001
+ message: t("registry.input"),
1002
+ initial: process.env.NPM_CONFIG_REGISTRY || "https://registry.npmjs.org/",
1003
+ validate: (input) => {
1004
+ if (!input.trim()) return t("registry.empty");
1005
+ try {
1006
+ new URL(input);
1007
+ return true;
1008
+ } catch {
1009
+ return t("registry.invalid");
1010
+ }
1011
+ }
1012
+ });
1013
+ if (!value) process.exit(0);
1014
+ return value.trim();
1015
+ }
1016
+ /**
1017
+ * 最终确认发布
1018
+ */
1019
+ async function confirmPublish(config) {
1020
+ console.log(chalk.default.bold(`\n📦 ${t("publish.preview")}`));
1021
+ console.log(chalk.default.gray("─".repeat(50)));
1022
+ console.log(chalk.default.cyan(`${t("publish.packageName")}:`), config.package.name);
1023
+ console.log(chalk.default.cyan(`${t("publish.currentVersion")}:`), config.package.version);
1024
+ console.log(chalk.default.cyan(`${t("publish.newVersion")}:`), config.newVersion);
1025
+ console.log(chalk.default.cyan(`${t("publish.tag")}:`), config.tag);
1026
+ console.log(chalk.default.cyan(`${t("publish.changelog")}:`), config.changelog);
1027
+ console.log(chalk.default.cyan(`${t("publish.registry")}:`), config.registry);
1028
+ console.log(chalk.default.cyan(`${t("publish.pushTag")}:`), config.pushTag ? t("common.yes") : t("common.no"));
1029
+ console.log(chalk.default.cyan(`${t("publish.generateChangelog")}:`), config.generateChangelog ? t("common.yes") : t("common.no"));
1030
+ if (config.otp) console.log(chalk.default.cyan(`${t("publish.otp")}:`), chalk.default.gray("***"));
1031
+ if (config.script) console.log(chalk.default.cyan(`${t("publish.script")}:`), config.script);
1032
+ console.log(chalk.default.gray("─".repeat(50)));
1033
+ const { value } = await (0, prompts.default)({
1034
+ type: "confirm",
1035
+ name: "value",
1036
+ message: t("publish.confirm"),
1037
+ initial: true
1038
+ });
1039
+ if (value === void 0) process.exit(0);
1040
+ return value;
1041
+ }
1042
+
1043
+ //#endregion
1044
+ //#region src/utils/changelog.ts
1045
+ /**
1046
+ * 生成 changelog 条目文本
1047
+ */
1048
+ function formatChangelogEntry(entry) {
1049
+ const typeLabels = {
1050
+ added: t("changelogTypes.added"),
1051
+ changed: t("changelogTypes.changed"),
1052
+ deprecated: t("changelogTypes.deprecated"),
1053
+ removed: t("changelogTypes.removed"),
1054
+ fixed: t("changelogTypes.fixed"),
1055
+ security: t("changelogTypes.security")
1056
+ };
1057
+ return `- ${typeLabels[entry.type]}: ${entry.description}`;
1058
+ }
1059
+ /**
1060
+ * 解析 changelog 文本为条目
1061
+ */
1062
+ function parseChangelog(changelogText) {
1063
+ const entries = [];
1064
+ const lines = changelogText.split("\n").filter((line) => line.trim());
1065
+ const typeMaps = {
1066
+ zh: {
1067
+ 新增: "added",
1068
+ 变更: "changed",
1069
+ 废弃: "deprecated",
1070
+ 移除: "removed",
1071
+ 修复: "fixed",
1072
+ 安全: "security"
1073
+ },
1074
+ en: {
1075
+ Added: "added",
1076
+ Changed: "changed",
1077
+ Deprecated: "deprecated",
1078
+ Removed: "removed",
1079
+ Fixed: "fixed",
1080
+ Security: "security"
1081
+ },
1082
+ ja: {
1083
+ 追加: "added",
1084
+ 変更: "changed",
1085
+ 非推奨: "deprecated",
1086
+ 削除: "removed",
1087
+ 修正: "fixed",
1088
+ セキュリティ: "security"
1089
+ },
1090
+ ko: {
1091
+ 추가됨: "added",
1092
+ 변경됨: "changed",
1093
+ 사용중단됨: "deprecated",
1094
+ 제거됨: "removed",
1095
+ 수정됨: "fixed",
1096
+ 보안: "security"
1097
+ }
1098
+ };
1099
+ const allTypeLabels = [];
1100
+ for (const langMap of Object.values(typeMaps)) allTypeLabels.push(...Object.keys(langMap));
1101
+ const typePattern = allTypeLabels.join("|");
1102
+ for (const line of lines) {
1103
+ const matchWithDash = line.match(new RegExp(`^-\\s*(${typePattern}):\\s*(.+)$`));
1104
+ if (matchWithDash) {
1105
+ const [, typeLabel, description] = matchWithDash;
1106
+ let type;
1107
+ for (const langMap of Object.values(typeMaps)) if (typeLabel in langMap) {
1108
+ type = langMap[typeLabel];
1109
+ break;
1110
+ }
1111
+ if (type) {
1112
+ entries.push({
1113
+ type,
1114
+ description: description.trim()
1115
+ });
1116
+ continue;
1117
+ }
1118
+ }
1119
+ const matchWithoutDash = line.match(new RegExp(`^(${typePattern}):\\s*(.+)$`));
1120
+ if (matchWithoutDash) {
1121
+ const [, typeLabel, description] = matchWithoutDash;
1122
+ let type;
1123
+ for (const langMap of Object.values(typeMaps)) if (typeLabel in langMap) {
1124
+ type = langMap[typeLabel];
1125
+ break;
1126
+ }
1127
+ if (type) {
1128
+ entries.push({
1129
+ type,
1130
+ description: description.trim()
1131
+ });
1132
+ continue;
1133
+ }
1134
+ }
1135
+ if (line.trim().startsWith("-")) {
1136
+ const description = line.replace(/^-\s*/, "").trim();
1137
+ if (description) {
1138
+ entries.push({
1139
+ type: "added",
1140
+ description
1141
+ });
1142
+ continue;
1143
+ }
1144
+ }
1145
+ const trimmedLine = line.trim();
1146
+ if (trimmedLine) entries.push({
1147
+ type: "added",
1148
+ description: trimmedLine
1149
+ });
1150
+ }
1151
+ return entries;
1152
+ }
1153
+ /**
1154
+ * 生成 changelog 版本区块
1155
+ */
1156
+ function generateChangelogSection(version, date, entries) {
1157
+ const sections = {
1158
+ added: [],
1159
+ changed: [],
1160
+ deprecated: [],
1161
+ removed: [],
1162
+ fixed: [],
1163
+ security: []
1164
+ };
1165
+ for (const entry of entries) sections[entry.type].push(formatChangelogEntry(entry));
1166
+ const lines = [];
1167
+ lines.push(`## [${version}] - ${date}`);
1168
+ lines.push("");
1169
+ const typeOrder = [
1170
+ "added",
1171
+ "changed",
1172
+ "deprecated",
1173
+ "removed",
1174
+ "fixed",
1175
+ "security"
1176
+ ];
1177
+ for (const type of typeOrder) if (sections[type].length > 0) {
1178
+ const typeLabels = {
1179
+ added: `### ${t("changelogTypes.added")}`,
1180
+ changed: `### ${t("changelogTypes.changed")}`,
1181
+ deprecated: `### ${t("changelogTypes.deprecated")}`,
1182
+ removed: `### ${t("changelogTypes.removed")}`,
1183
+ fixed: `### ${t("changelogTypes.fixed")}`,
1184
+ security: `### ${t("changelogTypes.security")}`
1185
+ };
1186
+ lines.push(typeLabels[type]);
1187
+ lines.push("");
1188
+ lines.push(...sections[type]);
1189
+ lines.push("");
1190
+ }
1191
+ return lines.join("\n");
1192
+ }
1193
+ /**
1194
+ * 读取现有的 CHANGELOG.md
1195
+ */
1196
+ function readChangelog(packagePath) {
1197
+ const changelogPath = (0, path.join)(packagePath, "CHANGELOG.md");
1198
+ if (!(0, fs.existsSync)(changelogPath)) return "";
1199
+ try {
1200
+ return (0, fs.readFileSync)(changelogPath, "utf-8");
1201
+ } catch {
1202
+ return "";
1203
+ }
1204
+ }
1205
+ /**
1206
+ * 更新 CHANGELOG.md 文件
1207
+ */
1208
+ function updateChangelog(packagePath, version, changelogText) {
1209
+ const changelogPath = (0, path.join)(packagePath, "CHANGELOG.md");
1210
+ const existingContent = readChangelog(packagePath);
1211
+ const entries = parseChangelog(changelogText);
1212
+ const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1213
+ const newSection = generateChangelogSection(version, date, entries);
1214
+ let newContent = "";
1215
+ if (existingContent) {
1216
+ const versionMatch = existingContent.match(/^##\s+\[/m);
1217
+ if (versionMatch && versionMatch.index !== void 0) newContent = existingContent.slice(0, versionMatch.index) + newSection + "\n\n" + existingContent.slice(versionMatch.index);
1218
+ else newContent = newSection + "\n\n" + existingContent;
1219
+ } else {
1220
+ const lang = t("common.yes") === "是" ? "zh-CN" : t("common.yes") === "Yes" ? "en" : t("common.yes") === "はい" ? "ja" : "ko";
1221
+ const headers = {
1222
+ "zh-CN": `# Changelog\n\n所有重要的项目变更都会记录在这个文件中。\n\n格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),\n本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。\n\n`,
1223
+ en: `# Changelog\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),\nand this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n`,
1224
+ ja: `# Changelog\n\nこのプロジェクトの重要な変更はすべてこのファイルに記録されます。\n\n形式は [Keep a Changelog](https://keepachangelog.com/ja/1.0.0/) に基づいており、\nこのプロジェクトは [セマンティックバージョニング](https://semver.org/lang/ja/) に準拠しています。\n\n`,
1225
+ ko: `# Changelog\n\n이 프로젝트의 모든 중요한 변경 사항은 이 파일에 기록됩니다.\n\n형식은 [Keep a Changelog](https://keepachangelog.com/ko/1.0.0/)를 기반으로 하며,\n이 프로젝트는 [시맨틱 버전 관리](https://semver.org/lang/ko/)를 준수합니다.\n\n`
1226
+ };
1227
+ newContent = `${headers[lang] || headers.en}${newSection}\n`;
1228
+ }
1229
+ (0, fs.writeFileSync)(changelogPath, newContent, "utf-8");
1230
+ }
1231
+
1232
+ //#endregion
1233
+ //#region src/publisher.ts
1234
+ /**
1235
+ * 读取 package.json 中的版本号
1236
+ */
1237
+ function readPackageVersion(packagePath) {
1238
+ const packageJsonPath = (0, path.join)(packagePath, "package.json");
1239
+ const packageJson = JSON.parse((0, fs.readFileSync)(packageJsonPath, "utf-8"));
1240
+ return packageJson.version;
1241
+ }
1242
+ /**
1243
+ * 更新 package.json 中的版本号
1244
+ */
1245
+ function updatePackageVersion(packagePath, newVersion) {
1246
+ const packageJsonPath = (0, path.join)(packagePath, "package.json");
1247
+ const packageJson = JSON.parse((0, fs.readFileSync)(packageJsonPath, "utf-8"));
1248
+ packageJson.version = newVersion;
1249
+ (0, fs.writeFileSync)(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", "utf-8");
1250
+ }
1251
+ /**
1252
+ * 恢复 package.json 中的版本号
1253
+ */
1254
+ function restorePackageVersion(packagePath, oldVersion) {
1255
+ updatePackageVersion(packagePath, oldVersion);
1256
+ }
1257
+ /**
1258
+ * 恢复 CHANGELOG.md 文件
1259
+ */
1260
+ function restoreChangelog(packagePath, oldContent) {
1261
+ const changelogPath = (0, path.join)(packagePath, "CHANGELOG.md");
1262
+ if (oldContent === "") {
1263
+ if ((0, fs.existsSync)(changelogPath)) try {
1264
+ (0, fs.unlinkSync)(changelogPath);
1265
+ } catch (error) {
1266
+ (0, fs.writeFileSync)(changelogPath, "", "utf-8");
1267
+ }
1268
+ } else (0, fs.writeFileSync)(changelogPath, oldContent, "utf-8");
1269
+ }
1270
+ /**
1271
+ * 创建 git tag
1272
+ */
1273
+ async function createGitTag(tag) {
1274
+ return new Promise((resolve$1, reject) => {
1275
+ const proc = (0, child_process.spawn)("git", ["tag", tag], { stdio: "inherit" });
1276
+ proc.on("close", (exitCode) => {
1277
+ if (exitCode !== 0) reject(new Error(t("git.createTagFailed", { exitCode: exitCode || 0 })));
1278
+ else resolve$1();
1279
+ });
1280
+ proc.on("error", (error) => {
1281
+ reject(error);
1282
+ });
1283
+ });
1284
+ }
1285
+ /**
1286
+ * 删除 git tag(用于回滚)
1287
+ */
1288
+ async function deleteGitTag(tag) {
1289
+ return new Promise((resolve$1) => {
1290
+ const proc = (0, child_process.spawn)("git", [
1291
+ "tag",
1292
+ "-d",
1293
+ tag
1294
+ ], { stdio: "pipe" });
1295
+ proc.on("close", () => {
1296
+ resolve$1();
1297
+ });
1298
+ proc.on("error", () => {
1299
+ resolve$1();
1300
+ });
1301
+ });
1302
+ }
1303
+ /**
1304
+ * 推送 git tag
1305
+ */
1306
+ async function pushGitTag(tag) {
1307
+ return new Promise((resolve$1, reject) => {
1308
+ const proc = (0, child_process.spawn)("git", [
1309
+ "push",
1310
+ "origin",
1311
+ tag
1312
+ ], { stdio: "inherit" });
1313
+ proc.on("close", (exitCode) => {
1314
+ if (exitCode !== 0) reject(new Error(t("git.pushTagFailed", { exitCode: exitCode || 0 })));
1315
+ else resolve$1();
1316
+ });
1317
+ proc.on("error", (error) => {
1318
+ reject(error);
1319
+ });
1320
+ });
1321
+ }
1322
+ /**
1323
+ * 检查 npm 登录状态
1324
+ * 使用 npm whoami 检查登录状态
1325
+ */
1326
+ async function checkNpmAuth(registry) {
1327
+ return new Promise((resolve$1, reject) => {
1328
+ const proc = (0, child_process.spawn)("npm", [
1329
+ "whoami",
1330
+ "--registry",
1331
+ registry
1332
+ ], { stdio: [
1333
+ "ignore",
1334
+ "pipe",
1335
+ "pipe"
1336
+ ] });
1337
+ let stdout = "";
1338
+ let stderr = "";
1339
+ proc.stdout?.on("data", (data) => {
1340
+ stdout += data.toString();
1341
+ });
1342
+ proc.stderr?.on("data", (data) => {
1343
+ stderr += data.toString();
1344
+ });
1345
+ proc.on("close", (exitCode) => {
1346
+ if (exitCode !== 0) {
1347
+ const errorMsg = stderr.trim();
1348
+ if (errorMsg.includes("not logged in") || errorMsg.includes("Unauthorized") || errorMsg === "") {
1349
+ reject(new Error(t("publish.npmNotLoggedIn", { registry })));
1350
+ return;
1351
+ }
1352
+ reject(new Error(t("publish.npmAuthCheckFailed", {
1353
+ registry,
1354
+ error: errorMsg
1355
+ })));
1356
+ return;
1357
+ }
1358
+ const username = stdout.trim();
1359
+ if (!username) {
1360
+ reject(new Error(t("publish.npmNotLoggedIn", { registry })));
1361
+ return;
1362
+ }
1363
+ resolve$1();
1364
+ });
1365
+ proc.on("error", (error) => {
1366
+ reject(error);
1367
+ });
1368
+ });
1369
+ }
1370
+ /**
1371
+ * 发布到 npm
1372
+ * 使用 npm publish 命令发布包
1373
+ */
1374
+ async function publishToNpm(packagePath, registry, otp) {
1375
+ return new Promise((resolve$1, reject) => {
1376
+ const args = [
1377
+ "npm",
1378
+ "publish",
1379
+ "--registry",
1380
+ registry
1381
+ ];
1382
+ if (otp) args.push("--otp", otp);
1383
+ const proc = (0, child_process.spawn)("npm", args, {
1384
+ cwd: packagePath,
1385
+ stdio: "inherit",
1386
+ env: {
1387
+ ...process.env,
1388
+ NPM_CONFIG_REGISTRY: registry
1389
+ }
1390
+ });
1391
+ proc.on("close", (exitCode) => {
1392
+ if (exitCode !== 0) reject(new Error(t("publish.npmPublishFailed", { exitCode: exitCode || 0 })));
1393
+ else resolve$1();
1394
+ });
1395
+ proc.on("error", (error) => {
1396
+ reject(error);
1397
+ });
1398
+ });
1399
+ }
1400
+ /**
1401
+ * 发布包
1402
+ * 如果发布失败,会自动回滚版本号和 changelog 的修改
1403
+ */
1404
+ async function publish(config) {
1405
+ const originalVersion = readPackageVersion(config.package.path);
1406
+ const originalChangelog = config.generateChangelog ? readChangelog(config.package.path) : "";
1407
+ let gitTagCreated = false;
1408
+ try {
1409
+ updatePackageVersion(config.package.path, config.newVersion);
1410
+ if (config.generateChangelog) updateChangelog(config.package.path, config.newVersion, config.changelog);
1411
+ await checkNpmAuth(config.registry);
1412
+ if (config.pushTag) {
1413
+ await createGitTag(config.tag);
1414
+ gitTagCreated = true;
1415
+ }
1416
+ await publishToNpm(config.package.path, config.registry, config.otp);
1417
+ if (config.pushTag) await pushGitTag(config.tag);
1418
+ } catch (error) {
1419
+ console.error(t("publish.rollingBack") || "发布失败,正在回滚修改...");
1420
+ try {
1421
+ restorePackageVersion(config.package.path, originalVersion);
1422
+ if (config.generateChangelog) restoreChangelog(config.package.path, originalChangelog);
1423
+ if (gitTagCreated) await deleteGitTag(config.tag);
1424
+ console.error(t("publish.rollbackComplete") || "回滚完成");
1425
+ } catch (rollbackError) {
1426
+ console.error(t("publish.rollbackFailed") || "回滚失败,请手动恢复版本号和 changelog:", rollbackError);
1427
+ }
1428
+ throw error;
1429
+ }
1430
+ }
1431
+
1432
+ //#endregion
1433
+ //#region src/logo.ts
1434
+ /**
1435
+ * 显示 logo
1436
+ */
1437
+ function showLogo() {
1438
+ try {
1439
+ const asciiText = figlet.default.textSync("lib-push", {
1440
+ font: "Standard",
1441
+ horizontalLayout: "default",
1442
+ verticalLayout: "default"
1443
+ });
1444
+ const lines = asciiText.split("\n").filter((line) => line.trim().length > 0);
1445
+ if (lines.length === 0) {
1446
+ console.log(chalk.default.cyan.bold("\n lib-push\n"));
1447
+ return;
1448
+ }
1449
+ const coloredLines = lines.map((line, index) => {
1450
+ const midPoint = Math.floor(line.length / 2);
1451
+ if (index < lines.length / 2) return chalk.default.red(line.substring(0, midPoint)) + chalk.default.yellow(line.substring(midPoint));
1452
+ else return chalk.default.magenta(line.substring(0, midPoint)) + chalk.default.blue(line.substring(midPoint));
1453
+ });
1454
+ const logo = "\n" + coloredLines.join("\n") + "\n";
1455
+ console.log(logo);
1456
+ } catch (error) {
1457
+ console.log(chalk.default.cyan.bold("\n lib-push\n"));
1458
+ }
1459
+ }
1460
+ /**
1461
+ * 显示成功提示
1462
+ */
1463
+ function showSuccessMessage(packageName, version, registry) {
1464
+ console.log(chalk.default.green.bold(`\n✅ ${t("success.title")}\n`));
1465
+ console.log(chalk.default.gray("─".repeat(60)));
1466
+ console.log(chalk.default.cyan.bold(`📦 ${t("success.packageName")}:`), chalk.default.white(packageName));
1467
+ console.log(chalk.default.cyan.bold(`🏷️ ${t("success.version")}:`), chalk.default.white(version));
1468
+ console.log(chalk.default.cyan.bold(`🌐 ${t("success.registry")}:`), chalk.default.white(registry));
1469
+ console.log(chalk.default.gray("─".repeat(60)));
1470
+ console.log(chalk.default.green(`\n🎉 ${t("success.thanks")}\n`));
1471
+ }
1472
+
1473
+ //#endregion
1474
+ //#region src/cli.ts
1475
+ /**
1476
+ * 主函数
1477
+ */
1478
+ async function main() {
1479
+ try {
1480
+ showLogo();
1481
+ const workspaceInfo = getWorkspaceInfo();
1482
+ let selectedPackage;
1483
+ if (workspaceInfo.isMonorepo) selectedPackage = await selectPackage(workspaceInfo.packages);
1484
+ else selectedPackage = workspaceInfo.packages[0];
1485
+ console.log(chalk.default.green(`\n✅ ${t("package.selectedPackage")}: ${chalk.default.bold(selectedPackage.name)} (${selectedPackage.version})`));
1486
+ const { version: newVersion } = await selectVersion(selectedPackage.version);
1487
+ const changelog = await inputChangelog(selectedPackage.name, selectedPackage.version, newVersion);
1488
+ const tag = generateTag(selectedPackage.name, newVersion);
1489
+ const script = await selectScript(selectedPackage);
1490
+ if (script) {
1491
+ const spinner = (0, ora.default)(`${t("script.running")}: ${chalk.default.cyan(script)}`).start();
1492
+ try {
1493
+ await runScript(selectedPackage, script);
1494
+ spinner.succeed(`${t("script.success")}: ${chalk.default.cyan(script)}`);
1495
+ } catch (error) {
1496
+ spinner.fail(`${t("script.failed")}: ${chalk.default.red(script)}`);
1497
+ throw error;
1498
+ }
1499
+ }
1500
+ const pushTag = await confirmPushTag();
1501
+ const registry = await confirmRegistry();
1502
+ const generateChangelog = await confirmGenerateChangelog();
1503
+ const otp = await confirmOtp();
1504
+ const config = {
1505
+ package: selectedPackage,
1506
+ changelog,
1507
+ newVersion,
1508
+ tag,
1509
+ script,
1510
+ pushTag,
1511
+ registry,
1512
+ generateChangelog,
1513
+ otp
1514
+ };
1515
+ const confirmed = await confirmPublish(config);
1516
+ if (!confirmed) {
1517
+ console.log(chalk.default.yellow(`\n❌ ${t("publish.cancelled")}`));
1518
+ process.exit(0);
1519
+ }
1520
+ const publishSpinner = (0, ora.default)(t("publish.publishing")).start();
1521
+ try {
1522
+ await publish(config);
1523
+ publishSpinner.succeed(t("publish.success"));
1524
+ showSuccessMessage(selectedPackage.name, newVersion, registry);
1525
+ } catch (error) {
1526
+ publishSpinner.fail(t("publish.failed"));
1527
+ console.error(chalk.default.red(`\n❌ ${t("publish.error")}:`), error);
1528
+ process.exit(1);
1529
+ }
1530
+ } catch (error) {
1531
+ console.error(chalk.default.red(`\n❌ ${t("publish.generalError")}:`), error);
1532
+ process.exit(1);
1533
+ }
1534
+ }
1535
+ main();
1536
+
1537
+ //#endregion