change-versions 1.2.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,11 +28,13 @@ bun src/cli.ts changed
28
28
  bun add --dev change-versions@<version>
29
29
  bunx --no-install change-versions init --yes
30
30
  bunx --no-install change-versions changed --baseline=<首次基线>
31
- bunx --no-install change-versions version prerelease --preid=alpha --baseline=<首次基线>
32
- bunx --no-install change-versions publish --dist-tag=alpha
31
+ bunx --no-install change-versions release prerelease --preid=alpha --baseline=<首次基线>
32
+ bunx --no-install change-versions status
33
+ # 发布失败后恢复:
34
+ bunx --no-install change-versions release --resume
33
35
  ```
34
36
 
35
- 运行 CLI 需要 Node.js,无需 Bun;Bun 用于源码开发与构建。正式档位使用 `version patch|minor|major`。第一次 version 提交建立基线后,可以省略 `--baseline`。version/publish 分开执行,重试发布时不要再升版本。
37
+ 运行 CLI 需要 Node.js,无需 Bun;Bun 用于源码开发与构建。正式档位使用 `version patch|minor|major`。第一次 version 提交建立基线后,可以省略 `--baseline`。日常使用 release 串起升版与发布;version/publish 也可分开执行。重试使用 release --resume,避免再次升版。
36
38
 
37
39
  `change-versions.yml` 使用键值配置与 include/exclude 列表,不兼容旧版缩进目录树配置。可先运行 init,在生成的文件中补上源码路径和 hooks。配置 branch 时,version 必须在该分支执行;不配置则不推送。
38
40
 
@@ -60,3 +62,47 @@ CLI 回归通过临时 npm 替身验证发布顺序、部分失败续发、登
60
62
  发生部分上传、hook 或 Git 标签失败时,先修复提示中的原因,再使用输出的 publish 命令重试,无需再次 version。重试重新查询 registry,跳过已上传版本并补齐必要标签;配置的 hook 仍会执行。Git 标签阶段失败时,本地或远端可能已有部分标签,不能据此认定全部未创建。
61
63
 
62
64
  `version --dry-run` 也会明确区分计划与修改。升版成功会说明“版本已提交,包尚未发布”,提示先预览或执行 publish。合并或重写 version 提交时须保留 `Co-authored-by: change-versions <publish@change-versions.com>`,否则 publish 可能找不到这一批版本。通过包装脚本使用时,恢复其发布步骤并保留原来的 root、配置、包目录及 dist-tag 选项,不要重新升版。
65
+
66
+
67
+ ## 交互式发布
68
+
69
+ 在终端直接运行:
70
+
71
+ ```bash
72
+ change-versions
73
+ ```
74
+
75
+ 无参数时显示发布新版本、恢复上一批、查询状态和退出的菜单;没有配置时先提供初始化入口。也可直接运行 `change-versions release`,逐步选择正式版或预发布、升版档位、预发布标识和 npm 标签。入选包与版本变化会在执行前展示,并列出构建 hooks 和推送分支。
76
+
77
+ 只询问缺少的信息,显式参数直接采用:
78
+
79
+ ```bash
80
+ change-versions release prerelease # 补问 preid 和 dist-tag
81
+ change-versions release patch --dist-tag=next
82
+ change-versions release patch --yes # 脚本/CI,不提问
83
+ ```
84
+
85
+ 输入错误可重试;输入 q、Ctrl-C 或输入结束可取消当前提问。取消停止后续步骤,已经创建的版本提交或已上传的包会保留。版本提交和实际上传分别确认;回车默认不执行。发现上一批未完成时,可查看状态、恢复发布,或选择仅对上一批包强制升版并发布。发布失败后可查看状态或重试,始终固定同一提交和标签;从失败菜单退出仍返回失败状态。
86
+
87
+ 非交互环境无参数时显示帮助;缺少升版档位或预发布标识时明确报错。`--yes` 跳过提问,需要提供必要参数,不会自动猜测档位。TTY 回归使用可选的 Python 3 标准库 PTY 中继;CLI 运行无需 Python。
88
+
89
+ ## 统一发布入口
90
+
91
+ `release patch` 完成选包、升版、提交和发布;`release --resume` 只恢复发布。自定义 dist-tag 记录在版本提交中,恢复时自动沿用。`status` 只读查询 npm 版本、标签和 Git 标签,区分待上传、待更新标签与已就绪;它不能证明历史 hook 是否成功。
92
+
93
+ 合并后丢失自动识别标记时,可使用 `publish --commit=<版本提交>` 或 `release --commit=<版本提交>`,版本与内容校验仍然生效。失败引导中的命令也固定 commit。
94
+
95
+ 实际操作使用仓库锁避免并发发布。升版仅暂存本次允许的文件;失败仅恢复仍属于本次写入的内容,外部文件与意外 hook 提交会保留。额外的 hook 生成文件通过 YAML 的 `commitFiles` 声明。配置仍兼容现有 YAML,无需迁移 JS 配置,也不增加 Bun 运行时依赖。完整规则见 [命令文档](docs/commands.md)。
96
+
97
+ 使用项目需要在包含这些命令的新版本发布后升级依赖,再将现有流程包装换成 release;1.2.1 不包含这些入口。构建通过既有 beforePublish 和发布上下文接入,增量构建策略继续由项目决定。
98
+
99
+
100
+ 无变更但需要重发上一批包的新版本时,交互会询问是否强制升版;也可显式执行:
101
+
102
+ ```bash
103
+ change-versions release prerelease --preid=alpha --force
104
+ # 仅升版,发布另行执行:
105
+ change-versions version patch --force
106
+ ```
107
+
108
+ `--force` 只使用最近一次可识别的版本提交里的包名单,不扩大到全部工作区包,也不追加其他变更包或依赖方。按指定档位从当前版本继续升版,再发布新版本;单纯重试未完成的发布仍使用 `release --resume`。`--force` 不能与恢复发布组合。`--yes` 本身不会强制升版。
package/dist/cli.js CHANGED
@@ -1,9 +1,15 @@
1
1
  #!/usr/bin/env node
2
- var be=(e,n,t)=>()=>{if(e)try{n=e(e=0)}catch(r){t=[r]}if(t)throw t[0];return n};function ye(){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,n,t=ye()){let r=Cn[e][t];if(n)for(let[s,o]of Object.entries(n))r=r.replaceAll(`{${s}}`,String(o));return r}var Cn;var z=be(()=>{Cn={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:"Packages are ready on the registry, but the Git tag stage is incomplete. Local or remote tags may be partially complete; 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,不要为了重试再次升版。",en:"If the previous version bump still needs publishing, resume publish instead of bumping again."},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 提交后又有改动。下一步: 先完成新一轮 version,再发布对应提交",en:"Release packages changed after the version commit. Next: create a new version commit before publishing"},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 仓库里重跑
2
+ var Be=(e,t,n)=>()=>{if(e)try{t=e(e=0)}catch(i){n=[i]}if(n)throw n[0];return t};function Ae(){let e=(process.env.LC_ALL||process.env.LC_MESSAGES||process.env.LANG||"").split(".")[0];return/^zh/i.test(e)?"zh":"en"}function r(e,t,n=Ae()){let i=Lt[e][n];if(t)for(let[o,s]of Object.entries(t))i=i.replaceAll(`{${o}}`,String(s));return i}var Lt;var R=Be(()=>{Lt={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)"},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."},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
+ 持有者: {owner}
4
+ 下一步:等待该进程结束;若进程已退出,确认没有其他发布操作后再删除该锁并重试。`,en:`Another release operation holds the repository lock: {file}
5
+ Owner: {owner}
6
+ 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}`,en:`The previous batch is not ready on the registry or required Git tags; a new version bump was stopped. Resume publication first:
8
+ {command}`},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:"Packages are ready on the registry, but the Git tag stage is incomplete. Local or remote tags may be partially complete; 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 提交后又有改动。下一步: 先完成新一轮 version,再发布对应提交",en:"Release packages changed after the version commit. Next: create a new version commit before publishing"},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 仓库里重跑
3
9
  {detail}`,en:`git failed. Next: rerun this inside a git repository
