release

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Release Skill

版本发布技能

Creates a release by comparing dev to main, generating changelog entries from commits, bumping the version, and creating a PR. After the tag is pushed and the release workflow finishes building binaries, updates the Homebrew formula with the real SHA256 values from the published
checksums.txt
, syncs the
coleam00/homebrew-archon
tap, and verifies the end-to-end install path via
/test-release
.
⚠️ CRITICAL — Homebrew formula SHAs cannot be known until after the release workflow builds binaries.
The
version
field in
homebrew/archon.rb
and the
sha256
fields must be updated atomically. Never update one without the other.
The correct sequence is:
  1. Tag is pushed → release workflow fires → binaries built →
    checksums.txt
    uploaded
  2. Fetch
    checksums.txt
    from the published release
  3. Parse the SHA256 per platform
  4. Update
    homebrew/archon.rb
    with the new version AND the new SHAs in a single commit
  5. Sync to the
    coleam00/homebrew-archon/Formula/archon.rb
    tap repo
Updating the formula's
version
field without also updating the
sha256
values creates a stale, misleading formula that looks valid but produces checksum mismatches on install. This has happened before (v0.3.0: version updated to 0.3.0 but SHAs were still from v0.2.13). Always do both or neither.
通过对比dev与main分支创建版本发布,根据提交记录生成变更日志条目,升级版本号,并创建PR。在标签推送完成且发布工作流构建好二进制文件后,使用已发布的
checksums.txt
中的真实SHA256值更新Homebrew公式,同步
coleam00/homebrew-archon
tap仓库,并通过
/test-release
验证端到端安装流程。
⚠️ 关键注意事项 — Homebrew公式的SHA值只有在发布工作流构建完二进制文件后才能确定。
homebrew/archon.rb
中的
version
字段和
sha256
字段必须原子性更新。绝对不能只更新其中一个。
正确的流程顺序是:
  1. 推送标签 → 触发发布工作流 → 构建二进制文件 → 上传
    checksums.txt
  2. 从已发布的版本中获取
    checksums.txt
  3. 按平台解析SHA256值
  4. 在单次提交中更新
    homebrew/archon.rb
    的新版本号和新SHA值
  5. 同步到
    coleam00/homebrew-archon/Formula/archon.rb
    tap仓库
仅更新公式的
version
字段而不同时更新
sha256
值会导致公式过期、误导用户,看似有效但安装时会出现校验不匹配的问题。之前曾发生过这种情况(v0.3.0:版本号更新到0.3.0但SHA值仍为v0.2.13的)。必须同时更新两者,或者都不更新。

Process

流程

Step 1: Validate State

步骤1:验证状态

bash
undefined
bash
undefined

Must be on dev branch with clean working tree

必须处于dev分支且工作区干净

git checkout dev git pull origin dev git status --porcelain # must be empty git fetch origin main

If not on dev or working tree is dirty, abort with a clear message.
git checkout dev git pull origin dev git status --porcelain # 必须为空 git fetch origin main

如果不在dev分支或工作区不干净,终止操作并给出明确提示。

Step 1.5: Pre-flight compiled-binary smoke test (MANDATORY before any other step)

步骤1.5:预编译二进制文件冒烟测试(所有步骤前的强制要求)

Why this is first: releases have ended up with zero working binaries because a module-init crash or bundler bug only surfaces in
bun build --compile
output, not in
bun run
. CI catches it — but only AFTER the tag is pushed and a GitHub Release is created. By then the damage (empty release, broken
releases/latest
, broken
install.sh
) is already live. Failing here, before any user-visible change, keeps the blast radius at "no release was cut."
Run locally on the native target. This takes ~15-30s and is cheaper than discovering the problem after tag+release.
bash
undefined
为什么这一步要放在最前面:曾出现过发布版本的二进制文件完全无法运行的情况,因为模块初始化崩溃或打包器bug仅在
bun build --compile
输出中出现,而在
bun run
中不会暴露。CI会检测到这个问题——但只有在标签推送完成、GitHub Release创建之后才会发现。到那时,损坏已经造成(空发布、
releases/latest
失效、
install.sh
无法使用)。在任何用户可见的变更之前在这里失败,能将影响范围控制在“未创建版本发布”。
在本地原生目标环境运行此测试。耗时约15-30秒,比在标签+发布后发现问题成本更低。
bash
undefined

Guard: only run this for Node/Bun projects with a CLI entry point + build-binaries script.

仅针对带有CLI入口点和build-binaries脚本的Node/Bun项目运行。

if [ -f scripts/build-binaries.sh ] && [ -f packages/cli/src/cli.ts ]; then TMP_BINARY=$(mktemp) trap "rm -f $TMP_BINARY" EXIT

Compile for the native target only (not full cross-compile — that's CI's job).

Match the real release flags so any bundler quirk reproduces locally.

bun build
--compile
--minify
--target=bun
--outfile="$TMP_BINARY"
packages/cli/src/cli.ts

Smoke test: the binary must start and exit 0 on a safe, non-interactive command.

Use
--help
(NOT
version
). The
version
command's compiled-binary code

path depends on BUNDLED_IS_BINARY=true, which is set by scripts/build-binaries.sh

— but we're doing a bare
bun build --compile
here to keep the smoke fast,

so BUNDLED_IS_BINARY is still
false
. That sends
version
down the dev

branch of version.ts which tries to read package.json from a path that only

exists in node_modules, producing a false-positive ENOENT.
--help
has no

such dev/binary branch and exercises the same module-init graph we're

actually testing. Must NOT touch network, database, or require env vars.

if ! "$TMP_BINARY" --help > /tmp/archon-preflight.log 2>&1; then echo "ERROR: compiled binary crashed at startup" cat /tmp/archon-preflight.log echo "" echo "This usually means a dependency has a module-init-time side effect that" echo "fails in a compiled binary context (readFileSync of a path that only" echo "exists in node_modules, etc.). Fix before cutting the release — do NOT" echo "proceed to version bump." exit 1 fi

Also grep for known crash markers that exit 0 but print a fatal error

(some module-init errors are caught by top-level try/catch but still log).

if grep -qE "Expected CommonJS module|TypeError:|ReferenceError:|SyntaxError:" /tmp/archon-preflight.log; then echo "ERROR: compiled binary emitted a runtime error despite exit 0" cat /tmp/archon-preflight.log exit 1 fi
echo "Pre-flight binary smoke: PASSED" fi

