change-versions 1.4.0 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -1
- package/dist/cli.js +34 -26
- package/docs/commands.md +17 -9
- package/docs/release-flow.md +143 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
只给需要发的包升版本,再按那次提交发布。非正式档位不写 CHANGELOG、不打 git tag。
|
|
4
4
|
|
|
5
|
+
正式版每个公开包发布成功后,立即创建对应的 `<name>@<version>` Git tag;配置推送时立即推送,再处理下一个包。后续包或 afterPublish 失败时,已成功包及标签保留。失败包和 private 包不创建 Git tag,恢复发布跳过已上传版本并补齐缺失操作。
|
|
6
|
+
|
|
7
|
+
默认按各包最近覆盖的源码提交识别后续变更,补发不会吞掉其他包同期的未发布改动。上传及重试前重查 registry,避免响应丢失后重复上传;npm 标签若已指向更高版本,会停止并提示核对批次或更换标签。独立克隆或不同 CI 的发布仍应串行化。
|
|
8
|
+
|
|
5
9
|
开发用 Bun。装好依赖后用 Node 跑 bin:
|
|
6
10
|
|
|
7
11
|
```bash
|
|
@@ -19,6 +23,7 @@ bun src/cli.ts changed
|
|
|
19
23
|
提示语看 `LC_ALL`、`LC_MESSAGES`、`LANG`。以 `zh` 开头用中文,否则用英文。
|
|
20
24
|
|
|
21
25
|
命令说明见 [docs/commands.md](docs/commands.md)。
|
|
26
|
+
流程图、成功与恢复的判定,以及待解决边界见 [docs/release-flow.md](docs/release-flow.md)。
|
|
22
27
|
|
|
23
28
|
## 安装使用
|
|
24
29
|
|
|
@@ -32,6 +37,8 @@ bunx --no-install change-versions release prerelease --preid=alpha --baseline=<
|
|
|
32
37
|
bunx --no-install change-versions status
|
|
33
38
|
# 发布失败后恢复:
|
|
34
39
|
bunx --no-install change-versions release --resume
|
|
40
|
+
# 仅未发布包的源码有修复时,先提交修复,再保留原版本号补发:
|
|
41
|
+
bunx --no-install change-versions release --retry-unpublished
|
|
35
42
|
```
|
|
36
43
|
|
|
37
44
|
运行 CLI 需要 Node.js,无需 Bun;Bun 用于源码开发与构建。正式档位使用 `version patch|minor|major`。第一次 version 提交建立基线后,可以省略 `--baseline`。日常使用 release 串起升版与发布;version/publish 也可分开执行。重试使用 release --resume,避免再次升版。
|
|
@@ -59,6 +66,8 @@ CLI 回归通过临时 npm 替身验证发布顺序、部分失败续发、登
|
|
|
59
66
|
|
|
60
67
|
完成用绿色、失败用红色、预览和待处理事项用黄色、引导和命令用青色、跳过项及 registry 用弱化颜色;状态始终有文字标签。颜色沿用终端检测,支持 `NO_COLOR`;重定向日志仍保留完整文字,`FORCE_COLOR=1` 可强制显示颜色。
|
|
61
68
|
|
|
69
|
+
交互菜单的标题、序号和输入引导用青色,恢复或重试用绿色,强制升版与修复补发用黄色,退出用弱化颜色。文本输入的默认值用绿色,确认输入 `[y/N/q]` 用黄色;关闭颜色后仍保留原有文案和默认值提示。
|
|
70
|
+
|
|
62
71
|
发生部分上传、hook 或 Git 标签失败时,先修复提示中的原因,再使用输出的 publish 命令重试,无需再次 version。重试重新查询 registry,跳过已上传版本并补齐必要标签;配置的 hook 仍会执行。Git 标签阶段失败时,本地或远端可能已有部分标签,不能据此认定全部未创建。
|
|
63
72
|
|
|
64
73
|
`version --dry-run` 也会明确区分计划与修改。升版成功会说明“版本已提交,包尚未发布”,提示先预览或执行 publish。合并或重写 version 提交时须保留 `Co-authored-by: change-versions <publish@change-versions.com>`,否则 publish 可能找不到这一批版本。通过包装脚本使用时,恢复其发布步骤并保留原来的 root、配置、包目录及 dist-tag 选项,不要重新升版。
|
|
@@ -82,7 +91,9 @@ change-versions release patch --dist-tag=next
|
|
|
82
91
|
change-versions release patch --yes # 脚本/CI,不提问
|
|
83
92
|
```
|
|
84
93
|
|
|
85
|
-
输入错误可重试;输入 q、Ctrl-C
|
|
94
|
+
输入错误可重试;输入 q、Ctrl-C 或输入结束可取消当前提问。取消停止后续步骤,已经创建的版本提交或已上传的包会保留。版本提交和实际上传分别确认;回车默认不执行。发现上一批未完成时,可查看状态、恢复发布、仅对上一批包强制升版并发布,或选择“使用当前代码重试未发布的包(保留原版本号)”。发布失败后也提供修复补发入口;普通重试固定同一提交和标签,从失败菜单退出仍返回失败状态。
|
|
95
|
+
|
|
96
|
+
例如四个包中三个已经发布,第四个需要改代码:先提交第四个包的修复,再选择修复补发或运行 `publish --retry-unpublished` / `release --retry-unpublished`。工具重新查询 registry,仅尚未发布的公开包可采用修复代码,所有版本号保持不变,已上传版本不重复上传。会创建一条空的 Git 恢复记录提交,记录整批每个包对应的源码提交;已发布包的正式版 Git 标签仍对应原提交,修复包的标签对应修复提交。再次中断后,沿用输出的新 publish 命令或 `release --resume` 即可。若仍需继续修改未发布包,再提交修复并重复使用 `--retry-unpublished`。`--dry-run` 可先预览,已发布包或私有包的源码变更会阻止此操作。
|
|
86
97
|
|
|
87
98
|
非交互环境无参数时显示帮助;缺少升版档位或预发布标识时明确报错。`--yes` 跳过提问,需要提供必要参数,不会自动猜测档位。TTY 回归使用可选的 Python 3 标准库 PTY 中继;CLI 运行无需 Python。
|
|
88
99
|
|
package/dist/cli.js
CHANGED
|
@@ -1,32 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
2
|
+
var G=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(r){n=[r]}if(n)throw n[0];return t};import{styleText as rn}from"node:util";function q(e,t,n){return rn(e,t,{stream:n})}function S(e){return q(["bold","cyan"],e,process.stdout)}function Q(e){return q("bold",e,process.stdout)}function oe(e){return q("green",e,process.stdout)}function v(e){return q("dim",e,process.stdout)}function F(e){return q("cyan",e,process.stdout)}function ct(e,t,n){return`${Q(e)} ${v(t)} ${v("=>")} ${oe(n)}`}function H(e){let[t,...n]=e.split(`
|
|
3
|
+
`),r=q("red",t,process.stderr);if(!n.length)return r;return[r,...n.map((s)=>q("yellow",s,process.stderr))].join(`
|
|
4
|
+
`)}function M(e){return q("green",e,process.stdout)}function k(e){return q("yellow",e,process.stdout)}function ze(e){return q("red",e,process.stdout)}var I=()=>{};function Ke(){let e=(process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||"").split(".")[0];return/^zh/i.test(e)?"zh":"en"}function i(e,t,n=Ke()){let r=on[e][n];if(t)for(let[s,o]of Object.entries(t))r=r.replaceAll(`{${s}}`,String(o));return r}var on;var D=G(()=>{on={interactiveCancelled:{zh:"已取消,尚未执行的步骤不会继续。",en:"Cancelled. Remaining steps will not run."},confirmAnswer:{zh:"请输入 y 确认、n 返回,或 q 退出。",en:"Enter y to confirm, n to decline, or q to quit."},chooseReleaseKind:{zh:"选择版本类型",en:"Choose a release type"},releaseKindFormal:{zh:"正式版(发布到 latest)",en:"Formal release (default tag: latest)"},releaseKindPre:{zh:"预发布(例如 alpha、beta)",en:"Prerelease (for example alpha or beta)"},choosePreid:{zh:"预发布标识,回车采用默认值,q 退出:",en:"Prerelease identifier; Enter accepts the default, q quits:"},invalidPreid:{zh:"标识不符合 semver,例如可使用 alpha、beta、rc。请重新输入。",en:"Invalid semver prerelease identifier. Try alpha, beta or rc."},chooseDistTag:{zh:"目标 npm 标签,回车采用默认值,q 退出:",en:"Target npm tag; Enter accepts the default, q quits:"},firstBaseline:{zh:"尚未找到版本基线。请指定一条已存在的提交或 Git 标签作为本轮比较起点;q 退出。",en:"No release baseline found. Choose an existing commit or Git tag as the comparison start; q quits."},chooseBaseline:{zh:"首次版本基线(SHA 或 Git 标签):",en:"First release baseline (SHA or Git tag):"},wizardCandidates:{zh:"本次入选包(含依赖方):",en:"Packages to version (including dependents):"},wizardExecutionPlan:{zh:"执行前确认发布设置",en:"Review release settings before execution"},wizardPlanContext:{zh:"目标 npm 标签: {tag};推送分支: {branch}",en:"Target npm tag: {tag}; push branch: {branch}"},wizardNeedsConfig:{zh:"未找到 change-versions.yml,请先初始化配置。",en:"No change-versions.yml found. Initialize the configuration first."},wizardAction:{zh:"选择操作(输入序号,q 退出)",en:"Choose an action (enter a number, q quits)"},actionNewRelease:{zh:"发布新版本",en:"Release new versions"},actionResume:{zh:"恢复上一次发布(不升版)",en:"Resume publication (no version bump)"},actionStatus:{zh:"查看发布状态",en:"View publication status"},actionInit:{zh:"初始化配置",en:"Initialize configuration"},actionExit:{zh:"退出",en:"Exit"},actionRetry:{zh:"重试当前批次(不升版)",en:"Retry this batch (no version bump)"},actionRetryUnpublished:{zh:"使用当前代码重试未发布的包(保留原版本号)",en:"Retry unpublished packages using current code (no version bump)"},optRetryUnpublished:{zh:"记录已提交的修复代码,保留原版本号,仅补发未发布包",en:"Record committed fixes and retry unpublished packages without changing versions"},repairPublication:{zh:"【修复后补发】保留原版本号,检查未发布包与源码提交",en:"[Repair publication] Keep versions and check unpublished package sources"},repairPlan:{zh:"将创建一条空的恢复记录提交,不修改版本或文件。仅未发布包可采用当前已提交的代码;已发布包继续对应原源码提交。",en:"An empty recovery commit will record package sources without changing versions or files. Only unpublished packages may use current committed code; published packages retain their original sources."},repairCurrentCode:{zh:"(采用修复后的代码)",en:"(use repaired code)"},confirmRepairPublication:{zh:"是否记录修复后的源码提交并保留原版本号?",en:"Record repaired package sources without changing versions?"},repairPublishedChanged:{zh:"已发布或私有包发生改动: {name}@{version}。此入口仅允许未发布的公开包采用修复代码;请还原该包改动,或为它另发新版本。",en:"Already published package changed: {name}@{version} (or the package is private). Only unpublished public packages may use repaired sources; restore this package or release a new version."},repairRecorded:{zh:"修复补发记录已提交,所有版本号保持不变。后续可直接恢复发布。版本提交: {commit}",en:"Recovery sources recorded; all versions are unchanged. Ordinary publication can now resume. Version commit: {commit}"},actionExitFailed:{zh:"退出,保留失败状态",en:"Exit with failure status"},recoveryAction:{zh:"发布未完成,选择下一步",en:"Publication incomplete. Choose the next action"},pendingAction:{zh:"上一批尚未完成,选择下一步",en:"The previous batch is incomplete. Choose the next action"},optDryRunRelease:{zh:"预览升版或恢复发布计划,不执行修改",en:"Preview versioning or resumed publication without changes"},badDistTag:{zh:"dist-tag 必须是有效的 npm 标签,不能是版本范围或含空白等 URL 保留字符,例如 latest、alpha、next。",en:"dist-tag must be a valid npm tag, not a version range or a value containing whitespace or URL-reserved characters. Try latest, alpha or next."},distTagDowngrade:{zh:"拒绝回退 npm 标签 {tag}:{name} 当前指向 {current},本批次目标为 {version}。请核对批次或改用其他发布标签。",en:"Refusing to move {tag} backward for {name}: it currently points to {current}, but this batch targets {version}. Review the batch or choose another publication tag."},registryVersionDisappeared:{zh:"之前已存在的版本 {name}@{version} 已无法查询确认。已停止,不将标签修复自动转换为重新上传;请核对 registry 后恢复。",en:"Previously published version {name}@{version} can no longer be confirmed. Stopped without converting a tag repair into an upload; check the registry before resuming."},publishSourceDirty:{zh:"发布期间工作区被修改。已成功上传的包保留;请检查并清理变更后恢复发布。",en:"The working tree changed during publication. Successful uploads are preserved; review and clean the changes before resuming."},cmdRelease:{zh:"升版并发布,失败后可恢复发布",en:"Version and publish, with publication recovery"},cmdStatus:{zh:"只读查询发布批次的 registry 与 Git 标签状态",en:"Inspect registry and Git tag state without changing anything"},optReleaseCommit:{zh:"指定待发布版本提交(必须在当前历史中)",en:"Use this version commit (must be an ancestor of HEAD)"},optResume:{zh:"恢复上一批发布,不再次升版",en:"Resume publication without another version bump"},badReleaseCommit:{zh:"无效的版本提交 {commit}:需要当前历史中的提交,正文包含唯一且有效的包名 old => new 版本列表。请核对后重试。",en:"Invalid version commit {commit}: it must be in the current history with unique package old => new version lines. Review the commit before retrying."},repositoryLocked:{zh:`另一个发布操作持有仓库锁: {file}
|
|
3
5
|
持有者: {owner}
|
|
4
6
|
下一步:等待该进程结束;若进程已退出,确认没有其他发布操作后再删除该锁并重试。`,en:`Another release operation holds the repository lock: {file}
|
|
5
7
|
Owner: {owner}
|
|
6
8
|
Wait for it to finish. If the owner has exited, verify no release is running before removing the lock and retrying.`},unsafeCommitFile:{zh:"不安全的提交路径: {file}。请使用仓库内的普通文件路径,不能包含通配符或符号链接。",en:"Unsafe commit path: {file}. Use a regular file inside the repository, without globs or symlinks."},versionHeadChanged:{zh:"升版期间 HEAD 被外部操作或 hook 改变;已保留提交与文件。下一步:检查 git log 和 git status,确认需要保留的改动后再继续。",en:"HEAD changed during versioning. Commits and files were preserved. Review git log and git status before continuing."},versionUnexpectedIndex:{zh:"升版期间暂存区被修改,已停止自动提交。下一步:检查 git diff --cached,处理外部暂存后重试。",en:"The index changed during versioning; automatic commit stopped. Review git diff --cached and resolve external staging before retrying."},versionUnexpectedFiles:{zh:"hook 或外部操作修改了未授权文件: {files}。已保留这些改动。下一步:检查 git status;确需随升版提交的文件请加入 commitFiles。",en:"A hook or external process changed unapproved files: {files}. These changes were preserved. Review git status; add intended version outputs to commitFiles."},versionRecovery:{zh:"升版已中断;仅尝试恢复本次写入且未再次改变的文件。下一步:检查 git status 后重试。",en:"Versioning interrupted; only unchanged files written by this operation were restored. Review git status before retrying."},statusNoBatch:{zh:"尚无可识别的版本批次。下一步:运行 release 创建批次;已有升版提交可用 status --commit=<提交> 指定。",en:"No version batch found. Run release to create one, or use status --commit=<revision> for an existing version commit."},statusHeading:{zh:"【发布状态】只读查询,不执行 hook、上传、提交或标签操作",en:"[Release status] Read-only; no hooks, uploads, commits or tag changes"},statusUpload:{zh:"待上传",en:"Upload pending"},statusRetag:{zh:"待更新 npm 标签",en:"npm tag update pending"},statusReady:{zh:"就绪",en:"ready"},statusMissing:{zh:"未就绪或无法确认",en:"pending or unknown"},statusNotConfigured:{zh:"未配置推送",en:"push not configured"},statusGitTag:{zh:"Git 标签 {tag}:本地 {local};远端 {remote}",en:"Git tag {tag}: local {local}; remote {remote}"},statusRemoteUnknown:{zh:"无法确认远端 Git 标签,请检查 origin 与网络后重试: {detail}",en:"Remote Git tag state is unknown. Check origin and the network, then retry: {detail}"},statusExternalReady:{zh:"registry 与要求的 Git 标签已就绪。",en:"Registry and required Git tags are ready."},statusPending:{zh:"仍有待处理或无法确认的状态,检查以上提示后恢复发布。",en:"Some state is pending or unknown. Review the messages above before resuming publication."},statusHooksUnknown:{zh:"status 无法证明历史 hook 是否成功执行。需要重跑完整发布阶段时使用下方命令;hook 应支持重试。",en:"Status cannot prove that past hooks succeeded. Use the command below to rerun the publication stage; hooks should support retries."},releaseResumeOptions:{zh:"恢复发布不能同时指定--force、升版档位、baseline、branch 或 commit-message。请移除这些升版参数后重试。",en:"Resume cannot be combined with --force, a bump, baseline, branch or commit-message. Remove versioning options and retry."},releasePending:{zh:`上一批版本或所需 Git 标签尚未就绪,已停止新一轮升版。下一步:先恢复发布,无需再次升版:
|
|
7
|
-
{command}
|
|
8
|
-
|
|
9
|
+
{command}
|
|
10
|
+
若已提交未发布包的修复代码,可在上述命令后加 --retry-unpublished,保留原版本号补发。`,en:`The previous batch is not ready on the registry or required Git tags; a new version bump was stopped. Resume publication first:
|
|
11
|
+
{command}
|
|
12
|
+
For committed fixes to unpublished packages, append --retry-unpublished to keep their versions.`},releaseVersionStage:{zh:"【发布流程 1/2】选择变更并提交版本",en:"[Release 1/2] Select changes and commit versions"},releasePublishStage:{zh:"【发布流程 2/2】发布刚创建的版本提交",en:"[Release 2/2] Publish the version commit just created"},releasePreviewComplete:{zh:"发布流程预览结束:未创建版本提交,未执行发布 hook、上传或标签操作。实际发布计划将在升版成功后查询 registry 生成。确认后去掉 --dry-run 重跑 release。",en:"Release preview complete: no version commit, publish hooks, uploads or tag changes. The actual publication plan will query the registry after versioning succeeds. Remove --dry-run and rerun release after review."},publishPreview:{zh:"【发布预览】仅查询 registry 并展示计划,以下操作尚未执行",en:"[Publish preview] Querying the registry and showing a plan; the operations below have not been executed"},publishPreparing:{zh:"【发布检查】正在确认版本、登录状态和 registry;尚未执行发布操作",en:"[Publish checks] Checking versions, authentication and the registry; publication has not started"},publishPlanSummary:{zh:"计划上传: {uploads},更新 npm 标签: {retags},校验/创建 Git 标签: {tags}",en:"Upload: {uploads}, npm tag updates: {retags}, Git tags to check/create: {tags}"},plannedStep:{zh:"[计划] {step}",en:"[Planned] {step}"},executingStep:{zh:"[执行] {step}",en:"[Running] {step}"},publishPreviewComplete:{zh:"预览结束:未执行 hook、上传、npm 标签修改或 Git 标签/推送操作。",en:"Preview complete. No hooks, uploads, npm tag changes or Git tag/push operations were executed."},publishPreviewNext:{zh:"下一步:确认计划后,去掉 --dry-run,沿用原来的 CLI 运行方式执行下方命令;包装脚本请关闭对应预览选项并使用恢复发布入口。",en:"Next: review the plan, then remove --dry-run and run the command below with your usual CLI runner. For wrapper scripts, disable preview and use their resume-publication entry."},publishResumeInfo:{zh:"将重新查询 registry,跳过已上传的版本,仅补必要的 npm 标签;配置的 hook 和正式版 Git 标签阶段仍会执行。",en:"This will query the registry again, skip uploaded versions and update npm tags only as needed. Configured hooks and the formal-release Git tag stage still run."},publishRetry:{zh:"下一步:修复上述错误后,无需再次升版,重试发布。沿用原来的 CLI 运行方式执行下方命令;包装脚本请使用恢复发布入口,不要重新执行 version。",en:"Next: fix the error, then retry publication without bumping versions. Run the command below with your usual CLI runner; wrapper scripts should resume publication instead of running version again."},publishRetryTitle:{zh:"无需再次升版,重试发布",en:"Retry publication without bumping versions"},publishTagRecovery:{zh:"当前包已在 registry 就绪,对应的 Git 标签尚未完成;本地或远端标签可能已部分完成,其余包可能尚未发布。请修复 Git 错误后重试。",en:"This package is ready on the registry, but its Git tag is incomplete. Local or remote tags may be partially complete; other packages may still be pending. Fix the Git error before retrying."},publishReady:{zh:"目标 npm 版本与标签已就绪;本批次无需再次升版或上传。",en:"Target npm versions and tags are ready; no further version bump or upload is needed for this batch."},gitTagsLocal:{zh:"Git 标签已在本地就绪;未配置推送分支,因此未推送标签。",en:"Git tags are ready locally. No push branch is configured, so tags were not pushed."},gitTagsPushed:{zh:"Git 标签已创建/校验并推送到 origin。",en:"Git tags were created/checked and pushed to origin."},versionPreview:{zh:"【升版预览】以下为计划版本,尚未修改文件或提交",en:"[Version preview] Planned versions only; no files or commits have been changed"},versionPreviewComplete:{zh:"预览结束:未修改文件、提交或推送。确认后去掉 --dry-run,保留相同档位和参数重跑 version。",en:"Preview complete. No files, commits or pushes were made. Remove --dry-run and rerun version with the same bump and options after reviewing the plan."},versionCommitted:{zh:"版本已提交,包尚未发布。版本提交: {commit}",en:"Versions committed; packages have not been published. Version commit: {commit}"},versionTrailerHint:{zh:"合并或重写 version 提交时,请保留正文中的 Co-authored-by: change-versions <publish@change-versions.com>,供 publish 识别。",en:"When squashing or rewriting a version commit, preserve its Co-authored-by: change-versions <publish@change-versions.com> trailer so publish can find it."},versionPublishNext:{zh:"下一步:沿用原来的 CLI 运行方式执行下方 publish 命令;也可以先加 --dry-run 预览发布计划。",en:"Next: run the publish command below with your usual CLI runner, or add --dry-run to preview the publication plan first."},noVersionChangesNext:{zh:"如果上一轮已经升版但尚未发布,可恢复 publish;如需重发上一批包的新版本,可选择强制升版或使用 --force。",en:"Resume publish if the previous batch still needs publishing. To release new versions of the previous batch, choose a forced bump or use --force."},optForceVersion:{zh:"仅对上一次版本提交中的包强制升版,不扩展为全量发布",en:"Force new versions of only the packages in the previous version commit"},confirmForceVersion:{zh:"是否仅对上一批包强制升版?",en:"Force new versions of only the previous batch?"},actionForceVersion:{zh:"仅对上一批包强制升版并发布",en:"Force new versions and publish only the previous batch"},forcePreviousBatch:{zh:"强制升版范围:仅版本提交 {commit} 中的包",en:"Forced version scope: only packages from version commit {commit}"},publishComplete:{zh:"发布完成,汇总:",en:"Publish complete. Summary:"},publishIncomplete:{zh:"发布未完成,汇总:",en:"Publish incomplete. Summary:"},publishSummaryContext:{zh:"版本提交: {commit},dist-tag: {tag}",en:"Version commit: {commit}, dist-tag: {tag}"},publishFailedStage:{zh:"失败或中断阶段: {stage}",en:"Failed or interrupted stage: {stage}"},summaryPublished:{zh:"已发布",en:"Published"},summaryRetagged:{zh:"标签已更新",en:"Tag updated"},summarySkipped:{zh:"已跳过(版本与标签已就绪)",en:"Skipped (version and tag ready)"},summaryPrivate:{zh:"已跳过(私有包)",en:"Skipped (private)"},summaryFailed:{zh:"失败(registry 状态需重跑确认)",en:"Failed (rerun to check registry state)"},summaryPending:{zh:"未执行",en:"Not executed"},alreadyTagged:{zh:"跳过 {name}@{version}:{tag} 已指向该版本,registry: {registry}",en:"Skipping {name}@{version}: {tag} already points to this version, registry: {registry}"},unexpectedRegistryTags:{zh:"registry {registry} 未返回有效标签信息,无法确认 {name} 的 {tag} 标签",en:"Registry {registry} did not return valid tag metadata for {name} ({tag})"},checkingRegistry:{zh:"检查 {name}@{version},registry: {registry}",en:"Checking {name}@{version}, registry: {registry}"},publishHeadChanged:{zh:"发布 hook 改变了 HEAD。下一步: 检查该提交,让 hook 只更新忽略的构建产物后重跑 publish",en:"A publish hook changed HEAD. Review that commit and keep hooks limited to ignored build output before retrying publish"},wrongBranch:{zh:"当前分支不是 {branch}。下一步: 切换到该分支后重跑 version",en:"Current branch is not {branch}. Next: switch to that branch and rerun version"},releaseVersionMismatch:{zh:"{name} 当前版本 {actual} 与 version 提交中的 {expected} 不一致。识别到版本提交: {commit}。下一步: 检查最新升版提交与 package.json,并确认合并/重写后仍保留 change-versions 的 Co-authored-by 标记,再恢复 publish;不要盲目重新升版",en:"{name} is at {actual}, but the version commit records {expected}. Version commit: {commit}. Check the latest version commit and package.json, including the change-versions Co-authored-by trailer after a squash/rewrite, before resuming publish; do not blindly bump again"},releaseContentsChanged:{zh:"待发布包在 version 提交后又有改动。若仅修复尚未发布的包,请提交修复后用 publish --retry-unpublished 保留原版本号补发;已发布包的代码变更需另发新版本。",en:"Release packages changed after the version commit. For fixes to unpublished packages only, commit them and use publish --retry-unpublished to keep versions. Changes to published packages require a new version."},unexpectedRegistryVersion:{zh:"registry {registry} 未返回预期版本 {name}@{version},无法确认是否已发布",en:"The registry did not return the expected version {name}@{version} ({registry})"},dirtyTree:{zh:"工作区不干净。下一步: 提交或还原后,重跑刚才那条命令",en:"Working tree is dirty. Next: commit or restore your changes, then rerun the same command"},gitFailed:{zh:`git 失败。下一步: 在 git 仓库里重跑
|
|
9
13
|
{detail}`,en:`git failed. Next: rerun this inside a git repository
|
|
10
14
|
{detail}`},noPackagesSince:{zh:"自 {rev} 以来没有需要升版的包",en:"No packages to version since {rev}"},changedHeader:{zh:"变更:",en:"Changed:"},dependentsHeader:{zh:"依赖方:",en:"Dependents:"},confirmVersions:{zh:"以上版本是否确认?",en:"Apply these versions?"},cancelledVersion:{zh:"已取消。还没改文件。想继续就再跑同一条命令",en:"Cancelled. No files were changed. Rerun the same command to continue"},branchPushFailed:{zh:`分支推送失败。commit 已在本地。下一步: git push origin {branch};成功后恢复 publish,不要重跑 version
|
|
11
15
|
{detail}`,en:`Branch push failed. The commit is local. Next: git push origin {branch}, then resume publish. Do not rerun version
|
|
12
|
-
{detail}`},noVersionCommit:{zh:"没有 version 提交。下一步: 尚未升版时先跑 version;若已升版,请先检查提交正文的 Co-authored-by: change-versions <publish@change-versions.com> 是否保留;也可用 publish --commit=<版本提交> 明确指定",en:"No version commit. Next: run version first if no bump exists; otherwise check that the version commit retains Co-authored-by: change-versions <publish@change-versions.com>, or use publish --commit=<version commit>"},packageNotInDir:{zh:"正文里的包不在 {dir}: {name}",en:"Package from the commit body is not in {dir}: {name}"},noGitTag:{zh:"不打 git tag",en:"No git tag"},willPublish:{zh:"即将执行(确认后开始):",en:"Publication plan (starts after confirmation):"},distTagOnlyMark:{zh:"(版本已存在,仅更新 npm 标签)",en:"(version exists; npm tag update only)"},privateMark:{zh:"(私有)",en:"(private)"},confirmPublish:{zh:"是否发布?",en:"Publish?"},cancelledPublish:{zh:"已取消。不跑 hook,不上传,不打 git tag。想继续时重跑同一条 publish,无需再次升版",en:"Cancelled. No hooks, no upload, no git tag. Rerun the same publish to continue without bumping versions"},publishInterrupted:{zh:"发布已中断,已完成的操作保留;registry 和 Git 标签可能部分完成。下一步: 重跑同一条 publish 确认状态,不要重跑 version",en:"Publish interrupted. Completed operations remain; registry and Git tags may be partially complete. Next: rerun the same publish to check state. Do not rerun version"},badBaseline:{zh:"修订无法解析: {rev}。下一步: 换成 git rev-parse 能解析的 SHA 或 tag",en:"Cannot resolve revision: {rev}. Next: pass a SHA or tag that git rev-parse accepts"},noBaseline:{zh:"没有基线。下一步: changed 或 version 加上 --baseline=SHA或tag",en:"No baseline. Next: rerun changed or version with --baseline=<sha-or-tag>"},chooseBump:{zh:"选择档位",en:"Select a bump"},versionRestored:{zh:"已尝试恢复本次拥有且未再次变化的文件。检查 git status 后重试",en:"Restored the tree to HEAD from when the command started. Fix the error, then rerun version"},tagPointsElsewhere:{zh:"git tag {tag} 指向别的 commit。下一步: 人工处理这个同名 tag 后,再重跑 publish。不要重跑 version",en:"git tag {tag} points at another commit. Next: fix that tag by hand, then rerun publish. Do not rerun version"},tagPushFailed:{zh:`git tag
|
|
13
|
-
{detail}`,en:`git tag was not pushed.
|
|
16
|
+
{detail}`},noVersionCommit:{zh:"没有 version 提交。下一步: 尚未升版时先跑 version;若已升版,请先检查提交正文的 Co-authored-by: change-versions <publish@change-versions.com> 是否保留;也可用 publish --commit=<版本提交> 明确指定",en:"No version commit. Next: run version first if no bump exists; otherwise check that the version commit retains Co-authored-by: change-versions <publish@change-versions.com>, or use publish --commit=<version commit>"},packageNotInDir:{zh:"正文里的包不在 {dir}: {name}",en:"Package from the commit body is not in {dir}: {name}"},noGitTag:{zh:"不打 git tag",en:"No git tag"},willPublish:{zh:"即将执行(确认后开始):",en:"Publication plan (starts after confirmation):"},distTagOnlyMark:{zh:"(版本已存在,仅更新 npm 标签)",en:"(version exists; npm tag update only)"},privateMark:{zh:"(私有)",en:"(private)"},privateVersionHint:{zh:"私有包仅升版,不上传,也不创建 Git tag。",en:"Private packages are versioned only; they are not uploaded and receive no Git tags."},confirmPublish:{zh:"是否发布?",en:"Publish?"},cancelledPublish:{zh:"已取消。不跑 hook,不上传,不打 git tag。想继续时重跑同一条 publish,无需再次升版",en:"Cancelled. No hooks, no upload, no git tag. Rerun the same publish to continue without bumping versions"},publishInterrupted:{zh:"发布已中断,已完成的操作保留;registry 和 Git 标签可能部分完成。下一步: 重跑同一条 publish 确认状态,不要重跑 version",en:"Publish interrupted. Completed operations remain; registry and Git tags may be partially complete. Next: rerun the same publish to check state. Do not rerun version"},badBaseline:{zh:"修订无法解析: {rev}。下一步: 换成 git rev-parse 能解析的 SHA 或 tag",en:"Cannot resolve revision: {rev}. Next: pass a SHA or tag that git rev-parse accepts"},noBaseline:{zh:"没有基线。下一步: changed 或 version 加上 --baseline=SHA或tag",en:"No baseline. Next: rerun changed or version with --baseline=<sha-or-tag>"},chooseBump:{zh:"选择档位",en:"Select a bump"},versionRestored:{zh:"已尝试恢复本次拥有且未再次变化的文件。检查 git status 后重试",en:"Restored the tree to HEAD from when the command started. Fix the error, then rerun version"},tagPointsElsewhere:{zh:"git tag {tag} 指向别的 commit。下一步: 人工处理这个同名 tag 后,再重跑 publish。不要重跑 version",en:"git tag {tag} points at another commit. Next: fix that tag by hand, then rerun publish. Do not rerun version"},tagPushFailed:{zh:`git tag 没推上去。当前包已在 registry,其余包可能尚未发布。下一步: 检查 Git 远端权限后重跑同一条 publish,补齐该包标签并继续;配置的 hook 仍会执行,不要重跑 version
|
|
17
|
+
{detail}`,en:`git tag was not pushed. This package is on the registry; other packages may still be pending. Next: check Git remote permissions, then rerun the same publish to finish its tag and continue; configured hooks still run. Do not rerun version
|
|
14
18
|
{detail}`},networkFailed:{zh:`操作失败,已重试 2 次。后续发布步骤已停止。下一步: 重跑同一条 publish,不要重跑 version
|
|
15
19
|
{detail}`,en:`Operation failed after 2 retries. Later publication steps were stopped. Next: rerun the same publish. Do not rerun version
|
|
16
20
|
{detail}`},notLoggedIn:{zh:"未登录 {registry}。下一步: npm login --registry={registry},然后重跑同一条 publish。不要重跑 version",en:"Not logged in to {registry}. Next: npm login --registry={registry}, then rerun the same publish. Do not rerun version"},registryUnreachable:{zh:`无法访问 {registry}。下一步: 检查网络后重跑同一条 publish。不要重跑 version
|
|
17
21
|
{detail}`,en:`Cannot reach {registry}. Next: check the network, then rerun the same publish. Do not rerun version
|
|
18
22
|
{detail}`},noNpmRegistry:{zh:`读不到 npm registry:
|
|
19
23
|
{detail}`,en:`Cannot read the npm registry:
|
|
20
|
-
{detail}`},npmFailed:{zh:"npm 失败",en:"npm failed"},npmViewFailed:{zh:"npm view 失败",en:"npm view failed"},hookFailed:{zh:`{name} 失败。下一步: 修好 hook 后重跑 publish
|
|
21
|
-
{detail}`,en:`{name} failed. Next: fix the hook, then rerun publish. Uploaded packages
|
|
22
|
-
{detail}`},beforePublishDirty:{zh:"beforePublish 改了被跟踪的文件。下一步: hook 只能改 git 忽略的构建产物,弄干净后重跑 publish",en:"beforePublish changed tracked files. Next: the hook may only change gitignored build output. Clean the tree, then rerun publish"},afterPublishDirty:{zh:"afterPublish
|
|
23
|
-
`)){if(!a.startsWith(
|
|
24
|
-
`)){let i=/^(\S+) (\S+) => (\S+)$/.exec(n.trim());if(i)t.push({name:i[1],from:i[2],to:i[3]})}return t}function mt(e){let t=new Map(e.map((s)=>[s.folder,s])),n=new Set,i=[],o=(s,a)=>{if(n.has(s.folder))return;if(a.has(s.folder))throw new l(r("dependencyCycle",{name:s.name}));a.add(s.folder);for(let c of s.deps){let g=t.get(c);if(g)o(g,a)}a.delete(s.folder),n.add(s.folder),i.push(s)};for(let s of e)o(s,new Set);return i}function ae(e){return/ENEEDAUTH|E401|E403|need auth|not logged in|401 Unauthorized|403 Forbidden/i.test(e)}function Oe(e){try{return JSON.parse(e)?.error?.code==="E404"}catch{return!1}}var l,Xe,tt,Wt,Jt,_t,Qt="publish@change-versions.com",Xt,ve;var F=Be(()=>{R();l=class l extends Error{auth;constructor(e,t=!1){super(e);this.name="Fail",this.auth=t}};Xe=["patch","minor","major","prerelease","prepatch","preminor","premajor"],tt=new Set(["patch","minor","major"]),Wt=new Set(["prerelease","prepatch","preminor","premajor"]);Jt=new Set(["packagesDir","commitMessage","branch","hooks","include","exclude","commitFiles"]),_t=new Set(["beforeCommit","beforePublish","afterPublish"]);Xt=`change-versions <${Qt}>`,ve=`Co-authored-by: ${Xt}`});import{CommitParser as Cn}from"conventional-commits-parser";import{writeChangelogString as Sn}from"conventional-changelog-writer";function At(e){return e.find((t)=>ke(xe(t.body)))?.hash}function It(e,t,n,i,o,s){let a=`${n}/${t}/package.json`,c=`${n}/${t}/`,g=[];for(let d of e)if(d.files.some((y)=>y!==a&&y.startsWith(c)&&He(y,i,o))||d.files.includes(a)&&s.has(d.hash))g.push({hash:d.hash,body:d.body});return g}async function jt(e){let t=new Date().toISOString().slice(0,10),n=[`## ${e.version} (${t})`];if(e.previousTag){let s=`../../compare/${encodeURIComponent(e.previousTag)}...${encodeURIComponent(e.currentTag)}`;n.push(`[${e.previousTag}...${e.currentTag}](${s})`)}let i=new Cn({noteKeywords:["BREAKING CHANGE","BREAKING-CHANGE"]}),o=[];for(let s of e.messages){let a;try{a=i.parse(s.body)}catch{continue}o.push({...a,hash:s.hash.slice(0,7),notes:a.notes??[],subject:a.subject})}if(o.length){let a=(await Sn(o,{version:e.version,date:t},{groupBy:"type",mainTemplate:Rn,transform(c){let d=(c.notes??[]).some((y)=>/breaking/i.test(y.title)),h=c.type??"";if(zn.has(h)&&!d)return null;if(!Et[h]&&!d)return null;return{type:Et[h]??null}}})).trim();if(a)n.push("",a);else if(e.dependencies.length)n.push("",Bt(e.dependencies))}else if(e.dependencies.length)n.push("",Bt(e.dependencies).trimEnd());return`${n.join(`
|
|
24
|
+
{detail}`},npmFailed:{zh:"npm 失败",en:"npm failed"},npmViewFailed:{zh:"npm view 失败",en:"npm view failed"},hookFailed:{zh:`{name} 失败。下一步: 修好 hook 后重跑 publish。已上传的包及已创建的 Git 标签保留
|
|
25
|
+
{detail}`,en:`{name} failed. Next: fix the hook, then rerun publish. Uploaded packages and existing Git tags are preserved
|
|
26
|
+
{detail}`},beforePublishDirty:{zh:"beforePublish 改了被跟踪的文件。下一步: hook 只能改 git 忽略的构建产物,弄干净后重跑 publish",en:"beforePublish changed tracked files. Next: the hook may only change gitignored build output. Clean the tree, then rerun publish"},afterPublishDirty:{zh:"afterPublish 改了被跟踪的文件。已上传包和已创建的 Git 标签保留。下一步: 让 hook 不改被跟踪的文件,弄干净后重跑 publish",en:"afterPublish changed tracked files. Uploaded packages and existing Git tags are preserved. Next: keep the hook off tracked files, clean the tree, then rerun publish"},configUnreadable:{zh:"配置读不了: {file}。下一步: 补上 include,删掉不认识的字段",en:"Cannot read config: {file}. Next: add include and remove unknown fields"},packagesDirMissing:{zh:"找不到目录 {dir}",en:"Directory not found: {dir}"},packageJsonIncomplete:{zh:"{folder} 的 package.json 缺少 name 或 version",en:"{folder} package.json is missing name or version"},publicDependsOnPrivate:{zh:"public 包 {name} 不能依赖 private 包 {dep}。下一步: 改依赖后重跑 version",en:"Public package {name} cannot depend on private package {dep}. Next: change the dependency, then rerun version"},missingVersionField:{zh:"{folder} 缺少 version",en:"{folder} is missing version"},badBump:{zh:"档位非法: {bump}。可用 {list}",en:"Invalid bump: {bump}. Use {list}"},preidRequired:{zh:"{kind} 必须带 --preid。预发布用 prepatch 这类档位",en:"{kind} requires --preid. Use a pre* bump for prereleases"},preidForbidden:{zh:"正式版不能带 --preid。预发布用 prepatch 这类档位",en:"A stable bump cannot take --preid. Use a pre* bump for prereleases"},badLine:{zh:"第 {line} 行无法解析",en:"Cannot parse line {line}"},unknownField:{zh:"不认识的字段 {name}",en:"Unknown field {name}"},missingValue:{zh:"{name} 缺少值",en:"{name} is missing a value"},includeRequired:{zh:"include 不能为空。下一步: 补上 include,删掉不认识的字段",en:"include must not be empty. Next: add include and remove unknown fields"},commitMessageNeedsToken:{zh:"commitMessage 需要 %s",en:"commitMessage must contain %s"},patternBang:{zh:"模式不能包含 !: {pattern}",en:"Patterns cannot contain !: {pattern}"},patternClass:{zh:"不支持字符组: {pattern}",en:"Character classes are not supported: {pattern}"},badHook:{zh:"hooks 无法解析: {line}",en:"Cannot parse hooks: {line}"},unknownHook:{zh:"不认识的 hook {name}",en:"Unknown hook {name}"},hookMissingCommand:{zh:"{name} 缺少命令",en:"{name} is missing a command"},badPatternLine:{zh:"路径列表无法解析: {line}",en:"Cannot parse path list: {line}"},badSemver:{zh:"无法解析版本 {version}",en:"Cannot parse version {version}"},dependencyCycle:{zh:"依赖成环: {name}",en:"Dependency cycle: {name}"},bumpRequired:{zh:"非交互环境或 --yes 模式必须指定档位,例如 release patch --yes;交互式发布请运行 release。",en:"A bump is required when not interactive or using --yes. Use release patch --yes, or run release interactively."},chooseIndex:{zh:"请输入序号(q 退出): ",en:"Enter a number (q to quit): "},invalidChoice:{zh:"无效选择: {answer}",en:"Invalid choice: {answer}"},emptyAnswer:{zh:"(空)",en:"(empty)"},yesRequired:{zh:"非交互环境需要 --yes",en:"Pass --yes when not interactive"},commandFailed:{zh:"{command} 失败: {detail}",en:"{command} failed: {detail}"},commandFailedShort:{zh:"{command} 失败",en:"{command} failed"},commandExit:{zh:"{command} 退出 {code}",en:"{command} exited {code}"},cliDescription:{zh:"只给需要发的包升版本,再按那次提交发布",en:"Version only the packages that need a release, then publish that commit"},optRoot:{zh:"仓库根目录",en:"Repository root"},optVersionsFile:{zh:"配置文件",en:"Config file"},optPackages:{zh:"覆盖 packagesDir",en:"Override packagesDir"},cmdChanged:{zh:"列出会升版的包",en:"List packages that would be versioned"},optBaseline:{zh:"这一次的比较起点,SHA 或 tag",en:"Comparison start for this run, SHA or tag"},cmdVersion:{zh:"升版本并提交",en:"Bump versions and commit"},argBump:{zh:"patch、minor、major、prerelease、prepatch、preminor、premajor",en:"patch, minor, major, prerelease, prepatch, preminor, or premajor"},optPreid:{zh:"预发布标识,pre* 必填",en:"Prerelease identifier, required for pre*"},optYes:{zh:"自动执行,不补问缺失参数",en:"Run without prompts; supply required options"},optDryRunVersion:{zh:"只打印旧版本到新版本",en:"Print old and new versions only"},optBranch:{zh:"覆盖配置里的 branch",en:"Override branch from the config"},optCommitMessage:{zh:"覆盖 commitMessage",en:"Override commitMessage"},cmdPublish:{zh:"发布最近一次 version 提交里的包",en:"Publish packages listed in the latest version commit"},optDistTag:{zh:"npm dist-tag",en:"npm dist-tag"},optDryRunPublish:{zh:"查询 registry 并预览计划;不执行 hook、上传、标签修改或推送",en:"Query the registry and preview the plan without hooks, uploads, tag changes or pushes"},cmdInit:{zh:"写入带注释的配置",en:"Write a commented config file"},optYesInit:{zh:"不提问,按探测到的目录写默认配置",en:"Write defaults from the detected directory, without prompts"},configExists:{zh:"已有 {file}。下一步: 直接改这个文件,或删掉后重跑 init",en:"Config already exists: {file}. Next: edit that file, or delete it and rerun init"},initIntro:{zh:"写入 {file}",en:"Write {file}"},initFoundDirs:{zh:"发现包目录: {dirs}",en:"Package directories: {dirs}"},initPackagesDir:{zh:"包目录",en:"Package directory"},initInclude:{zh:"源码路径,逗号分隔",en:"Source paths, comma-separated"},initExclude:{zh:"排除路径,逗号分隔",en:"Excluded paths, comma-separated"},initBranch:{zh:"推送分支,回车跳过",en:"Branch to push, Enter to skip"},initBeforeCommit:{zh:"beforeCommit,回车跳过",en:"beforeCommit, Enter to skip"},initBeforePublish:{zh:"beforePublish,回车跳过",en:"beforePublish, Enter to skip"},initWrote:{zh:"已写入 {file}",en:"Wrote {file}"},initNotePackagesDir:{zh:"包所在目录。这次可用 --packages 覆盖",en:"Directory of packages. Override once with --packages"},initNoteCommitMessage:{zh:"%s 换成档位。有 --preid 时再空一格接上,例如 bump: prerelease alpha。查找看正文末尾的 Co-authored-by: change-versions <publish@change-versions.com>,不改提交作者",en:"%s becomes the bump. With --preid, a space and the id follow, for example bump: prerelease alpha. Lookup uses the Co-authored-by: change-versions <publish@change-versions.com> trailer. The commit author stays unchanged"},initNoteBranch:{zh:"不写就不推送。version 只推这个分支,不推 tag",en:"Omit to skip pushing. version pushes this branch only, not tags"},initNoteBeforeCommit:{zh:"版本和 CHANGELOG 写完之后、git commit 之前。失败仅恢复本次拥有的文件",en:"After versions and CHANGELOG are written, before git commit. Failure restores only files owned by this operation"},initNoteBeforePublish:{zh:"确认之后、npm publish 之前。只能改 git 忽略的构建产物",en:"After confirm, before npm publish. May only change gitignored build output"},initNoteAfterPublish:{zh:"要发的包都已在 registry 上之后。不能把工作区弄脏",en:"After every selected package is on the registry. Must leave the tree clean"},initNoteInclude:{zh:"相对仓库根。* 和 ? 不跨过 /,** 可以。命中目录时,目录里的文件也算",en:"Relative to the repo root. * and ? do not cross /, ** may. A matching directory includes files under it"},initNoteExclude:{zh:"命中这里的文件不触发升版。package.json 另比,去掉 devDependencies 后有差异才算",en:"Files that match here do not trigger a bump. package.json is compared separately, after dropping devDependencies"}}});import lt from"picomatch";import Te from"semver";import{YAMLParseError as sn,parse as an}from"yaml";function Xe(e){return dt.has(e)}function De(e,t){if(!mt.includes(e))throw new l(i("badBump",{bump:e,list:mt.join(", ")}));let n=e;if(cn.has(n)&&!t)throw new l(i("preidRequired",{kind:n}));if(dt.has(n)&&t)throw new l(i("preidForbidden"));return n}function Fe(e){let t=gn(e);for(let d of Object.keys(t))if(!ln.has(d))throw new l(i("unknownField",{name:d}));let n=t.packagesDir===void 0?"packages":Qe(t.packagesDir,"packagesDir"),r=t.commitMessage===void 0?"bump: %s":Qe(t.commitMessage,"commitMessage"),s=t.branch===void 0?void 0:Qe(t.branch,"branch"),o=t.hooks==null?{}:un(t.hooks),a=t.include==null?[]:Ye(t.include,"include"),c=t.exclude==null?[]:Ye(t.exclude,"exclude");if(!a.length)throw new l(i("includeRequired"));if(!r.includes("%s"))throw new l(i("commitMessageNeedsToken"));for(let d of[...a,...c]){if(d.includes("!"))throw new l(i("patternBang",{pattern:d}));if(/\[[^\]]+\]/.test(d))throw new l(i("patternClass",{pattern:d}))}let m=t.commitFiles==null?void 0:Ye(t.commitFiles,"commitFiles");return{packagesDir:n,commitMessage:r,branch:s,hooks:o,include:a,exclude:c,...m?{commitFiles:m}:{}}}function gn(e){try{let t=an(e);if(t==null)return{};if(!pt(t))throw new l(i("badLine",{line:1}));return t}catch(t){if(t instanceof l)throw t;if(t instanceof sn)throw new l(i("badLine",{line:t.linePos?.[0]?.line??1}));throw t}}function un(e){if(!pt(e))throw new l(i("badHook",{line:"hooks"}));let t={};for(let[n,r]of Object.entries(e)){if(!mn.has(n))throw new l(i("unknownHook",{name:n}));if(typeof r!=="string"||!r)throw new l(i("hookMissingCommand",{name:n}));t[n]=r}return t}function Ye(e,t){if(!Array.isArray(e))throw new l(i("badPatternLine",{line:t}));return e.map((n)=>{if(typeof n!=="string"||!n)throw new l(i("badPatternLine",{line:t}));return n})}function Qe(e,t){if(typeof e!=="string"||!e)throw new l(i("missingValue",{name:t}));return e}function pt(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function gt(e,t){let n={dot:!0};if(lt(t,n)(e))return!0;if(t.endsWith("/**"))return!1;return lt(`${t}/**`,n)(e)}function Ze(e,t,n){return t.some((r)=>gt(e,r))&&!n.some((r)=>gt(e,r))}function ht(e,t,n){let r=new Set(n),s=`${t}/`,o=new Map;for(let a of e.split(`
|
|
27
|
+
`)){if(!a.startsWith(s))continue;let c=a.slice(s.length),m=c.split("/")[0];if(!m||!c.includes("/")||!r.has(m))continue;let d=o.get(m)??[];d.push(a),o.set(m,d)}return o}function ft(e,t,n,r,s,o){let a=[],c=[];for(let m of e){let d=t.get(m);if(!d?.length){c.push(m);continue}let h=`${o}/${m}/package.json`;if(d.some((f)=>f!==h&&Ze(f,n,r))||d.includes(h)&&!s(m))a.push(m);else c.push(m)}return{changed:a,ignored:c}}function bt(e,t){return JSON.stringify($e(ut(e)))===JSON.stringify($e(ut(t)))}function ut(e){if(!e||typeof e!=="object"||Array.isArray(e))return e;let t={...e};return delete t.devDependencies,t}function $e(e){if(Array.isArray(e))return e.map($e);if(e&&typeof e==="object"){let t=e;return Object.fromEntries(Object.keys(t).sort().map((n)=>[n,$e(t[n])]))}return e}function wt(e,t,n){let r=n?Te.inc(e,t,n):Te.inc(e,t);if(!r)throw new l(i("badSemver",{version:e}));return r}function yt(e,t,n){let r=new Set(t),s=new Map(e.map((a)=>[a,[]]));for(let a of e)for(let c of n(a))s.get(c)?.push(a);let o=[...t];while(o.length){let a=o.pop();if(!a)break;for(let c of s.get(a)??[]){if(r.has(c))continue;r.add(c),o.push(c)}}return e.filter((a)=>r.has(a))}function vt(e,t,n){let r=e.replace("%s",t);return n?`${r} ${n}`:r}function Ne(e){return e.length>0&&e.every((t)=>Boolean(Te.valid(t.to))&&Te.prerelease(t.to)==null)}function et(e){return/^v\d/.test(e)}function kt(e){return/^v\d+\.\d+\.\d+$/.test(e)}function de(e){let t=[];for(let n of e.split(`
|
|
28
|
+
`)){let r=/^(\S+) (\S+) => (\S+)$/.exec(n.trim());if(r)t.push({name:r[1],from:r[2],to:r[3]})}return t}function Pt(e){let t=new Map(e.map((o)=>[o.folder,o])),n=new Set,r=[],s=(o,a)=>{if(n.has(o.folder))return;if(a.has(o.folder))throw new l(i("dependencyCycle",{name:o.name}));a.add(o.folder);for(let c of o.deps){let m=t.get(c);if(m)s(m,a)}a.delete(o.folder),n.add(o.folder),r.push(o)};for(let o of e)s(o,new Set);return r}function ye(e){return/ENEEDAUTH|E401|E403|need auth|not logged in|401 Unauthorized|403 Forbidden/i.test(e)}function ve(e){try{return JSON.parse(e)?.error?.code==="E404"}catch{return!1}}var l,mt,dt,cn,ln,mn,dn="publish@change-versions.com",pn,ue;var N=G(()=>{D();l=class l extends Error{auth;constructor(e,t=!1){super(e);this.name="Fail",this.auth=t}};mt=["patch","minor","major","prerelease","prepatch","preminor","premajor"],dt=new Set(["patch","minor","major"]),cn=new Set(["prerelease","prepatch","preminor","premajor"]);ln=new Set(["packagesDir","commitMessage","branch","hooks","include","exclude","commitFiles"]),mn=new Set(["beforeCommit","beforePublish","afterPublish"]);pn=`change-versions <${dn}>`,ue=`Co-authored-by: ${pn}`});import{spawn as xt}from"node:child_process";function x(e,t,n){return new Promise((r)=>{let s=xt(e,t,{cwd:n,stdio:["ignore","pipe","pipe"]}),o="",a="";s.stdout.on("data",(c)=>{o+=c}),s.stderr.on("data",(c)=>{a+=c}),s.on("error",(c)=>r({code:1,stdout:o,stderr:`${a}${c.message}`})),s.on("close",(c)=>r({code:c??1,stdout:o,stderr:a}))})}async function y(e,t,n){let r=await x(e,t,n);if(r.code!==0){let s=(r.stderr||r.stdout).trim();throw new l(s?i("commandFailed",{command:e,detail:s}):i("commandFailedShort",{command:e}))}return r.stdout}function Ee(e,t,n,r){return new Promise((s,o)=>{let a=xt(e,t,{cwd:n,stdio:"inherit",env:{...process.env,...r}});a.on("error",o),a.on("exit",(c)=>{if(c===0)s();else o(new l(i("commandExit",{command:e,code:c??1})))})})}var W=G(()=>{D();N()});function Ct(e){let t=e.packages.map((m)=>m.folder),n=new Map(e.packages.map((m)=>[m.folder,m])),r=new Map(e.packages.map((m)=>[m.name,m])),s=new Map(e.packages.map((m)=>[m.name,m.folder])),{changed:o}=ft(t,e.filesByFolder,e.include,e.exclude,(m)=>e.devOnly.has(m),e.packagesDir),a=yt(t,o,(m)=>hn(n.get(m),s));for(let m of a){let d=n.get(m);if(!d||d.private)continue;for(let h of Object.keys(d.dependencies??{}))if(r.get(h)?.private)throw new l(i("publicDependsOnPrivate",{name:d.name,dep:h}))}let c=new Set(o);return{changed:o,dependents:a.filter((m)=>!c.has(m))}}function hn(e,t){if(!e)return[];return[...Object.keys(e.dependencies??{}),...Object.keys(e.devDependencies??{})].flatMap((r)=>{let s=t.get(r);return s?[s]:[]})}var St=G(()=>{D();N()});import pe from"node:fs";import tt from"node:path";import fn from"node:os";import{randomUUID as bn}from"node:crypto";import{AsyncLocalStorage as wn}from"node:async_hooks";async function X(e,t,n){if(t)return n();e=tt.resolve(e);let r=tt.resolve(e,(await y("git",["rev-parse","--git-common-dir"],e)).trim()),s=tt.join(r,"change-versions.lock");if(nt.getStore()?.has(s))return n();let o={pid:process.pid,host:fn.hostname(),token:bn()},a;try{a=pe.openSync(s,"wx",384)}catch(d){if(d.code!=="EEXIST")throw d;let h="";try{h=pe.readFileSync(s,"utf8")}catch{}throw new l(i("repositoryLocked",{file:s,owner:h.trim()}))}let c=()=>{try{if(JSON.parse(pe.readFileSync(s,"utf8")).token===o.token)pe.unlinkSync(s)}catch{}};try{pe.writeFileSync(a,JSON.stringify(o))}finally{pe.closeSync(a)}let m=()=>{if(process.listenerCount("SIGINT")<=1&&process.listenerCount("SIGTERM")<=1)process.exit(1)};process.on("exit",c),process.on("SIGINT",m),process.on("SIGTERM",m);try{return await nt.run(new Set([...nt.getStore()??[],s]),n)}finally{process.off("SIGINT",m),process.off("SIGTERM",m),process.off("exit",c),c()}}var nt;var ke=G(()=>{W();N();D();nt=new wn});function vn(e){if(/^[a-zA-Z0-9_./:@=+-]+$/.test(e))return e;return"'"+e.replaceAll("'","'\\''")+"'"}function O(e){let t=["change-versions","publish",`--dist-tag=${e.distTag}`,`--root=${e.root}`,`--versions-file=${e.versionsFile}`];if(e.commit)t.push(`--commit=${e.commit}`);if(e.packages)t.push(`--packages=${e.packages}`);if(e.retryUnpublished)t.push("--retry-unpublished");return t.map(vn).join(" ")}import kn from"node:readline/promises";import{stdin as Rt,stdout as zt}from"node:process";async function it(e){let t=kn.createInterface({input:Rt,output:zt}),n=new AbortController,r=()=>n.abort();t.once("SIGINT",r),t.once("close",r);try{return await t.question(e,{signal:n.signal})}catch(s){if(n.signal.aborted)throw new J;throw s}finally{t.off("SIGINT",r),t.off("close",r),t.close()}}function T(){return Boolean(Rt.isTTY&&zt.isTTY)}async function Tt(e,t){if(!T())throw new l(i("bumpRequired"));console.log(S(e)),t.forEach((n,r)=>{let s=n.tone?Pn[n.tone](n.label):n.label;console.log(` ${F(String(r+1))}) ${s}`)});while(!0){let n=(await it(F(i("chooseIndex")))).trim();if(n.toLowerCase()==="q")throw new J;let r=/^\d+$/.test(n)?Number(n)-1:-1;if(Number.isInteger(r)&&r>=0&&r<t.length)return r;console.log(k(i("invalidChoice",{answer:n||i("emptyAnswer")})))}}async function $t(e,t){return t[await Tt(e,t.map((n)=>({label:n})))]}async function Z(e,t){return t[await Tt(e,t)].value}async function L(e,t=""){if(!T())throw new l(i("yesRequired"));let n=t?` ${M(`[${t}]`)}`:"",r=(await it(`${S(e)}${n} `)).trim();if(r.toLowerCase()==="q")throw new J;return r||t}async function se(e){if(!T())throw new l(i("yesRequired"));console.log(S(e));while(!0){let t=(await it(`${k("[y/N/q]")} `)).trim().toLowerCase();if(t==="q")throw new J;if(t==="y"||t==="yes")return!0;if(!t||t==="n"||t==="no")return!1;console.log(k(i("confirmAnswer")))}}var J,Pn;var _=G(()=>{I();D();N();J=class J extends l{constructor(){super(i("interactiveCancelled"))}};Pn={positive:M,caution:k,muted:v}});function Dt(e){let t=[];if(e.beforePublish)t.push({kind:"hook",name:"beforePublish",command:e.beforePublish});for(let n of Pt(e.packages.filter((r)=>!r.private))){let r=n.registry??"";if(!n.published||n.distTagVersion!==n.version)t.push(n.published?{kind:"dist-tag",name:n.name,version:n.version,folder:n.folder,registry:r,tag:e.distTag}:{kind:"publish",name:n.name,version:n.version,folder:n.folder,registry:r,tag:e.distTag});if(e.formal)t.push({kind:"tag",name:n.name,version:n.version,commit:n.commit??e.commit})}if(e.afterPublish)t.push({kind:"hook",name:"afterPublish",command:e.afterPublish});return t}var Ft=G(()=>{N()});import Ie from"node:path";import je from"semver";async function Bt(e){return X(e.root,Boolean(e.dryRun),()=>xn(e))}async function xn(e){console.log(e.dryRun?k(i("publishPreview")):S(i("publishPreparing")));let{root:t,startHead:n,config:r,release:s,entries:o,formal:a,registryOf:c,published:m,distTagVersions:d,steps:h}=await ae(e),C=O({...e,root:t,commit:s.hash}),f={CHANGE_VERSIONS_PUBLISH_CONTEXT:JSON.stringify({schemaVersion:1,root:t,packagesDir:r.packagesDir,commit:s.hash,distTag:e.distTag,packages:h.flatMap((g)=>g.kind==="publish"?[{name:g.name,version:g.version,path:Ie.join(r.packagesDir,g.folder)}]:[])})};for(let g of o)if(m.has(g.folder)&&d.get(g.folder)===g.to)console.log(v(i("alreadyTagged",{name:g.name,version:g.to,tag:e.distTag,registry:c.get(g.folder)||""})));if(console.log(i("publishPlanSummary",{uploads:h.filter((g)=>g.kind==="publish").length,retags:h.filter((g)=>g.kind==="dist-tag").length,tags:h.filter((g)=>g.kind==="tag").length})),e.dryRun){rt({steps:h,formal:a,config:r,entries:o},C);return}console.log(v(i("publishResumeInfo"))),console.log(S(i("willPublish")));for(let g of o){if(m.has(g.folder)&&d.get(g.folder)===g.to)continue;let E=g.pkg.private?` ${v(i("privateMark"))}`:m.has(g.folder)?` ${v(i("distTagOnlyMark"))}`:"";console.log(` ${Q(g.name)} ${oe(g.to)}${E}`)}if(!e.yes&&!await se(i("confirmPublish")))throw new l(i("cancelledPublish"));let u=new Map(o.map((g)=>[g.folder,g.pkg.private?"summaryPrivate":m.has(g.folder)&&d.get(g.folder)===g.to?"summarySkipped":"summaryPending"])),w="beforePublish",p,P=!1,b=(g)=>g==="summaryPublished"||g==="summaryRetagged"?M:g==="summaryFailed"?ze:g==="summaryPending"?k:v,R=()=>{console.log((P?M:ze)(i(P?"publishComplete":"publishIncomplete"))),console.log(i("publishSummaryContext",{commit:s.hash,tag:e.distTag}));let g=new Map;for(let E of o){let z=u.get(E.folder);g.set(z,(g.get(z)??0)+1);let re=c.get(E.folder);console.log(` ${b(z)(i(z))}: ${Q(E.name)}@${Q(E.to)}${re?` — ${v(re)}`:""}`)}if(console.log([...g].map(([E,z])=>`${b(E)(i(E))}: ${Q(String(z))}`).join(", ")),P)console.log(M(i("publishReady"))),console.log(v(i(h.some((E)=>E.kind==="tag")?r.branch?"gitTagsPushed":"gitTagsLocal":"noGitTag")));else{if(console.log(ze(i("publishFailedStage",{stage:w}))),w==="git tag / git push")console.log(k(i("publishTagRecovery")));console.log(k(i("publishRetryTitle"))),console.log(S(i("publishRetry"))),console.log(v(i("publishResumeInfo"))),console.log(F(C))}},B=()=>{if(p)u.set(p,"summaryFailed");R(),console.error(H(i("publishInterrupted"))),process.exit(1)};process.on("SIGINT",B),process.on("SIGTERM",B);try{await At(t,r.hooks.beforePublish,"beforePublish",f),await Pe(t,i("beforePublishDirty")),await Ae(t,n);for(let g of h){if(g.kind==="tag"){w="git tag / git push",console.log(S(i("executingStep",{step:Be(g)}))),await Cn(t,r.branch,[{name:g.name,to:g.version,commit:g.commit}]);continue}if(g.kind!=="publish"&&g.kind!=="dist-tag")continue;let E=Ie.join(t,r.packagesDir,g.folder);w=`${g.kind==="publish"?"npm publish":"npm dist-tag add"} ${g.name}@${g.version}`,p=g.folder;let z="summaryPending";await It(async()=>{let re=await jt(t,g.name,g.version,g.registry);if(!re&&g.kind==="dist-tag")throw new l(i("registryVersionDisappeared",{name:g.name,version:g.version}));let at=await Mt(t,g.name,g.tag,g.registry,!re);if(Ht(g.name,g.version,at,g.tag),await Pe(t,i("publishSourceDirty")),await Ae(t,n),re&&at===g.version)z="summarySkipped",console.log(v(i("alreadyTagged",{name:g.name,version:g.version,tag:g.tag,registry:g.registry})));else if(re)w=`npm dist-tag add ${g.name}@${g.version}`,console.log(S(i("executingStep",{step:Be({...g,kind:"dist-tag"})}))),await Nt(t,["dist-tag","add",`${g.name}@${g.version}`,g.tag,`--registry=${g.registry}`],g.registry),z="summaryRetagged";else w=`npm publish ${g.name}@${g.version}`,console.log(S(i("executingStep",{step:Be({...g,kind:"publish"})}))),await Nt(E,["publish",`--tag=${g.tag}`,`--registry=${g.registry}`],g.registry),z="summaryPublished"}),u.set(g.folder,z),p=void 0,await Pe(t,i("publishSourceDirty")),await Ae(t,n)}w="afterPublish",await At(t,r.hooks.afterPublish,"afterPublish",f),await Pe(t,i("afterPublishDirty")),await Ae(t,n),P=!0}catch(g){if(p)u.set(p,"summaryFailed");throw g}finally{process.off("SIGINT",B),process.off("SIGTERM",B),R()}}async function ae(e,t=!1,n=!1){let r=Ie.resolve(e.root);if(!t)await V(r);let s=(await y("git",["rev-parse","HEAD"],r)).trim(),o=he(r,e.versionsFile);if(e.packages)o.packagesDir=e.packages;let a=await j(r,e.commit);if(!a?.lines.length)throw new l(i("noVersionCommit"));let c=ee(r,o.packagesDir),m=new Map(c.map((b)=>[A(r,o.packagesDir,b).name,b])),d=a.lines.map((b)=>{let R=m.get(b.name);if(!R)throw new l(i("packageNotInDir",{dir:o.packagesDir,name:b.name}));let B=A(r,o.packagesDir,R);if(B.version!==b.to)throw new l(i("releaseVersionMismatch",{name:b.name,expected:b.to,actual:B.version,commit:a.hash}));return{...b,folder:R,pkg:B,commit:a.sourceCommits.get(b.name)??a.hash,deps:He(B,m)}}),h=new Set;for(let b of d){let R=await x("git",["diff","--quiet",b.commit,s,"--",`${o.packagesDir}/${b.folder}`],r);if(R.code===1)h.add(b.folder);if(R.code!==0&&R.code!==1)throw new l(i("gitFailed",{detail:R.stderr.trim()}))}if(h.size&&!n)throw new l(i("releaseContentsChanged"));if(!t)console.log(i("publishSummaryContext",{commit:a.hash,tag:e.distTag}));let C=Ne(a.lines);if(C)await Me(r,d.filter((b)=>!b.pkg.private));let f=new Map;for(let b of d){if(b.pkg.private)continue;let R=await Rn(r,b.pkg);if(f.set(b.folder,R),!t)console.log(i("checkingRegistry",{name:b.name,version:b.to,registry:R}))}let u=new Set;for(let b of d){let R=f.get(b.folder);if(!R||u.has(R))continue;if(u.add(R),!t)await Sn(r,R)}let w=new Set,p=new Map;for(let b of d){if(b.pkg.private)continue;let R=f.get(b.folder);if(!R)continue;await It(async()=>{let B=await jt(r,b.name,b.to,R);if(B)w.add(b.folder);let g=await Mt(r,b.name,e.distTag,R,!B);if(!t)Ht(b.name,b.to,g,e.distTag);p.set(b.folder,g)})}let P=Dt({packages:d.map((b)=>({name:b.name,version:b.to,folder:b.folder,private:b.pkg.private,deps:b.deps,registry:f.get(b.folder),published:w.has(b.folder),distTagVersion:p.get(b.folder),commit:b.commit})),distTag:e.distTag,formal:C,commit:a.hash,beforePublish:o.hooks.beforePublish,afterPublish:o.hooks.afterPublish});return{root:r,startHead:s,config:o,release:a,entries:d,formal:C,registryOf:f,published:w,distTagVersions:p,steps:P,changed:h}}function rt(e,t){for(let n of e.steps)if(console.log(`${k(i("plannedStep",{step:""}))}${Be(n)}`),n.kind==="tag"&&e.config.branch)console.log(k(i("plannedStep",{step:`git push origin refs/tags/${n.name}@${n.version}`})));if(!e.formal)console.log(v(i("noGitTag")));console.log(k(i("publishPreviewComplete"))),console.log(S(i("publishPreviewNext"))),console.log(F(t))}function Be(e){if(e.kind==="hook")return`${v(`${e.name}:`)} ${F(e.command)}`;if(e.kind==="tag")return F(`git tag ${e.name}@${e.version} ${e.commit}`);if(e.kind==="dist-tag")return F(`npm dist-tag add ${e.name}@${e.version} ${e.tag} --registry=${e.registry}`);return F(`npm publish --tag=${e.tag} --registry=${e.registry} ${e.name}@${e.version}`)}async function j(e,t){if((await x("git",["rev-parse","--verify","HEAD"],e)).code!==0)return null;let r;if(t){let c=await x("git",["rev-parse","--verify","--end-of-options",`${t}^{commit}`],e);if(c.code!==0)throw new l(i("badReleaseCommit",{commit:t}));let m=c.stdout.trim();if((await x("git",["merge-base","--is-ancestor",m,"HEAD"],e)).code!==0)throw new l(i("badReleaseCommit",{commit:t}));r={hash:m,subject:(await y("git",["show","-s","--format=%s",m],e)).trim(),body:await y("git",["show","-s","--format=%b",m],e)}}else r=(await fe(e))[0];if(!r)return null;let s=de(r.body);if(!s.length){if(t)throw new l(i("badReleaseCommit",{commit:t}));return null}if(new Set(s.map((c)=>c.name)).size!==s.length||s.some((c)=>!je.valid(c.from)||!je.valid(c.to)))throw new l(i("badReleaseCommit",{commit:r.hash}));let o=/^Change-Versions-Dist-Tag: (\S+)$/m.exec(r.body)?.[1],a=new Map;for(let c of r.body.split(`
|
|
29
|
+
`).filter((m)=>m.startsWith("Change-Versions-Source:"))){let m=/^Change-Versions-Source: (\S+) ([a-f0-9]{40}|[a-f0-9]{64})$/.exec(c);if(!m||a.has(m[1])||!s.some((d)=>d.name===m[1]))throw new l(i("badReleaseCommit",{commit:r.hash}));a.set(m[1],m[2])}if(a.size&&a.size!==s.length)throw new l(i("badReleaseCommit",{commit:r.hash}));for(let c of new Set(a.values()))if((await x("git",["merge-base","--is-ancestor",c,r.hash],e)).code!==0)throw new l(i("badReleaseCommit",{commit:r.hash}));return{hash:r.hash,subject:r.subject,lines:s,distTag:o,sourceCommits:a}}async function Cn(e,t,n){await Me(e,n);let r=n.map((o)=>`${o.name}@${o.to}`);for(let o of n){let a=`${o.name}@${o.to}`;if((await x("git",["rev-parse","--verify",`refs/tags/${a}^{commit}`],e)).code===0)continue;await y("git",["tag",a,o.commit],e)}if(!t)return;let s=await x("git",["push","origin",...r.map((o)=>`refs/tags/${o}`)],e);if(s.code!==0)throw new l(i("tagPushFailed",{detail:s.stderr.trim()}))}async function Me(e,t){for(let n of t){let r=`${n.name}@${n.to}`,s=await x("git",["rev-parse","--verify",`refs/tags/${r}^{commit}`],e);if(s.code===0&&s.stdout.trim()!==n.commit)throw new l(i("tagPointsElsewhere",{tag:r}))}}async function Ae(e,t){if((await y("git",["rev-parse","HEAD"],e)).trim()!==t)throw new l(i("publishHeadChanged"))}async function It(e){let t="";for(let n=0;n<3;n++)try{await e();return}catch(r){if(r instanceof l)throw r;t=r instanceof Error?r.message:String(r)}throw new l(i("networkFailed",{detail:t}))}async function Nt(e,t,n){let r=await x("npm",t,e);if(r.code===0)return;let s=`${r.stderr}${r.stdout}`;if(process.stderr.write(r.stderr),ye(s))throw new l(i("notLoggedIn",{registry:n}),!0);throw Error(s.trim()||i("npmFailed"))}async function jt(e,t,n,r){let s=await x("npm",["view",`${t}@${n}`,"version","--json",`--registry=${r}`],e);if(s.code===0){let a;try{a=JSON.parse(s.stdout)}catch{}if(a===n||Array.isArray(a)&&a.length===1&&a[0]===n)return!0;throw Error(i("unexpectedRegistryVersion",{name:t,version:n,registry:r}))}let o=`${s.stderr}${s.stdout}`;if(ye(o))throw new l(i("notLoggedIn",{registry:r}),!0);if(ve(s.stdout)||ve(s.stderr))return!1;throw Error(o.trim()||i("npmViewFailed"))}async function Mt(e,t,n,r,s=!1){let o=await x("npm",["view",t,"dist-tags","--json",`--registry=${r}`],e);if(o.code!==0){let m=`${o.stderr}${o.stdout}`.trim();if(ye(m))throw new l(i("notLoggedIn",{registry:r}),!0);if(s&&(ve(o.stdout)||ve(o.stderr)))return;throw Error(m||i("npmViewFailed"))}let a;try{a=JSON.parse(o.stdout)}catch{}if(Array.isArray(a)&&a.length===1)a=a[0];if(!a||typeof a!=="object"||Array.isArray(a))throw Error(i("unexpectedRegistryTags",{name:t,tag:n,registry:r}));let c=Object.prototype.hasOwnProperty.call(a,n)?a[n]:void 0;if(c!==void 0&&(typeof c!=="string"||!je.valid(c)))throw Error(i("unexpectedRegistryTags",{name:t,tag:n,registry:r}));return c}function Ht(e,t,n,r){if(n&&je.gt(n,t))throw new l(i("distTagDowngrade",{name:e,version:t,current:n,tag:r}))}async function Sn(e,t){let n=await x("npm",["whoami",`--registry=${t}`],e);if(n.code===0)return;let r=`${n.stderr}${n.stdout}`;if(ye(r))throw new l(i("notLoggedIn",{registry:t}),!0);throw new l(i("registryUnreachable",{registry:t,detail:r.trim()}))}async function Rn(e,t){if(t.publishConfig?.registry)return t.publishConfig.registry.replace(/\/$/,"");if(t.name.startsWith("@")&&t.name.includes("/")){let r=t.name.slice(0,t.name.indexOf("/")),s=await Et(e,`${r}:registry`);if(s&&s!=="undefined"&&s!=="null")return s.replace(/\/$/,"")}let n=await Et(e,"registry");if(!n||n==="undefined"||n==="null")throw new l(i("noNpmRegistry",{detail:"npm config get registry: empty value"}));return n.replace(/\/$/,"")}async function Et(e,t){let n=await x("npm",["config","get",t],e);if(n.code!==0){let r=n.stderr.trim()||n.stdout.trim()||`npm config get ${t}: exit ${n.code}`;throw new l(i("noNpmRegistry",{detail:r}))}return n.stdout.trim()}async function At(e,t,n,r){if(!t)return;console.log(S(i("executingStep",{step:`${n}: ${t}`})));try{await Ee("sh",["-c",t],e,r)}catch(s){let o=s instanceof Error?s.message:String(s);throw new l(i("hookFailed",{name:n,detail:o}))}}async function xe(e,t,n){return t??(await j(Ie.resolve(e),n))?.distTag??"latest"}var K=G(()=>{ke();I();D();N();W();_();Ft();ce()});import be from"node:fs";import Oe from"node:path";function he(e,t){let n=Oe.resolve(e,t);if(!be.existsSync(n))throw new l(i("configUnreadable",{file:t}));return Fe(be.readFileSync(n,"utf8"))}function ee(e,t){let n=Oe.join(e,t);if(!be.existsSync(n))throw new l(i("packagesDirMissing",{dir:t}));return be.readdirSync(n).filter((r)=>!r.startsWith(".")&&be.existsSync(Oe.join(n,r,"package.json")))}function A(e,t,n){let r=JSON.parse(be.readFileSync(Oe.join(e,t,n,"package.json"),"utf8"));if(!r.name||!r.version)throw new l(i("packageJsonIncomplete",{folder:n}));return r}function He(e,t){let n=[];for(let r of["dependencies","devDependencies"])for(let s of Object.keys(e[r]??{})){let o=t.get(s);if(o)n.push(o)}return n}async function V(e){let t=await x("git",["status","--porcelain"],e);if(t.code!==0)throw new l(i("gitFailed",{detail:t.stderr.trim()}));if(t.stdout.trim())throw new l(i("dirtyTree"))}async function Pe(e,t){let n=await x("git",["status","--porcelain"],e);if(n.code!==0)throw new l(i("gitFailed",{detail:n.stderr.trim()}));if(n.stdout.trim())throw new l(t)}async function Ve(e){return(await y("git",["log","--format=%H%x1f%s"],e)).split(`
|
|
30
|
+
`).filter(Boolean).map((n)=>{let[r,s]=n.split("\x1F");return{hash:r,subject:s??""}})}async function fe(e){let t=await y("git",["log","-F",`--grep=${ue}`,"--format=%H%x1f%s%x1f%b%x1e"],e),n=[];for(let r of t.split("\x1E")){let s=r.replace(/^\n/,"").trim();if(!s)continue;let[o,a,c]=s.split("\x1F");if(!o)continue;n.push({hash:o,subject:a??"",body:c??""})}return n}async function te(e,t){if(t){let o=await x("git",["rev-parse","--verify",`${t}^{commit}`],e);if(o.code!==0)throw new l(i("badBaseline",{rev:t}));return o.stdout.trim()}if((await x("git",["rev-parse","--verify","HEAD"],e)).code!==0)throw new l(i("noBaseline"));let r=await fe(e),s=(await Ve(e)).find((o)=>et(o.subject));if(r[0]){if(s&&s.hash!==r[0].hash&&(await x("git",["merge-base","--is-ancestor",r[0].hash,s.hash],e)).code===0)return s.hash;return r[0].hash}return s?.hash??Tn()}async function Ge(e,t,n,r=!n){let s=await te(e,n),o=ee(e,t.packagesDir),a=o.map((u)=>({...A(e,t.packagesDir,u),folder:u})),c=await zn(e,a,s,r),m=new Map,d=new Map;for(let u of o){let w=c.get(u);d.set(w,[...d.get(w)??[],u])}for(let[u,w]of d){let p=await y("git",["diff","--name-only",u,"HEAD","--",...w.map((P)=>`${t.packagesDir}/${P}`)],e);for(let[P,b]of ht(p,t.packagesDir,w))m.set(P,b)}let h=new Set;for(let[u,w]of m){let p=c.get(u),P=`${t.packagesDir}/${u}/package.json`;if(w.includes(P)&&await ot(e,p,"HEAD",P))h.add(u)}let{changed:C,dependents:f}=Ct({packages:a,filesByFolder:m,devOnly:h,include:t.include,exclude:t.exclude,packagesDir:t.packagesDir});return{baseline:s,changed:C,dependents:f}}async function zn(e,t,n,r){let s=new Map(t.map((f)=>[f.folder,n]));if(!r)return s;let o=await fe(e);if(!o.length||o[0].hash!==n)return s;let a=(await Ve(e)).find((f)=>et(f.subject))?.hash,c=o[o.length-1].hash,m=await x("git",["rev-parse","--verify",`${c}^`],e),d=a??(m.code===0?m.stdout.trim():c);for(let f of t)s.set(f.folder,d);let h=new Map(t.map((f)=>[f.name,f.folder]));await Promise.resolve().then(() => K());for(let f of o){if(!h.size)break;if(!de(f.body).some((w)=>h.has(w.name)))continue;let u=await j(e,f.hash);if(!u)continue;for(let w of u.lines){let p=h.get(w.name);if(!p)continue;let P=u.sourceCommits.get(w.name)??u.hash,b=a&&(await x("git",["merge-base","--is-ancestor",P,a],e)).code===0;s.set(p,b?a:P),h.delete(w.name)}}return s}async function ot(e,t,n,r){let s=await Ot(e,`${t}:${r}`),o=await Ot(e,`${n}:${r}`);if(s===null||o===null)return!1;try{return bt(JSON.parse(s),JSON.parse(o))}catch{return!1}}async function Ot(e,t){let n=await x("git",["show",t],e);return n.code===0?n.stdout:null}function Tn(){throw new l(i("noBaseline"))}var ce=G(()=>{D();N();W();St()});import{CommitParser as On}from"conventional-commits-parser";import{writeChangelogString as Vn}from"conventional-changelog-writer";function Kt(e){return e.find((t)=>Ne(de(t.body)))?.hash}function Yt(e,t,n,r,s,o){let a=`${n}/${t}/package.json`,c=`${n}/${t}/`,m=[];for(let d of e)if(d.files.some((C)=>C!==a&&C.startsWith(c)&&Ze(C,r,s))||d.files.includes(a)&&o.has(d.hash))m.push({hash:d.hash,body:d.body});return m}async function Qt(e){let t=new Date().toISOString().slice(0,10),n=[`## ${e.version} (${t})`];if(e.previousTag){let o=`../../compare/${encodeURIComponent(e.previousTag)}...${encodeURIComponent(e.currentTag)}`;n.push(`[${e.previousTag}...${e.currentTag}](${o})`)}let r=new On({noteKeywords:["BREAKING CHANGE","BREAKING-CHANGE"]}),s=[];for(let o of e.messages){let a;try{a=r.parse(o.body)}catch{continue}s.push({...a,hash:o.hash.slice(0,7),notes:a.notes??[],subject:a.subject})}if(s.length){let a=(await Vn(s,{version:e.version,date:t},{groupBy:"type",mainTemplate:Ln,transform(c){let d=(c.notes??[]).some((C)=>/breaking/i.test(C.title)),h=c.type??"";if(Gn.has(h)&&!d)return null;if(!Jt[h]&&!d)return null;return{type:Jt[h]??null}}})).trim();if(a)n.push("",a);else if(e.dependencies.length)n.push("",_t(e.dependencies))}else if(e.dependencies.length)n.push("",_t(e.dependencies).trimEnd());return`${n.join(`
|
|
25
31
|
`).trim()}
|
|
26
|
-
`}function
|
|
32
|
+
`}function _t(e){return`### Dependencies
|
|
27
33
|
|
|
28
34
|
* update dependencies ${e.map((t)=>`${t.name}@${t.version}`).join(", ")}
|
|
29
|
-
`}var
|
|
35
|
+
`}var Gn,Jt,Ln=`{{#each commitGroups}}
|
|
30
36
|
{{#if title}}
|
|
31
37
|
### {{title}}
|
|
32
38
|
|
|
@@ -44,21 +50,23 @@ Wait for it to finish. If the owner has exited, verify no release is running bef
|
|
|
44
50
|
{{/each}}
|
|
45
51
|
|
|
46
52
|
{{/each}}
|
|
47
|
-
`;var
|
|
48
|
-
`),i=O("red",t,process.stderr);if(!n.length)return i;return[i,...n.map((o)=>O("yellow",o,process.stderr))].join(`
|
|
49
|
-
`)}function W(e){return O("green",e,process.stdout)}function k(e){return O("yellow",e,process.stdout)}function pe(e){return O("red",e,process.stdout)}R();R();F();import{spawn as dt}from"node:child_process";function x(e,t,n){return new Promise((i)=>{let o=dt(e,t,{cwd:n,stdio:["ignore","pipe","pipe"]}),s="",a="";o.stdout.on("data",(c)=>{s+=c}),o.stderr.on("data",(c)=>{a+=c}),o.on("error",(c)=>i({code:1,stdout:s,stderr:`${a}${c.message}`})),o.on("close",(c)=>i({code:c??1,stdout:s,stderr:a}))})}async function w(e,t,n){let i=await x(e,t,n);if(i.code!==0){let o=(i.stderr||i.stdout).trim();throw new l(o?r("commandFailed",{command:e,detail:o}):r("commandFailedShort",{command:e}))}return i.stdout}function Pe(e,t,n,i){return new Promise((o,s)=>{let a=dt(e,t,{cwd:n,stdio:"inherit",env:{...process.env,...i}});a.on("error",s),a.on("exit",(c)=>{if(c===0)o();else s(new l(r("commandExit",{command:e,code:c??1})))})})}R();F();import ne from"node:fs";import Ce from"node:path";R();F();function ut(e){let t=e.packages.map((g)=>g.folder),n=new Map(e.packages.map((g)=>[g.folder,g])),i=new Map(e.packages.map((g)=>[g.name,g])),o=new Map(e.packages.map((g)=>[g.name,g.folder])),{changed:s}=rt(t,e.filesByFolder,e.include,e.exclude,(g)=>e.devOnly.has(g),e.packagesDir),a=at(t,s,(g)=>Zt(n.get(g),o));for(let g of a){let d=n.get(g);if(!d||d.private)continue;for(let h of Object.keys(d.dependencies??{}))if(i.get(h)?.private)throw new l(r("publicDependsOnPrivate",{name:d.name,dep:h}))}let c=new Set(s);return{changed:s,dependents:a.filter((g)=>!c.has(g))}}function Zt(e,t){if(!e)return[];return[...Object.keys(e.dependencies??{}),...Object.keys(e.devDependencies??{})].flatMap((i)=>{let o=t.get(i);return o?[o]:[]})}function ie(e,t){let n=Ce.resolve(e,t);if(!ne.existsSync(n))throw new l(r("configUnreadable",{file:t}));return ye(ne.readFileSync(n,"utf8"))}function J(e,t){let n=Ce.join(e,t);if(!ne.existsSync(n))throw new l(r("packagesDirMissing",{dir:t}));return ne.readdirSync(n).filter((i)=>!i.startsWith(".")&&ne.existsSync(Ce.join(n,i,"package.json")))}function D(e,t,n){let i=JSON.parse(ne.readFileSync(Ce.join(e,t,n,"package.json"),"utf8"));if(!i.name||!i.version)throw new l(r("packageJsonIncomplete",{folder:n}));return i}function Se(e,t){let n=[];for(let i of["dependencies","devDependencies"])for(let o of Object.keys(e[i]??{})){let s=t.get(o);if(s)n.push(s)}return n}async function L(e){let t=await x("git",["status","--porcelain"],e);if(t.code!==0)throw new l(r("gitFailed",{detail:t.stderr.trim()}));if(t.stdout.trim())throw new l(r("dirtyTree"))}async function Ge(e,t){let n=await x("git",["status","--porcelain"],e);if(n.code!==0)throw new l(r("gitFailed",{detail:n.stderr.trim()}));if(n.stdout.trim())throw new l(t)}async function Ve(e){return(await w("git",["log","--format=%H%x1f%s"],e)).split(`
|
|
50
|
-
`).filter(Boolean).map((n)=>{let[i,o]=n.split("\x1F");return{hash:i,subject:o??""}})}async function ce(e){let t=await w("git",["log","-F",`--grep=${ve}`,"--format=%H%x1f%s%x1f%b%x1e"],e),n=[];for(let i of t.split("\x1E")){let o=i.replace(/^\n/,"").trim();if(!o)continue;let[s,a,c]=o.split("\x1F");if(!s)continue;n.push({hash:s,subject:a??"",body:c??""})}return n}async function _(e,t){if(t){let s=await x("git",["rev-parse","--verify",`${t}^{commit}`],e);if(s.code!==0)throw new l(r("badBaseline",{rev:t}));return s.stdout.trim()}if((await x("git",["rev-parse","--verify","HEAD"],e)).code!==0)throw new l(r("noBaseline"));let i=await ce(e),o=(await Ve(e)).find((s)=>lt(s.subject));if(i[0]){if(o&&o.hash!==i[0].hash&&(await x("git",["merge-base","--is-ancestor",i[0].hash,o.hash],e)).code===0)return o.hash;return i[0].hash}return o?.hash??en()}async function ze(e,t,n){let i=await _(e,n),o=J(e,t.packagesDir),s=await w("git",["diff","--name-only",i,"HEAD"],e),a=it(s,t.packagesDir,o),c=new Set;for(let[h,y]of a){let f=`${t.packagesDir}/${h}/package.json`;if(y.includes(f)&&await Le(e,i,"HEAD",f))c.add(h)}let{changed:g,dependents:d}=ut({packages:o.map((h)=>({...D(e,t.packagesDir,h),folder:h})),filesByFolder:a,devOnly:c,include:t.include,exclude:t.exclude,packagesDir:t.packagesDir});return{baseline:i,changed:g,dependents:d}}async function Le(e,t,n,i){let o=await ht(e,`${t}:${i}`),s=await ht(e,`${n}:${i}`);if(o===null||s===null)return!1;try{return st(JSON.parse(o),JSON.parse(s))}catch{return!1}}async function ht(e,t){let n=await x("git",["show",t],e);return n.code===0?n.stdout:null}function en(){throw new l(r("noBaseline"))}async function pt(e){let t=tn.resolve(e.root),n=ie(t,e.versionsFile);if(e.packages)n.packagesDir=e.packages;await L(t);let{baseline:i,changed:o,dependents:s}=await ze(t,n,e.baseline);if(!o.length&&!s.length){let a=(await w("git",["rev-parse","--short",i],t)).trim();console.log(P(r("noPackagesSince",{rev:a})));return}console.log(C(r("changedHeader")));for(let a of o)console.log(` ${G(D(t,n.packagesDir,a).name)}`);if(s.length){console.log(C(r("dependentsHeader")));for(let a of s)console.log(` ${X(D(t,n.packagesDir,a).name)}`)}}import H from"node:fs";import Z from"node:path";R();F();import nn from"node:readline/promises";import{stdin as ft,stdout as wt}from"node:process";R();F();class V extends l{constructor(){super(r("interactiveCancelled"))}}async function qe(e){let t=nn.createInterface({input:ft,output:wt}),n=new AbortController,i=()=>n.abort();t.once("SIGINT",i),t.once("close",i);try{return await t.question(e,{signal:n.signal})}catch(o){if(n.signal.aborted)throw new V;throw o}finally{t.off("SIGINT",i),t.off("close",i),t.close()}}function z(){return Boolean(ft.isTTY&&wt.isTTY)}async function Ue(e,t){if(!z())throw new l(r("bumpRequired"));console.log(C(e)),t.forEach((n,i)=>console.log(` ${G(String(i+1))}) ${n}`));while(!0){let n=(await qe(r("chooseIndex"))).trim();if(n.toLowerCase()==="q")throw new V;let i=/^\d+$/.test(n)?Number(n)-1:-1;if(Number.isInteger(i)&&i>=0&&i<t.length)return t[i];console.log(k(r("invalidChoice",{answer:n||r("emptyAnswer")})))}}async function K(e,t){let n=await Ue(e,t.map((i)=>i.label));return t.find((i)=>i.label===n).value}async function M(e,t=""){if(!z())throw new l(r("yesRequired"));let n=t?` [${t}]`:"",i=(await qe(`${e}${n} `)).trim();if(i.toLowerCase()==="q")throw new V;return i||t}async function le(e){if(!z())throw new l(r("yesRequired"));console.log(C(e));while(!0){let t=(await qe("[y/N/q] ")).trim().toLowerCase();if(t==="q")throw new V;if(t==="y"||t==="yes")return!0;if(!t||t==="n"||t==="no")return!1;console.log(k(r("confirmAnswer")))}}function rn(e){let t=new Set,n=[];for(let i of[...cn(e),...ln(e)]){if(t.has(i))continue;t.add(i),n.push(i)}return n}function sn(e,t=Ae()){let n=(s,a="")=>r(s,void 0,t).split(`
|
|
53
|
+
`;var Xt=G(()=>{N();Gn=new Set(["docs","style","chore","refactor","test","build","ci"]),Jt={feat:"Features",feature:"Features",fix:"Bug Fixes",perf:"Performance Improvements",revert:"Reverts"}});import{Command as ti}from"commander";import{readFileSync as ni}from"node:fs";I();D();W();ce();import $n from"node:path";async function Vt(e){let t=$n.resolve(e.root),n=he(t,e.versionsFile);if(e.packages)n.packagesDir=e.packages;await V(t);let{baseline:r,changed:s,dependents:o}=await Ge(t,n,e.baseline);if(!s.length&&!o.length){let a=(await y("git",["rev-parse","--short",r],t)).trim();console.log(v(i("noPackagesSince",{rev:a})));return}console.log(S(i("changedHeader")));for(let a of s){let c=A(t,n.packagesDir,a);console.log(` ${Q(c.name)}${c.private?` ${v(i("privateMark"))}`:""}`)}if(o.length){console.log(S(i("dependentsHeader")));for(let a of o){let c=A(t,n.packagesDir,a);console.log(` ${oe(c.name)}${c.private?` ${v(i("privateMark"))}`:""}`)}}}I();D();N();_();import U from"node:fs";import le from"node:path";function Dn(e){let t=new Set,n=[];for(let r of[...An(e),...Bn(e)]){if(t.has(r))continue;t.add(r),n.push(r)}return n}function Fn(e,t=Ke()){let n=(o,a="")=>i(o,void 0,t).split(`
|
|
51
54
|
`).map((c)=>`${a}# ${c}`).join(`
|
|
52
|
-
`),
|
|
53
|
-
`),
|
|
55
|
+
`),r=(o,a,c,m)=>[n(m," "),a?` ${o}: ${Ce(a)}`:` # ${o}: ${c}`].join(`
|
|
56
|
+
`),s=[n("initNotePackagesDir"),`packagesDir: ${Ce(e.packagesDir)}`,"",n("initNoteCommitMessage"),'commitMessage: "bump: %s"',"",n("initNoteBranch"),e.branch?`branch: ${Ce(e.branch)}`:"# branch: main","","hooks:",r("beforeCommit",e.beforeCommit,"bun install","initNoteBeforeCommit"),r("beforePublish",e.beforePublish,"bun run build","initNoteBeforePublish"),r("afterPublish",void 0,"echo published","initNoteAfterPublish"),"",n("initNoteInclude"),"include:",...e.include.map((o)=>` - ${Ce(o)}`),` # - ${e.packagesDir}/*/bin`,"",n("initNoteExclude")];if(e.exclude.length)s.push("exclude:",...e.exclude.map((o)=>` - ${Ce(o)}`));else s.push("# exclude:",`# - ${e.packagesDir}/*/src/**/__tests__/**`);return`${s.join(`
|
|
54
57
|
`)}
|
|
55
|
-
`}async function Re(e){let t=Z.resolve(e.root),n=Z.resolve(t,e.versionsFile);if(H.existsSync(n))throw new l(r("configExists",{file:e.versionsFile}));let i=rn(t),o=i[0]??"packages",s=e.yes?on(o):await an(e.versionsFile,i,o);if(!s.include.length)throw new l(r("includeRequired"));let a=sn(s);ye(a),H.mkdirSync(Z.dirname(n),{recursive:!0}),H.writeFileSync(n,a),console.log(X(r("initWrote",{file:e.versionsFile})))}function on(e){return{packagesDir:e,include:[`${e}/*/src`],exclude:[`${e}/*/src/**/__tests__/**`]}}async function an(e,t,n){if(!z())throw new l(r("yesRequired"));if(console.log(C(r("initIntro",{file:e}))),t.length)console.log(P(r("initFoundDirs",{dirs:t.join(", ")})));let i=await M(r("initPackagesDir"),n),o=bt(await M(r("initInclude"),`${i}/*/src`)),s=bt(await M(r("initExclude"),`${i}/*/src/**/__tests__/**`)),a=await M(r("initBranch")),c=await M(r("initBeforeCommit")),g=await M(r("initBeforePublish"));return{packagesDir:i,branch:a||void 0,beforeCommit:c||void 0,beforePublish:g||void 0,include:o,exclude:s}}function bt(e){return e.split(",").map((t)=>t.trim()).filter(Boolean)}function ge(e){return/^[A-Za-z0-9_./@*+-]+$/.test(e)?e:JSON.stringify(e)}function cn(e){return mn(e).flatMap((t)=>{let n=t.replace(/\/\*\*?$/,"");if(!n||n===t||n.includes("*"))return[];return H.existsSync(Z.join(e,n))?[n]:[]})}function ln(e){if(!H.existsSync(e))return[];let t=[];for(let n of H.readdirSync(e)){if(n.startsWith(".")||n==="node_modules")continue;let i=Z.join(e,n);if(!H.statSync(i).isDirectory())continue;if(gn(i))t.push(n)}return t}function gn(e){return H.readdirSync(e).some((t)=>H.existsSync(Z.join(e,t,"package.json")))}function mn(e){let t=Z.join(e,"package.json");if(!H.existsSync(t))return[];try{let n=JSON.parse(H.readFileSync(t,"utf8")),i=Array.isArray(n.workspaces)?n.workspaces:n.workspaces?.packages;return Array.isArray(i)?i.filter((o)=>typeof o==="string"):[]}catch{return[]}}import Te from"node:path";import vt from"semver";import re from"node:fs";import We from"node:path";import dn from"node:os";import{randomUUID as un}from"node:crypto";import{AsyncLocalStorage as hn}from"node:async_hooks";F();R();var Je=new hn;async function se(e,t,n){if(t)return n();e=We.resolve(e);let i=We.resolve(e,(await w("git",["rev-parse","--git-common-dir"],e)).trim()),o=We.join(i,"change-versions.lock");if(Je.getStore()?.has(o))return n();let s={pid:process.pid,host:dn.hostname(),token:un()},a;try{a=re.openSync(o,"wx",384)}catch(d){if(d.code!=="EEXIST")throw d;let h="";try{h=re.readFileSync(o,"utf8")}catch{}throw new l(r("repositoryLocked",{file:o,owner:h.trim()}))}let c=()=>{try{if(JSON.parse(re.readFileSync(o,"utf8")).token===s.token)re.unlinkSync(o)}catch{}};try{re.writeFileSync(a,JSON.stringify(s))}finally{re.closeSync(a)}let g=()=>{if(process.listenerCount("SIGINT")<=1&&process.listenerCount("SIGTERM")<=1)process.exit(1)};process.on("exit",c),process.on("SIGINT",g),process.on("SIGTERM",g);try{return await Je.run(new Set([...Je.getStore()??[],o]),n)}finally{process.off("SIGINT",g),process.off("SIGTERM",g),process.off("exit",c),c()}}R();function pn(e){if(/^[a-zA-Z0-9_./:@=+-]+$/.test(e))return e;return"'"+e.replaceAll("'","'\\''")+"'"}function q(e){let t=["change-versions","publish",`--dist-tag=${e.distTag}`,`--root=${e.root}`,`--versions-file=${e.versionsFile}`];if(e.commit)t.push(`--commit=${e.commit}`);if(e.packages)t.push(`--packages=${e.packages}`);return t.map(pn).join(" ")}F();F();function yt(e){let t=[];if(e.beforePublish)t.push({kind:"hook",name:"beforePublish",command:e.beforePublish});for(let n of mt(e.packages.filter((i)=>!i.private))){if(n.published&&n.distTagVersion===n.version)continue;let i=n.registry??"";t.push(n.published?{kind:"dist-tag",name:n.name,version:n.version,folder:n.folder,registry:i,tag:e.distTag}:{kind:"publish",name:n.name,version:n.version,folder:n.folder,registry:i,tag:e.distTag})}if(e.afterPublish)t.push({kind:"hook",name:"afterPublish",command:e.afterPublish});if(e.formal)for(let n of e.packages)t.push({kind:"tag",name:n.name,version:n.version,commit:e.commit});return t}async function zt(e){return se(e.root,Boolean(e.dryRun),()=>fn(e))}async function fn(e){console.log(e.dryRun?k(r("publishPreview")):C(r("publishPreparing")));let{root:t,startHead:n,config:i,release:o,entries:s,formal:a,registryOf:c,published:g,distTagVersions:d,steps:h}=await me(e),y=q({...e,root:t,commit:o.hash}),f={CHANGE_VERSIONS_PUBLISH_CONTEXT:JSON.stringify({schemaVersion:1,root:t,packagesDir:i.packagesDir,commit:o.hash,distTag:e.distTag,packages:h.flatMap((m)=>m.kind==="publish"?[{name:m.name,version:m.version,path:Te.join(i.packagesDir,m.folder)}]:[])})};for(let m of s)if(g.has(m.folder)&&d.get(m.folder)===m.to)console.log(P(r("alreadyTagged",{name:m.name,version:m.to,tag:e.distTag,registry:c.get(m.folder)||""})));if(console.log(r("publishPlanSummary",{uploads:h.filter((m)=>m.kind==="publish").length,retags:h.filter((m)=>m.kind==="dist-tag").length,tags:h.filter((m)=>m.kind==="tag").length})),e.dryRun){for(let m of h)console.log(`${k(r("plannedStep",{step:""}))}${kt(m)}`);if(a&&i.branch)console.log(k(r("plannedStep",{step:`git push origin ${s.map((m)=>`refs/tags/${m.name}@${m.to}`).join(" ")}`})));if(!a)console.log(P(r("noGitTag")));console.log(k(r("publishPreviewComplete"))),console.log(C(r("publishPreviewNext"))),console.log(B(y));return}console.log(P(r("publishResumeInfo"))),console.log(C(r("willPublish")));for(let m of s){if(g.has(m.folder)&&d.get(m.folder)===m.to)continue;let E=m.pkg.private?` ${P(r("privateMark"))}`:g.has(m.folder)?` ${P(r("distTagOnlyMark"))}`:"";console.log(` ${G(m.name)} ${X(m.to)}${E}`)}if(!e.yes&&!await le(r("confirmPublish")))throw new l(r("cancelledPublish"));let u=new Map(s.map((m)=>[m.folder,m.pkg.private?"summaryPrivate":g.has(m.folder)&&d.get(m.folder)===m.to?"summarySkipped":"summaryPending"])),v="beforePublish",b,A=!1,p=(m)=>m==="summaryPublished"||m==="summaryRetagged"?W:m==="summaryFailed"?pe:m==="summaryPending"?k:P,S=()=>{console.log((A?W:pe)(r(A?"publishComplete":"publishIncomplete"))),console.log(r("publishSummaryContext",{commit:o.hash,tag:e.distTag}));let m=new Map;for(let E of s){let T=u.get(E.folder);m.set(T,(m.get(T)??0)+1);let Ke=c.get(E.folder);console.log(` ${p(T)(r(T))}: ${G(E.name)}@${G(E.to)}${Ke?` — ${P(Ke)}`:""}`)}if(console.log([...m].map(([E,T])=>`${p(E)(r(E))}: ${G(String(T))}`).join(", ")),A)console.log(W(r("publishReady"))),console.log(P(r(a?i.branch?"gitTagsPushed":"gitTagsLocal":"noGitTag")));else{if(console.log(pe(r("publishFailedStage",{stage:v}))),v==="git tag / git push")console.log(k(r("publishTagRecovery")));console.log(k(r("publishRetryTitle"))),console.log(C(r("publishRetry"))),console.log(P(r("publishResumeInfo"))),console.log(B(y))}},N=()=>{if(b)u.set(b,"summaryFailed");S(),console.error(I(r("publishInterrupted"))),process.exit(1)};process.on("SIGINT",N),process.on("SIGTERM",N);try{await St(t,i.hooks.beforePublish,"beforePublish",f),await Ge(t,r("beforePublishDirty")),await xt(t,n);for(let m of h){if(m.kind!=="publish"&&m.kind!=="dist-tag")continue;console.log(C(r("executingStep",{step:kt(m)})));let E=Te.join(t,i.packagesDir,m.folder);v=`${m.kind==="publish"?"npm publish":"npm dist-tag add"} ${m.name}@${m.version}`,b=m.folder,await Tt(async()=>{if(m.kind==="dist-tag")await Pt(t,["dist-tag","add",`${m.name}@${m.version}`,m.tag,`--registry=${m.registry}`],m.registry);else await Pt(E,["publish",`--tag=${m.tag}`,`--registry=${m.registry}`],m.registry)}),u.set(m.folder,m.kind==="publish"?"summaryPublished":"summaryRetagged"),b=void 0}if(v="afterPublish",await St(t,i.hooks.afterPublish,"afterPublish",f),await Ge(t,r("afterPublishDirty")),await xt(t,n),v="git tag / git push",a)console.log(C(r("executingStep",{step:v}))),await wn(t,i.branch,s,o.hash);A=!0}catch(m){if(b)u.set(b,"summaryFailed");throw m}finally{process.off("SIGINT",N),process.off("SIGTERM",N),S()}}async function me(e,t=!1,n=!1){let i=Te.resolve(e.root);if(!t)await L(i);let o=(await w("git",["rev-parse","HEAD"],i)).trim(),s=ie(i,e.versionsFile);if(e.packages)s.packagesDir=e.packages;let a=await j(i,e.commit);if(!a?.lines.length)throw new l(r("noVersionCommit"));let c=J(i,s.packagesDir),g=new Map(c.map((p)=>[D(i,s.packagesDir,p).name,p])),d=a.lines.map((p)=>{let S=g.get(p.name);if(!S)throw new l(r("packageNotInDir",{dir:s.packagesDir,name:p.name}));let N=D(i,s.packagesDir,S);if(N.version!==p.to)throw new l(r("releaseVersionMismatch",{name:p.name,expected:p.to,actual:N.version,commit:a.hash}));return{...p,folder:S,pkg:N,deps:Se(N,g)}}),h=await x("git",["diff","--quiet",a.hash,"HEAD","--",...d.map((p)=>`${s.packagesDir}/${p.folder}`)],i);if(h.code===1&&!n)throw new l(r("releaseContentsChanged"));if(h.code!==0&&h.code!==1)throw new l(r("gitFailed",{detail:h.stderr.trim()}));if(!t)console.log(r("publishSummaryContext",{commit:a.hash,tag:e.distTag}));let y=ke(a.lines);if(y)await Rt(i,d,a.hash);let f=new Map;for(let p of d){if(p.pkg.private)continue;let S=await kn(i,p.pkg);if(f.set(p.folder,S),!t)console.log(r("checkingRegistry",{name:p.name,version:p.to,registry:S}))}let u=new Set;for(let p of d){let S=f.get(p.folder);if(!S||u.has(S))continue;if(u.add(S),!t)await vn(i,S)}let v=new Set,b=new Map;for(let p of d){if(p.pkg.private)continue;let S=f.get(p.folder);if(!S)continue;await Tt(async()=>{if(await bn(i,p.name,p.to,S)){v.add(p.folder);let N=await yn(i,p.name,e.distTag,S);b.set(p.folder,N)}})}let A=yt({packages:d.map((p)=>({name:p.name,version:p.to,folder:p.folder,private:p.pkg.private,deps:p.deps,registry:f.get(p.folder),published:v.has(p.folder),distTagVersion:b.get(p.folder)})),distTag:e.distTag,formal:y,commit:a.hash,beforePublish:s.hooks.beforePublish,afterPublish:s.hooks.afterPublish});return{root:i,startHead:o,config:s,release:a,entries:d,formal:y,registryOf:f,published:v,distTagVersions:b,steps:A}}function kt(e){if(e.kind==="hook")return`${P(`${e.name}:`)} ${B(e.command)}`;if(e.kind==="tag")return B(`git tag ${e.name}@${e.version} ${e.commit}`);if(e.kind==="dist-tag")return B(`npm dist-tag add ${e.name}@${e.version} ${e.tag} --registry=${e.registry}`);return B(`npm publish --tag=${e.tag} --registry=${e.registry} ${e.name}@${e.version}`)}async function j(e,t){if((await x("git",["rev-parse","--verify","HEAD"],e)).code!==0)return null;let i;if(t){let a=await x("git",["rev-parse","--verify","--end-of-options",`${t}^{commit}`],e);if(a.code!==0)throw new l(r("badReleaseCommit",{commit:t}));let c=a.stdout.trim();if((await x("git",["merge-base","--is-ancestor",c,"HEAD"],e)).code!==0)throw new l(r("badReleaseCommit",{commit:t}));i={hash:c,subject:(await w("git",["show","-s","--format=%s",c],e)).trim(),body:await w("git",["show","-s","--format=%b",c],e)}}else i=(await ce(e))[0];if(!i)return null;let o=xe(i.body);if(!o.length){if(t)throw new l(r("badReleaseCommit",{commit:t}));return null}if(new Set(o.map((a)=>a.name)).size!==o.length||o.some((a)=>!vt.valid(a.from)||!vt.valid(a.to)))throw new l(r("badReleaseCommit",{commit:i.hash}));let s=/^Change-Versions-Dist-Tag: (\S+)$/m.exec(i.body)?.[1];return{hash:i.hash,subject:i.subject,lines:o,distTag:s}}async function wn(e,t,n,i){await Rt(e,n,i);let o=n.map((a)=>`${a.name}@${a.to}`);for(let a of o){if((await x("git",["rev-parse","--verify",`refs/tags/${a}^{commit}`],e)).code===0)continue;await w("git",["tag",a,i],e)}if(!t)return;let s=await x("git",["push","origin",...o.map((a)=>`refs/tags/${a}`)],e);if(s.code!==0)throw new l(r("tagPushFailed",{detail:s.stderr.trim()}))}async function Rt(e,t,n){for(let i of t){let o=`${i.name}@${i.to}`,s=await x("git",["rev-parse","--verify",`refs/tags/${o}^{commit}`],e);if(s.code===0&&s.stdout.trim()!==n)throw new l(r("tagPointsElsewhere",{tag:o}))}}async function xt(e,t){if((await w("git",["rev-parse","HEAD"],e)).trim()!==t)throw new l(r("publishHeadChanged"))}async function Tt(e){let t="";for(let n=0;n<3;n++)try{await e();return}catch(i){if(i instanceof l&&i.auth)throw i;t=i instanceof Error?i.message:String(i)}throw new l(r("networkFailed",{detail:t}))}async function Pt(e,t,n){let i=await x("npm",t,e);if(i.code===0)return;let o=`${i.stderr}${i.stdout}`;if(process.stderr.write(i.stderr),ae(o))throw new l(r("notLoggedIn",{registry:n}),!0);throw Error(o.trim()||r("npmFailed"))}async function bn(e,t,n,i){let o=await x("npm",["view",`${t}@${n}`,"version","--json",`--registry=${i}`],e);if(o.code===0){let a;try{a=JSON.parse(o.stdout)}catch{}if(a===n||Array.isArray(a)&&a.length===1&&a[0]===n)return!0;throw Error(r("unexpectedRegistryVersion",{name:t,version:n,registry:i}))}let s=`${o.stderr}${o.stdout}`;if(ae(s))throw new l(r("notLoggedIn",{registry:i}),!0);if(Oe(o.stdout)||Oe(o.stderr))return!1;throw Error(s.trim()||r("npmViewFailed"))}async function yn(e,t,n,i){let o=await x("npm",["view",t,"dist-tags","--json",`--registry=${i}`],e);if(o.code!==0){let c=`${o.stderr}${o.stdout}`.trim();if(ae(c))throw new l(r("notLoggedIn",{registry:i}),!0);throw Error(c||r("npmViewFailed"))}let s;try{s=JSON.parse(o.stdout)}catch{}if(Array.isArray(s)&&s.length===1)s=s[0];if(!s||typeof s!=="object"||Array.isArray(s))throw Error(r("unexpectedRegistryTags",{name:t,tag:n,registry:i}));let a=Object.prototype.hasOwnProperty.call(s,n)?s[n]:void 0;if(a!==void 0&&typeof a!=="string")throw Error(r("unexpectedRegistryTags",{name:t,tag:n,registry:i}));return a}async function vn(e,t){let n=await x("npm",["whoami",`--registry=${t}`],e);if(n.code===0)return;let i=`${n.stderr}${n.stdout}`;if(ae(i))throw new l(r("notLoggedIn",{registry:t}),!0);throw new l(r("registryUnreachable",{registry:t,detail:i.trim()}))}async function kn(e,t){if(t.publishConfig?.registry)return t.publishConfig.registry.replace(/\/$/,"");if(t.name.startsWith("@")&&t.name.includes("/")){let i=t.name.slice(0,t.name.indexOf("/")),o=await Ct(e,`${i}:registry`);if(o&&o!=="undefined"&&o!=="null")return o.replace(/\/$/,"")}let n=await Ct(e,"registry");if(!n||n==="undefined"||n==="null")throw new l(r("noNpmRegistry",{detail:"npm config get registry: empty value"}));return n.replace(/\/$/,"")}async function Ct(e,t){let n=await x("npm",["config","get",t],e);if(n.code!==0){let i=n.stderr.trim()||n.stdout.trim()||`npm config get ${t}: exit ${n.code}`;throw new l(r("noNpmRegistry",{detail:i}))}return n.stdout.trim()}async function St(e,t,n,i){if(!t)return;console.log(C(r("executingStep",{step:`${n}: ${t}`})));try{await Pe("sh",["-c",t],e,i)}catch(o){let s=o instanceof Error?o.message:String(o);throw new l(r("hookFailed",{name:n,detail:s}))}}async function de(e,t,n){return t??(await j(Te.resolve(e),n))?.distTag??"latest"}import An from"node:path";import Ot from"semver";import te from"node:fs";import Fe from"node:path";import ee from"node:fs";import Y from"node:path";import{spawnSync as xn}from"node:child_process";F();R();function _e(e){try{let t=ee.lstatSync(e);if(!t.isFile())throw new l(r("unsafeCommitFile",{file:e}));return{bytes:ee.readFileSync(e),mode:t.mode&511}}catch(t){if(t.code==="ENOENT")return;throw t}}function Pn(e,t){return e===t||Boolean(e&&t&&e.mode===t.mode&&e.bytes.equals(t.bytes))}async function $t(e,t,n){let i=(await w("git",["rev-parse","HEAD"],e)).trim();if(n&&i!==n)throw new l(r("versionHeadChanged"));let o=new Map;for(let f of new Set(t)){let u=Y.resolve(e,f),v=Y.relative(e,u);if(!v||v.startsWith("..")||Y.isAbsolute(v)||/[*?\[\]\\]/.test(f)||v.split(Y.sep).includes(".git"))throw new l(r("unsafeCommitFile",{file:f}));for(let b=Y.dirname(u);b!==e;b=Y.dirname(b))if(ee.existsSync(b)&&ee.lstatSync(b).isSymbolicLink())throw new l(r("unsafeCommitFile",{file:f}));o.set(v,_e(u))}let s=new Map(o),a,c=!0,g=()=>{s=new Map([...o.keys()].map((f)=>[f,_e(Y.join(e,f))]))},d=(...f)=>xn("git",f,{cwd:e,encoding:"utf8"}),h=()=>{if(!c)return;c=!1,process.off("SIGINT",y),process.off("SIGTERM",y);let f=d("rev-parse","HEAD");if(f.status!==0||f.stdout.trim()!==i){console.error(I(r("versionHeadChanged")));return}if(a!==void 0&&d("write-tree").stdout.trim()===a)d("restore","--staged","--",...o.keys());for(let[u,v]of o){let b=Y.join(e,u);try{if(!Pn(_e(b),s.get(u)))continue;if(v)ee.writeFileSync(b,v.bytes),ee.chmodSync(b,v.mode);else ee.rmSync(b,{force:!0})}catch{}}},y=()=>{h(),console.error(I(r("versionRecovery"))),process.exit(1)};return process.on("SIGINT",y),process.on("SIGTERM",y),{checkpoint:g,async stage(){if((await w("git",["rev-parse","HEAD"],e)).trim()!==i)throw new l(r("versionHeadChanged"));if(await w("git",["diff","--cached","--name-only","-z"],e))throw new l(r("versionUnexpectedIndex"));let u=(await w("git",["diff","--name-only","-z"],e)).split("\x00").filter(Boolean),v=(await w("git",["ls-files","--others","--exclude-standard","-z"],e)).split("\x00").filter(Boolean),b=[...u,...v].filter((S)=>!o.has(S));if(b.length)throw new l(r("versionUnexpectedFiles",{files:b.join(", ")}));g();let A=[...new Set([...u,...v])];if(!A.length)throw new l(r("versionUnexpectedIndex"));if(await w("git",["add","--",...A],e),a=(await w("git",["write-tree"],e)).trim(),(await w("git",["diff","--cached","--name-only","-z"],e)).split("\x00").filter(Boolean).some((S)=>!o.has(S)))throw new l(r("versionUnexpectedIndex"))},async verifyCommit(){let f=(await w("git",["rev-parse","HEAD^"],e)).trim(),u=(await w("git",["rev-parse","HEAD^{tree}"],e)).trim();if(f!==i||u!==a)throw new l(r("versionHeadChanged"))},disarm(){c=!1,process.off("SIGINT",y),process.off("SIGTERM",y)},fail(f){throw h(),f}}}R();F();import Ft from"semver";R();F();async function Dt(e){let{bump:t,preid:n}=e;if(!t){if(e.yes||!z())throw new l(r("bumpRequired"));let i=n?"pre":await K(r("chooseReleaseKind"),[{value:"formal",label:r("releaseKindFormal")},{value:"pre",label:r("releaseKindPre")}]);t=await Ue(r("chooseBump"),i==="pre"?["prerelease","prepatch","preminor","premajor"]:["patch","minor","major"])}if(!t.startsWith("pre")||n||!["prerelease","prepatch","preminor","premajor"].includes(t))return{bump:be(t,n),preid:n};if(e.yes||!z())return{bump:be(t,n),preid:n};while(!n){let i=await M(r("choosePreid"),"alpha");if(Ft.valid(`0.0.0-${i}.0`))n=i;else console.log(k(r("invalidPreid")))}return{bump:be(t,n),preid:n}}function $e(e){return Boolean(e)&&encodeURIComponent(e)===e&&!Ft.validRange(e)}async function ue(e,t,n){if(e!==void 0||n||!z()){let i=e??t;if(!$e(i))throw new l(r("badDistTag"));return i}while(!0){let i=await M(r("chooseDistTag"),t);if($e(i))return i;console.log(k(r("badDistTag")))}}async function Nt(e,t,n){try{return await _(e,t)}catch(i){if(t||n||!z()||!(i instanceof l)||i.message!==r("noBaseline"))throw i}console.log(k(r("firstBaseline")));while(!0){let i=await M(r("chooseBaseline"));if(!i)continue;try{return await _(e,i)}catch(o){if(!(o instanceof l))throw o;console.log(k(o.message))}}}async function De(e){return se(e.root,Boolean(e.dryRun),()=>Tn(e))}async function Tn(e){let t=Fe.resolve(e.root),n=ie(t,e.versionsFile);if(e.packages)n.packagesDir=e.packages;if(e.messageFromCli&&e.commitMessage)n.commitMessage=e.commitMessage;if(e.branchFromCli)n.branch=e.branch||void 0;if(await L(t),n.branch){let u=await x("git",["symbolic-ref","--quiet","--short","HEAD"],t);if(u.code!==0||u.stdout.trim()!==n.branch)throw new l(r("wrongBranch",{branch:n.branch}))}let i=await Nt(t,e.baseline,e.yes),o=(await w("git",["rev-parse","HEAD"],t)).trim(),s=e.force?{baseline:i,changed:await Ht(t,n),dependents:[]}:await ze(t,n,i);if(!s.changed.length&&!s.dependents.length){let u=(await w("git",["rev-parse","--short",s.baseline],t)).trim();if(console.log(P(r("noPackagesSince",{rev:u}))),console.log(P(r("noVersionChangesNext"))),e.yes||!z()||!await j(t)||!await le(r("confirmForceVersion")))return;s.changed=await Ht(t,n)}if(z()&&!e.yes){console.log(C(r("wizardCandidates")));for(let u of[...s.changed,...s.dependents])console.log(` ${D(t,n.packagesDir,u).name}`)}let{bump:a,preid:c}=await Dt(e),g=[...s.changed,...s.dependents].map((u)=>{let v=D(t,n.packagesDir,u);return{folder:u,name:v.name,from:v.version,to:ot(v.version,a,c)}});if(e.dryRun)console.log(k(r("versionPreview")));for(let u of g)console.log(Ye(u.name,u.from,u.to));let d=e.preparePublish?await e.preparePublish({preid:c,config:n}):e.publishTag;if(e.dryRun){console.log(C(r("versionPreviewComplete")));return}if(!e.yes&&!await le(r("confirmVersions")))throw new l(r("cancelledVersion"));if(await L(t),(await w("git",["rev-parse","HEAD"],t)).trim()!==o)throw new l(r("versionHeadChanged"));let h=J(t,n.packagesDir).map((u)=>`${n.packagesDir}/${u}/package.json`);if(Me(a))h.push(...g.map((u)=>`${n.packagesDir}/${u.folder}/CHANGELOG.md`));h.push("bun.lock","bun.lockb","package-lock.json","npm-shrinkwrap.json","yarn.lock","pnpm-lock.yaml",...n.commitFiles??[]);let y=await $t(t,h,o);try{try{for(let b of g)Nn(t,n.packagesDir,b.folder,b.to);if(En(t,n.packagesDir),Me(a))await $n(t,n,g,i)}finally{y.checkpoint()}if(n.hooks.beforeCommit)await Pe("sh",["-c",n.hooks.beforeCommit],t);let u=ct(n.commitMessage,a,c),v=g.map((b)=>`${b.name} ${b.from} => ${b.to}`).join(`
|
|
58
|
+
`}async function Le(e){let t=le.resolve(e.root),n=le.resolve(t,e.versionsFile);if(U.existsSync(n))throw new l(i("configExists",{file:e.versionsFile}));let r=Dn(t),s=r[0]??"packages",o=e.yes?Nn(s):await En(e.versionsFile,r,s);if(!o.include.length)throw new l(i("includeRequired"));let a=Fn(o);Fe(a),U.mkdirSync(le.dirname(n),{recursive:!0}),U.writeFileSync(n,a),console.log(oe(i("initWrote",{file:e.versionsFile})))}function Nn(e){return{packagesDir:e,include:[`${e}/*/src`],exclude:[`${e}/*/src/**/__tests__/**`]}}async function En(e,t,n){if(!T())throw new l(i("yesRequired"));if(console.log(S(i("initIntro",{file:e}))),t.length)console.log(v(i("initFoundDirs",{dirs:t.join(", ")})));let r=await L(i("initPackagesDir"),n),s=Gt(await L(i("initInclude"),`${r}/*/src`)),o=Gt(await L(i("initExclude"),`${r}/*/src/**/__tests__/**`)),a=await L(i("initBranch")),c=await L(i("initBeforeCommit")),m=await L(i("initBeforePublish"));return{packagesDir:r,branch:a||void 0,beforeCommit:c||void 0,beforePublish:m||void 0,include:s,exclude:o}}function Gt(e){return e.split(",").map((t)=>t.trim()).filter(Boolean)}function Ce(e){return/^[A-Za-z0-9_./@*+-]+$/.test(e)?e:JSON.stringify(e)}function An(e){return jn(e).flatMap((t)=>{let n=t.replace(/\/\*\*?$/,"");if(!n||n===t||n.includes("*"))return[];return U.existsSync(le.join(e,n))?[n]:[]})}function Bn(e){if(!U.existsSync(e))return[];let t=[];for(let n of U.readdirSync(e)){if(n.startsWith(".")||n==="node_modules")continue;let r=le.join(e,n);if(!U.statSync(r).isDirectory())continue;if(In(r))t.push(n)}return t}function In(e){return U.readdirSync(e).some((t)=>U.existsSync(le.join(e,t,"package.json")))}function jn(e){let t=le.join(e,"package.json");if(!U.existsSync(t))return[];try{let n=JSON.parse(U.readFileSync(t,"utf8")),r=Array.isArray(n.workspaces)?n.workspaces:n.workspaces?.packages;return Array.isArray(r)?r.filter((s)=>typeof s==="string"):[]}catch{return[]}}K();ke();K();import Xn from"node:path";import tn from"semver";ke();import ge from"node:fs";import qe from"node:path";W();N();I();D();import me from"node:fs";import ne from"node:path";import{spawnSync as Mn}from"node:child_process";function st(e){try{let t=me.lstatSync(e);if(!t.isFile())throw new l(i("unsafeCommitFile",{file:e}));return{bytes:me.readFileSync(e),mode:t.mode&511}}catch(t){if(t.code==="ENOENT")return;throw t}}function Hn(e,t){return e===t||Boolean(e&&t&&e.mode===t.mode&&e.bytes.equals(t.bytes))}async function Lt(e,t,n){let r=(await y("git",["rev-parse","HEAD"],e)).trim();if(n&&r!==n)throw new l(i("versionHeadChanged"));let s=new Map;for(let f of new Set(t)){let u=ne.resolve(e,f),w=ne.relative(e,u);if(!w||w.startsWith("..")||ne.isAbsolute(w)||/[*?\[\]\\]/.test(f)||w.split(ne.sep).includes(".git"))throw new l(i("unsafeCommitFile",{file:f}));for(let p=ne.dirname(u);p!==e;p=ne.dirname(p))if(me.existsSync(p)&&me.lstatSync(p).isSymbolicLink())throw new l(i("unsafeCommitFile",{file:f}));s.set(w,st(u))}let o=new Map(s),a,c=!0,m=()=>{o=new Map([...s.keys()].map((f)=>[f,st(ne.join(e,f))]))},d=(...f)=>Mn("git",f,{cwd:e,encoding:"utf8"}),h=()=>{if(!c)return;c=!1,process.off("SIGINT",C),process.off("SIGTERM",C);let f=d("rev-parse","HEAD");if(f.status!==0||f.stdout.trim()!==r){console.error(H(i("versionHeadChanged")));return}if(a!==void 0&&d("write-tree").stdout.trim()===a)d("restore","--staged","--",...s.keys());for(let[u,w]of s){let p=ne.join(e,u);try{if(!Hn(st(p),o.get(u)))continue;if(w)me.writeFileSync(p,w.bytes),me.chmodSync(p,w.mode);else me.rmSync(p,{force:!0})}catch{}}},C=()=>{h(),console.error(H(i("versionRecovery"))),process.exit(1)};return process.on("SIGINT",C),process.on("SIGTERM",C),{checkpoint:m,async stage(){if((await y("git",["rev-parse","HEAD"],e)).trim()!==r)throw new l(i("versionHeadChanged"));if(await y("git",["diff","--cached","--name-only","-z"],e))throw new l(i("versionUnexpectedIndex"));let u=(await y("git",["diff","--name-only","-z"],e)).split("\x00").filter(Boolean),w=(await y("git",["ls-files","--others","--exclude-standard","-z"],e)).split("\x00").filter(Boolean),p=[...u,...w].filter((R)=>!s.has(R));if(p.length)throw new l(i("versionUnexpectedFiles",{files:p.join(", ")}));m();let P=[...new Set([...u,...w])];if(!P.length)throw new l(i("versionUnexpectedIndex"));if(await y("git",["add","--",...P],e),a=(await y("git",["write-tree"],e)).trim(),(await y("git",["diff","--cached","--name-only","-z"],e)).split("\x00").filter(Boolean).some((R)=>!s.has(R)))throw new l(i("versionUnexpectedIndex"))},async verifyCommit(){let f=(await y("git",["rev-parse","HEAD^"],e)).trim(),u=(await y("git",["rev-parse","HEAD^{tree}"],e)).trim();if(f!==r||u!==a)throw new l(i("versionHeadChanged"))},disarm(){c=!1,process.off("SIGINT",C),process.off("SIGTERM",C)},fail(f){throw h(),f}}}I();D();K();N();W();_();I();D();N();_();ce();import Ut from"semver";async function qt(e){let{bump:t,preid:n}=e;if(!t){if(e.yes||!T())throw new l(i("bumpRequired"));let r=n?"pre":await Z(i("chooseReleaseKind"),[{value:"formal",label:i("releaseKindFormal")},{value:"pre",label:i("releaseKindPre")}]);t=await $t(i("chooseBump"),r==="pre"?["prerelease","prepatch","preminor","premajor"]:["patch","minor","major"])}if(!t.startsWith("pre")||n||!["prerelease","prepatch","preminor","premajor"].includes(t))return{bump:De(t,n),preid:n};if(e.yes||!T())return{bump:De(t,n),preid:n};while(!n){let r=await L(i("choosePreid"),"alpha");if(Ut.valid(`0.0.0-${r}.0`))n=r;else console.log(k(i("invalidPreid")))}return{bump:De(t,n),preid:n}}function Ue(e){return Boolean(e)&&encodeURIComponent(e)===e&&!Ut.validRange(e)}async function Se(e,t,n){if(e!==void 0||n||!T()){let r=e??t;if(!Ue(r))throw new l(i("badDistTag"));return r}while(!0){let r=await L(i("chooseDistTag"),t);if(Ue(r))return r;console.log(k(i("badDistTag")))}}async function Wt(e,t,n){try{return await te(e,t)}catch(r){if(t||n||!T()||!(r instanceof l)||r.message!==i("noBaseline"))throw r}console.log(k(i("firstBaseline")));while(!0){let r=await L(i("chooseBaseline"));if(!r)continue;try{return await te(e,r)}catch(s){if(!(s instanceof l))throw s;console.log(k(s.message))}}}ce();async function We(e){return X(e.root,Boolean(e.dryRun),()=>Un(e))}async function Un(e){let t=qe.resolve(e.root),n=he(t,e.versionsFile);if(e.packages)n.packagesDir=e.packages;if(e.messageFromCli&&e.commitMessage)n.commitMessage=e.commitMessage;if(e.branchFromCli)n.branch=e.branch||void 0;if(await V(t),n.branch){let u=await x("git",["symbolic-ref","--quiet","--short","HEAD"],t);if(u.code!==0||u.stdout.trim()!==n.branch)throw new l(i("wrongBranch",{branch:n.branch}))}let r=await Wt(t,e.baseline,e.yes),s=(await y("git",["rev-parse","HEAD"],t)).trim(),o=e.force?{baseline:r,changed:await Zt(t,n),dependents:[]}:await Ge(t,n,r,!e.baseline);if(!o.changed.length&&!o.dependents.length){let u=(await y("git",["rev-parse","--short",o.baseline],t)).trim();if(console.log(v(i("noPackagesSince",{rev:u}))),console.log(v(i("noVersionChangesNext"))),e.yes||!T()||!await j(t)||!await se(i("confirmForceVersion")))return;o.changed=await Zt(t,n)}if(T()&&!e.yes){console.log(S(i("wizardCandidates")));for(let u of[...o.changed,...o.dependents]){let w=A(t,n.packagesDir,u);console.log(` ${w.name}${w.private?` ${v(i("privateMark"))}`:""}`)}}let{bump:a,preid:c}=await qt(e),m=[...o.changed,...o.dependents].map((u)=>{let w=A(t,n.packagesDir,u);return{folder:u,name:w.name,private:w.private,from:w.version,to:wt(w.version,a,c)}});if(e.dryRun)console.log(k(i("versionPreview")));for(let u of m)console.log(`${ct(u.name,u.from,u.to)}${u.private?` ${v(i("privateMark"))}`:""}`);if(m.some((u)=>u.private))console.log(v(i("privateVersionHint")));let d=e.preparePublish?await e.preparePublish({preid:c,config:n}):e.publishTag;if(e.dryRun){console.log(S(i("versionPreviewComplete")));return}if(!e.yes&&!await se(i("confirmVersions")))throw new l(i("cancelledVersion"));if(await V(t),(await y("git",["rev-parse","HEAD"],t)).trim()!==s)throw new l(i("versionHeadChanged"));let h=ee(t,n.packagesDir).map((u)=>`${n.packagesDir}/${u}/package.json`);if(Xe(a))h.push(...m.map((u)=>`${n.packagesDir}/${u.folder}/CHANGELOG.md`));h.push("bun.lock","bun.lockb","package-lock.json","npm-shrinkwrap.json","yarn.lock","pnpm-lock.yaml",...n.commitFiles??[]);let C=await Lt(t,h,s);try{try{for(let p of m)_n(t,n.packagesDir,p.folder,p.to);if(Kn(t,n.packagesDir),Xe(a))await qn(t,n,m,r)}finally{C.checkpoint()}if(n.hooks.beforeCommit)await Ee("sh",["-c",n.hooks.beforeCommit],t);let u=vt(n.commitMessage,a,c),w=m.map((p)=>`${p.name} ${p.from} => ${p.to}`).join(`
|
|
56
59
|
`)+(d?`
|
|
57
60
|
|
|
58
|
-
Change-Versions-Dist-Tag: ${d}`:"");await
|
|
59
|
-
${E}`:
|
|
60
|
-
`).filter(Boolean),
|
|
61
|
-
`).filter(Boolean):[]})}return
|
|
62
|
-
`)}function
|
|
63
|
-
`)}}}async function
|
|
64
|
-
`).filter(Boolean)){let[c,
|
|
61
|
+
Change-Versions-Dist-Tag: ${d}`:"");await C.stage(),await y("git",["commit","-m",u,"-m",w,"-m",ue],t),await C.verifyCommit(),C.disarm()}catch(u){await C.fail(u)}let f=(await y("git",["rev-parse","HEAD"],t)).trim();if(console.log(M(i("versionCommitted",{commit:f}))),console.log(k(i("versionTrailerHint"))),n.branch){let u=await x("git",["push","origin",n.branch],t);if(u.code!==0)throw new l(i("branchPushFailed",{branch:n.branch,detail:u.stderr.trim()}))}return console.log(S(i("versionPublishNext"))),console.log(F(O({...e,root:t,commit:f,distTag:d??c??"latest"}))),f}async function Zt(e,t){let n=await j(e);if(!n)throw new l(i("noVersionCommit"));let r=ee(e,t.packagesDir).map((o)=>({folder:o,...A(e,t.packagesDir,o)})),s=new Map(r.map((o)=>[o.name,o]));return console.log(k(i("forcePreviousBatch",{commit:n.hash}))),n.lines.map((o)=>{let a=s.get(o.name);if(!a)throw new l(i("packageNotInDir",{dir:t.packagesDir,name:o.name}));if(a.version!==o.to)throw new l(i("releaseVersionMismatch",{name:o.name,expected:o.to,actual:a.version,commit:n.hash}));if(!a.private){for(let c of Object.keys(a.dependencies??{}))if(s.get(c)?.private)throw new l(i("publicDependsOnPrivate",{name:a.name,dep:c}))}return a.folder})}async function qn(e,t,n,r){await Promise.resolve().then(() => Xt());let c=await fe(e),m=(await Ve(e)).find((u)=>kt(u.subject))?.hash,d=Kt(c)??m??(r?await te(e,r):void 0),h=await Wn(e,d),C=new Set(n.map((u)=>u.folder)),f=new Map(ee(e,t.packagesDir).map((u)=>[A(e,t.packagesDir,u).name,u]));for(let u of n){let w=`${t.packagesDir}/${u.folder}/package.json`,p=new Set;for(let z of h)if(z.files.includes(w)&&await Jn(e,z.hash,w))p.add(z.hash);let P=Yt(h,u.folder,t.packagesDir,t.include,t.exclude,p),b=A(e,t.packagesDir,u.folder),R=P.length?[]:He(b,f).filter((z)=>C.has(z)).map((z)=>A(e,t.packagesDir,z)).map((z)=>({name:z.name,version:z.version})),B=await Qt({messages:P,version:u.to,previousTag:`${u.name}@${u.from}`,currentTag:`${u.name}@${u.to}`,dependencies:R}),g=qe.join(e,t.packagesDir,u.folder,"CHANGELOG.md"),E=ge.existsSync(g)?ge.readFileSync(g,"utf8"):"";ge.writeFileSync(g,E?`${B}
|
|
62
|
+
${E}`:B)}}async function Wn(e,t){let n=t?["rev-list","--reverse",`${t}..HEAD`]:["rev-list","--reverse","HEAD"],r=(await y("git",n,e)).split(`
|
|
63
|
+
`).filter(Boolean),s=[];for(let o of r){let a=await y("git",["log","-1","--format=%B",o],e),c=await x("git",["diff-tree","--no-commit-id","--name-only","-r","--root",o],e);s.push({hash:o,body:a,files:c.code===0?c.stdout.split(`
|
|
64
|
+
`).filter(Boolean):[]})}return s}async function Jn(e,t,n){return!await ot(e,`${t}^`,t,n)}function _n(e,t,n,r){let s=qe.join(e,t,n,"package.json"),o=ge.readFileSync(s,"utf8"),a=JSON.parse(o);if(typeof a.version!=="string")throw new l(i("missingVersionField",{folder:n}));a.version=r;let c=/\n([\t ]+)"/.exec(o)?.[1]??" ";ge.writeFileSync(s,JSON.stringify(a,null,c)+`
|
|
65
|
+
`)}function Kn(e,t){let n=ee(e,t),r=new Map(n.map((s)=>[A(e,t,s).name,A(e,t,s)]));for(let s of n){let o=qe.join(e,t,s,"package.json"),a=ge.readFileSync(o,"utf8"),c=JSON.parse(a),m=!1;for(let d of["dependencies","devDependencies"])for(let h of Object.keys(c[d]??{})){let C=r.get(h);if(!C)continue;let f=`^${C.version}`;if(c[d][h]!==f)c[d][h]=f,m=!0}if(m){let d=/\n([\t ]+)"/.exec(a)?.[1]??" ";ge.writeFileSync(o,JSON.stringify(c,null,d)+`
|
|
66
|
+
`)}}}ce();W();async function Je(e){let t=[],n=new Map,r;if(!e.formal||e.entries.every((s)=>s.pkg.private))return{entries:t,remoteError:r};if(e.config.branch){let s=e.entries.filter((a)=>!a.pkg.private).flatMap((a)=>[`refs/tags/${a.name}@${a.to}`,`refs/tags/${a.name}@${a.to}^{}`]),o=await x("git",["ls-remote","--tags","origin",...s],e.root);if(o.code!==0)r=o.stderr.trim()||o.stdout.trim()||`git ls-remote: exit ${o.code}`;else for(let a of o.stdout.trim().split(`
|
|
67
|
+
`).filter(Boolean)){let[c,m]=a.split(/\s+/);n.set(m,c)}}for(let s of e.entries){if(s.pkg.private)continue;let o=`${s.name}@${s.to}`,a=await x("git",["rev-parse","--verify",`refs/tags/${o}^{commit}`],e.root),c=n.get(`refs/tags/${o}^{}`)??n.get(`refs/tags/${o}`);t.push({tag:o,localReady:a.code===0&&a.stdout.trim()===s.commit,remoteReady:!e.config.branch||!r&&c===s.commit})}return{entries:t,remoteError:r}}N();D();I();I();N();D();K();_();I();D();K();import Yn from"node:path";W();async function ie(e){let t=Yn.resolve(e.root);if(await y("git",["rev-parse","--show-toplevel"],t),!await j(t,e.commit)){console.log(v(i("statusNoBatch")));return}console.log(S(i("statusHeading")));let n=await ae(e,!0);console.log(i("publishSummaryContext",{commit:n.release.hash,tag:e.distTag}));let r=!0;for(let a of n.entries){let c=a.pkg.private?"summaryPrivate":!n.published.has(a.folder)?"statusUpload":n.distTagVersions.get(a.folder)!==a.to?"statusRetag":"summarySkipped";if(c==="statusUpload"||c==="statusRetag")r=!1;console.log(` ${(c==="statusUpload"||c==="statusRetag"?k:v)(i(c))}: ${a.name}@${a.to}`)}let s=await Je(n);if(s.remoteError)r=!1,console.log(k(i("statusRemoteUnknown",{detail:s.remoteError})));for(let{tag:a,localReady:c,remoteReady:m}of s.entries){if(!c||!m)r=!1;console.log((c&&m?v:k)(i("statusGitTag",{tag:a,local:c?i("statusReady"):i("statusMissing"),remote:n.config.branch?m?i("statusReady"):i("statusMissing"):i("statusNotConfigured")})))}let o=await x("git",["status","--porcelain"],t);if(o.code!==0||o.stdout.trim())r=!1,console.log(k(i("dirtyTree")));console.log((r?M:k)(i(r?"statusExternalReady":"statusPending"))),console.log(v(i("statusHooksUnknown"))),console.log(F(O({...e,root:t,commit:n.release.hash})))}ke();I();D();N();W();_();K();ce();async function en(e,t){console.log(S(i("repairPublication")));let n=await ae(e,!1,!0),{root:r,startHead:s,config:o,release:a,entries:c,changed:m,published:d}=n;for(let p of c){if(!m.has(p.folder))continue;if(d.has(p.folder)||p.pkg.private)throw new l(i("repairPublishedChanged",{name:p.name,version:p.to}))}if(!m.size)return a.hash;if(o.branch){let p=await x("git",["symbolic-ref","--quiet","--short","HEAD"],r);if(p.code!==0||p.stdout.trim()!==o.branch)throw new l(i("wrongBranch",{branch:o.branch}))}let h=c.map((p)=>({...p,commit:m.has(p.folder)?s:p.commit}));if(n.formal)await Me(r,h.filter((p)=>!p.pkg.private));console.log(k(i("repairPlan")));for(let p of h)console.log(` ${p.name}@${p.to}: ${p.commit}${m.has(p.folder)?` ${i("repairCurrentCode")}`:""}`);if(e.dryRun){console.log(k(i("publishPreview"))),console.log(k(i("plannedStep",{step:i("confirmRepairPublication")}))),console.log(i("publishPlanSummary",{uploads:n.steps.filter((P)=>P.kind==="publish").length,retags:n.steps.filter((P)=>P.kind==="dist-tag").length,tags:n.steps.filter((P)=>P.kind==="tag").length}));let p=new Map(h.map((P)=>[P.name,P.commit]));rt({...n,entries:h,steps:n.steps.map((P)=>P.kind==="tag"?{...P,commit:p.get(P.name)}:P)},O({...e,root:r,commit:a.hash}));return}if(!e.yes&&!await se(i("confirmRepairPublication")))throw new l(i("cancelledPublish"));if(await V(r),(await y("git",["rev-parse","HEAD"],r)).trim()!==s)throw new l(i("versionHeadChanged"));let C=a.lines.map((p)=>`${p.name} ${p.from} => ${p.to}`).join(`
|
|
68
|
+
`)+`
|
|
69
|
+
|
|
70
|
+
Change-Versions-Dist-Tag: ${e.distTag}
|
|
71
|
+
`+h.map((p)=>`Change-Versions-Source: ${p.name} ${p.commit}`).join(`
|
|
72
|
+
`);await y("git",["commit","--allow-empty","-m","chore: record repaired publication","-m",C,"-m",ue],r);let f=(await y("git",["rev-parse","HEAD"],r)).trim(),u=(await y("git",["rev-parse","HEAD^"],r)).trim(),w=(await y("git",["rev-parse","HEAD^{tree}"],r)).trim();if(u!==s||w!==(await y("git",["rev-parse",`${s}^{tree}`],r)).trim())throw new l(i("versionHeadChanged"));if(await V(r),t?.(f),console.log(M(i("repairRecorded",{commit:f}))),console.log(F(O({...e,root:r,commit:f,retryUnpublished:!1}))),o.branch){let p=await x("git",["push","origin",o.branch],r);if(p.code!==0)throw new l(i("branchPushFailed",{branch:o.branch,detail:p.stderr.trim()}))}return console.log(v(i("publishResumeInfo"))),f}async function we(e){return X(e.root,Boolean(e.dryRun),()=>Qn(e))}async function Qn(e){let t=await j(e.root,e.commit),n={...e,commit:t?.hash??e.commit};while(!0)try{if(n.retryUnpublished){let r=await en(n,(s)=>{n.commit=s,n.retryUnpublished=!1});if(!r)return;n.commit=r,n.retryUnpublished=!1}await Bt(n);return}catch(r){if(r instanceof J||r instanceof l&&r.message===i("cancelledPublish")||e.yes||e.dryRun||!T()||!n.commit)throw r;console.error(H(r instanceof Error?r.message:String(r)));while(!0){let s;try{s=await Z(i("recoveryAction"),[{value:"retry",label:i("actionRetry"),tone:"positive"},{value:"status",label:i("actionStatus")},{value:"exit",label:i("actionExitFailed"),tone:"muted"},{value:"repair",label:i("actionRetryUnpublished"),tone:"caution"}])}catch(o){if(o instanceof J)throw r;throw o}if(s==="exit")throw r;if(s==="retry")break;if(s==="repair"){n.retryUnpublished=!0;break}try{await ie(n)}catch(o){console.error(H(o instanceof Error?o.message:String(o)))}}}}_();async function _e(e){let t=Xn.resolve(e.root);if(e.distTag!==void 0&&!Ue(e.distTag))throw new l(i("badDistTag"));await X(t,Boolean(e.dryRun),async()=>{if(e.resume||e.commit||e.retryUnpublished){if(e.force||e.bump||e.baseline||e.branchFromCli||e.messageFromCli)throw new l(i("releaseResumeOptions"));let o=await j(t,e.commit);if(!o)throw new l(i("noVersionCommit"));let a=o?tn.prerelease(o.lines[0].to)?.[0]:void 0,c=e.distTag??e.preid??o?.distTag??String(a??"latest");await we({...e,root:t,commit:o?.hash??e.commit,distTag:await Se(e.distTag,c,e.yes)});return}await V(t);let n=await j(t);if(!e.force&&n&&await te(t,e.baseline)===n.hash){let o=n.distTag??String(tn.prerelease(n.lines[0].to)?.[0]??"latest"),a=await ae({...e,root:t,distTag:o},!0,!0),c=await Je(a);if(c.remoteError)throw new l(i("statusRemoteUnknown",{detail:c.remoteError}));if(a.steps.some((m)=>m.kind==="publish"||m.kind==="dist-tag")||c.entries.some((m)=>!m.localReady||!m.remoteReady)){let m=i("releasePending",{command:O({...e,root:t,distTag:o,commit:n.hash})});if(e.yes||!T())throw new l(m);console.log(k(m));while(!0){let d=await Z(i("pendingAction"),[{value:"resume",label:i("actionResume"),tone:"positive"},{value:"status",label:i("actionStatus")},{value:"exit",label:i("actionExit"),tone:"muted"},{value:"force",label:i("actionForceVersion"),tone:"caution"},{value:"repair",label:i("actionRetryUnpublished"),tone:"caution"}]);if(d==="exit")return;if(d==="force"){e={...e,force:!0};break}if(d==="status"){try{await ie({...e,root:t,commit:n.hash,distTag:o})}catch(h){console.error(H(h instanceof Error?h.message:String(h)))}continue}await we({...e,root:t,commit:n.hash,distTag:o,retryUnpublished:d==="repair"});return}}}console.log(S(i("releaseVersionStage")));let r=e.distTag??e.preid??"latest",s=await We({...e,root:t,preparePublish:async({preid:o,config:a})=>{if(r=await Se(e.distTag,o??"latest",e.yes),T()&&!e.yes){console.log(S(i("wizardExecutionPlan"))),console.log(i("wizardPlanContext",{tag:r,branch:a.branch??i("statusNotConfigured")}));for(let[c,m]of Object.entries(a.hooks))if(m)console.log(` ${c}: ${m}`)}return r}});if(e.dryRun){console.log(k(i("releasePreviewComplete")));return}if(!s)return;console.log(S(i("releasePublishStage"))),console.log(F(O({...e,root:t,distTag:r,commit:s}))),await we({...e,root:t,distTag:r,commit:s})})}I();D();I();D();import Zn from"node:fs";import ei from"node:path";K();_();async function nn(e=process.cwd()){let t={root:e,versionsFile:"change-versions.yml",branchFromCli:!1,messageFromCli:!1};while(!0){let n=Zn.existsSync(ei.resolve(e,t.versionsFile));if(!n)console.log(k(i("wizardNeedsConfig")));let r=n?[{value:"release",label:i("actionNewRelease")},{value:"resume",label:i("actionResume"),tone:"positive"},{value:"status",label:i("actionStatus")},{value:"exit",label:i("actionExit"),tone:"muted"}]:[{value:"init",label:i("actionInit")},{value:"exit",label:i("actionExit"),tone:"muted"}],s=await Z(i("wizardAction"),r);if(s==="exit")return;if(s==="init"){await Le(t);continue}if(s==="status"){await ie({...t,distTag:await xe(e)});continue}await _e({...t,resume:s==="resume"});return}}_();N();var Y=new ti;Y.name("change-versions").version(JSON.parse(ni(new URL("../package.json",import.meta.url),"utf8")).version).description(i("cliDescription"));function Re(e){return e.option("--root <dir>",i("optRoot"),process.cwd()).option("--versions-file <file>",i("optVersionsFile"),"change-versions.yml").option("--packages <dir>",i("optPackages"))}Y.command("init").description(i("cmdInit")).option("--root <dir>",i("optRoot"),process.cwd()).option("--versions-file <file>",i("optVersionsFile"),"change-versions.yml").option("--yes",i("optYesInit")).action(async function(){let e=this.opts();await Le(e)});Re(Y.command("changed").description(i("cmdChanged"))).option("--baseline <rev>",i("optBaseline")).action(async function(){let e=this.opts();await Vt(e)});Re(Y.command("version").description(i("cmdVersion")).argument("[bump]",i("argBump"))).option("--force",i("optForceVersion")).option("--preid <id>",i("optPreid")).option("--yes",i("optYes")).option("--dry-run",i("optDryRunVersion")).option("--baseline <rev>",i("optBaseline")).option("--branch <name>",i("optBranch")).option("--commit-message <template>",i("optCommitMessage")).action(async function(e){let t=this.opts();await We({...t,bump:e,branchFromCli:this.getOptionValueSource("branch")==="cli",messageFromCli:this.getOptionValueSource("commitMessage")==="cli"})});Re(Y.command("publish").description(i("cmdPublish"))).option("--retry-unpublished",i("optRetryUnpublished")).option("--commit <rev>",i("optReleaseCommit")).option("--dist-tag <tag>",i("optDistTag")).option("--yes",i("optYes")).option("--dry-run",i("optDryRunPublish")).action(async function(){let e=this.opts();await we({...e,distTag:await Se(e.distTag,await xe(e.root,e.distTag,e.commit),e.yes)})});Re(Y.command("status").description(i("cmdStatus"))).option("--commit <rev>",i("optReleaseCommit")).option("--dist-tag <tag>",i("optDistTag")).action(async function(){let e=this.opts();await ie({...e,distTag:await xe(e.root,e.distTag,e.commit)})});Re(Y.command("release").description(i("cmdRelease")).argument("[bump]",i("argBump"))).option("--retry-unpublished",i("optRetryUnpublished")).option("--force",i("optForceVersion")).option("--preid <id>",i("optPreid")).option("--dist-tag <tag>",i("optDistTag")).option("--yes",i("optYes")).option("--dry-run",i("optDryRunRelease")).option("--baseline <rev>",i("optBaseline")).option("--branch <name>",i("optBranch")).option("--commit-message <template>",i("optCommitMessage")).option("--resume",i("optResume")).option("--commit <rev>",i("optReleaseCommit")).action(async function(e){await _e({...this.opts(),bump:e,branchFromCli:this.getOptionValueSource("branch")==="cli",messageFromCli:this.getOptionValueSource("commitMessage")==="cli"})});async function ii(){if(process.argv.length<=2){if(T())await nn();else Y.outputHelp();return}await Y.parseAsync(process.argv)}ii().catch((e)=>{if(e instanceof J){console.log(v(e.message));return}if(e instanceof l)console.error(H(e.message));else console.error(e);process.exit(1)});
|
package/docs/commands.md
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
和 Lerna 差两处:
|
|
8
8
|
|
|
9
9
|
- 非正式档位不写 CHANGELOG,也不打 git tag。`prerelease`、`prepatch`、`preminor`、`premajor` 需要预发布标识;交互时可补填,非交互或 `--yes` 时必须带 `--preid`。`patch` 再带 `--preid` 不接受。
|
|
10
|
-
-
|
|
10
|
+
- 按需升版本。默认从带 `Co-authored-by: change-versions <publish@change-versions.com>` 标记的历史批次中,找出各包最近覆盖的源码提交,分别比较到 HEAD;修复批次按 `Change-Versions-Source` 记录比较。不属于最近批次的包继续使用自身的历史起点,不被恢复记录或其他包的升版提交掩盖。没有自身历史时采用旧式版本基线,若无旧式基线则回退到首条工具批次的父提交(无父提交则使用该批次)。较新的旧式 `v<数字>` 基线可统一推进起点;显式 `--baseline` 则所有包按指定起点比较。起点不取自 `commitMessage` 或 Git tag,提交作者仍是执行命令的人。命中 `include` 且没有命中 `exclude` 的文件,或去掉 `devDependencies` 后仍有差异的 `package.json`,才让该包入选。入选包的依赖方一并升版。没有入选包时默认退出;交互可选择仅对上一批包强制升版,或显式使用 `--force`。
|
|
11
11
|
|
|
12
|
-
正式版(`patch`、`minor`、`major`)写各包 CHANGELOG,并把 workspace 依赖订正成 `^` 当前版本,然后提交。
|
|
12
|
+
正式版(`patch`、`minor`、`major`)写各包 CHANGELOG,并把 workspace 依赖订正成 `^` 当前版本,然后提交。publish 每个公开包成功后立即创建 `<name>@<version>` Git tag;配置 branch 时立即推送该 tag,再处理下一个包。tag 指向该包的源码提交,通常是 version 提交;修复补发时按恢复记录确定。失败包不创建 tag,afterPublish 失败也保留已成功包的 tag。
|
|
13
13
|
|
|
14
14
|
## 使用
|
|
15
15
|
|
|
@@ -30,7 +30,7 @@ change-versions version patch
|
|
|
30
30
|
change-versions publish
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
`publish` 未传 `--dist-tag` 时沿用原生 `release` 记录的标签;没有记录的旧提交默认 `latest
|
|
33
|
+
`publish` 未传 `--dist-tag` 时沿用原生 `release` 记录的标签;没有记录的旧提交默认 `latest`。正式版逐包成功后立即创建该包的 Git tag。
|
|
34
34
|
|
|
35
35
|
仓库里还没有这条 `Co-authored-by` 的提交时,不把整段历史当成变更。加上 `--baseline`,值是 `git rev-parse` 能解析的 SHA 或 tag。它不写入配置。较新的旧式 `v<数字>` 提交也可覆盖较旧的工具提交,兼容混用旧流程或合并后标题保留版本号的历史。
|
|
36
36
|
|
|
@@ -48,7 +48,7 @@ change-versions publish
|
|
|
48
48
|
|
|
49
49
|
选择菜单使用数字;非法输入重新提问,不退出进程。文本问题按回车采用提示中的默认值,q 保留为取消指令。提问中的 q、Ctrl-C、EOF 会停止后续步骤并退出 0,已完成的阶段保留。发布运行期间的中断仍按失败处理。在发布失败后的恢复菜单退出或取消仍返回原失败状态,避免脚本误判成功。
|
|
50
50
|
|
|
51
|
-
上一批未完成时,交互式 release
|
|
51
|
+
上一批未完成时,交互式 release 提供查询状态、恢复发布、仅对上一批强制升版、使用修复代码补发未发布包或退出;非交互与 `--yes` 默认报错并输出恢复命令,显式 `--force` 时仅对上一批包生成新版本。发布失败后的菜单同样支持状态查询、重试和修复补发;普通重试固定原 commit、root、配置、包目录与 dist-tag。重试重新查询 registry、跳过已上传版本,hooks 仍会执行。预览失败不会进入执行重试菜单。
|
|
52
52
|
|
|
53
53
|
`--yes` 表示自动执行,不再补问缺少的档位、preid 或首次基线。CI 应传入必要参数,例如 `release prerelease --preid=alpha --yes`。确认计划后还会复查工作区与 HEAD;等待输入期间发生的外部改动会中止升版并保留。
|
|
54
54
|
|
|
@@ -100,7 +100,7 @@ exclude:
|
|
|
100
100
|
{"schemaVersion":1,"root":"/repo","packagesDir":"packages","commit":"<version commit>","distTag":"latest","packages":[{"name":"@scope/app","version":"1.2.3","path":"packages/app"}]}
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-
`packages`
|
|
103
|
+
`packages` 按发布依赖顺序列出本轮检查时计划执行 `npm publish` 的包,`path` 相对 `root`。不包含 private 包、已查询到的上传版本和仅需补 dist-tag 的包;没有待上传包时为空数组。续发时重新查询 registry 并计算,覆盖同名外部环境变量。执行前若另一发布者已上传,会再次查询后跳过,因此计划可能多于最终实际上传的包。`afterPublish` 收到本轮开始时同一份队列,不会因为上传已完成而变空。dry-run 不执行 hooks。工具只传递队列;构建命令及必要 workspace 依赖由调用仓库自行决定。`beforeCommit` 不提供该发布上下文。
|
|
104
104
|
|
|
105
105
|
命令行同名参数覆盖配置。`--root` 默认当前目录,`--versions-file` 默认 `change-versions.yml`。这两项不进配置文件。
|
|
106
106
|
|
|
@@ -110,7 +110,7 @@ registry 也不进配置。每个包按这个顺序解析,查询、上传、di
|
|
|
110
110
|
2. 否则,`@scope/name` 用 `.npmrc` 里的 `@scope:registry`
|
|
111
111
|
3. 否则用 `npm config get registry`
|
|
112
112
|
|
|
113
|
-
`"private": true`
|
|
113
|
+
`"private": true` 的包仍参与变更检测、依赖方传播和入选升版,用版本批次记录其源码变化;不上传,也不创建 Git tag。`changed`、交互入选列表和版本预览会显示私有标记;升版预览还会说明“私有包仅升版,不上传,也不创建 Git tag”。
|
|
114
114
|
|
|
115
115
|
## 退出后下一步
|
|
116
116
|
|
|
@@ -167,7 +167,7 @@ flowchart TD
|
|
|
167
167
|
notLoggedIn --> hLogin["退出 1. npm login --registry=该地址, 然后重跑同一条 publish"]
|
|
168
168
|
beforePub --> hBefore["还没上传也没打 git tag. 修好 hook 后重跑 publish"]
|
|
169
169
|
partialNpm --> hPartial["不要重跑 version. 重跑同一条 publish, 已在 registry 的跳过"]
|
|
170
|
-
afterDirty --> hAfter["
|
|
170
|
+
afterDirty --> hAfter["已成功包与 tag 保留. 弄干净后重跑 publish"]
|
|
171
171
|
tagGap --> hTag["重跑 publish. 指向同一 commit 的 tag 跳过"]
|
|
172
172
|
tagClash --> hClash["不覆盖. 人工处理这个同名 tag 后, 再重跑 publish"]
|
|
173
173
|
```
|
|
@@ -176,7 +176,9 @@ flowchart TD
|
|
|
176
176
|
|
|
177
177
|
实际 `version`、`publish`、`release` 操作通过 Git 公共目录中的 `change-versions.lock` 互斥,同仓库不同 worktree 也共享锁。正常退出和可处理的中断会释放锁。工具不会自动删除疑似过期锁;确认记录中的进程已退出且没有发布运行后才能手动删除。`status` 和 dry-run 不创建或删除锁。
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
每次上传或修改 npm dist-tag 前(包括失败后的每次自动重试)重新查询 registry。若响应丢失但上传已经生效,会跳过重复上传;若通道已指向 semver 更高版本,会拒绝回退,即使本批次目标版本尚不存在。需要发布旧版本时改用其他通道。原本已存在的版本若在标签修复前消失,会停止核对,不自动改为上传。发布前后还检查工作区和 HEAD,避免 npm 生命周期修改源码后继续打 tag。明确的校验失败不进行网络重试。查询与写入不是原子操作,不同克隆或 CI 仍须串行发布。
|
|
180
|
+
|
|
181
|
+
五个包里前三个发布成功、第四个失败时,正式版已立即创建前三个包的 Git tag,第四个和未执行的第五个没有 tag。重跑同一条 `publish` 会跳过已有版本、补齐缺失的标签,只上传剩余包。若上传成功但 Git tag 创建或推送失败,停止后续包,恢复时先补齐该包标签再继续,不重复上传。401、403、ENEEDAUTH 不重试,先 `npm login --registry=<url>`。其余网络错误每个包重试 2 次。只有 npm view 的 JSON 错误明确给出 E404 才视为目标版本不存在;认证失败、DNS/网络错误、无效响应不视为未发布。`npm publish` 和 `dist-tag add` 都算。
|
|
180
182
|
|
|
181
183
|
打 tag 如果停在半路,再跑时指向同一条 version 提交的 tag 跳过,指向别处则退出并且不覆盖。有 `branch` 时再推这些 tag,不用 `git push --tags`。远程已有同一个 tag 算成功。
|
|
182
184
|
|
|
@@ -210,6 +212,12 @@ change-versions release --commit=<版本提交> --dry-run
|
|
|
210
212
|
|
|
211
213
|
失败后使用输出的 publish 命令或 `release --resume` 恢复,跳过已上传版本;不要再次运行 `release patch`。`--commit` 同样进入恢复阶段。dry-run 只预览升版,并在需要检查上一批时只读查询 registry;新版本尚未创建时,不会把旧批次的 registry 结果冒充新发布计划。
|
|
212
214
|
|
|
215
|
+
如果失败后修改了未发布包的源码,先提交修复,再执行 `release --retry-unpublished` 或 `publish --retry-unpublished`。可用 `--commit=<原版本提交>` 明确选择原批次,可保留原 root、versions-file、packages 与 dist-tag,也支持 `--yes` 和 `--dry-run`。release 的此选项进入恢复流程,不可同时指定 `--force`、升版档位、baseline、branch 或 commit-message。所有包的当前版本仍须与批次匹配,工作区须干净,registry 查询失败时停止;已发布包或私有包若有源码改动也会停止,不会覆盖已有版本。
|
|
216
|
+
|
|
217
|
+
修复补发先展示各包的源码提交,再单独确认创建空的恢复记录提交;没有源码变化则直接执行原恢复流程。记录沿用整批包名和版本,使用 `Change-Versions-Source: <包名> <源码提交>` 保存每个包的完整 SHA,所有源码提交必须在记录提交的历史中。记录不修改 package.json、依赖范围、CHANGELOG 或其他文件,不执行 beforeCommit;配置 branch 时先推送记录提交,再进入普通发布确认。beforePublish / afterPublish 和发布上下文沿用普通发布行为,上下文只列出需上传的包。已发布包继续对应其原源码提交,未发布且有变更的包对应当前修复提交;正式版创建或校验各包对应提交的 Git 标签,不移动旧标签。
|
|
218
|
+
|
|
219
|
+
恢复记录在上传前保存,因此部分失败、退出、标签失败后都可直接用输出的新 publish 命令或 `release --resume`,保留原版本号继续。需要再次修改未发布包时,提交修复并重复 `--retry-unpublished`,会创建新的恢复记录。dry-run 仅查询并展示恢复记录和发布计划,不提交、不推送、不执行 hook 或修改任何标签。
|
|
220
|
+
|
|
213
221
|
## status
|
|
214
222
|
|
|
215
223
|
```bash
|
|
@@ -243,7 +251,7 @@ change-versions publish --dist-tag=<tag>
|
|
|
243
251
|
|
|
244
252
|
默认发布最近一条带这条 `Co-authored-by` 的提交正文里的包。`--commit=<SHA或引用>` 可指定当前 HEAD 历史中的版本提交,即使合并时丢失标记也能恢复;正文仍须包含有效且包名不重复的 `<name> <old> => <new>` 列表。 当前 package.json 的版本必须与该提交记录一致,且这些包的目录在该提交之后没有改动;其他目录的提交可以保留。检查失败时不会访问 npm 或上传。正式版先检查已有本地同名 tag 是否指向这条 version 提交,冲突则在上传前退出。先看工作区,再对每个目标 registry 跑 `npm whoami --registry=<url>`。未登录就不确认、不跑 hook、不上传、不打 tag。`--dry-run` 也先做这次检查,并用 `npm view` 决定打印 `npm publish` 还是 `dist-tag add`。正文里的新版本都没有预发布后缀时才打 git tag。
|
|
245
253
|
|
|
246
|
-
确认后跑 `beforePublish`,再按依赖顺序处理非 private 包。发布 hooks 不得改变 HEAD;即便把改动提交成了干净工作区,也会中止。registry 上没有该版本就 `npm publish --tag=<dist-tag> --registry=<url
|
|
254
|
+
确认后跑 `beforePublish`,再按依赖顺序处理非 private 包。发布 hooks 不得改变 HEAD;即便把改动提交成了干净工作区,也会中止。registry 上没有该版本就 `npm publish --tag=<dist-tag> --registry=<url>`;已经有了就跳过上传,仅在目标 npm 标签不正确时执行 `npm dist-tag add`。正式版每个包在 registry 版本及目标 npm 标签就绪后立即创建或校验对应 Git tag,配置 branch 时立即推送,再处理下一个包;已经就绪的版本恢复时也可补齐该包 Git tag。所有包处理完成后跑 `afterPublish`。`pre*` 不打 git tag。
|
|
247
255
|
|
|
248
256
|
确认执行后,无论成功还是中途失败,都会输出汇总:版本提交、dist-tag、各包的版本与 registry,以及已发布、标签已更新、已跳过、失败、未执行的状态和数量。失败或中断时显示所在阶段,具体原因见错误提示;hook 或 git tag 失败不会把已成功上传的包记为发布失败。上传失败可能已在 registry 生效,重跑同一条 publish 会重新查询确认。dry-run 仅展示计划,不输出完成汇总。开始显示“发布预览”与版本提交、dist-tag;操作前统一标注 `[计划]`,末尾明确所有计划尚未执行,并给出去掉 `--dry-run` 后的 publish 命令。预览仍需查询 registry;检查失败时不会输出预览完成提示。
|
|
249
257
|
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# 按需发布流程与边界
|
|
2
|
+
|
|
3
|
+
本文记录已经确认的产品规则、当前实现和待解决边界。命令参数见 [commands.md](commands.md)。CHANGELOG 方案尚未确定,下面的流程图不将其列为已确认步骤。
|
|
4
|
+
|
|
5
|
+
## 核心规则
|
|
6
|
+
|
|
7
|
+
1. 日常发布只选择有变动的包及受依赖变动影响的包,没有入选包就结束。
|
|
8
|
+
2. 失败后重新查询实际状态,已上传版本不重复上传。
|
|
9
|
+
3. 尚未发布的包可以提交修复后保留原版本号补发;已发布版本的源码变化需要新版本。
|
|
10
|
+
4. 正式版逐包发布:一个公开包成功,就立即创建或校验对应的 `<name>@<version>` Git tag;配置推送时立即推送,再处理下一个包。
|
|
11
|
+
5. 失败包和 private 包不创建 Git tag;预发布继续不创建 Git tag。
|
|
12
|
+
6. 后续包、Git 操作或 afterPublish 失败,不撤销已上传包或已创建的 tag。
|
|
13
|
+
|
|
14
|
+
## 主流程
|
|
15
|
+
|
|
16
|
+
图中省略具体参数提问。新版本提交与修复记录提交在配置分支推送时,都须先推送成功再上传包。各执行入口还会检查工作区、版本、源码身份和标签冲突;认证或查询失败会停止流程。
|
|
17
|
+
|
|
18
|
+
```mermaid
|
|
19
|
+
flowchart TD
|
|
20
|
+
A[开始] --> B{上一批是否未完成?}
|
|
21
|
+
B -->|否| C[识别变动包及受影响的依赖方]
|
|
22
|
+
C --> D{有包需要发布?}
|
|
23
|
+
D -->|否| Z[结束]
|
|
24
|
+
D -->|是| E[准备版本并提交]
|
|
25
|
+
B -->|是| R{恢复方式}
|
|
26
|
+
R -->|直接恢复| F
|
|
27
|
+
R -->|修复未发布包| S[提交修复,保留版本号<br/>记录各包对应的源码提交]
|
|
28
|
+
S --> F
|
|
29
|
+
E --> F[查询 registry,生成剩余发布计划]
|
|
30
|
+
F --> G[执行 beforePublish]
|
|
31
|
+
G --> H[按依赖顺序处理下一个公开包]
|
|
32
|
+
H --> I{目标版本是否已上传?}
|
|
33
|
+
I -->|否| J[执行前重查 registry<br/>确认仍未上传且通道不回退后上传]
|
|
34
|
+
I -->|是| K[跳过上传,按需补 npm 标签]
|
|
35
|
+
J --> L{正式版?}
|
|
36
|
+
K --> L
|
|
37
|
+
L -->|是| M[立即创建或校验该包 Git tag<br/>按配置推送]
|
|
38
|
+
L -->|否| N{还有待处理包?}
|
|
39
|
+
M --> N
|
|
40
|
+
N -->|是| H
|
|
41
|
+
N -->|否| O[执行 afterPublish]
|
|
42
|
+
O --> Z
|
|
43
|
+
|
|
44
|
+
F -.查询或校验失败.-> X[停止,保留已成功的包和 tag]
|
|
45
|
+
G -.失败.-> X
|
|
46
|
+
J -.失败或结果不确定.-> X
|
|
47
|
+
K -.失败.-> X
|
|
48
|
+
M -.失败.-> X
|
|
49
|
+
O -.失败.-> X
|
|
50
|
+
X --> R
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
补充说明:
|
|
54
|
+
|
|
55
|
+
- 未完成检测默认围绕当前基线批次;显式指定 baseline 或 `--force` 的既有入口可以绕过默认保护。图中描述日常流程,不将这些例外视为恢复发布。
|
|
56
|
+
- 第一轮发布没有历史基线时,需要指定一条已有提交或 Git tag 作为比较起点。
|
|
57
|
+
- 全部是 private 包时,没有上传和 Git tag 步骤。
|
|
58
|
+
- “修复未发布包”仅适用于 registry 确认目标版本不存在、版本号未漂移的公开包;已发布包或 private 包的目录变化会阻止该操作。
|
|
59
|
+
- 修复记录保存整批各包的源码提交。已成功包的 tag 继续对应原源码,修复包的 tag 对应修复提交;tag 不要求全部指向同一提交。
|
|
60
|
+
- 查询、身份校验或 Git 问题应先修复对应问题;修复源码入口不能解决这类失败。
|
|
61
|
+
|
|
62
|
+
## 成功与恢复的判定
|
|
63
|
+
|
|
64
|
+
包的状态与整次命令的状态需要分开描述:一个包已经发布成功,整次命令仍可能因为后续操作失败而退出非零。
|
|
65
|
+
|
|
66
|
+
| 实际状态 | 恢复操作 | Git tag |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| 目标版本明确不存在 | 上传该版本 | 上传成功后才创建 |
|
|
69
|
+
| 上传报错,是否生效不确定 | 重新查询 registry,再决定是否上传 | 不因失败日志猜测成功 |
|
|
70
|
+
| 版本已存在,npm dist-tag 不正确 | 跳过上传,补 npm dist-tag | npm 状态就绪后补齐 |
|
|
71
|
+
| 版本及 npm dist-tag 已就绪 | 跳过上传 | 正式版校验或补齐 tag |
|
|
72
|
+
| 本地 tag 已创建,推送失败 | 不重复上传,补推该 tag 后继续 | 保留本地 tag |
|
|
73
|
+
| 同名 tag 指向错误提交 | 停止,人工处理冲突 | 不自动覆盖或移动 |
|
|
74
|
+
| afterPublish 失败 | 修复 hook 后恢复,跳过已上传版本 | 保留已成功包的 tag |
|
|
75
|
+
|
|
76
|
+
registry 认证失败、网络错误、无效响应都不能当作“版本不存在”。当前仅接受精确版本查询返回的明确 E404 作为缺失依据。
|
|
77
|
+
|
|
78
|
+
Git tag 证明该包对应的源码已发布,不代表整批全部成功,也不证明 afterPublish 曾经成功。`status` 的退出码 0 表示查询完成,不表示发布全部就绪;它不能证明历史 hook 是否成功。
|
|
79
|
+
|
|
80
|
+
## 已覆盖的边界
|
|
81
|
+
|
|
82
|
+
| 边界 | 当前行为 |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| 部分包发布后中断 | 保留成果,恢复时重查 registry,只补缺失操作 |
|
|
85
|
+
| 修复同一个未发布包多次 | 每次提交修复后可重复补发,不改变版本号 |
|
|
86
|
+
| 包版本号与批次不一致 | 停止,避免误发其他版本 |
|
|
87
|
+
| 公开包依赖 private 工作区包 | 新版本入选阶段拒绝 |
|
|
88
|
+
| 待发布包存在依赖环 | 发布计划生成时拒绝 |
|
|
89
|
+
| 工作区脏或 hook 改变 HEAD | 停止,保留外部改动供检查 |
|
|
90
|
+
| 同一 Git 公共目录并发发布 | 仓库锁互斥,涵盖 linked worktree |
|
|
91
|
+
| dry-run | 展示计划,不提交、上传、执行 hook 或改标签 |
|
|
92
|
+
|
|
93
|
+
## 需要补充或明确的边界
|
|
94
|
+
|
|
95
|
+
### 1. 恢复记录不能吞掉其他包的未发布变更:已修复并覆盖回归
|
|
96
|
+
|
|
97
|
+
已覆盖的回归场景:
|
|
98
|
+
|
|
99
|
+
1. 上一批包含 A、B,A 成功,B 失败。
|
|
100
|
+
2. 等待修复时,C 也提交了新功能,但 C 不属于上一批。
|
|
101
|
+
3. 提交 B 的修复,再创建 A、B 的恢复记录。
|
|
102
|
+
4. 下一轮按需选包仍应发现 C 的新功能。
|
|
103
|
+
|
|
104
|
+
原实现统一以最近的工具标记提交作为比较起点,会在恢复记录之后漏选 C。现在默认选包逐包查找最近批次覆盖的源码提交:B 对比其修复提交,C 继续对比自身最近批次的提交;没有自身批次时使用历史基线。后续发布或强制升版其他包也不会推进 C 的比较起点。
|
|
105
|
+
|
|
106
|
+
显式 `--baseline` 仍按用户指定的统一起点比较;较新的旧式版本基线也可以统一推进起点。最近批次仍用于展示批次信息和检查是否需要恢复,与各包实际比较源码的起点分开。
|
|
107
|
+
|
|
108
|
+
### 2. 共享输入如何影响选包:规则待定
|
|
109
|
+
|
|
110
|
+
根目录的构建脚本、共享配置和锁文件可能影响多个包的实际产物。当前变更归属按包目录分组,包目录外的文件不会仅因为命中 include 就自动映射到受影响包。
|
|
111
|
+
|
|
112
|
+
应先明确这些共享文件影响哪些包。否则会出现源码目录没变、产物实际改变,却没有入选包的情况。这与“只发布对应变动的包”直接相关,不宜用默认全量发布掩盖。
|
|
113
|
+
|
|
114
|
+
依赖边界也需保持明确:当前受影响传播考虑 dependencies 和 devDependencies,不根据 peerDependencies 或 optionalDependencies 单独建立传播关系;只改本包 devDependencies 默认不触发本包入选。
|
|
115
|
+
|
|
116
|
+
### 3. 不同克隆或 CI 的并发:当前本地锁不覆盖
|
|
117
|
+
|
|
118
|
+
现有锁只覆盖共享同一 Git 公共目录的执行进程,不能阻止另一台机器或独立克隆同时发布。CI 应先串行化同一发布通道,避免重复上传以及互相修改 latest 等 npm dist-tag。
|
|
119
|
+
|
|
120
|
+
已增加执行保护:上传及每次重试前重查版本和 npm dist-tag;发现其他发布者已经上传则跳过重复上传,npm 通道已指向 semver 更高版本时拒绝回退,包括目标版本尚不存在的情况。需要发布旧版本时选择其他通道。`status` 仍可只读查看旧批次状态。
|
|
121
|
+
|
|
122
|
+
这些同步查询与实际写入不是原子操作,不能替代分布式锁。Git tag 是固定源码标识,npm dist-tag 是可变通道指针,两者不能混为一种状态。
|
|
123
|
+
|
|
124
|
+
### 4. hook 的重试约定:需要调用项目遵守
|
|
125
|
+
|
|
126
|
+
beforePublish、afterPublish 在恢复时可能再次执行,因此需要可重复执行,不重复发送通知或制造不可恢复的副作用。afterPublish 不能作为 Git tag 是否创建的前提。
|
|
127
|
+
|
|
128
|
+
发布前和每次包操作完成后还会检查工作区与 HEAD。npm 自身的生命周期脚本若改了被跟踪源码,会保留已上传包并停止,不为变化后的源码创建 tag,也不继续上传后续包。已存在的版本若在执行标签修复时消失,会停止核对,不自动改为重新上传。
|
|
129
|
+
|
|
130
|
+
当前记录的是源码身份,没有保存待上传 tarball 的哈希。相同源码在构建时间、外部下载或依赖解析发生变化时,产物仍可能不同。优先要求锁定依赖和可重复构建;是否保存 tarball 可根据实际问题决定,不必现在扩展流程。
|
|
131
|
+
|
|
132
|
+
## CHANGELOG:待定
|
|
133
|
+
|
|
134
|
+
当前实现:正式版升版阶段生成各包 CHANGELOG,随版本提交保存;预发布不生成;普通恢复和修复补发都不会自动追加新的修复说明。
|
|
135
|
+
|
|
136
|
+
建议方案尚未采纳:正式版升版时生成,未发布包修复补发时将新增修复补入同一版本条目,实际上传阶段不修改文件。需同时满足:
|
|
137
|
+
|
|
138
|
+
- 已发布包的同版本记录不因恢复发布而改写。
|
|
139
|
+
- 同一个未发布包反复修复时不重复追加版本标题或提交记录。
|
|
140
|
+
- 包内最终 CHANGELOG、上传内容与对应源码 tag 一致。
|
|
141
|
+
- CHANGELOG 的修复更新与恢复记录一起保存,失败后可继续恢复。
|
|
142
|
+
|
|
143
|
+
在确定方案前,保持现有行为,不把上述建议写成已实现功能。
|