4
10
  {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
5
11
  {detail}`,en:`Branch push failed. The commit is local. Next: git push origin {branch}, then resume publish. Do not rerun version
6
- {detail}`},noVersionCommit:{zh:"没有 version 提交。下一步: 尚未升版时先跑 version;若已升版,请先检查提交正文的 Co-authored-by: change-versions <publish@change-versions.com> 是否保留",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>"},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:"已退回命令开始时的 HEAD。修好后重跑 version",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
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 没推上去。包已在 registry。下一步: 检查 Git 远端权限后重跑同一条 publish,补齐标签阶段;配置的 hook 仍会执行,不要重跑 version
7
13
  {detail}`,en:`git tag was not pushed. Packages are already on the registry. Next: check Git remote permissions, then rerun the same publish to finish tags; configured hooks still run. Do not rerun version
8
14
  {detail}`},networkFailed:{zh:`操作失败,已重试 2 次。后续发布步骤已停止。下一步: 重跑同一条 publish,不要重跑 version
9
15
  {detail}`,en:`Operation failed after 2 retries. Later publication steps were stopped. Next: rerun the same publish. Do not rerun version
@@ -13,14 +19,14 @@ var be=(e,n,t)=>()=>{if(e)try{n=e(e=0)}catch(r){t=[r]}if(t)throw t[0];return n};
13
19
  {detail}`,en:`Cannot read the npm registry:
14
20
  {detail}`},npmFailed:{zh:"npm 失败",en:"npm failed"},npmViewFailed:{zh:"npm view 失败",en:"npm view failed"},hookFailed:{zh:`{name} 失败。下一步: 修好 hook 后重跑 publish。已上传的包保留在 registry,尚未执行 git tag 阶段
15
21
  {detail}`,en:`{name} failed. Next: fix the hook, then rerun publish. Uploaded packages remain on the registry; the git tag stage was not reached
16
- {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 tag。下一步: 让 hook 不改被跟踪的文件,弄干净后重跑 publish",en:"afterPublish changed tracked files, so no git tag was created. 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:"非交互环境必须写上档位",en:"A bump is required when not interactive"},chooseIndex:{zh:"请输入序号: ",en:"Enter a number: "},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:"Skip confirmation"},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 之前。失败会退回 HEAD",en:"After versions and CHANGELOG are written, before git commit. Failure restores HEAD"},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 je from"picomatch";import ie from"semver";import{YAMLParseError as Sn,parse as $n}from"yaml";function ve(e){return Me.has(e)}function Oe(e,n){if(!Ae.includes(e))throw new g(i("badBump",{bump:e,list:Ae.join(", ")}));let t=e;if(zn.has(t)&&!n)throw new g(i("preidRequired",{kind:t}));if(Me.has(t)&&n)throw new g(i("preidForbidden"));return t}function oe(e){let n=Nn(e);for(let l of Object.keys(n))if(!Dn.has(l))throw new g(i("unknownField",{name:l}));let t=n.packagesDir===void 0?"packages":we(n.packagesDir,"packagesDir"),r=n.commitMessage===void 0?"bump: %s":we(n.commitMessage,"commitMessage"),s=n.branch===void 0?void 0:we(n.branch,"branch"),o=n.hooks==null?{}:Tn(n.hooks),c=n.include==null?[]:Ee(n.include,"include"),d=n.exclude==null?[]:Ee(n.exclude,"exclude");if(!c.length)throw new g(i("includeRequired"));if(!r.includes("%s"))throw new g(i("commitMessageNeedsToken"));for(let l of[...c,...d]){if(l.includes("!"))throw new g(i("patternBang",{pattern:l}));if(/\[[^\]]+\]/.test(l))throw new g(i("patternClass",{pattern:l}))}return{packagesDir:t,commitMessage:r,branch:s,hooks:o,include:c,exclude:d}}function Nn(e){try{let n=$n(e);if(n==null)return{};if(!He(n))throw new g(i("badLine",{line:1}));return n}catch(n){if(n instanceof g)throw n;if(n instanceof Sn)throw new g(i("badLine",{line:n.linePos?.[0]?.line??1}));throw n}}function Tn(e){if(!He(e))throw new g(i("badHook",{line:"hooks"}));let n={};for(let[t,r]of Object.entries(e)){if(!Rn.has(t))throw new g(i("unknownHook",{name:t}));if(typeof r!=="string"||!r)throw new g(i("hookMissingCommand",{name:t}));n[t]=r}return n}function Ee(e,n){if(!Array.isArray(e))throw new g(i("badPatternLine",{line:n}));return e.map((t)=>{if(typeof t!=="string"||!t)throw new g(i("badPatternLine",{line:n}));return t})}function we(e,n){if(typeof e!=="string"||!e)throw new g(i("missingValue",{name:n}));return e}function He(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function Be(e,n){let t={dot:!0};if(je(n,t)(e))return!0;if(n.endsWith("/**"))return!1;return je(`${n}/**`,t)(e)}function ke(e,n,t){return n.some((r)=>Be(e,r))&&!t.some((r)=>Be(e,r))}function Le(e,n,t){let r=new Set(t),s=`${n}/`,o=new Map;for(let c of e.split(`
17
- `)){if(!c.startsWith(s))continue;let d=c.slice(s.length),l=d.split("/")[0];if(!l||!d.includes("/")||!r.has(l))continue;let u=o.get(l)??[];u.push(c),o.set(l,u)}return o}function Ve(e,n,t,r,s,o){let c=[],d=[];for(let l of e){let u=n.get(l);if(!u?.length){d.push(l);continue}let m=`${o}/${l}/package.json`;if(u.some((P)=>P!==m&&ke(P,t,r))||u.includes(m)&&!s(l))c.push(l);else d.push(l)}return{changed:c,ignored:d}}function Ge(e,n){return JSON.stringify(se(Ie(e)))===JSON.stringify(se(Ie(n)))}function Ie(e){if(!e||typeof e!=="object"||Array.isArray(e))return e;let n={...e};return delete n.devDependencies,n}function se(e){if(Array.isArray(e))return e.map(se);if(e&&typeof e==="object"){let n=e;return Object.fromEntries(Object.keys(n).sort().map((t)=>[t,se(n[t])]))}return e}function qe(e,n,t){let r=t?ie.inc(e,n,t):ie.inc(e,n);if(!r)throw new g(i("badSemver",{version:e}));return r}function _e(e,n,t){let r=new Set(n),s=new Map(e.map((c)=>[c,[]]));for(let c of e)for(let d of t(c))s.get(d)?.push(c);let o=[...n];while(o.length){let c=o.pop();if(!c)break;for(let d of s.get(c)??[]){if(r.has(d))continue;r.add(d),o.push(d)}}return e.filter((c)=>r.has(c))}function Je(e,n,t){let r=e.replace("%s",n);return t?`${r} ${t}`:r}function ce(e){return e.length>0&&e.every((n)=>Boolean(ie.valid(n.to))&&ie.prerelease(n.to)==null)}function We(e){return/^v\d/.test(e)}function Ue(e){return/^v\d+\.\d+\.\d+$/.test(e)}function ge(e){let n=[];for(let t of e.split(`
18
- `)){let r=/^(\S+) (\S+) => (\S+)$/.exec(t.trim());if(r)n.push({name:r[1],from:r[2],to:r[3]})}return n}function Ke(e){let n=new Map(e.map((o)=>[o.folder,o])),t=new Set,r=[],s=(o,c)=>{if(t.has(o.folder))return;if(c.has(o.folder))throw new g(i("dependencyCycle",{name:o.name}));c.add(o.folder);for(let d of o.deps){let l=n.get(d);if(l)s(l,c)}c.delete(o.folder),t.add(o.folder),r.push(o)};for(let o of e)s(o,new Set);return r}function Z(e){return/ENEEDAUTH|E401|E403|need auth|not logged in|401 Unauthorized|403 Forbidden/i.test(e)}function Pe(e){try{return JSON.parse(e)?.error?.code==="E404"}catch{return!1}}var g,Ae,Me,zn,Dn,Rn,Fn="publish@change-versions.com",jn,ae;var D=be(()=>{z();g=class g extends Error{auth;constructor(e,n=!1){super(e);this.name="Fail",this.auth=n}};Ae=["patch","minor","major","prerelease","prepatch","preminor","premajor"],Me=new Set(["patch","minor","major"]),zn=new Set(["prerelease","prepatch","preminor","premajor"]);Dn=new Set(["packagesDir","commitMessage","branch","hooks","include","exclude"]),Rn=new Set(["beforeCommit","beforePublish","afterPublish"]);jn=`change-versions <${Fn}>`,ae=`Co-authored-by: ${jn}`});import{CommitParser as Xn}from"conventional-commits-parser";import{writeChangelogString as et}from"conventional-changelog-writer";function yn(e){return e.find((n)=>ce(ge(n.body)))?.hash}function wn(e,n,t,r,s,o){let c=`${t}/${n}/package.json`,d=`${t}/${n}/`,l=[];for(let u of e)if(u.files.some((p)=>p!==c&&p.startsWith(d)&&ke(p,r,s))||u.files.includes(c)&&o.has(u.hash))l.push({hash:u.hash,body:u.body});return l}async function vn(e){let n=new Date().toISOString().slice(0,10),t=[`## ${e.version} (${n})`];if(e.previousTag){let o=`../../compare/${encodeURIComponent(e.previousTag)}...${encodeURIComponent(e.currentTag)}`;t.push(`[${e.previousTag}...${e.currentTag}](${o})`)}let r=new Xn({noteKeywords:["BREAKING CHANGE","BREAKING-CHANGE"]}),s=[];for(let o of e.messages){let c;try{c=r.parse(o.body)}catch{continue}s.push({...c,hash:o.hash.slice(0,7),notes:c.notes??[],subject:c.subject})}if(s.length){let c=(await et(s,{version:e.version,date:n},{groupBy:"type",mainTemplate:tt,transform(d){let u=(d.notes??[]).some((p)=>/breaking/i.test(p.title)),m=d.type??"";if(nt.has(m)&&!u)return null;if(!fn[m]&&!u)return null;return{type:fn[m]??null}}})).trim();if(c)t.push("",c);else if(e.dependencies.length)t.push("",bn(e.dependencies))}else if(e.dependencies.length)t.push("",bn(e.dependencies).trimEnd());return`${t.join(`
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 改了被跟踪的文件,还没打 git tag。下一步: 让 hook 不改被跟踪的文件,弄干净后重跑 publish",en:"afterPublish changed tracked files, so no git tag was created. 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 Qe from"picomatch";import fe from"semver";import{YAMLParseError as qt,parse as Ut}from"yaml";function Me(e){return tt.has(e)}function be(e,t){if(!Xe.includes(e))throw new l(r("badBump",{bump:e,list:Xe.join(", ")}));let n=e;if(Wt.has(n)&&!t)throw new l(r("preidRequired",{kind:n}));if(tt.has(n)&&t)throw new l(r("preidForbidden"));return n}function ye(e){let t=Kt(e);for(let d of Object.keys(t))if(!Jt.has(d))throw new l(r("unknownField",{name:d}));let n=t.packagesDir===void 0?"packages":je(t.packagesDir,"packagesDir"),i=t.commitMessage===void 0?"bump: %s":je(t.commitMessage,"commitMessage"),o=t.branch===void 0?void 0:je(t.branch,"branch"),s=t.hooks==null?{}:Yt(t.hooks),a=t.include==null?[]:Ie(t.include,"include"),c=t.exclude==null?[]:Ie(t.exclude,"exclude");if(!a.length)throw new l(r("includeRequired"));if(!i.includes("%s"))throw new l(r("commitMessageNeedsToken"));for(let d of[...a,...c]){if(d.includes("!"))throw new l(r("patternBang",{pattern:d}));if(/\[[^\]]+\]/.test(d))throw new l(r("patternClass",{pattern:d}))}let g=t.commitFiles==null?void 0:Ie(t.commitFiles,"commitFiles");return{packagesDir:n,commitMessage:i,branch:o,hooks:s,include:a,exclude:c,...g?{commitFiles:g}:{}}}function Kt(e){try{let t=Ut(e);if(t==null)return{};if(!nt(t))throw new l(r("badLine",{line:1}));return t}catch(t){if(t instanceof l)throw t;if(t instanceof qt)throw new l(r("badLine",{line:t.linePos?.[0]?.line??1}));throw t}}function Yt(e){if(!nt(e))throw new l(r("badHook",{line:"hooks"}));let t={};for(let[n,i]of Object.entries(e)){if(!_t.has(n))throw new l(r("unknownHook",{name:n}));if(typeof i!=="string"||!i)throw new l(r("hookMissingCommand",{name:n}));t[n]=i}return t}function Ie(e,t){if(!Array.isArray(e))throw new l(r("badPatternLine",{line:t}));return e.map((n)=>{if(typeof n!=="string"||!n)throw new l(r("badPatternLine",{line:t}));return n})}function je(e,t){if(typeof e!=="string"||!e)throw new l(r("missingValue",{name:t}));return e}function nt(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function Ze(e,t){let n={dot:!0};if(Qe(t,n)(e))return!0;if(t.endsWith("/**"))return!1;return Qe(`${t}/**`,n)(e)}function He(e,t,n){return t.some((i)=>Ze(e,i))&&!n.some((i)=>Ze(e,i))}function it(e,t,n){let i=new Set(n),o=`${t}/`,s=new Map;for(let a of e.split(`
23
+ `)){if(!a.startsWith(o))continue;let c=a.slice(o.length),g=c.split("/")[0];if(!g||!c.includes("/")||!i.has(g))continue;let d=s.get(g)??[];d.push(a),s.set(g,d)}return s}function rt(e,t,n,i,o,s){let a=[],c=[];for(let g of e){let d=t.get(g);if(!d?.length){c.push(g);continue}let h=`${s}/${g}/package.json`;if(d.some((f)=>f!==h&&He(f,n,i))||d.includes(h)&&!o(g))a.push(g);else c.push(g)}return{changed:a,ignored:c}}function st(e,t){return JSON.stringify(we(et(e)))===JSON.stringify(we(et(t)))}function et(e){if(!e||typeof e!=="object"||Array.isArray(e))return e;let t={...e};return delete t.devDependencies,t}function we(e){if(Array.isArray(e))return e.map(we);if(e&&typeof e==="object"){let t=e;return Object.fromEntries(Object.keys(t).sort().map((n)=>[n,we(t[n])]))}return e}function ot(e,t,n){let i=n?fe.inc(e,t,n):fe.inc(e,t);if(!i)throw new l(r("badSemver",{version:e}));return i}function at(e,t,n){let i=new Set(t),o=new Map(e.map((a)=>[a,[]]));for(let a of e)for(let c of n(a))o.get(c)?.push(a);let s=[...t];while(s.length){let a=s.pop();if(!a)break;for(let c of o.get(a)??[]){if(i.has(c))continue;i.add(c),s.push(c)}}return e.filter((a)=>i.has(a))}function ct(e,t,n){let i=e.replace("%s",t);return n?`${i} ${n}`:i}function ke(e){return e.length>0&&e.every((t)=>Boolean(fe.valid(t.to))&&fe.prerelease(t.to)==null)}function lt(e){return/^v\d/.test(e)}function gt(e){return/^v\d+\.\d+\.\d+$/.test(e)}function xe(e){let t=[];for(let n of e.split(`
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(`
19
25
  `).trim()}
20
- `}function bn(e){return`### Dependencies
26
+ `}function Bt(e){return`### Dependencies
21
27
 
22
- * update dependencies ${e.map((n)=>`${n.name}@${n.version}`).join(", ")}
23
- `}var nt,fn,tt=`{{#each commitGroups}}
28
+ * update dependencies ${e.map((t)=>`${t.name}@${t.version}`).join(", ")}
29
+ `}var zn,Et,Rn=`{{#each commitGroups}}
24
30
  {{#if title}}
25
31
  ### {{title}}
26
32
 
@@ -38,18 +44,21 @@ var be=(e,n,t)=>()=>{if(e)try{n=e(e=0)}catch(r){t=[r]}if(t)throw t[0];return n};
38
44
  {{/each}}
39
45
 
40
46
  {{/each}}
41
- `;var kn=be(()=>{D();nt=new Set(["docs","style","chore","refactor","test","build","ci"]),fn={feat:"Features",feature:"Features",fix:"Bug Fixes",perf:"Performance Improvements",revert:"Reverts"}});import{Command as ut}from"commander";import{readFileSync as mt}from"node:fs";import Bn from"node:path";import{styleText as xn}from"node:util";function N(e,n,t){return xn(e,n,{stream:t})}function w(e){return N(["bold","cyan"],e,process.stdout)}function T(e){return N("bold",e,process.stdout)}function M(e){return N("green",e,process.stdout)}function y(e){return N("dim",e,process.stdout)}function A(e){return N("cyan",e,process.stdout)}function Fe(e,n,t){return`${T(e)} ${y(n)} ${y("=>")} ${M(t)}`}function q(e){let[n,...t]=e.split(`
42
- `),r=N("red",n,process.stderr);if(!t.length)return r;return[r,...t.map((s)=>N("yellow",s,process.stderr))].join(`
43
- `)}function _(e){return N("green",e,process.stdout)}function S(e){return N("yellow",e,process.stdout)}function re(e){return N("red",e,process.stdout)}z();z();D();import{spawn as Qe,spawnSync as Ye}from"node:child_process";function b(e,n,t){return new Promise((r)=>{let s=Qe(e,n,{cwd:t,stdio:["ignore","pipe","pipe"]}),o="",c="";s.stdout.on("data",(d)=>{o+=d}),s.stderr.on("data",(d)=>{c+=d}),s.on("error",(d)=>r({code:1,stdout:o,stderr:`${c}${d.message}`})),s.on("close",(d)=>r({code:d??1,stdout:o,stderr:c}))})}async function v(e,n,t){let r=await b(e,n,t);if(r.code!==0){let s=(r.stderr||r.stdout).trim();throw new g(s?i("commandFailed",{command:e,detail:s}):i("commandFailedShort",{command:e}))}return r.stdout}function le(e,n,t,r){return new Promise((s,o)=>{let c=Qe(e,n,{cwd:t,stdio:"inherit",env:{...process.env,...r}});c.on("error",o),c.on("exit",(d)=>{if(d===0)s();else o(new g(i("commandExit",{command:e,code:d??1})))})})}function xe(e,n="HEAD"){Ye("git",["reset","--hard",n],{cwd:e,stdio:"inherit"}),Ye("git",["clean","-fd"],{cwd:e,stdio:"inherit"})}z();D();import J from"node:fs";import de from"node:path";z();D();function Ze(e){let n=e.packages.map((l)=>l.folder),t=new Map(e.packages.map((l)=>[l.folder,l])),r=new Map(e.packages.map((l)=>[l.name,l])),s=new Map(e.packages.map((l)=>[l.name,l.folder])),{changed:o}=Ve(n,e.filesByFolder,e.include,e.exclude,(l)=>e.devOnly.has(l),e.packagesDir),c=_e(n,o,(l)=>An(t.get(l),s));for(let l of c){let u=t.get(l);if(!u||u.private)continue;for(let m of Object.keys(u.dependencies??{}))if(r.get(m)?.private)throw new g(i("publicDependsOnPrivate",{name:u.name,dep:m}))}let d=new Set(o);return{changed:o,dependents:c.filter((l)=>!d.has(l))}}function An(e,n){if(!e)return[];return[...Object.keys(e.dependencies??{}),...Object.keys(e.devDependencies??{})].flatMap((r)=>{let s=n.get(r);return s?[s]:[]})}function W(e,n){let t=de.resolve(e,n);if(!J.existsSync(t))throw new g(i("configUnreadable",{file:n}));return oe(J.readFileSync(t,"utf8"))}function U(e,n){let t=de.join(e,n);if(!J.existsSync(t))throw new g(i("packagesDirMissing",{dir:n}));return J.readdirSync(t).filter((r)=>!r.startsWith(".")&&J.existsSync(de.join(t,r,"package.json")))}function k(e,n,t){let r=JSON.parse(J.readFileSync(de.join(e,n,t,"package.json"),"utf8"));if(!r.name||!r.version)throw new g(i("packageJsonIncomplete",{folder:t}));return r}function ue(e,n){let t=[];for(let r of["dependencies","devDependencies"])for(let s of Object.keys(e[r]??{})){let o=n.get(s);if(o)t.push(o)}return t}async function K(e){let n=await b("git",["status","--porcelain"],e);if(n.code!==0)throw new g(i("gitFailed",{detail:n.stderr.trim()}));if(n.stdout.trim())throw new g(i("dirtyTree"))}async function Ce(e,n){let t=await b("git",["status","--porcelain"],e);if(t.code!==0)throw new g(i("gitFailed",{detail:t.stderr.trim()}));if(t.stdout.trim())throw new g(n)}async function Se(e){return(await v("git",["log","--format=%H%x1f%s"],e)).split(`
44
- `).filter(Boolean).map((t)=>{let[r,s]=t.split("\x1F");return{hash:r,subject:s??""}})}async function X(e){let n=await v("git",["log","-F",`--grep=${ae}`,"--format=%H%x1f%s%x1f%b%x1e"],e),t=[];for(let r of n.split("\x1E")){let s=r.replace(/^\n/,"").trim();if(!s)continue;let[o,c,d]=s.split("\x1F");if(!o)continue;t.push({hash:o,subject:c??"",body:d??""})}return t}async function $e(e,n){if(n){let o=await b("git",["rev-parse","--verify",`${n}^{commit}`],e);if(o.code!==0)throw new g(i("badBaseline",{rev:n}));return o.stdout.trim()}if((await b("git",["rev-parse","--verify","HEAD"],e)).code!==0)throw new g(i("noBaseline"));let r=await X(e);if(r[0])return r[0].hash;return(await Se(e)).find((o)=>We(o.subject))?.hash??En()}async function me(e,n,t){let r=await $e(e,t),s=U(e,n.packagesDir),o=await v("git",["diff","--name-only",r,"HEAD"],e),c=Le(o,n.packagesDir,s),d=new Set;for(let[m,p]of c){let P=`${n.packagesDir}/${m}/package.json`;if(p.includes(P)&&await ze(e,r,"HEAD",P))d.add(m)}let{changed:l,dependents:u}=Ze({packages:s.map((m)=>({...k(e,n.packagesDir,m),folder:m})),filesByFolder:c,devOnly:d,include:n.include,exclude:n.exclude,packagesDir:n.packagesDir});return{baseline:r,changed:l,dependents:u}}async function ze(e,n,t,r){let s=await Xe(e,`${n}:${r}`),o=await Xe(e,`${t}:${r}`);if(s===null||o===null)return!1;try{return Ge(JSON.parse(s),JSON.parse(o))}catch{return!1}}async function Xe(e,n){let t=await b("git",["show",n],e);return t.code===0?t.stdout:null}function En(){throw new g(i("noBaseline"))}async function en(e){let n=Bn.resolve(e.root),t=W(n,e.versionsFile);if(e.packages)t.packagesDir=e.packages;await K(n);let{baseline:r,changed:s,dependents:o}=await me(n,t,e.baseline);if(!s.length&&!o.length){let c=(await v("git",["rev-parse","--short",r],n)).trim();console.log(y(i("noPackagesSince",{rev:c})));return}console.log(w(i("changedHeader")));for(let c of s)console.log(` ${T(k(n,t.packagesDir,c).name)}`);if(o.length){console.log(w(i("dependentsHeader")));for(let c of o)console.log(` ${M(k(n,t.packagesDir,c).name)}`)}}import R from"node:fs";import H from"node:path";z();D();import In from"node:readline/promises";import{stdin as nn,stdout as tn}from"node:process";z();D();function De(e){let n=In.createInterface({input:nn,output:tn});return n.question(e).finally(()=>n.close())}function ee(){return Boolean(nn.isTTY&&tn.isTTY)}async function rn(e,n){if(!ee())throw new g(i("bumpRequired"));console.log(w(e)),n.forEach((s,o)=>{console.log(` ${T(String(o+1))}) ${s}`)});let t=(await De(i("chooseIndex"))).trim(),r=Number(t)-1;if(!Number.isInteger(r)||r<0||r>=n.length)throw new g(i("invalidChoice",{answer:t||i("emptyAnswer")}));return n[r]}async function O(e,n=""){if(!ee())throw new g(i("yesRequired"));let t=n?` [${n}]`:"";return(await De(`${e}${t} `)).trim()||n}async function pe(e){if(!ee())throw new g(i("yesRequired"));console.log(w(e));let n=(await De("[y/N] ")).trim().toLowerCase();return n==="y"||n==="yes"}function Mn(e){let n=new Set,t=[];for(let r of[...Vn(e),...Gn(e)]){if(n.has(r))continue;n.add(r),t.push(r)}return t}function On(e,n=ye()){let t=(o,c="")=>i(o,void 0,n).split(`
45
- `).map((d)=>`${c}# ${d}`).join(`
46
- `),r=(o,c,d,l)=>[t(l," "),c?` ${o}: ${ne(c)}`:` # ${o}: ${d}`].join(`
47
- `),s=[t("initNotePackagesDir"),`packagesDir: ${ne(e.packagesDir)}`,"",t("initNoteCommitMessage"),'commitMessage: "bump: %s"',"",t("initNoteBranch"),e.branch?`branch: ${ne(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"),"",t("initNoteInclude"),"include:",...e.include.map((o)=>` - ${ne(o)}`),` # - ${e.packagesDir}/*/bin`,"",t("initNoteExclude")];if(e.exclude.length)s.push("exclude:",...e.exclude.map((o)=>` - ${ne(o)}`));else s.push("# exclude:",`# - ${e.packagesDir}/*/src/**/__tests__/**`);return`${s.join(`
47
+ `;var Mt=Be(()=>{F();zn=new Set(["docs","style","chore","refactor","test","build","ci"]),Et={feat:"Features",feature:"Features",fix:"Bug Fixes",perf:"Performance Improvements",revert:"Reverts"}});import{Command as Mn}from"commander";import{readFileSync as Hn}from"node:fs";import tn from"node:path";import{styleText as Vt}from"node:util";function O(e,t,n){return Vt(e,t,{stream:n})}function C(e){return O(["bold","cyan"],e,process.stdout)}function G(e){return O("bold",e,process.stdout)}function X(e){return O("green",e,process.stdout)}function P(e){return O("dim",e,process.stdout)}function B(e){return O("cyan",e,process.stdout)}function Ye(e,t,n){return`${G(e)} ${P(t)} ${P("=>")} ${X(n)}`}function I(e){let[t,...n]=e.split(`
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(`
51
+ `).map((c)=>`${a}# ${c}`).join(`
52
+ `),i=(s,a,c,g)=>[n(g," "),a?` ${s}: ${ge(a)}`:` # ${s}: ${c}`].join(`
53
+ `),o=[n("initNotePackagesDir"),`packagesDir: ${ge(e.packagesDir)}`,"",n("initNoteCommitMessage"),'commitMessage: "bump: %s"',"",n("initNoteBranch"),e.branch?`branch: ${ge(e.branch)}`:"# branch: main","","hooks:",i("beforeCommit",e.beforeCommit,"bun install","initNoteBeforeCommit"),i("beforePublish",e.beforePublish,"bun run build","initNoteBeforePublish"),i("afterPublish",void 0,"echo published","initNoteAfterPublish"),"",n("initNoteInclude"),"include:",...e.include.map((s)=>` - ${ge(s)}`),` # - ${e.packagesDir}/*/bin`,"",n("initNoteExclude")];if(e.exclude.length)o.push("exclude:",...e.exclude.map((s)=>` - ${ge(s)}`));else o.push("# exclude:",`# - ${e.packagesDir}/*/src/**/__tests__/**`);return`${o.join(`
48
54
  `)}
49
- `}async function on(e){let n=H.resolve(e.root),t=H.resolve(n,e.versionsFile);if(R.existsSync(t))throw new g(i("configExists",{file:e.versionsFile}));let r=Mn(n),s=r[0]??"packages",o=e.yes?Hn(s):await Ln(e.versionsFile,r,s);if(!o.include.length)throw new g(i("includeRequired"));let c=On(o);oe(c),R.mkdirSync(H.dirname(t),{recursive:!0}),R.writeFileSync(t,c),console.log(M(i("initWrote",{file:e.versionsFile})))}function Hn(e){return{packagesDir:e,include:[`${e}/*/src`],exclude:[`${e}/*/src/**/__tests__/**`]}}async function Ln(e,n,t){if(!ee())throw new g(i("yesRequired"));if(console.log(w(i("initIntro",{file:e}))),n.length)console.log(y(i("initFoundDirs",{dirs:n.join(", ")})));let r=await O(i("initPackagesDir"),t),s=sn(await O(i("initInclude"),`${r}/*/src`)),o=sn(await O(i("initExclude"),`${r}/*/src/**/__tests__/**`)),c=await O(i("initBranch")),d=await O(i("initBeforeCommit")),l=await O(i("initBeforePublish"));return{packagesDir:r,branch:c||void 0,beforeCommit:d||void 0,beforePublish:l||void 0,include:s,exclude:o}}function sn(e){return e.split(",").map((n)=>n.trim()).filter(Boolean)}function ne(e){return/^[A-Za-z0-9_./@*+-]+$/.test(e)?e:JSON.stringify(e)}function Vn(e){return _n(e).flatMap((n)=>{let t=n.replace(/\/\*\*?$/,"");if(!t||t===n||t.includes("*"))return[];return R.existsSync(H.join(e,t))?[t]:[]})}function Gn(e){if(!R.existsSync(e))return[];let n=[];for(let t of R.readdirSync(e)){if(t.startsWith(".")||t==="node_modules")continue;let r=H.join(e,t);if(!R.statSync(r).isDirectory())continue;if(qn(r))n.push(t)}return n}function qn(e){return R.readdirSync(e).some((n)=>R.existsSync(H.join(e,n,"package.json")))}function _n(e){let n=H.join(e,"package.json");if(!R.existsSync(n))return[];try{let t=JSON.parse(R.readFileSync(n,"utf8")),r=Array.isArray(t.workspaces)?t.workspaces:t.workspaces?.packages;return Array.isArray(r)?r.filter((s)=>typeof s==="string"):[]}catch{return[]}}import Re from"node:path";z();function Jn(e){if(/^[a-zA-Z0-9_./:@=+-]+$/.test(e))return e;return"'"+e.replaceAll("'","'\\''")+"'"}function he(e){let n=["change-versions","publish",`--dist-tag=${e.distTag}`,`--root=${e.root}`,`--versions-file=${e.versionsFile}`];if(e.packages)n.push(`--packages=${e.packages}`);return n.map(Jn).join(" ")}D();D();function an(e){let n=[];if(e.beforePublish)n.push({kind:"hook",name:"beforePublish",command:e.beforePublish});for(let t of Ke(e.packages.filter((r)=>!r.private))){if(t.published&&t.distTagVersion===t.version)continue;let r=t.registry??"";n.push(t.published?{kind:"dist-tag",name:t.name,version:t.version,folder:t.folder,registry:r,tag:e.distTag}:{kind:"publish",name:t.name,version:t.version,folder:t.folder,registry:r,tag:e.distTag})}if(e.afterPublish)n.push({kind:"hook",name:"afterPublish",command:e.afterPublish});if(e.formal)for(let t of e.packages)n.push({kind:"tag",name:t.name,version:t.version,commit:e.commit});return n}async function pn(e){let n=Re.resolve(e.root),t=he({...e,root:n});console.log(e.dryRun?S(i("publishPreview")):w(i("publishPreparing"))),await K(n);let r=(await v("git",["rev-parse","HEAD"],n)).trim(),s=W(n,e.versionsFile);if(e.packages)s.packagesDir=e.packages;let o=await Wn(n);if(!o?.lines.length)throw new g(i("noVersionCommit"));let c=U(n,s.packagesDir),d=new Map(c.map((a)=>[k(n,s.packagesDir,a).name,a])),l=o.lines.map((a)=>{let h=d.get(a.name);if(!h)throw new g(i("packageNotInDir",{dir:s.packagesDir,name:a.name}));let C=k(n,s.packagesDir,h);if(C.version!==a.to)throw new g(i("releaseVersionMismatch",{name:a.name,expected:a.to,actual:C.version,commit:o.hash}));return{...a,folder:h,pkg:C,deps:ue(C,d)}}),u=await b("git",["diff","--quiet",o.hash,"HEAD","--",...l.map((a)=>`${s.packagesDir}/${a.folder}`)],n);if(u.code===1)throw new g(i("releaseContentsChanged"));if(u.code!==0)throw new g(i("gitFailed",{detail:u.stderr.trim()}));console.log(i("publishSummaryContext",{commit:o.hash,tag:e.distTag}));let m=ce(o.lines);if(m)await hn(n,l,o.hash);let p=new Map;for(let a of l){if(a.pkg.private)continue;let h=await Zn(n,a.pkg);p.set(a.folder,h),console.log(i("checkingRegistry",{name:a.name,version:a.to,registry:h}))}let P=new Set;for(let a of l){let h=p.get(a.folder);if(!h||P.has(h))continue;P.add(h),await Qn(n,h)}let f=new Set,E=new Map;for(let a of l){if(a.pkg.private)continue;let h=p.get(a.folder);if(!h)continue;await ln(async()=>{if(await Kn(n,a.name,a.to,h)){f.add(a.folder);let C=await Yn(n,a.name,e.distTag,h);E.set(a.folder,C)}})}let F=an({packages:l.map((a)=>({name:a.name,version:a.to,folder:a.folder,private:a.pkg.private,deps:a.deps,registry:p.get(a.folder),published:f.has(a.folder),distTagVersion:E.get(a.folder)})),distTag:e.distTag,formal:m,commit:o.hash,beforePublish:s.hooks.beforePublish,afterPublish:s.hooks.afterPublish}),Y={CHANGE_VERSIONS_PUBLISH_CONTEXT:JSON.stringify({schemaVersion:1,root:n,packagesDir:s.packagesDir,commit:o.hash,distTag:e.distTag,packages:F.flatMap((a)=>a.kind==="publish"?[{name:a.name,version:a.version,path:Re.join(s.packagesDir,a.folder)}]:[])})};for(let a of l)if(f.has(a.folder)&&E.get(a.folder)===a.to)console.log(y(i("alreadyTagged",{name:a.name,version:a.to,tag:e.distTag,registry:p.get(a.folder)||""})));if(console.log(i("publishPlanSummary",{uploads:F.filter((a)=>a.kind==="publish").length,retags:F.filter((a)=>a.kind==="dist-tag").length,tags:F.filter((a)=>a.kind==="tag").length})),e.dryRun){for(let a of F)console.log(`${S(i("plannedStep",{step:""}))}${cn(a)}`);if(m&&s.branch)console.log(S(i("plannedStep",{step:`git push origin ${l.map((a)=>`refs/tags/${a.name}@${a.to}`).join(" ")}`})));if(!m)console.log(y(i("noGitTag")));console.log(S(i("publishPreviewComplete"))),console.log(w(i("publishPreviewNext"))),console.log(A(t));return}console.log(y(i("publishResumeInfo"))),console.log(w(i("willPublish")));for(let a of l){if(f.has(a.folder)&&E.get(a.folder)===a.to)continue;let h=a.pkg.private?` ${y(i("privateMark"))}`:f.has(a.folder)?` ${y(i("distTagOnlyMark"))}`:"";console.log(` ${T(a.name)} ${M(a.to)}${h}`)}if(!e.yes&&!await pe(i("confirmPublish")))throw new g(i("cancelledPublish"));let G=new Map(l.map((a)=>[a.folder,a.pkg.private?"summaryPrivate":f.has(a.folder)&&E.get(a.folder)===a.to?"summarySkipped":"summaryPending"])),B="beforePublish",j,I=!1,Q=(a)=>a==="summaryPublished"||a==="summaryRetagged"?_:a==="summaryFailed"?re:a==="summaryPending"?S:y,x=()=>{console.log((I?_:re)(i(I?"publishComplete":"publishIncomplete"))),console.log(i("publishSummaryContext",{commit:o.hash,tag:e.distTag}));let a=new Map;for(let h of l){let C=G.get(h.folder);a.set(C,(a.get(C)??0)+1);let Te=p.get(h.folder);console.log(` ${Q(C)(i(C))}: ${T(h.name)}@${T(h.to)}${Te?` — ${y(Te)}`:""}`)}if(console.log([...a].map(([h,C])=>`${Q(h)(i(h))}: ${T(String(C))}`).join(", ")),I)console.log(_(i("publishReady"))),console.log(y(i(m?s.branch?"gitTagsPushed":"gitTagsLocal":"noGitTag")));else{if(console.log(re(i("publishFailedStage",{stage:B}))),B==="git tag / git push")console.log(S(i("publishTagRecovery")));console.log(S(i("publishRetryTitle"))),console.log(w(i("publishRetry"))),console.log(y(i("publishResumeInfo"))),console.log(A(t))}},te=()=>{if(j)G.set(j,"summaryFailed");x(),console.error(q(i("publishInterrupted"))),process.exit(1)};process.on("SIGINT",te),process.on("SIGTERM",te);try{await mn(n,s.hooks.beforePublish,"beforePublish",Y),await Ce(n,i("beforePublishDirty")),await gn(n,r);for(let a of F){if(a.kind!=="publish"&&a.kind!=="dist-tag")continue;console.log(w(i("executingStep",{step:cn(a)})));let h=Re.join(n,s.packagesDir,a.folder);B=`${a.kind==="publish"?"npm publish":"npm dist-tag add"} ${a.name}@${a.version}`,j=a.folder,await ln(async()=>{if(a.kind==="dist-tag")await dn(n,["dist-tag","add",`${a.name}@${a.version}`,a.tag,`--registry=${a.registry}`],a.registry);else await dn(h,["publish",`--tag=${a.tag}`,`--registry=${a.registry}`],a.registry)}),G.set(a.folder,a.kind==="publish"?"summaryPublished":"summaryRetagged"),j=void 0}if(B="afterPublish",await mn(n,s.hooks.afterPublish,"afterPublish",Y),await Ce(n,i("afterPublishDirty")),await gn(n,r),B="git tag / git push",m)console.log(w(i("executingStep",{step:B}))),await Un(n,s.branch,l,o.hash);I=!0}catch(a){if(j)G.set(j,"summaryFailed");throw a}finally{process.off("SIGINT",te),process.off("SIGTERM",te),x()}}function cn(e){if(e.kind==="hook")return`${y(`${e.name}:`)} ${A(e.command)}`;if(e.kind==="tag")return A(`git tag ${e.name}@${e.version} ${e.commit}`);if(e.kind==="dist-tag")return A(`npm dist-tag add ${e.name}@${e.version} ${e.tag} --registry=${e.registry}`);return A(`npm publish --tag=${e.tag} --registry=${e.registry} ${e.name}@${e.version}`)}async function Wn(e){if((await b("git",["rev-parse","--verify","HEAD"],e)).code!==0)return null;let t=(await X(e))[0];if(!t)return null;let r=ge(t.body);if(!r.length)return null;return{hash:t.hash,subject:t.subject,lines:r}}async function Un(e,n,t,r){await hn(e,t,r);let s=t.map((c)=>`${c.name}@${c.to}`);for(let c of s){if((await b("git",["rev-parse","--verify",`refs/tags/${c}^{commit}`],e)).code===0)continue;await v("git",["tag",c,r],e)}if(!n)return;let o=await b("git",["push","origin",...s.map((c)=>`refs/tags/${c}`)],e);if(o.code!==0)throw new g(i("tagPushFailed",{detail:o.stderr.trim()}))}async function hn(e,n,t){for(let r of n){let s=`${r.name}@${r.to}`,o=await b("git",["rev-parse","--verify",`refs/tags/${s}^{commit}`],e);if(o.code===0&&o.stdout.trim()!==t)throw new g(i("tagPointsElsewhere",{tag:s}))}}async function gn(e,n){if((await v("git",["rev-parse","HEAD"],e)).trim()!==n)throw new g(i("publishHeadChanged"))}async function ln(e){let n="";for(let t=0;t<3;t++)try{await e();return}catch(r){if(r instanceof g&&r.auth)throw r;n=r instanceof Error?r.message:String(r)}throw new g(i("networkFailed",{detail:n}))}async function dn(e,n,t){let r=await b("npm",n,e);if(r.code===0)return;let s=`${r.stderr}${r.stdout}`;if(process.stderr.write(r.stderr),Z(s))throw new g(i("notLoggedIn",{registry:t}),!0);throw Error(s.trim()||i("npmFailed"))}async function Kn(e,n,t,r){let s=await b("npm",["view",`${n}@${t}`,"version","--json",`--registry=${r}`],e);if(s.code===0){let c;try{c=JSON.parse(s.stdout)}catch{}if(c===t||Array.isArray(c)&&c.length===1&&c[0]===t)return!0;throw Error(i("unexpectedRegistryVersion",{name:n,version:t,registry:r}))}let o=`${s.stderr}${s.stdout}`;if(Z(o))throw new g(i("notLoggedIn",{registry:r}),!0);if(Pe(s.stdout)||Pe(s.stderr))return!1;throw Error(o.trim()||i("npmViewFailed"))}async function Yn(e,n,t,r){let s=await b("npm",["view",n,"dist-tags","--json",`--registry=${r}`],e);if(s.code!==0){let d=`${s.stderr}${s.stdout}`.trim();if(Z(d))throw new g(i("notLoggedIn",{registry:r}),!0);throw Error(d||i("npmViewFailed"))}let o;try{o=JSON.parse(s.stdout)}catch{}if(Array.isArray(o)&&o.length===1)o=o[0];if(!o||typeof o!=="object"||Array.isArray(o))throw Error(i("unexpectedRegistryTags",{name:n,tag:t,registry:r}));let c=Object.prototype.hasOwnProperty.call(o,t)?o[t]:void 0;if(c!==void 0&&typeof c!=="string")throw Error(i("unexpectedRegistryTags",{name:n,tag:t,registry:r}));return c}async function Qn(e,n){let t=await b("npm",["whoami",`--registry=${n}`],e);if(t.code===0)return;let r=`${t.stderr}${t.stdout}`;if(Z(r))throw new g(i("notLoggedIn",{registry:n}),!0);throw new g(i("registryUnreachable",{registry:n,detail:r.trim()}))}async function Zn(e,n){if(n.publishConfig?.registry)return n.publishConfig.registry.replace(/\/$/,"");if(n.name.startsWith("@")&&n.name.includes("/")){let r=n.name.slice(0,n.name.indexOf("/")),s=await un(e,`${r}:registry`);if(s&&s!=="undefined"&&s!=="null")return s.replace(/\/$/,"")}let t=await un(e,"registry");if(!t||t==="undefined"||t==="null")throw new g(i("noNpmRegistry",{detail:"npm config get registry: empty value"}));return t.replace(/\/$/,"")}async function un(e,n){let t=await b("npm",["config","get",n],e);if(t.code!==0){let r=t.stderr.trim()||t.stdout.trim()||`npm config get ${n}: exit ${t.code}`;throw new g(i("noNpmRegistry",{detail:r}))}return t.stdout.trim()}async function mn(e,n,t,r){if(!n)return;console.log(w(i("executingStep",{step:`${t}: ${n}`})));try{await le("sh",["-c",n],e,r)}catch(s){let o=s instanceof Error?s.message:String(s);throw new g(i("hookFailed",{name:t,detail:o}))}}import L from"node:fs";import fe from"node:path";z();D();var rt=["patch","minor","major"],it=["prerelease","prepatch","preminor","premajor"];async function Pn(e){let n=fe.resolve(e.root),t=W(n,e.versionsFile);if(e.packages)t.packagesDir=e.packages;if(e.messageFromCli&&e.commitMessage)t.commitMessage=e.commitMessage;if(e.branchFromCli)t.branch=e.branch||void 0;if(await K(n),t.branch){let u=await b("git",["symbolic-ref","--quiet","--short","HEAD"],n);if(u.code!==0||u.stdout.trim()!==t.branch)throw new g(i("wrongBranch",{branch:t.branch}))}let r=await me(n,t,e.baseline);if(!r.changed.length&&!r.dependents.length){let u=(await v("git",["rev-parse","--short",r.baseline],n)).trim();console.log(y(i("noPackagesSince",{rev:u}))),console.log(y(i("noVersionChangesNext")));return}let s=await st(e.bump,e.preid),o=ve(s)?void 0:e.preid,c=[...r.changed,...r.dependents].map((u)=>{let m=k(n,t.packagesDir,u);return{folder:u,name:m.name,from:m.version,to:qe(m.version,s,o)}});if(e.dryRun)console.log(S(i("versionPreview")));for(let u of c)console.log(Fe(u.name,u.from,u.to));if(e.dryRun){console.log(w(i("versionPreviewComplete")));return}if(!e.yes&&!await pe(i("confirmVersions")))throw new g(i("cancelledVersion"));let d=ot(n,(await v("git",["rev-parse","HEAD"],n)).trim());try{for(let p of c)lt(n,t.packagesDir,p.folder,p.to);if(dt(n,t.packagesDir),ve(s))await at(n,t,c,e.baseline);if(t.hooks.beforeCommit)await le("sh",["-c",t.hooks.beforeCommit],n);let u=Je(t.commitMessage,s,o),m=c.map((p)=>`${p.name} ${p.from} => ${p.to}`).join(`
50
- `);await v("git",["add","--all"],n),await v("git",["commit","-m",u,"-m",m,"-m",ae],n),d.disarm()}catch(u){await d.fail(u)}let l=(await v("git",["rev-parse","HEAD"],n)).trim();if(console.log(_(i("versionCommitted",{commit:l}))),console.log(S(i("versionTrailerHint"))),t.branch){let u=await b("git",["push","origin",t.branch],n);if(u.code!==0)throw new g(i("branchPushFailed",{branch:t.branch,detail:u.stderr.trim()}))}console.log(w(i("versionPublishNext"))),console.log(A(he({...e,root:n,distTag:o??"latest"})))}async function st(e,n){let t=e??await rn(i("chooseBump"),n?it:rt);return Oe(t,n)}function ot(e,n){let t=!0,r=()=>{if(!t)return;t=!1,xe(e,n),console.error(q(i("versionRestored"))),process.exit(1)};return process.on("SIGINT",r),process.on("SIGTERM",r),{disarm(){t=!1,process.off("SIGINT",r),process.off("SIGTERM",r)},fail(s){if(t)t=!1,process.off("SIGINT",r),process.off("SIGTERM",r),xe(e,n);throw s}}}async function at(e,n,t,r){await Promise.resolve().then(() => kn());let d=await X(e),l=(await Se(e)).find((f)=>Ue(f.subject))?.hash,u=yn(d)??l??(r?await $e(e,r):void 0),m=await ct(e,u),p=new Set(t.map((f)=>f.folder)),P=new Map(U(e,n.packagesDir).map((f)=>[k(e,n.packagesDir,f).name,f]));for(let f of t){let E=`${n.packagesDir}/${f.folder}/package.json`,F=new Set;for(let x of m)if(x.files.includes(E)&&await gt(e,x.hash,E))F.add(x.hash);let Y=wn(m,f.folder,n.packagesDir,n.include,n.exclude,F),G=k(e,n.packagesDir,f.folder),B=Y.length?[]:ue(G,P).filter((x)=>p.has(x)).map((x)=>k(e,n.packagesDir,x)).map((x)=>({name:x.name,version:x.version})),j=await vn({messages:Y,version:f.to,previousTag:`${f.name}@${f.from}`,currentTag:`${f.name}@${f.to}`,dependencies:B}),I=fe.join(e,n.packagesDir,f.folder,"CHANGELOG.md"),Q=L.existsSync(I)?L.readFileSync(I,"utf8"):"";L.writeFileSync(I,Q?`${j}
51
- ${Q}`:j)}}async function ct(e,n){let t=n?["rev-list","--reverse",`${n}..HEAD`]:["rev-list","--reverse","HEAD"],r=(await v("git",t,e)).split(`
52
- `).filter(Boolean),s=[];for(let o of r){let c=await v("git",["log","-1","--format=%B",o],e),d=await b("git",["diff-tree","--no-commit-id","--name-only","-r","--root",o],e);s.push({hash:o,body:c,files:d.code===0?d.stdout.split(`
53
- `).filter(Boolean):[]})}return s}async function gt(e,n,t){return!await ze(e,`${n}^`,n,t)}function lt(e,n,t,r){let s=fe.join(e,n,t,"package.json"),o=L.readFileSync(s,"utf8"),c=JSON.parse(o);if(typeof c.version!=="string")throw new g(i("missingVersionField",{folder:t}));c.version=r;let d=/\n([\t ]+)"/.exec(o)?.[1]??" ";L.writeFileSync(s,JSON.stringify(c,null,d)+`
54
- `)}function dt(e,n){let t=U(e,n),r=new Map(t.map((s)=>[k(e,n,s).name,k(e,n,s)]));for(let s of t){let o=fe.join(e,n,s,"package.json"),c=L.readFileSync(o,"utf8"),d=JSON.parse(c),l=!1;for(let u of["dependencies","devDependencies"])for(let m of Object.keys(d[u]??{})){let p=r.get(m);if(!p)continue;let P=`^${p.version}`;if(d[u][m]!==P)d[u][m]=P,l=!0}if(l){let u=/\n([\t ]+)"/.exec(c)?.[1]??" ";L.writeFileSync(o,JSON.stringify(d,null,u)+`
55
- `)}}}z();D();var V=new ut;V.name("change-versions").version(JSON.parse(mt(new URL("../package.json",import.meta.url),"utf8")).version).description(i("cliDescription"));function Ne(e){return e.option("--root <dir>",i("optRoot"),process.cwd()).option("--versions-file <file>",i("optVersionsFile"),"change-versions.yml").option("--packages <dir>",i("optPackages"))}V.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 on(e)});Ne(V.command("changed").description(i("cmdChanged"))).option("--baseline <rev>",i("optBaseline")).action(async function(){let e=this.opts();await en(e)});Ne(V.command("version").description(i("cmdVersion")).argument("[bump]",i("argBump"))).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 n=this.opts();await Pn({...n,bump:e,branchFromCli:this.getOptionValueSource("branch")==="cli",messageFromCli:this.getOptionValueSource("commitMessage")==="cli"})});Ne(V.command("publish").description(i("cmdPublish"))).option("--dist-tag <tag>",i("optDistTag"),"latest").option("--yes",i("optYes")).option("--dry-run",i("optDryRunPublish")).action(async function(){let e=this.opts();await pn(e)});if(process.argv.length<=2)V.help();V.parseAsync(process.argv).catch((e)=>{if(e instanceof g)console.error(q(e.message));else console.error(e);process.exit(1)});
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(`
56
+ `)+(d?`
57
+
58
+ Change-Versions-Dist-Tag: ${d}`:"");await y.stage(),await w("git",["commit","-m",u,"-m",v,"-m",ve],t),await y.verifyCommit(),y.disarm()}catch(u){await y.fail(u)}let f=(await w("git",["rev-parse","HEAD"],t)).trim();if(console.log(W(r("versionCommitted",{commit:f}))),console.log(k(r("versionTrailerHint"))),n.branch){let u=await x("git",["push","origin",n.branch],t);if(u.code!==0)throw new l(r("branchPushFailed",{branch:n.branch,detail:u.stderr.trim()}))}return console.log(C(r("versionPublishNext"))),console.log(B(q({...e,root:t,commit:f,distTag:d??c??"latest"}))),f}async function Ht(e,t){let n=await j(e);if(!n)throw new l(r("noVersionCommit"));let i=J(e,t.packagesDir).map((s)=>({folder:s,...D(e,t.packagesDir,s)})),o=new Map(i.map((s)=>[s.name,s]));return console.log(k(r("forcePreviousBatch",{commit:n.hash}))),n.lines.map((s)=>{let a=o.get(s.name);if(!a)throw new l(r("packageNotInDir",{dir:t.packagesDir,name:s.name}));if(a.version!==s.to)throw new l(r("releaseVersionMismatch",{name:s.name,expected:s.to,actual:a.version,commit:n.hash}));if(!a.private){for(let c of Object.keys(a.dependencies??{}))if(o.get(c)?.private)throw new l(r("publicDependsOnPrivate",{name:a.name,dep:c}))}return a.folder})}async function $n(e,t,n,i){await Promise.resolve().then(() => Mt());let c=await ce(e),g=(await Ve(e)).find((u)=>gt(u.subject))?.hash,d=At(c)??g??(i?await _(e,i):void 0),h=await Fn(e,d),y=new Set(n.map((u)=>u.folder)),f=new Map(J(e,t.packagesDir).map((u)=>[D(e,t.packagesDir,u).name,u]));for(let u of n){let v=`${t.packagesDir}/${u.folder}/package.json`,b=new Set;for(let T of h)if(T.files.includes(v)&&await Dn(e,T.hash,v))b.add(T.hash);let A=It(h,u.folder,t.packagesDir,t.include,t.exclude,b),p=D(e,t.packagesDir,u.folder),S=A.length?[]:Se(p,f).filter((T)=>y.has(T)).map((T)=>D(e,t.packagesDir,T)).map((T)=>({name:T.name,version:T.version})),N=await jt({messages:A,version:u.to,previousTag:`${u.name}@${u.from}`,currentTag:`${u.name}@${u.to}`,dependencies:S}),m=Fe.join(e,t.packagesDir,u.folder,"CHANGELOG.md"),E=te.existsSync(m)?te.readFileSync(m,"utf8"):"";te.writeFileSync(m,E?`${N}
59
+ ${E}`:N)}}async function Fn(e,t){let n=t?["rev-list","--reverse",`${t}..HEAD`]:["rev-list","--reverse","HEAD"],i=(await w("git",n,e)).split(`
60
+ `).filter(Boolean),o=[];for(let s of i){let a=await w("git",["log","-1","--format=%B",s],e),c=await x("git",["diff-tree","--no-commit-id","--name-only","-r","--root",s],e);o.push({hash:s,body:a,files:c.code===0?c.stdout.split(`
61
+ `).filter(Boolean):[]})}return o}async function Dn(e,t,n){return!await Le(e,`${t}^`,t,n)}function Nn(e,t,n,i){let o=Fe.join(e,t,n,"package.json"),s=te.readFileSync(o,"utf8"),a=JSON.parse(s);if(typeof a.version!=="string")throw new l(r("missingVersionField",{folder:n}));a.version=i;let c=/\n([\t ]+)"/.exec(s)?.[1]??" ";te.writeFileSync(o,JSON.stringify(a,null,c)+`
62
+ `)}function En(e,t){let n=J(e,t),i=new Map(n.map((o)=>[D(e,t,o).name,D(e,t,o)]));for(let o of n){let s=Fe.join(e,t,o,"package.json"),a=te.readFileSync(s,"utf8"),c=JSON.parse(a),g=!1;for(let d of["dependencies","devDependencies"])for(let h of Object.keys(c[d]??{})){let y=i.get(h);if(!y)continue;let f=`^${y.version}`;if(c[d][h]!==f)c[d][h]=f,g=!0}if(g){let d=/\n([\t ]+)"/.exec(a)?.[1]??" ";te.writeFileSync(s,JSON.stringify(c,null,d)+`
63
+ `)}}}async function Ne(e){let t=[],n=new Map,i;if(!e.formal)return{entries:t,remoteError:i};if(e.config.branch){let o=e.entries.flatMap((a)=>[`refs/tags/${a.name}@${a.to}`,`refs/tags/${a.name}@${a.to}^{}`]),s=await x("git",["ls-remote","--tags","origin",...o],e.root);if(s.code!==0)i=s.stderr.trim()||s.stdout.trim()||`git ls-remote: exit ${s.code}`;else for(let a of s.stdout.trim().split(`
64
+ `).filter(Boolean)){let[c,g]=a.split(/\s+/);n.set(g,c)}}for(let o of e.entries){let s=`${o.name}@${o.to}`,a=await x("git",["rev-parse","--verify",`refs/tags/${s}^{commit}`],e.root),c=n.get(`refs/tags/${s}^{}`)??n.get(`refs/tags/${s}`);t.push({tag:s,localReady:a.code===0&&a.stdout.trim()===e.release.hash,remoteReady:!e.config.branch||!i&&c===e.release.hash})}return{entries:t,remoteError:i}}F();R();F();R();import Bn from"node:path";R();async function Q(e){let t=Bn.resolve(e.root);if(await w("git",["rev-parse","--show-toplevel"],t),!await j(t,e.commit)){console.log(P(r("statusNoBatch")));return}console.log(C(r("statusHeading")));let n=await me(e,!0);console.log(r("publishSummaryContext",{commit:n.release.hash,tag:e.distTag}));let i=!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")i=!1;console.log(` ${(c==="statusUpload"||c==="statusRetag"?k:P)(r(c))}: ${a.name}@${a.to}`)}let o=await Ne(n);if(o.remoteError)i=!1,console.log(k(r("statusRemoteUnknown",{detail:o.remoteError})));for(let{tag:a,localReady:c,remoteReady:g}of o.entries){if(!c||!g)i=!1;console.log((c&&g?P:k)(r("statusGitTag",{tag:a,local:c?r("statusReady"):r("statusMissing"),remote:n.config.branch?g?r("statusReady"):r("statusMissing"):r("statusNotConfigured")})))}let s=await x("git",["status","--porcelain"],t);if(s.code!==0||s.stdout.trim())i=!1,console.log(k(r("dirtyTree")));console.log((i?W:k)(r(i?"statusExternalReady":"statusPending"))),console.log(P(r("statusHooksUnknown"))),console.log(B(q({...e,root:t,commit:n.release.hash})))}async function oe(e){let t=await j(e.root,e.commit),n={...e,commit:t?.hash??e.commit};while(!0)try{await zt(n);return}catch(i){if(i instanceof V||i instanceof l&&i.message===r("cancelledPublish")||e.yes||e.dryRun||!z()||!n.commit)throw i;console.error(I(i instanceof Error?i.message:String(i)));while(!0){let o;try{o=await K(r("recoveryAction"),[{value:"retry",label:r("actionRetry")},{value:"status",label:r("actionStatus")},{value:"exit",label:r("actionExitFailed")}])}catch(s){if(s instanceof V)throw i;throw s}if(o==="exit")throw i;if(o==="retry")break;try{await Q(n)}catch(s){console.error(I(s instanceof Error?s.message:String(s)))}}}}async function Ee(e){let t=An.resolve(e.root);if(e.distTag!==void 0&&!$e(e.distTag))throw new l(r("badDistTag"));await se(t,Boolean(e.dryRun),async()=>{if(e.resume||e.commit){if(e.force||e.bump||e.baseline||e.branchFromCli||e.messageFromCli)throw new l(r("releaseResumeOptions"));let s=await j(t,e.commit);if(!s)throw new l(r("noVersionCommit"));let a=s?Ot.prerelease(s.lines[0].to)?.[0]:void 0,c=e.distTag??e.preid??s?.distTag??String(a??"latest");await oe({...e,root:t,commit:s?.hash??e.commit,distTag:await ue(e.distTag,c,e.yes)});return}await L(t);let n=await j(t);if(!e.force&&n&&await _(t,e.baseline)===n.hash){let s=n.distTag??String(Ot.prerelease(n.lines[0].to)?.[0]??"latest"),a=await me({...e,root:t,distTag:s},!0,!0),c=await Ne(a);if(c.remoteError)throw new l(r("statusRemoteUnknown",{detail:c.remoteError}));if(a.steps.some((g)=>g.kind==="publish"||g.kind==="dist-tag")||c.entries.some((g)=>!g.localReady||!g.remoteReady)){let g=r("releasePending",{command:q({...e,root:t,distTag:s,commit:n.hash})});if(e.yes||!z())throw new l(g);console.log(k(g));while(!0){let d=await K(r("pendingAction"),[{value:"resume",label:r("actionResume")},{value:"status",label:r("actionStatus")},{value:"exit",label:r("actionExit")},{value:"force",label:r("actionForceVersion")}]);if(d==="exit")return;if(d==="force"){e={...e,force:!0};break}if(d==="status"){try{await Q({...e,root:t,commit:n.hash,distTag:s})}catch(h){console.error(I(h instanceof Error?h.message:String(h)))}continue}await oe({...e,root:t,commit:n.hash,distTag:s});return}}}console.log(C(r("releaseVersionStage")));let i=e.distTag??e.preid??"latest",o=await De({...e,root:t,preparePublish:async({preid:s,config:a})=>{if(i=await ue(e.distTag,s??"latest",e.yes),z()&&!e.yes){console.log(C(r("wizardExecutionPlan"))),console.log(r("wizardPlanContext",{tag:i,branch:a.branch??r("statusNotConfigured")}));for(let[c,g]of Object.entries(a.hooks))if(g)console.log(` ${c}: ${g}`)}return i}});if(e.dryRun){console.log(k(r("releasePreviewComplete")));return}if(!o)return;console.log(C(r("releasePublishStage"))),console.log(B(q({...e,root:t,distTag:i,commit:o}))),await oe({...e,root:t,distTag:i,commit:o})})}R();import In from"node:fs";import jn from"node:path";R();async function Gt(e=process.cwd()){let t={root:e,versionsFile:"change-versions.yml",branchFromCli:!1,messageFromCli:!1};while(!0){let n=In.existsSync(jn.resolve(e,t.versionsFile));if(!n)console.log(k(r("wizardNeedsConfig")));let i=n?[{value:"release",label:r("actionNewRelease")},{value:"resume",label:r("actionResume")},{value:"status",label:r("actionStatus")},{value:"exit",label:r("actionExit")}]:[{value:"init",label:r("actionInit")},{value:"exit",label:r("actionExit")}],o=await K(r("wizardAction"),i);if(o==="exit")return;if(o==="init"){await Re(t);continue}if(o==="status"){await Q({...t,distTag:await de(e)});continue}await Ee({...t,resume:o==="resume"});return}}F();var U=new Mn;U.name("change-versions").version(JSON.parse(Hn(new URL("../package.json",import.meta.url),"utf8")).version).description(r("cliDescription"));function he(e){return e.option("--root <dir>",r("optRoot"),process.cwd()).option("--versions-file <file>",r("optVersionsFile"),"change-versions.yml").option("--packages <dir>",r("optPackages"))}U.command("init").description(r("cmdInit")).option("--root <dir>",r("optRoot"),process.cwd()).option("--versions-file <file>",r("optVersionsFile"),"change-versions.yml").option("--yes",r("optYesInit")).action(async function(){let e=this.opts();await Re(e)});he(U.command("changed").description(r("cmdChanged"))).option("--baseline <rev>",r("optBaseline")).action(async function(){let e=this.opts();await pt(e)});he(U.command("version").description(r("cmdVersion")).argument("[bump]",r("argBump"))).option("--force",r("optForceVersion")).option("--preid <id>",r("optPreid")).option("--yes",r("optYes")).option("--dry-run",r("optDryRunVersion")).option("--baseline <rev>",r("optBaseline")).option("--branch <name>",r("optBranch")).option("--commit-message <template>",r("optCommitMessage")).action(async function(e){let t=this.opts();await De({...t,bump:e,branchFromCli:this.getOptionValueSource("branch")==="cli",messageFromCli:this.getOptionValueSource("commitMessage")==="cli"})});he(U.command("publish").description(r("cmdPublish"))).option("--commit <rev>",r("optReleaseCommit")).option("--dist-tag <tag>",r("optDistTag")).option("--yes",r("optYes")).option("--dry-run",r("optDryRunPublish")).action(async function(){let e=this.opts();await oe({...e,distTag:await ue(e.distTag,await de(e.root,e.distTag,e.commit),e.yes)})});he(U.command("status").description(r("cmdStatus"))).option("--commit <rev>",r("optReleaseCommit")).option("--dist-tag <tag>",r("optDistTag")).action(async function(){let e=this.opts();await Q({...e,distTag:await de(e.root,e.distTag,e.commit)})});he(U.command("release").description(r("cmdRelease")).argument("[bump]",r("argBump"))).option("--force",r("optForceVersion")).option("--preid <id>",r("optPreid")).option("--dist-tag <tag>",r("optDistTag")).option("--yes",r("optYes")).option("--dry-run",r("optDryRunRelease")).option("--baseline <rev>",r("optBaseline")).option("--branch <name>",r("optBranch")).option("--commit-message <template>",r("optCommitMessage")).option("--resume",r("optResume")).option("--commit <rev>",r("optReleaseCommit")).action(async function(e){await Ee({...this.opts(),bump:e,branchFromCli:this.getOptionValueSource("branch")==="cli",messageFromCli:this.getOptionValueSource("commitMessage")==="cli"})});async function On(){if(process.argv.length<=2){if(z())await Gt();else U.outputHelp();return}await U.parseAsync(process.argv)}On().catch((e)=>{if(e instanceof V){console.log(P(e.message));return}if(e instanceof l)console.error(I(e.message));else console.error(e);process.exit(1)});
package/docs/commands.md CHANGED
@@ -2,12 +2,12 @@
2
2
 
3
3
  对标 Lerna 的 `changed`、`version`、`publish from-package`。不做 `bootstrap`、`run`、`exec`、`add`、`link`。
4
4
 
5
- `publish` 不升版,所以没有 `lerna publish patch` 这种一条命令又升版又发布。
5
+ `release` 编排升版和发布;`version`、`publish` 保留为独立阶段。
6
6
 
7
7
  和 Lerna 差两处:
8
8
 
9
- - 非正式档位不写 CHANGELOG,也不打 git tag。`prerelease`、`prepatch`、`preminor`、`premajor` 必须带 `--preid`。`patch` 再带 `--preid` 不接受。
10
- - 按需升版本。基线是最近一条正文带 `Co-authored-by: change-versions <publish@change-versions.com>` 的提交,不是 `commitMessage`,也不是上一个 git tag。提交作者仍是执行命令的人。命中 `include` 且没有命中 `exclude` 的文件,或去掉 `devDependencies` 后仍有差异的 `package.json`,才让该包入选。入选包的依赖方一并升版。没有入选包就退出,不升任何版本。
9
+ - 非正式档位不写 CHANGELOG,也不打 git tag。`prerelease`、`prepatch`、`preminor`、`premajor` 需要预发布标识;交互时可补填,非交互或 `--yes` 时必须带 `--preid`。`patch` 再带 `--preid` 不接受。
10
+ - 按需升版本。基线优先使用较新的旧式 `v<数字>` 提交,否则使用最近一条正文带 `Co-authored-by: change-versions <publish@change-versions.com>` 的提交,不是 `commitMessage`,也不是上一个 git tag。提交作者仍是执行命令的人。命中 `include` 且没有命中 `exclude` 的文件,或去掉 `devDependencies` 后仍有差异的 `package.json`,才让该包入选。入选包的依赖方一并升版。没有入选包时默认退出;交互可选择仅对上一批包强制升版,或显式使用 `--force`。
11
11
 
12
12
  正式版(`patch`、`minor`、`major`)写各包 CHANGELOG,并把 workspace 依赖订正成 `^` 当前版本,然后提交。git tag 要等 `publish` 把非 private 包全部送到 registry,并且 `afterPublish` 成功,才打 `<name>@<version>`。tag 指向那条 version 提交。
13
13
 
@@ -30,13 +30,27 @@ change-versions version patch
30
30
  change-versions publish
31
31
  ```
32
32
 
33
- `publish` 不传 `--dist-tag` 时是 `latest`。全部成功之后才打 git tag。
33
+ `publish` 未传 `--dist-tag` 时沿用原生 `release` 记录的标签;没有记录的旧提交默认 `latest`。全部成功之后才打 git tag。
34
34
 
35
- 仓库里还没有这条 `Co-authored-by` 的提交时,不把整段历史当成变更。加上 `--baseline`,值是 `git rev-parse` 能解析的 SHA 或 tag。它不写入配置。在第一条这种提交出现之前,仍把最近一条标题以 `v` 加数字开头的提交当作基线。
35
+ 仓库里还没有这条 `Co-authored-by` 的提交时,不把整段历史当成变更。加上 `--baseline`,值是 `git rev-parse` 能解析的 SHA 或 tag。它不写入配置。较新的旧式 `v<数字>` 提交也可覆盖较旧的工具提交,兼容混用旧流程或合并后标题保留版本号的历史。
36
36
 
37
- 没有需要发的包时,`changed` 和 `version` 退出 0,不改文件。
37
+ 没有需要发的包时,`changed` 退出 0;`version` 默认不改文件,交互时可选择强制升版。`version <bump> --force` / `release <bump> --force` 仅使用最近一次可识别的版本提交中的包名单,不追加其他变更包或依赖方,不全量发布;缺少历史批次、包缺失或当前版本与该批次不符时失败。`--force` 不可与 `--resume` / `--commit` 组合。
38
38
 
39
- 三条命令在执行变更或访问 registry 前都看 `git status --porcelain`。工作区不干净就退出 1。提示语看 `LC_ALL`、`LC_MESSAGES`、`LANG`:以 `zh` 开头用中文,否则用英文。
39
+ `changed`、`version`、`publish`、`release` 在执行变更前都看 `git status --porcelain`。工作区不干净就退出 1。提示语看 `LC_ALL`、`LC_MESSAGES`、`LANG`:以 `zh` 开头用中文,否则用英文。
40
+
41
+ ## 默认交互入口
42
+
43
+ 终端中直接运行 `change-versions` 显示操作菜单:发布新版本、恢复上一批、查看发布状态、退出。没有默认配置时显示初始化与退出;初始化完成后返回菜单,新增配置仍需由项目维护者提交。无终端的无参数调用显示帮助并退出,不进入菜单。
44
+
45
+ `release` 或 `version` 缺少档位时引导选择版本类型和档位;预发布缺少标识时提示输入。首次没有基线时要求输入已有 SHA 或 Git 标签,错误修订可以重输。显式传入的参数直接校验采用,错误不会被静默改成默认值。
46
+
47
+ `release` 和 `publish` 未传 dist-tag 时补问,并显示推荐值。已记录的发布批次沿用记录标签作为默认值。`status` 始终只读,不询问发布参数。升版前展示入选包和版本变化;release 还展示目标 npm 标签、推送分支和已配置 hooks。确认提交之后,查询 registry 并确认实际发布;两次确认都默认拒绝执行。
48
+
49
+ 选择菜单使用数字;非法输入重新提问,不退出进程。文本问题按回车采用提示中的默认值,q 保留为取消指令。提问中的 q、Ctrl-C、EOF 会停止后续步骤并退出 0,已完成的阶段保留。发布运行期间的中断仍按失败处理。在发布失败后的恢复菜单退出或取消仍返回原失败状态,避免脚本误判成功。
50
+
51
+ 上一批未完成时,交互式 release 提供查询状态、恢复发布、仅对上一批强制升版或退出;非交互与 `--yes` 默认报错并输出恢复命令,显式 `--force` 时仅对上一批包生成新版本。发布失败后的菜单同样支持状态查询和重试,固定原 commit、root、配置、包目录与 dist-tag;重试重新查询 registry、跳过已上传版本,hooks 仍会执行。预览失败不会进入执行重试菜单。
52
+
53
+ `--yes` 表示自动执行,不再补问缺少的档位、preid 或首次基线。CI 应传入必要参数,例如 `release prerelease --preid=alpha --yes`。确认计划后还会复查工作区与 HEAD;等待输入期间发生的外部改动会中止升版并保留。
40
54
 
41
55
  ## init
42
56
 
@@ -68,6 +82,7 @@ exclude:
68
82
  ```
69
83
 
70
84
  - `packagesDir` 默认 `packages`。
85
+ - `commitFiles` 可选,例如 `commitFiles: [release-note.txt]`,只接受仓库内普通文件的精确相对路径,拒绝通配符、越界路径和符号链接。工作区各包的 package.json、本次 CHANGELOG,以及根目录 bun.lock、bun.lockb、package-lock.json、npm-shrinkwrap.json、yarn.lock、pnpm-lock.yaml 自动允许,无需重复声明。
71
86
  - `commitMessage` 默认 `bump: %s`。只决定提交标题。`%s` 换成档位;有 `--preid` 时再空一格接上 preid。正文一行一个包:`<name> <old> => <new>`。`version` 在正文末尾追加 `Co-authored-by: change-versions <publish@change-versions.com>`,不覆盖提交作者。下次 `changed`、`version`、`publish` 按这行查找。
72
87
  - `branch` 不写就不推送。配置了 branch 时,version 要求当前分支与其一致(包括 dry-run),避免升版提交留在别的分支却推送旧分支。`version` 只推分支,不推 tag。
73
88
  - `include` 必填。`exclude` 可以不写。标准 YAML 列表。`*` 和 `?` 不跨过 `/`,`**` 可以。模式相对仓库根。命中目录时,目录里的文件也算命中。不支持 `!` 和方括号字符组。
@@ -75,7 +90,7 @@ exclude:
75
90
 
76
91
  `hooks` 在仓库根用 shell 执行一次,不按包重复。
77
92
 
78
- - `beforeCommit`:版本、依赖范围和 CHANGELOG 写完之后、`git commit` 之前。锁文件进同一次提交。失败则把工作区退回命令开始时的 HEAD。
93
+ - `beforeCommit`:版本、依赖范围和 CHANGELOG 写完之后、`git commit` 之前。常见根锁文件会随版本提交;其他生成文件使用 `commitFiles` 显式声明。hook 不应自行暂存或提交。失败时按下文的文件保护规则恢复。
79
94
  - `beforePublish`:确认之后、第一个 `npm publish` 之前。只能改 git 忽略的构建产物。
80
95
  - `afterPublish`:要发的包都已在 registry 上之后。不能把工作区弄脏。
81
96
 
@@ -145,8 +160,8 @@ flowchart TD
145
160
  noneChanged --> hNone["退出 0. 不用做"]
146
161
  badBump --> hBump["退出 1. pre 档位带 --preid, 正式版不要带"]
147
162
  userNo --> hNo["还没写文件也没上传. 想继续就再跑同一条命令"]
148
- versionRollback --> hRoll["已退回命令开始时的 HEAD. 修好后重跑 version"]
149
- killed --> hKill["下一步: git reset --hard 回到命令开始时的 HEAD, 再重跑 version"]
163
+ versionRollback --> hRoll["仅恢复本次拥有且未再次改变的文件. 检查 git status 后重试"]
164
+ killed --> hKill["下一步: 检查 git status 和遗留锁, 保留需要的改动后再重试"]
150
165
  branchPush --> hPush["commit 已在本地. 手动推送该分支, 不要重跑 version"]
151
166
  noCommit --> hCommit["退出 1. 先跑 version, 不要直接 publish"]
152
167
  notLoggedIn --> hLogin["退出 1. npm login --registry=该地址, 然后重跑同一条 publish"]
@@ -157,7 +172,9 @@ flowchart TD
157
172
  tagClash --> hClash["不覆盖. 人工处理这个同名 tag 后, 再重跑 publish"]
158
173
  ```
159
174
 
160
- `version` 在确认之后才写文件。写入、`beforeCommit`、提交失败,以及 SIGINT、SIGTERM,都退回命令开始时的 HEAD。因为开始时工作区是干净的,提交用 `git add --all`,锁文件会一起进去。SIGKILL 来不及还原,自己 `git reset --hard` 回到命令开始时的 HEAD。
175
+ `version` 在确认之后才写文件,只按明确文件列表暂存。失败或收到 SIGINT/SIGTERM 时,仅恢复本次拥有且内容没有再次变化的文件;外部新增、修改或暂存的文件会保留。若 HEAD 被 hook 或其他操作改变,保留提交与文件并提示人工检查,不重写历史。hook 失败后留下的自有输出也可能需要人工处理。SIGKILL 无法执行恢复;检查 `git status`、`git diff` 和锁的持有者后再处理。
176
+
177
+ 实际 `version`、`publish`、`release` 操作通过 Git 公共目录中的 `change-versions.lock` 互斥,同仓库不同 worktree 也共享锁。正常退出和可处理的中断会释放锁。工具不会自动删除疑似过期锁;确认记录中的进程已退出且没有发布运行后才能手动删除。`status` 和 dry-run 不创建或删除锁。
161
178
 
162
179
  五个包里三个已经在 registry 上、两个失败时,还没有这五个 git tag。重跑同一条 `publish` 会跳过已有版本,只发剩下的。401、403、ENEEDAUTH 不重试,先 `npm login --registry=<url>`。其余网络错误每个包重试 2 次。只有 npm view 的 JSON 错误明确给出 E404 才视为目标版本不存在;认证失败、DNS/网络错误、无效响应不视为未发布。`npm publish` 和 `dist-tag add` 都算。
163
180
 
@@ -175,6 +192,35 @@ change-versions changed
175
192
 
176
193
  找到基线且分类成功则退出 0,包括一个包都没有。工作区不干净、没有基线、修订解析失败、配置或 git 失败则退出 1。
177
194
 
195
+ ## release
196
+
197
+ ```bash
198
+ change-versions release patch --yes
199
+ change-versions release prerelease --preid=alpha --yes
200
+ change-versions release patch --dry-run
201
+ change-versions release --resume --yes
202
+ change-versions release --commit=<版本提交> --dry-run
203
+ ```
204
+
205
+ 默认先执行 version,只有本轮确实创建了版本提交且分支推送成功才进入 publish。没有入选包、取消、升版失败或 dry-run 都不会转而发布旧批次。version 和 publish 的选项可以用于 release;恢复模式不能同时传升版档位、baseline、branch 或 commit-message。
206
+
207
+ 未显式指定 dist-tag 时,终端中会补问,默认采用 preid 或 latest;`--yes` 和非交互环境直接采用该默认值。原生 release 将 dist-tag 写入版本提交的 `Change-Versions-Dist-Tag` 字段;status、publish 和 release 恢复入口可据此沿用标签。旧提交的 release 恢复入口按 preid 后缀推断,必要时显式传 `--dist-tag`。
208
+
209
+ 当前默认基线批次仍有待上传、待更新 npm 标签的包,或正式版所需 Git 标签未就绪时,release 阻止新一轮升版,并给出固定提交的恢复命令。该检查依赖 registry 查询,网络或认证错误会停止流程。显式更换 baseline 或较新的旧式版本提交会改变基线判断。该保护不追踪历史 hook 是否完成,不能证明已成功运行过 hook。
210
+
211
+ 失败后使用输出的 publish 命令或 `release --resume` 恢复,跳过已上传版本;不要再次运行 `release patch`。`--commit` 同样进入恢复阶段。dry-run 只预览升版,并在需要检查上一批时只读查询 registry;新版本尚未创建时,不会把旧批次的 registry 结果冒充新发布计划。
212
+
213
+ ## status
214
+
215
+ ```bash
216
+ change-versions status
217
+ change-versions status --commit=<版本提交> --dist-tag=alpha
218
+ ```
219
+
220
+ 只读查询批次的 npm 版本、dist-tag、正式版本地 Git 标签,以及配置 branch 后要求的 origin 远端标签。不会执行 hook、上传、暂存、提交、打标签或推送,也不要求写入锁。远端不可达会显示未知,不能视为已就绪;版本或内容漂移、本地标签冲突、registry 查询失败则给出错误并退出 1。工作区脏会提示先处理。批次不存在时显示创建或指定提交的引导。
221
+
222
+ 状态查询完成退出 0,包括仍有待处理项;这不是供 CI 判断已发布的成功码。只有查询失败或校验失败才退出 1。即使外部状态全部就绪,也无法证明历史 hook 成功;输出会明确说明这一限制,并给出需要重跑发布阶段时的命令。
223
+
178
224
  ## version
179
225
 
180
226
  ```text
@@ -183,11 +229,11 @@ change-versions version [bump] --preid=<id>
183
229
 
184
230
  `[bump]` 传给 `semver.inc`:`patch`、`minor`、`major`、`prerelease`、`prepatch`、`preminor`、`premajor`。每个包用自己的当前版本。`5.0.0-alpha.28` 加 `--preid=alpha` 时,`prerelease` 得到 `5.0.0-alpha.29`,`prepatch` 得到 `5.0.1-alpha.0`。
185
231
 
186
- 顺序是:工作区、选包、档位、打印旧版本到新版本、确认、写 `package.json`、订正 workspace 范围、正式版写 CHANGELOG、`beforeCommit`、`git add --all`、提交、按配置推分支。不 `npm publish`,不打 git tag。
232
+ 顺序是:工作区、选包、档位、打印旧版本到新版本、确认、写 `package.json`、订正 workspace 范围、正式版写 CHANGELOG、`beforeCommit`、按允许文件列表暂存、提交、按配置推分支。不 `npm publish`,不打 git tag。
187
233
 
188
- 没写档位时会提问。已有 `--preid` 时选项是四种 `pre*`,否则是 `patch`、`minor`、`major`。`--yes` 跳过确认。非交互环境必须写上档位。`--dry-run` 只打印,不写文件。
234
+ 终端中没写档位时,先选择正式版或预发布,再选择对应档位;已有 `--preid` 时直接选择四种 `pre*`。预发布缺少标识时补问,默认 alpha。`--yes` 跳过提问,非交互和 `--yes` 都必须写上必要档位与标识。`--dry-run` 只打印,不写文件。
189
235
 
190
- 没有包可升为 0。其余失败为 1。
236
+ 没有包可升为 0;在提问中用 q、Ctrl-C 或 EOF 取消为 0。其余失败为 1。
191
237
 
192
238
  ## publish
193
239
 
@@ -195,13 +241,13 @@ change-versions version [bump] --preid=<id>
195
241
  change-versions publish --dist-tag=<tag>
196
242
  ```
197
243
 
198
- 只发布最近一条带这条 `Co-authored-by` 的提交正文里的包。 当前 package.json 的版本必须与该提交记录一致,且这些包的目录在该提交之后没有改动;其他目录的提交可以保留。检查失败时不会访问 npm 或上传。正式版先检查已有本地同名 tag 是否指向这条 version 提交,冲突则在上传前退出。先看工作区,再对每个目标 registry 跑 `npm whoami --registry=<url>`。未登录就不确认、不跑 hook、不上传、不打 tag。`--dry-run` 也先做这次检查,并用 `npm view` 决定打印 `npm publish` 还是 `dist-tag add`。正文里的新版本都没有预发布后缀时才打 git tag。
244
+ 默认发布最近一条带这条 `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。
199
245
 
200
246
  确认后跑 `beforePublish`,再按依赖顺序处理非 private 包。发布 hooks 不得改变 HEAD;即便把改动提交成了干净工作区,也会中止。registry 上没有该版本就 `npm publish --tag=<dist-tag> --registry=<url>`;已经有了就跳过上传,并 `npm dist-tag add`。全部上去之后跑 `afterPublish`,然后正式版才打 git tag。`pre*` 不打 git tag。
201
247
 
202
248
  确认执行后,无论成功还是中途失败,都会输出汇总:版本提交、dist-tag、各包的版本与 registry,以及已发布、标签已更新、已跳过、失败、未执行的状态和数量。失败或中断时显示所在阶段,具体原因见错误提示;hook 或 git tag 失败不会把已成功上传的包记为发布失败。上传失败可能已在 registry 生效,重跑同一条 publish 会重新查询确认。dry-run 仅展示计划,不输出完成汇总。开始显示“发布预览”与版本提交、dist-tag;操作前统一标注 `[计划]`,末尾明确所有计划尚未执行,并给出去掉 `--dry-run` 后的 publish 命令。预览仍需查询 registry;检查失败时不会输出预览完成提示。
203
249
 
204
- 真实执行用 `[执行]` 标识当前步骤;失败汇总附带修复后重试的 publish 命令,保留 root、配置文件、包目录和 dist-tag。重试会重新查询 registry,已上传版本不重复上传,配置的 hook 仍执行。Git 标签阶段失败时可能已有部分本地或远端标签。成功、失败、预览、下一步命令和跳过项使用不同颜色,`NO_COLOR` 或关闭颜色时仍有完整状态文字。
250
+ 真实执行用 `[执行]` 标识当前步骤;失败汇总附带修复后重试的 publish 命令,保留 root、配置文件、包目录、dist-tag,并固定 `--commit`,避免后续重试误选另一个批次。重试会重新查询 registry,已上传版本不重复上传,配置的 hook 仍执行。Git 标签阶段失败时可能已有部分本地或远端标签。成功、失败、预览、下一步命令和跳过项使用不同颜色,`NO_COLOR` 或关闭颜色时仍有完整状态文字。
205
251
 
206
252
  不升版本,不改 CHANGELOG,不提交,不 unpublish。
207
253
 
@@ -209,7 +255,7 @@ change-versions publish --dist-tag=<tag>
209
255
 
210
256
  只在正式版 `version` 里生成。`pre*` 不加载解析器。
211
257
 
212
- 上一次正式版是带这条 `Co-authored-by` 的提交里,正文每个新版本都没有预发布后缀的那一条。还没有这种提交时,认标题为 `v` 加 `主.次.修`、且不含预发布后缀的提交。都没有时,这次若带了 `--baseline` 就从那里算起,否则从仓库根算起。
258
+ 上一次正式版是带这条 `Co-authored-by` 的提交里,正文每个新版本都没有预发布后缀的那一条。还没有这种提交时,认标题为 `v` 加 `主.次.修`、且不含预发布后缀的提交。都没有时,使用本轮比较基线(包括交互输入的首次基线)。
213
259
 
214
260
  一个提交归给某个包,当它改过的文件命中该包的 `include` 且没有命中 `exclude`,或该包的 `package.json` 在去掉 `devDependencies` 后有差异。只因依赖方被升版的包,写一条依赖更新。`feat` 进 Features,`fix` 进 Bug Fixes,`BREAKING CHANGE` 进破坏性变更。`docs`、`style`、`chore`、`refactor`、`test`、`build`、`ci` 不出现。解析不了的提交跳过。比较链接写 tag 名字,此时 tag 还没打。
215
261
 
@@ -232,7 +278,7 @@ change-versions version prerelease --preid=alpha --baseline=<首次修订>
232
278
  change-versions publish --dist-tag=alpha
233
279
  ```
234
280
 
235
- minipack-cli 的日常预发布把不变的项放在仓库根的 `change-versions.yml`:`packagesDir` 为 `packages`,`commitMessage` 为 `bump: %s`,`branch` 为 `v5`,`beforeCommit` 是 `bun install`,`beforePublish` 是构建。命令只留下档位和 dist-tag。`@tuya-miniapp` 的私有 registry 写在各包的 `publishConfig.registry` 或 `.npmrc`,不写进这个工具。正式版仍可先用现有的 `make release`,以后再换成 `version patch` 加 `publish`。
281
+ minipack-cli 的日常预发布把不变的项放在仓库根的 `change-versions.yml`:`packagesDir` 为 `packages`,`commitMessage` 为 `bump: %s`,`branch` 为 `v5`,`beforeCommit` 是 `bun install`,`beforePublish` 是构建。命令只留下档位和 dist-tag。`@tuya-miniapp` 的私有 registry 写在各包的 `publishConfig.registry` 或 `.npmrc`,不写进这个工具。工具新版本发布并升级依赖后,可让 `make release` 直接执行 `change-versions release patch`,恢复入口执行 `change-versions release --resume`,替换仓库中的流程包装脚本。构建仍通过 `beforePublish` 和发布上下文接入,本工具不内置 Bun 构建策略。
236
282
 
237
283
 
238
284
  ## 工具自身的打包检查
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "change-versions",
3
- "version": "1.2.1",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "description": "Version and publish only the workspace packages that changed.",
6
6
  "bin": {