If this fails, **abort the release entirely** — do not bump version, do not modify CHANGELOG, do not create a PR. Surface the error to the user, point at the failing output, and stop. Recovery is: fix the bundler / dependency issue on a feature branch, merge to dev, re-run `/release`.

**Common failure modes this catches:**
- Bun `--bytecode` flag producing broken bytecode for the current module graph
- A dependency (e.g. an SDK) reading `package.json` or other files at module top level via paths that resolve fine in `node_modules/` but not next to a compiled binary
- Circular imports that break under minification but work under plain `bun run`
- A newly added package that ships CJS with an unusual wrapper shape
if [ -f scripts/build-binaries.sh ] && [ -f packages/cli/src/cli.ts ]; then TMP_BINARY=$(mktemp) trap "rm -f $TMP_BINARY" EXIT

仅为原生目标编译(不进行完整跨编译——这是CI的工作)。

匹配真实的发布参数,以便任何打包器问题都能在本地复现。

bun build
--compile
--minify
--target=bun
--outfile="$TMP_BINARY"
packages/cli/src/cli.ts

冒烟测试:二进制文件必须能启动并在执行安全的非交互式命令后以0状态退出。

使用
--help
(不要用
version
)。
version
命令的编译二进制代码路径依赖于BUNDLED_IS_BINARY=true,该变量由scripts/build-binaries.sh设置

——但我们在这里使用裸
bun build --compile
以保持冒烟测试快速,

因此BUNDLED_IS_BINARY仍为
false
。这会使
version
命令进入version.ts的开发分支,尝试从仅存在于node_modules中的路径读取package.json,产生误报的ENOENT错误。
--help
没有这种开发/二进制分支的区分,并且能测试我们实际要验证的模块初始化流程。绝对不能涉及网络、数据库或需要环境变量。

if ! "$TMP_BINARY" --help > /tmp/archon-preflight.log 2>&1; then echo "ERROR: 编译后的二进制文件启动时崩溃" cat /tmp/archon-preflight.log echo "" echo "这通常意味着某个依赖在模块初始化阶段有副作用,在编译二进制文件的环境中失败(比如readFileSync读取仅存在于node_modules中的路径等)。在创建版本发布前修复此问题——不要继续进行版本号升级。" exit 1 fi

同时检查已知的崩溃标记,这些标记会以0状态退出但打印致命错误

#(某些模块初始化错误被顶级try/catch捕获但仍会记录日志)。 if grep -qE "Expected CommonJS module|TypeError:|ReferenceError:|SyntaxError:" /tmp/archon-preflight.log; then echo "ERROR: 编译后的二进制文件虽以0状态退出但抛出了运行时错误" cat /tmp/archon-preflight.log exit 1 fi
echo "预编译二进制文件冒烟测试:通过" fi

如果此测试失败,**完全终止版本发布流程**——不要升级版本号、不要修改CHANGELOG、不要创建PR。向用户展示错误信息,指向失败输出,然后停止。恢复流程:在功能分支上修复打包器/依赖问题,合并到dev,重新运行`/release`。

**此测试能捕获的常见失败模式:**
- Bun的`--bytecode`标志为当前模块图生成无效字节码
- 某个依赖(例如SDK)在模块顶部通过路径读取`package.json`或其他文件,该路径在`node_modules/`中能正常解析,但在编译后的二进制文件旁无法解析
- 循环导入在压缩时失效,但在普通`bun run`中正常工作
- 新增的包以不寻常的包装形式提供CJS模块

Step 2: Detect Stack and Current Version

步骤2:检测技术栈和当前版本

Detect the project's package manager and version file:
  1. Check for
    pyproject.toml
    — Python project, version in
    version = "x.y.z"
  2. Check for
    package.json
    — Node/Bun project, version in
    "version": "x.y.z"
  3. Check for
    Cargo.toml
    — Rust project, version in
    version = "x.y.z"
  4. Check for
    go.mod
    — Go project (version from git tags only, no file to bump)
If none found, abort: "Could not detect project stack — no version file found."
Read the current version from the detected file.
检测项目的包管理器和版本文件:
  1. 检查
    pyproject.toml
    — Python项目,版本在
    version = "x.y.z"
  2. 检查
    package.json
    — Node/Bun项目,版本在
    "version": "x.y.z"
  3. 检查
    Cargo.toml
    — Rust项目,版本在
    version = "x.y.z"
  4. 检查
    go.mod
    — Go项目(仅从Git标签获取版本,无需更新文件)
如果未找到任何文件,终止操作:“无法检测项目技术栈——未找到版本文件。”
从检测到的文件中读取当前版本。

Step 3: Determine Version Bump

步骤3:确定版本号升级规则

Bump rules based on argument:
  • No argument or
    patch
    (default):
    0.1.0 -> 0.1.1
  • minor
    :
    0.1.3 -> 0.2.0
  • major
    :
    0.3.5 -> 1.0.0
基于参数的升级规则:
  • 无参数或
    patch
    (默认):
    0.1.0 -> 0.1.1
  • minor
    0.1.3 -> 0.2.0
  • major
    0.3.5 -> 1.0.0

Step 4: Collect Commits

步骤4:收集提交记录

bash
undefined
bash
undefined

Get all commits on dev that aren't on main

获取dev分支上所有不在main分支的提交

git log main..dev --oneline --no-merges

If no new commits, abort: "Nothing to release — dev is up to date with main."
git log main..dev --oneline --no-merges

如果没有新提交,终止操作:“没有内容可发布——dev分支与main分支保持同步。”

Step 5: Draft Changelog Entries

步骤5:草拟变更日志条目

Read the commit messages and the actual diffs (
git diff main..dev
) to understand what changed.
Categorize into Keep a Changelog sections:
  • Added — new features, new files, new capabilities
  • Changed — modifications to existing behavior
  • Fixed — bug fixes
  • Removed — deleted features or code
Writing rules:
  • Write entries as a human would — clear, concise, user-facing language
  • Do NOT just copy commit messages verbatim — rewrite them into proper changelog entries
  • Group related commits into single entries where it makes sense
  • Include PR numbers in parentheses when available:
    (#12)
  • Each entry should start with a noun or gerund describing WHAT changed
  • Skip internal-only changes (CI tweaks, typo fixes) unless they affect behavior
  • One blank line between sections
读取提交消息和实际差异(
git diff main..dev
)以了解变更内容。
按Keep a Changelog的分类方式整理:
  • 新增 — 新功能、新文件、新能力
  • 变更 — 对现有行为的修改
  • 修复 — 漏洞修复
  • 移除 — 删除的功能或代码
撰写规则:
  • 以人类可读的方式撰写——清晰、简洁、面向用户的语言
  • 不要直接复制提交消息——将其重写为规范的变更日志条目
  • 合理将相关提交合并为单个条目
  • 如有PR编号,在括号中包含:
    (#12)
  • 每个条目应以描述变更内容的名词或动名词开头
  • 跳过仅内部变更(CI调整、拼写错误修复),除非它们影响行为
  • 各部分之间留一行空白

Step 6: Update Files

步骤6:更新文件

  1. Version file — update version to new value:
    • package.json
      : update
      "version": "x.y.z"
    • pyproject.toml
      : update
      version = "x.y.z"
    • Cargo.toml
      : update
      version = "x.y.z"
  2. Workspace version sync (monorepo only):
    • If
      scripts/sync-versions.sh
      exists, run
      bash scripts/sync-versions.sh
      to sync all
      packages/*/package.json
      versions to match the root version.
  3. Lockfile refresh (stack-dependent):
    • package.json
      +
      bun.lock
      : run
      bun install
    • package.json
      +
      package-lock.json
      : run
      npm install --package-lock-only
    • pyproject.toml
      +
      uv.lock
      : run
      uv lock --quiet
    • Cargo.toml
      : run
      cargo update --workspace
  4. CHANGELOG.md
    — prepend new version section:
markdown
undefined
  1. 版本文件 — 将版本更新为新值:
    • package.json
      :更新
      "version": "x.y.z"
    • pyproject.toml
      :更新
      version = "x.y.z"
    • Cargo.toml
      :更新
      version = "x.y.z"
  2. 工作区版本同步(仅针对单体仓库):
    • 如果存在
      scripts/sync-versions.sh
      ,运行
      bash scripts/sync-versions.sh
      以同步所有
      packages/*/package.json
      的版本与根版本一致。
  3. 锁文件刷新(取决于技术栈):
    • package.json
      +
      bun.lock
      :运行
      bun install
    • package.json
      +
      package-lock.json
      :运行
      npm install --package-lock-only
    • pyproject.toml
      +
      uv.lock
      :运行
      uv lock --quiet
    • Cargo.toml
      :运行
      cargo update --workspace
  4. CHANGELOG.md
    — 在开头添加新版本章节:
markdown
undefined

[x.y.z] - YYYY-MM-DD

[x.y.z] - YYYY-MM-DD

One-line summary of the release.
版本发布的单行摘要。

Added

新增

  • Entry one (#PR)
  • Entry two (#PR)
  • 条目一 (#PR)
  • 条目二 (#PR)

Changed

变更

  • Entry one (#PR)
  • 条目一 (#PR)

Fixed

修复

  • Entry one (#PR)

Move any content under `[Unreleased]` into the new version section. Leave `[Unreleased]` header with nothing under it.
  • 条目一 (#PR)

将`[Unreleased]`下的所有内容移至新版本章节中。保留`[Unreleased]`标题,其下留空。

Step 7: Present for Review

步骤7:提交审核

Show the user:
  1. The detected stack and version file
  2. The version bump (old -> new)
  3. The full changelog section that will be added
  4. The list of commits being included
Ask: "Does this look good? I'll commit and create the PR."
向用户展示:
  1. 检测到的技术栈和版本文件
  2. 版本号升级(旧版本 -> 新版本)
  3. 将添加的完整变更日志章节
  4. 包含的提交记录列表
询问:“这样看起来没问题吗?我将提交并创建PR。”

Step 8: Commit and PR

步骤8:提交并创建PR

Only after user approval:
bash
undefined
仅在用户批准后执行:
bash
undefined

Stage version file, workspace packages, lockfile, and changelog

暂存版本文件、工作区包、锁文件和变更日志

git add <version-file> packages/*/package.json <lockfile> CHANGELOG.md git commit -m "Release x.y.z"
git add <version-file> packages/*/package.json <lockfile> CHANGELOG.md git commit -m "Release x.y.z"

Push dev

推送dev分支

git push origin dev
git push origin dev

Create PR: dev -> main

创建PR:dev -> main

gh pr create --base main --head dev
--title "Release x.y.z"
--body "$(cat <<'EOF'
gh pr create --base main --head dev
--title "Release x.y.z"
--body "$(cat <<'EOF'

Release x.y.z

Release x.y.z

{changelog section content}

Merging this PR releases x.y.z to main. EOF )"

Return the PR URL to the user.
{changelog section content}

Merging this PR releases x.y.z to main. EOF )"

向用户返回PR的URL。

Step 9: Tag, Release, and Sync After Merge

步骤9:合并后打标签、发布并同步

After the PR is merged (either by the user or via
gh pr merge
):
bash
undefined
在PR合并后(由用户手动合并或通过
gh pr merge
合并):
bash
undefined

Fetch the merge commit on main

获取main分支上的合并提交

git fetch origin main
git fetch origin main

Tag the merge commit

为合并提交打标签

git tag vx.y.z origin/main git push origin vx.y.z
git tag vx.y.z origin/main git push origin vx.y.z

Create a GitHub Release from the tag (uses changelog content as release notes)

从标签创建GitHub Release(使用变更日志内容作为发布说明)

gh release create vx.y.z --title "vx.y.z" --notes "{changelog section content without the ## header}"
gh release create vx.y.z --title "vx.y.z" --notes "{changelog section content without the ## header}"

Sync dev with main so both branches are identical

同步dev分支与main分支,使两者保持一致

git checkout dev git pull origin main git push origin dev

> **Important**: This sync ensures dev has the merge commit from main. Without it,
> dev and main diverge. The CI `update-homebrew` job only pushes the formula
> commit to dev — it does not bring the PR merge commit onto dev. This manual
> `git pull origin main` is what ensures dev has the merge commit.

> **Do NOT** use `git pull origin main --ff-only` or `git reset --hard origin/main`
> for this sync. Fast-forward is impossible across a squash merge — main's squash
> commit has a different SHA than dev's release commit, so dev is never
> fast-forwardable to main. And resetting dev to main rewrites dev's history,
> which severs every open PR's merge-base from its original commit and balloons
> their diffs to thousands of lines (confirmed against v0.3.10's release: PRs
> went from `+80/-1` to `+6626/-300` after a `git reset --hard origin/main` on
> dev). The plain `git pull origin main` above creates a regular merge commit on
> dev. The merge bubble in dev's `git log` is the right cost for preserving
> open-PR sanity. If the merge produces a `homebrew/archon.rb` conflict during a
> recovery flow, resolve with `git checkout origin/main -- homebrew/archon.rb`
> (note: `origin/main`, NOT `main` — local main is often stale because the
> release pushes via `git push origin dev:main` without fast-forwarding the local
> branch).

The GitHub Release is distinct from the git tag — without it, the release won't appear on the repository's Releases page. Always create it.

If the user merges the PR themselves and comes back, still offer to tag, release, and sync.
git checkout dev git pull origin main git push origin dev

> **重要提示**:此同步操作确保dev分支包含main分支的合并提交。如果没有此操作,dev和main分支会出现分歧。CI的`update-homebrew`任务仅将公式更新提交推送到dev分支——不会将PR合并提交同步到dev分支。上述的`git pull origin main`操作确保dev分支包含合并提交。
>
> **不要**使用`git pull origin main --ff-only`或`git reset --hard origin/main`进行此同步。在 squash merge 情况下无法进行快进——main分支的squash提交SHA与dev分支的发布提交不同,因此dev分支永远无法快进到main分支。将dev分支重置为main分支会重写dev分支的历史,破坏所有开放PR的合并基准与原始提交的关联,并使它们的差异膨胀至数千行(针对v0.3.10的发布已确认:在dev分支执行`git reset --hard origin/main`后,PR的差异从`+80/-1`变为`+6626/-300`)。上述的普通`git pull origin main`操作会在dev分支创建常规合并提交。dev分支`git log`中的合并气泡是为了保持开放PR正常而付出的合理代价。如果在恢复流程中合并时产生`homebrew/archon.rb`冲突,使用`git checkout origin/main -- homebrew/archon.rb`解决(注意:是`origin/main`,不是`main`——本地main分支通常是过时的,因为发布流程通过`git push origin dev:main`推送,而没有快进本地分支)。

GitHub Release与Git标签是不同的——如果不创建Release,版本发布不会显示在仓库的Releases页面上。务必创建它。

如果用户自行合并PR后返回,仍需提供打标签、发布和同步的操作。

Step 10: Wait for Release Workflow and Update Homebrew Formula

步骤10:等待发布工作流完成并更新Homebrew公式

Note: The
update-homebrew
CI job in
.github/workflows/release.yml
runs automatically after the release job and handles the formula update + push to dev (part of Step 10). Step 11 (tap sync to
coleam00/homebrew-archon
) is always manual. Check the Actions tab before running Step 10 manually.
After the tag is pushed,
.github/workflows/release.yml
builds platform binaries and uploads them to the GitHub release. This takes 5-10 minutes. The Homebrew formula SHA256 values cannot be known until these binaries exist.
Wait for all assets to appear on the release:
bash
echo "Waiting for release workflow to finish uploading binaries..."
WORKFLOW_FAILED=0
for i in {1..30}; do
  ASSET_COUNT=$(gh release view "vx.y.z" --repo coleam00/Archon --json assets --jq '.assets | length')
  # Expect 7 assets: 5 binaries (darwin-arm64, darwin-x64, linux-arm64, linux-x64, windows-x64.exe) + archon-web.tar.gz + checksums.txt
  if [ "$ASSET_COUNT" -ge 7 ]; then
    echo "All $ASSET_COUNT assets uploaded"
    break
  fi

  # Short-circuit: if the release workflow itself has failed, stop waiting.
  # Hanging for 15 min when CI already crashed just delays the recovery path.
  WORKFLOW_STATUS=$(gh run list --workflow release.yml --event push --limit 1 --json conclusion,status --jq '.[0] | "\(.status)|\(.conclusion)"')
  if [[ "$WORKFLOW_STATUS" == "completed|failure" ]]; then
    echo "Release workflow FAILED — no point waiting longer"
    WORKFLOW_FAILED=1
    break
  fi

  echo "  Assets so far: $ASSET_COUNT/7 — waiting 30s (attempt $i/30)..."
  sleep 30
done

if [ "$WORKFLOW_FAILED" -eq 1 ] || [ "$ASSET_COUNT" -lt 7 ]; then
  # Triage: rerun once in case it's transient, then check again.
  RUN_ID=$(gh run list --workflow release.yml --event push --limit 1 --json databaseId --jq '.[0].databaseId')
  echo "Release workflow failed on run $RUN_ID. Rerunning failed jobs once to confirm..."
  gh run rerun "$RUN_ID" --failed
  gh run watch "$RUN_ID" --exit-status --interval 30 || true

  # Re-check asset count + run status after rerun.
  ASSET_COUNT=$(gh release view "vx.y.z" --repo coleam00/Archon --json assets --jq '.assets | length')
  if [ "$ASSET_COUNT" -ge 7 ]; then
    echo "Rerun succeeded — all assets now present"
  else
    echo ""
    echo "===== DETERMINISTIC CI FAILURE ====="
    echo "The release workflow failed on two consecutive runs. This is NOT a flake."
    echo "The tag and release exist but have no (or incomplete) assets."
    echo ""
    echo "install.sh and similar 'releases/latest' paths are now 404-ing."
    echo "Proceeding with Homebrew/tap sync would publish a formula pointing at"
    echo "missing or inconsistent binaries."
    echo ""
    echo "Jump to the 'Recovery: deterministic release CI failure' section at the"
    echo "bottom of this skill and execute it. Do NOT continue past this point."
    exit 1
  fi
fi
Fetch checksums.txt and extract SHA256 values:
bash
TMP_DIR=$(mktemp -d)
gh release download "vx.y.z" --repo coleam00/Archon --pattern "checksums.txt" --dir "$TMP_DIR"

DARWIN_ARM64_SHA=$(awk '/archon-darwin-arm64$/ {print $1}' "$TMP_DIR/checksums.txt")
DARWIN_X64_SHA=$(awk '/archon-darwin-x64$/ {print $1}' "$TMP_DIR/checksums.txt")
LINUX_ARM64_SHA=$(awk '/archon-linux-arm64$/ {print $1}' "$TMP_DIR/checksums.txt")
LINUX_X64_SHA=$(awk '/archon-linux-x64$/ {print $1}' "$TMP_DIR/checksums.txt")
注意
.github/workflows/release.yml
中的
update-homebrew
CI任务会在发布任务完成后自动运行,处理公式更新并推送到dev分支(属于步骤10的一部分)。步骤11(同步到
coleam00/homebrew-archon
tap仓库)始终需要手动执行。在手动运行步骤10之前,请先检查Actions标签页。
推送标签后,
.github/workflows/release.yml
会构建平台二进制文件并上传到GitHub Release。此过程耗时5-10分钟。Homebrew公式的SHA256值只有在这些二进制文件生成后才能确定。
等待所有资产上传到版本发布页面:
bash
echo "等待发布工作流完成二进制文件上传..."
WORKFLOW_FAILED=0
for i in {1..30}; do
  ASSET_COUNT=$(gh release view "vx.y.z" --repo coleam00/Archon --json assets --jq '.assets | length')
  # 预期7个资产:5个二进制文件(darwin-arm64、darwin-x64、linux-arm64、linux-x64、windows-x64.exe) + archon-web.tar.gz + checksums.txt
  if [ "$ASSET_COUNT" -ge 7 ]; then
    echo "所有$ASSET_COUNT个资产已上传"
    break
  fi

  # 短路处理:如果发布工作流本身已失败,停止等待。
  # 当CI已崩溃时仍等待15分钟只会延迟恢复流程。
  WORKFLOW_STATUS=$(gh run list --workflow release.yml --event push --limit 1 --json conclusion,status --jq '.[0] | "\(.status)|\(.conclusion)"')
  if [[ "$WORKFLOW_STATUS" == "completed|failure" ]]; then
    echo "发布工作流失败——无需继续等待"
    WORKFLOW_FAILED=1
    break
  fi

  echo "  当前资产数:$ASSET_COUNT/7 —— 等待30秒(第$i/30次尝试)..."
  sleep 30
done

if [ "$WORKFLOW_FAILED" -eq 1 ] || [ "$ASSET_COUNT" -lt 7 ]; then
  # 排查:重新运行一次以确认是否为临时故障,然后再次检查。
  RUN_ID=$(gh run list --workflow release.yml --event push --limit 1 --json databaseId --jq '.[0].databaseId')
  echo "发布工作流在运行$RUN_ID时失败。重新运行失败的任务一次以确认..."
  gh run rerun "$RUN_ID" --failed
  gh run watch "$RUN_ID" --exit-status --interval 30 || true

  # 重新运行后重新检查资产数和运行状态。
  ASSET_COUNT=$(gh release view "vx.y.z" --repo coleam00/Archon --json assets --jq '.assets | length')
  if [ "$ASSET_COUNT" -ge 7 ]; then
    echo "重新运行成功——所有资产已上传"
  else
    echo ""
    echo "===== 确定性CI失败 ======"
    echo "发布工作流连续两次运行失败。这不是临时故障。"
    echo "标签和版本发布已存在,但资产缺失或不完整。"
    echo ""
    echo "install.sh和类似的'releases/latest'路径现在返回404错误。"
    echo "继续进行Homebrew/tap同步会发布指向缺失或不一致二进制文件的公式。"
    echo ""
    echo "跳转到本技能底部的'恢复:确定性发布CI失败'章节并执行相应操作。不要继续此步骤之后的操作。"
    exit 1
  fi
fi
获取checksums.txt并提取SHA256值:
bash
TMP_DIR=$(mktemp -d)
gh release download "vx.y.z" --repo coleam00/Archon --pattern "checksums.txt" --dir "$TMP_DIR"

DARWIN_ARM64_SHA=$(awk '/archon-darwin-arm64$/ {print $1}' "$TMP_DIR/checksums.txt")
DARWIN_X64_SHA=$(awk '/archon-darwin-x64$/ {print $1}' "$TMP_DIR/checksums.txt")
LINUX_ARM64_SHA=$(awk '/archon-linux-arm64$/ {print $1}' "$TMP_DIR/checksums.txt")
LINUX_X64_SHA=$(awk '/archon-linux-x64$/ {print $1}' "$TMP_DIR/checksums.txt")

Sanity check — all four must be present and non-empty

完整性检查——四个值必须全部存在且非空

for var in DARWIN_ARM64_SHA DARWIN_X64_SHA LINUX_ARM64_SHA LINUX_X64_SHA; do if [ -z "${!var}" ]; then echo "ERROR: $var is empty — checksums.txt may be malformed" cat "$TMP_DIR/checksums.txt" exit 1 fi done
rm -rf "$TMP_DIR"

**Update `homebrew/archon.rb` in the main repo atomically with version AND SHAs:**

Rewrite the formula file using the exact template below. Do NOT edit in place with sed — the whole file should be regenerated from this template so there is zero risk of partial updates.

```bash
cat > homebrew/archon.rb << EOF
for var in DARWIN_ARM64_SHA DARWIN_X64_SHA LINUX_ARM64_SHA LINUX_X64_SHA; do if [ -z "${!var}" ]; then echo "ERROR: $var为空——checksums.txt可能格式错误" cat "$TMP_DIR/checksums.txt" exit 1 fi done
rm -rf "$TMP_DIR"

**原子性更新主仓库中的`homebrew/archon.rb`的版本号和SHA值:**

使用以下精确模板重写公式文件。不要使用sed就地编辑——应从模板重新生成整个文件,以避免部分更新的风险。

```bash
cat > homebrew/archon.rb << EOF

Homebrew formula for Archon CLI

Homebrew formula for Archon CLI

To install: brew install coleam00/archon/archon

To install: brew install coleam00/archon/archon

This formula downloads pre-built binaries from GitHub releases.

This formula downloads pre-built binaries from GitHub releases.

class Archon < Formula desc "Remote agentic coding platform - control AI assistants from anywhere" homepage "https://github.com/coleam00/Archon" version "x.y.z" license "MIT"
on_macos do on_arm do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-darwin-arm64" sha256 "${DARWIN_ARM64_SHA}" end on_intel do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-darwin-x64" sha256 "${DARWIN_X64_SHA}" end end
on_linux do on_arm do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-linux-arm64" sha256 "${LINUX_ARM64_SHA}" end on_intel do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-linux-x64" sha256 "${LINUX_X64_SHA}" end end
def install binary_name = case when OS.mac? && Hardware::CPU.arm? "archon-darwin-arm64" when OS.mac? && Hardware::CPU.intel? "archon-darwin-x64" when OS.linux? && Hardware::CPU.arm? "archon-linux-arm64" when OS.linux? && Hardware::CPU.intel? "archon-linux-x64" end
bin.install binary_name => "archon"
end
test do # Basic version check - archon version should exit with 0 on success assert_match version.to_s, shell_output("#{bin}/archon version") end end EOF

**Commit the formula update to main, then sync back to dev:**

```bash
git checkout main
git pull origin main
git add homebrew/archon.rb
git commit -m "chore(homebrew): update formula to vx.y.z"
git push origin main
class Archon < Formula desc "Remote agentic coding platform - control AI assistants from anywhere" homepage "https://github.com/coleam00/Archon" version "x.y.z" license "MIT"
on_macos do on_arm do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-darwin-arm64" sha256 "${DARWIN_ARM64_SHA}" end on_intel do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-darwin-x64" sha256 "${DARWIN_X64_SHA}" end end
on_linux do on_arm do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-linux-arm64" sha256 "${LINUX_ARM64_SHA}" end on_intel do url "https://github.com/coleam00/Archon/releases/download/v#{version}/archon-linux-x64" sha256 "${LINUX_X64_SHA}" end end
def install binary_name = case when OS.mac? && Hardware::CPU.arm? "archon-darwin-arm64" when OS.mac? && Hardware::CPU.intel? "archon-darwin-x64" when OS.linux? && Hardware::CPU.arm? "archon-linux-arm64" when OS.linux? && Hardware::CPU.intel? "archon-linux-x64" end
bin.install binary_name => "archon"
end
test do # Basic version check - archon version should exit with 0 on success assert_match version.to_s, shell_output("#{bin}/archon version") end end EOF

**将公式更新提交到main分支,然后同步回dev分支:**

```bash
git checkout main
git pull origin main
git add homebrew/archon.rb
git commit -m "chore(homebrew): update formula to vx.y.z"
git push origin main

Sync dev with main so the formula update is on both branches

同步dev分支与main分支,使公式更新同时存在于两个分支

git checkout dev git pull origin main git push origin dev
undefined
git checkout dev git pull origin main git push origin dev
undefined

Step 11: Sync the Homebrew Tap Repo

步骤11:同步Homebrew Tap仓库

The
coleam00/homebrew-archon
repository hosts the actual tap formula that Homebrew reads when users run
brew tap coleam00/archon && brew install coleam00/archon/archon
. The file
coleam00/Archon/homebrew/archon.rb
is the source-of-truth template; the file
coleam00/homebrew-archon/Formula/archon.rb
is what users actually install from. These must be kept in sync.
bash
TAP_DIR=$(mktemp -d)
git clone git@github.com:coleam00/homebrew-archon.git "$TAP_DIR"
cp homebrew/archon.rb "$TAP_DIR/Formula/archon.rb"

cd "$TAP_DIR"
if git diff --quiet; then
  echo "Tap formula already matches — no sync needed"
else
  git add Formula/archon.rb
  git commit -m "chore: sync formula to vx.y.z"
  git push origin main
fi
cd -
rm -rf "$TAP_DIR"
If the
git clone
fails with a permissions error, the user running the release skill does not have push access to
coleam00/homebrew-archon
. Ask them to request push access from the repo owner, or to perform the sync manually via the GitHub web UI. Do not skip this step silently — the release is not complete until the tap is synced.
coleam00/homebrew-archon
仓库托管用户运行
brew tap coleam00/archon && brew install coleam00/archon/archon
时Homebrew读取的实际tap公式。
coleam00/Archon/homebrew/archon.rb
是源模板;
coleam00/homebrew-archon/Formula/archon.rb
是用户实际安装的文件。必须保持两者同步。
bash
TAP_DIR=$(mktemp -d)
git clone git@github.com:coleam00/homebrew-archon.git "$TAP_DIR"
cp homebrew/archon.rb "$TAP_DIR/Formula/archon.rb"

cd "$TAP_DIR"
if git diff --quiet; then
  echo "Tap公式已匹配——无需同步"
else
  git add Formula/archon.rb
  git commit -m "chore: sync formula to vx.y.z"
  git push origin main
fi
cd -
rm -rf "$TAP_DIR"
如果
git clone
因权限错误失败,运行版本发布技能的用户没有
coleam00/homebrew-archon
的推送权限。请用户向仓库所有者申请推送权限,或通过GitHub网页UI手动执行同步操作。不要静默跳过此步骤——只有在tap仓库同步完成后,版本发布才算完成。

Step 12: Verify the Release End-to-End

步骤12:端到端验证版本发布

After the formula is synced, the final verification step is to actually install the released binary via Homebrew and run smoke tests. Use the
test-release
skill:
/test-release brew x.y.z
This will:
  • Install via
    brew tap coleam00/archon && brew install coleam00/archon/archon
  • Verify the binary reports the correct version and
    Build: binary
  • Verify bundled workflows load
  • Verify the SDK spawn path works (a minimal assist workflow)
  • Verify the env-leak gate is active (if shipped in this release)
  • Uninstall cleanly
  • Produce a PASS/FAIL report
If
/test-release brew
fails, the release is not ready to announce.
File a hotfix issue for whatever broke, cut
x.y.z+1
with the fix, and re-run this skill. Do NOT advertise a release that fails
test-release
.
Also run
/test-release curl-mac x.y.z
to cover the curl install path. The two install paths test slightly different things (Homebrew tests the tap formula, curl tests
install.sh
and checksums from the release) and both need to work for users to have a reliable install experience.
If you have a VPS available, also run
/test-release curl-vps x.y.z <vps-target>
to verify the Linux binary.
公式同步完成后,最终的验证步骤是通过Homebrew实际安装发布的二进制文件并运行冒烟测试。使用
test-release
技能:
/test-release brew x.y.z
此操作将:
  • 通过
    brew tap coleam00/archon && brew install coleam00/archon/archon
    安装
  • 验证二进制文件报告正确的版本和
    Build: binary
  • 验证捆绑的工作流能加载
  • 验证SDK生成路径正常工作(最小化辅助工作流)
  • 验证环境泄露防护已激活(如果在此版本中包含)
  • 干净卸载
  • 生成通过/失败报告
如果
/test-release brew
失败,版本发布尚未准备好对外宣布。
针对出现的问题创建热修复issue,修复后发布
x.y.z+1
版本,并重新运行此技能。不要宣传未通过
test-release
的版本发布。
同时运行
/test-release curl-mac x.y.z
以覆盖curl安装路径。两种安装路径测试的内容略有不同(Homebrew测试tap公式,curl测试
install.sh
和版本发布的校验和),两者都必须正常工作才能为用户提供可靠的安装体验。
如果有可用的VPS,还可以运行
/test-release curl-vps x.y.z <vps-target>
以验证Linux二进制文件。

Recovery: deterministic release CI failure

恢复:确定性发布CI失败

Reached here because Step 10 detected two consecutive workflow failures. The tag
vx.y.z
is pushed, the GitHub release exists, but assets are missing or incomplete. Every
install.sh
run currently resolves
releases/latest
to this broken release and 404s on download. Homebrew users are safe because Step 10's atomic formula update was blocked.
Do not re-run the release workflow a third time hoping it succeeds. If the failure was reproducible twice, it's a code bug — you need to ship code to fix it.
到达此步骤是因为步骤10检测到连续两次工作流失败。标签
vx.y.z
已推送,GitHub Release已存在,但资产缺失或不完整。当前所有
install.sh
运行都会将
releases/latest
解析为这个损坏的版本发布,并在下载时返回404错误。Homebrew用户是安全的,因为步骤10的原子公式更新已被阻止。
不要第三次重新运行发布工作流期望它成功。 如果失败已连续两次复现,这是代码bug——需要修复代码后重新发布。

Immediate mitigation (restore
install.sh
)

立即缓解措施(恢复
install.sh

Delete the GitHub Release so
releases/latest
falls back to the previous version. Keep the git tag — tag immutability matters and there are no shipped artifacts pointing at it anyway.
bash
gh release delete "vx.y.z" --yes
删除GitHub Release,使
releases/latest
回退到上一个版本。保留Git标签——标签的不可变性很重要,并且没有已发布的工件指向它。
bash
gh release delete "vx.y.z" --yes

Do NOT delete the tag:

不要删除标签:

git push --delete origin vx.y.z ← do not run

git push --delete origin vx.y.z ← 不要运行此命令

Tag stays so git history records the attempt; no release means no assets

保留标签以便Git历史记录记录此次尝试;没有版本发布意味着没有资产

means releases/latest resolves to the prior working release.

意味着releases/latest会解析为之前可用的版本。


Verify:

```bash
gh api repos/coleam00/Archon/releases/latest --jq '.tag_name'

验证:

```bash
gh api repos/coleam00/Archon/releases/latest --jq '.tag_name'

should now print the prior version (e.g. v0.3.6), not vx.y.z

现在应显示上一个版本(例如v0.3.6),而不是vx.y.z

undefined
undefined

Diagnose

诊断

The release workflow logs tell you which target failed and at what stage (compile vs. smoke-test vs. upload):
bash
gh run list --workflow release.yml --limit 2 --json databaseId,conclusion
gh run view <RUN_ID> --log-failed
Common causes:
  • Bundler/bytecode bug — Bun
    --bytecode
    produces invalid output for the current module graph. Symptom:
    TypeError: Expected CommonJS module to have a function wrapper
    at binary startup. Historically caused by a new dependency's CJS/ESM shape interacting with
    --bytecode
    — dropping the flag or lazy-importing the offending module has been the fix.
  • Module-init crash — a dependency does
    readFileSync('package.json')
    or similar at module top level via a path that exists in
    node_modules/
    but not next to a compiled binary. Symptom: every binary subcommand crashes immediately; error typically mentions a missing file adjacent to
    process.execPath
    . Fix by lazy-importing the dependency behind the code path that actually uses it.
  • Smoke-test timeout on Windows — not actually a bug in the code; the Windows runner is slow. Rerun once; if it recurs, bump the test timeout.
Step 1.5 now runs a local compiled-binary smoke test before any user-visible step. If the failure mode above reproduces locally, you've found it. If it doesn't, the bug is platform-specific (Windows cross-compile, Linux glibc, etc.) and you need the CI logs.
发布工作流日志会告诉你哪个目标失败以及在哪个阶段(编译、冒烟测试、上传):
bash
gh run list --workflow release.yml --limit 2 --json databaseId,conclusion
gh run view <RUN_ID> --log-failed
常见原因:
  • 打包器/字节码bug — Bun的
    --bytecode
    为当前模块图生成无效输出。症状:二进制文件启动时出现
    TypeError: Expected CommonJS module to have a function wrapper
    。历史上是由于新依赖的CJS/ESM格式与
    --bytecode
    交互导致——解决方案是移除该标志或延迟导入有问题的模块。
  • 模块初始化崩溃 — 某个依赖在模块顶部执行
    readFileSync('package.json')
    或类似操作,读取的路径在
    node_modules/
    中存在,但在编译后的二进制文件旁不存在。症状:所有二进制子命令立即崩溃;错误通常提到
    process.execPath
    附近缺少文件。解决方案是在实际使用该依赖的代码路径后延迟导入它。
  • Windows冒烟测试超时 — 实际上不是代码bug;Windows运行器速度较慢。重新运行一次;如果再次出现,增加测试超时时间。
步骤1.5现在在任何用户可见的步骤之前运行本地编译二进制文件冒烟测试。如果上述失败模式能在本地复现,你就找到了问题所在。如果不能,bug是平台特定的(Windows跨编译、Linux glibc等),你需要查看CI日志。

Fix and re-release as the NEXT patch

修复并作为下一个补丁版本重新发布

Do not reuse
vx.y.z
.
Cut
vx.y.(z+1)
(or next-minor if warranted) with the fix. Rationale:
  • Tag immutability:
    vx.y.z
    is already recorded in git history and release cache
  • Semver clarity: users and tooling should see a new version number when the bits change
  • Audit trail: "v0.3.7 was cut but had no shipped binaries; v0.3.8 is the first release with <fix>" is cleaner than rewriting v0.3.7
Steps:
  1. Cut a fix branch off dev, implement the fix, PR to dev, merge.
  2. Re-run
    /release
    (it will bump to the next patch — e.g.
    0.3.8
    — automatically).
  3. Step 1.5's pre-flight smoke will catch the same bug locally if the fix didn't actually fix it. Iterate until it passes before tagging.
不要重用
vx.y.z
版本号。
修复后发布
vx.y.(z+1)
版本(如有必要,发布下一个次要版本)。理由:
  • 标签不可变性:
    vx.y.z
    已记录在Git历史和发布缓存中
  • 语义化版本清晰:用户和工具在二进制文件变更时应看到新的版本号
  • 审计追踪:“v0.3.7已创建但没有可运行的二进制文件;v0.3.8是第一个包含<修复>的版本”比重写v0.3.7更清晰
步骤:
  1. 从dev分支创建修复分支,实现修复,创建PR到dev分支并合并。
  2. 重新运行
    /release
    (它会自动升级到下一个补丁版本——例如
    0.3.8
    )。
  3. 步骤1.5的预编译冒烟测试会在本地检测到相同的bug(如果修复未生效)。在打标签前迭代直到测试通过。

CHANGELOG note for the hotfix release

热修复版本的CHANGELOG说明

Include a line in the new release's CHANGELOG that references the broken prior version so users understand why there's no binary artifact under that tag:
markdown
undefined
在新版本的CHANGELOG中添加一行,提及损坏的上一个版本,以便用户理解为什么该标签下没有二进制工件:
markdown
undefined

Fixed

修复

  • First release with working compiled binaries after vx.y.z's <bug>. vx.y.z was tagged but its binary smoke test failed deterministically (see RUN_ID in CI history). The tag is preserved for history; this release (vx.y.(z+1)) is the first with shipped binaries.
    install.sh
    and Homebrew were never updated to vx.y.z, so users were not exposed to the broken state.
undefined
  • 在vx.y.z的<bug>问题后,首个包含可运行编译二进制文件的版本。 vx.y.z已打标签,但其二进制冒烟测试确定性失败(查看CI历史中的RUN_ID)。标签被保留用于历史记录;此版本(vx.y.(z+1))是第一个包含可运行二进制文件的版本。
    install.sh
    和Homebrew从未更新到vx.y.z版本,因此用户未受到损坏状态的影响。
undefined

What NOT to do

禁止操作

  • Do not force-push or rewrite the tag. Once a tag exists, it's a public promise of that SHA. Deleting and re-creating to a different SHA is tag-spoofing and breaks any downstream that cached the original.
  • Do not skip this recovery path to "just push more binaries to the broken release". The release exists with a specific commit SHA; uploading binaries built from a newer SHA creates binary/source drift that is hard to diagnose later.
  • Do not update the Homebrew formula before v0.3.(z+1) is fully shipped. The formula should always point at a version with all 7 assets uploaded and
    /test-release brew
    passing.
  • 不要强制推送或重写标签。 标签一旦存在,就是对该SHA的公开承诺。删除并重新创建指向不同SHA的标签是标签伪造行为,会破坏所有缓存了原始标签的下游系统。
  • 不要跳过此恢复流程而“直接向损坏的版本发布推送更多二进制文件”。 版本发布与特定提交SHA关联;上传从较新SHA构建的二进制文件会导致二进制/源代码不一致,后续难以诊断。
  • 不要在v0.3.(z+1)完全发布前更新Homebrew公式。 公式应始终指向已上传所有7个资产且
    /test-release brew
    通过的版本。

Important Rules

重要规则

  • NEVER force push
  • NEVER skip Step 1.5 (pre-flight compiled-binary smoke). If the stack is a Bun/Node project with a build-binaries script, the
    bun build --compile
    smoke test runs before version bump, PR, or tag. Skipping it means every bundler regression or module-init crash only surfaces after the tag is pushed — by which point
    releases/latest
    is already 404-ing for every user. The ~30s cost is paid to keep the failure mode local.
  • If Step 1.5 fails, abort the release and fix the underlying issue on a feature branch. Do not "just skip it" and hope CI doesn't repro the problem.
  • NEVER skip the review step — always show the changelog before committing
  • NEVER include "Co-Authored-By: Claude" or any AI attribution in the commit
  • NEVER add emoji to changelog entries unless the user asks
  • If the user says "ship it" without specifying bump type, default to patch
  • The commit message is just
    Release x.y.z
    — clean and simple
  • NEVER update
    homebrew/archon.rb
    version field without also updating the
    sha256
    values
    . They must move together atomically. The correct SHAs only exist after the release workflow finishes building binaries — see Step 10. Updating the version field alone produces a stale formula that looks valid but causes checksum mismatches on install.
  • NEVER skip Step 11 (tap sync). The
    coleam00/Archon/homebrew/archon.rb
    file is only a template; users install from
    coleam00/homebrew-archon/Formula/archon.rb
    . If you update one without the other, users get stale or wrong data.
  • NEVER announce a release that failed
    /test-release brew
    .
    A release that installs but crashes on first invocation is worse than no release — it burns user trust. If the release verification fails, cut a hotfix before telling anyone the release exists.
  • 永远不要强制推送
  • 永远不要跳过步骤1.5(预编译二进制文件冒烟测试)。 如果技术栈是带有build-binaries脚本的Bun/Node项目,
    bun build --compile
    冒烟测试会在版本号升级、PR创建或打标签之前运行。跳过此步骤意味着每个打包器回归或模块初始化崩溃只有在标签推送后才会暴露——到那时
    releases/latest
    已对所有用户返回404错误。付出约30秒的时间成本是为了将失败模式控制在本地。
  • 如果步骤1.5失败,终止版本发布流程并在功能分支上修复根本问题。不要“跳过它”并期望CI不会复现该问题。
  • 永远不要跳过审核步骤——在提交前始终向用户展示变更日志
  • 永远不要在提交中包含“Co-Authored-By: Claude”或任何AI署名
  • 永远不要在变更日志条目中添加表情符号,除非用户要求
  • 如果用户说“ship it”但未指定升级类型,默认使用补丁版本
  • 提交消息应为
    Release x.y.z
    ——简洁明了
  • 永远不要仅更新
    homebrew/archon.rb
    的version字段而不同时更新
    sha256
    值。
    必须同时更新两者。正确的SHA值只有在发布工作流完成二进制文件构建后才存在——参见步骤10。仅更新version字段会生成过期的公式,看似有效但安装时会出现校验不匹配的问题。
  • 永远不要跳过步骤11(tap仓库同步)。
    coleam00/Archon/homebrew/archon.rb
    文件只是模板;用户从
    coleam00/homebrew-archon/Formula/archon.rb
    安装。如果只更新其中一个,用户会获取到过期或错误的数据。
  • 永远不要宣布未通过
    /test-release brew
    的版本发布。
    安装后首次调用就崩溃的版本发布比不发布更糟糕——会消耗用户信任。如果版本发布验证失败,在告知任何人之前先发布热修复版本。