☰
Plannotator 发布流水线实战指南:从 Release Notes 草拟到带 SLSA/SBOM 的标签驱动发布
2026/9/25 13:01:33 网站建设 项目流程

【免费下载链接】plannotator

Annotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.

项目地址:https://gitcode.com/gh_mirrors/pl/plannotator
点击查看免费下载

本文基于 Plannotator 仓库内置的发布技能文档 .agents/skills/release/SKILL.md 展开,系统讲解该项目从"准备发布"到"版本正式上线"的完整四阶段流程:草拟 Release Notes、全局版本号提升、按依赖顺序构建并执行 Pi 包一致性审计、提交标签并交由 CI 流水线完成跨平台产物、供应链安全校验与 npm 发布。读完本文,你将掌握 Plannotator 每次 cut 新版本时的可复现操作路径,包括 7 个需要同步版本号的文件清单、构建命令的依赖顺序、标签驱动流水线的安全检查项,以及发布前后的完整核对清单。

发布流程总览:四个阶段

SKILL.md 将发布过程划分为四个阶段,其中大部分实质工作集中在第一阶段(Release Notes 草拟),草稿必须提交给用户评审通过后才能进入后续阶段:

阶段名称核心产出
Phase 1Draft Release NotesRELEASE_NOTES_v<VERSION>.md(仓库根目录,保持 untracked)
Phase 2Version Bump7 个文件中的版本号同步更新
Phase 3Build按依赖顺序完成 review → hook → opencode → pi 四个构建
Phase 4Commit, Tag, and Release提交版本提升、推送v*标签触发 .github/workflows/release.yml,创建 GitHub Release

该技能由.agents/skills/release/SKILL.md的 frontmatter 定义,名称为release-plannotator,适用于提及"准备发布、提升版本、撰写 release notes、打标签、发布"等场景的 Agent 调用。

Phase 1:草拟 Release Notes(最重要的一步)

Release Notes 是每个版本的对外门面,也是社区成员看到自己贡献被认可的主要途径,因此该阶段被明确标注为"most important phase"。

确定发布范围

  1. 查找最新发布标签:git tag --sort=-v:refname | head -1
  2. 确定新版本号。若不明确是 patch、minor 还是 major,必须先询问用户
  3. 收集自上个标签以来的全部变更:
    • git log --oneline <last-tag>..HEAD查看提交历史
    • git log --merges --oneline <last-tag>..HEAD查看合并的 PR
  4. 对每个 PR 使用gh pr view <number> --json title,author,body,closedIssues,labels获取详情

调研贡献者:不止是 PR 作者

SKILL.md 强调"Every person who participated in the release gets credit——not just PR authors"。对每个 PR 和关联 issue,需要收集五类角色:PR 作者(写代码的人)、Issue 报告者(提交 bug 或功能请求的人)、Issue 评论者(参与讨论并提供有价值上下文的人)、Discussion 发起者、以及通过"closes #N"关联的功能请求者。

使用gh调用 GitHub API 收集这些信息:

# 获取 issue 详情(含作者) gh issue view <number> --json author,title,body # 获取 issue 评论以发现参与者 gh api repos/backnotprop/plannotator/issues/<number>/comments --jq '.[].user.login' # 获取 PR 评审评论 gh api repos/backnotprop/plannotator/pulls/<number>/comments --jq '.[].user.login'

参考模板:三种典型发布形态

仓库在.agents/skills/release/references/下保留了三个真实历史版本的 Release Notes 作为规范模板,用于匹配不同发布形态:

  • release-notes-v0.13.0.md:大型发布,14 个 PR、3 位首次贡献者,采用 "New Contributors" + 叙述性 "Contributors" 章节
  • release-notes-v0.12.0.md:大型社区发布,14 个 PR、其中 10 个来自外部贡献者,详细的叙述性 "Contributors" 章节
  • release-notes-v0.13.1.md:小型 patch 发布,2 个 PR、无外部作者,采用更轻量的 "Community" 章节聚焦 issue 报告者

选择模板的原则:外部 PR 多的发布适合叙述性 "Contributors" 章节;以 issue 报告驱动的 patch 发布则使用更轻的 "Community" 章节。草稿写入仓库根目录RELEASE_NOTES_v<VERSION>.md,不要git add或提交该文件——Release Notes 设计上保持 untracked。

正文结构(8 个组成部分)

  1. X/Twitter 关注链接——首行固定为 "Follow @plannotator on X for updates" 形式的关注引导
  2. "Missed recent releases?" 折叠表格——从上个版本的 notes 中复制,然后:
    • 把被接替的上一个版本作为最新行加入
    • 保持约 10-12 行,必要时丢弃最旧的行
    • 每行 = 版本链接 + 逗号分隔的功能亮点短语
  3. "What's New in vX.Y.Z"——整个 notes 的核心:
    • 开头用 1-3 句话概括版本主题与范围,说明 PR 数量、外部贡献者数量、是否有首次贡献者
    • 每个主要功能/修复拥有独立###小节,包含描述性标题(不要照抄 PR 标题,要重新措辞)、1-4 段说明"之前的问题 → 这次改了什么 → 用户如何体验"的具体叙述,以及底部署名行(PR 链接、以closing [#N]形式关联的 issue、贡献者归属)
    • 次要变更归入### Additional Changes,以加粗标题的 bullet 呈现
  4. Install / Update——标准块,从上个版本的 notes 读取并原样复用
  5. "What's Changed"——逐条列出发布内每个 PR,格式- feat: descriptive PR title by @author in #N
  6. "New Contributors"——如有首次贡献者,格式- @username made their first contribution in #N
  7. "Contributors" 或 "Community"——叙述性章节:PR 作者获得一段"做了什么"的介绍;issue 报告者与评论者被列出其报告/讨论内容;社区 issue 报告者在结尾以 bullet 列表分组
  8. Full Changelog 链接——指向上一个标签到新标签的对比页,形如**Full Changelog**: .../compare/<prev-tag>...<new-tag>

写作准则

SKILL.md 给出了一组非常具体的写作约束,实际是这份文档最值得借鉴的部分:

  • 叙事优先于噪音:用清晰可读的散文,不是营销腔,也不是 changelog 堆砌;用平实语言说明"改了什么、为什么值得关心"
  • 善用 bullet:枚举离散事项(次要变更、贡献者列表)用列表,解释功能用段落
  • 禁用陈词滥调:不写 "exciting"、"game-changing"、"seamless"、"powerful",只描述事实
  • 不要抖机灵:章节结尾不写俏皮话或总结金句,让功能自己说话
  • 讲实际收益:用具体、可靠的语言描述变更对用户意味着什么
  • 克制使用破折号:整个发布 notes 里一两个 em dash 即可
  • 注意语法结构:句子结构要有变化,用主动语态、具体的名词和动词
  • 贡献者标签用裸 @mention:使用@username而非@user形式的 markdown 链接——GitHub 会在 Release Notes 中把裸 @mention 渲染出头像图标,这对社区认可是重要的
  • 人人有份:每个提交 issue、留下影响决策的评论、参与讨论的人都应被提及——"This project's community is its lifeblood"

提交评审

将草稿写入仓库根目录的RELEASE_NOTES_v<VERSION>.md,告知用户已就绪待评审,等待反馈后再进入 Phase 2。

Phase 2:版本号提升(恰好 7 个文件)

SKILL.md 明确列出了需要提升版本号的7 个文件(且只有这 7 个——其他 package.json 使用 stub 版本):

文件字段
package.json(根)"version"
apps/opencode-plugin/package.json"version"
apps/pi-extension/package.json"version"
apps/hook/.claude-plugin/plugin.json"version"
apps/copilot/plugin.json"version"
openpackage.yml(根)version:
packages/server/package.json"version"

读取每个文件、确认当前版本符合预期后,原子地更新全部 7 处。

明确不提升的例外:apps/vscode-extension/package.json(VS Code 扩展)拥有独立的版本管理。

以当前仓库实际内容印证这 7 个文件确实存在且版本一致(均为0.27.18):package.json(根,同时定义"version": "0.27.18"与根 scripts)、apps/opencode-plugin/package.json(@plannotator/opencode)、apps/pi-extension/package.json(@plannotator/pi-extension)、apps/hook/.claude-plugin/plugin.json(Claude Code 插件清单)、apps/copilot/plugin.json(Copilot 插件清单)、openpackage.yml(根,version: 0.27.18)、packages/server/package.json(@plannotator/server,private: true)。这 7 处保持同步是每次发布的硬性前提,检查清单的第一项即为此。

Phase 3:按依赖顺序构建 + Pi Parity Gate

构建依赖顺序

bun run build:review # 1. Code review editor(独立 Vite 构建) bun run build:hook # 2. Plan review + hook server(把 review 的构建 HTML 复制进 hook dist) bun run build:opencode # 3. OpenCode plugin(从 hook + review 复制构建 HTML) bun run build:pi # 4. Pi extension(内部串联 review → hook → pi,在步骤 1-2 之后执行是安全的)

build:pi内部串联了 review 和 hook,因此在完成步骤 1-2 后,它只运行 pi 特有的构建。这一点可以从根 package.json 的 scripts 得到印证:"build:pi": "bun run build:review && bun run build:hook && bun run --cwd apps/pi-extension build",而apps/pi-extension/package.json的 build 脚本为"build": "cp ../hook/dist/index.html plannotator.html && cp ../hook/dist/review.html review-editor.html && bash vendor.sh"——可见 HTML 资产确实从 hook 的 dist 复制而来。

所有构建必须全部成功后才能继续。

Pi Parity Gate(发布前的完整性审计)

构建通过后,必须审计 Pi 扩展,确保其发布包内所有服务端导入都能解析,避免文件缺失流入 npm。共 4 个步骤:

  1. 核对 imports 与files数组:从index.ts、server.ts、tool-scope.ts及server/下每个文件追踪所有以./或../开头的本地导入,验证每个目标都被apps/pi-extension/package.json的files数组中的某个模式覆盖。当前文件的files数组包含index.ts、server.ts、tool-scope.ts、server/、generated/、skills/、plannotator.html、review-editor.html等条目,正是这一审计的落点。
  2. 核对vendor.sh覆盖所有 shared/ai 导入:server 文件中每个../generated/*.js导入都必须在vendor.sh的复制循环中有对应条目。若本周期在packages/shared/或packages/ai/新增了共享/AI 模块并被 Pi 服务端代码导入,必须同步加入vendor.sh。apps/pi-extension/vendor.sh 的头部注释说明它是"Single source of truth":# Vendor shared modules into generated/ for Pi extension. Single source of truth — used by both npm run build and CI test workflow,其for循环分别从packages/core/、packages/shared/复制模块并在头部写入// @generated — DO NOT EDIT标记,这正是 Pi 包使用../generated/相对路径而非@plannotator/shared/@plannotator/ai包名的机制。
  3. Dry-run 打包:运行cd apps/pi-extension && bun pm pack --dry-run,验证输出包含服务端导入的每个文件,特别注意自上次发布以来新增的文件。
  4. 快速冒烟测试:确认构建后generated/包含全部预期文件,尤其注意本周期新增的模块。

发现缺失时的常见修复:

  • 把文件加入vendor.sh的复制循环
  • 把文件或目录加入package.json的files数组
  • 修正导入路径(Pi 使用../generated/,而非@plannotator/shared或@plannotator/ai)

Phase 4:提交、打标签、发布

提交版本提升

以chore: bump version to X.Y.Z提交,只暂存那 7 个版本文件,不暂存 Release Notes 文件(其设计上保持 untracked)。

创建并推送标签

git tag vX.Y.Z git push origin main git push origin vX.Y.Z

推送v*标签即触发发布流水线(.github/workflows/release.yml)。流水线会自动完成其余全部工作:

  • 运行测试
  • 为6 个平台交叉编译二进制:macOS ARM64/x64、Linux x64/ARM64、Windows x64/ARM64
  • 编译 paste service 二进制(同样 6 个平台)
  • 在无凭据作业中打包两个 npm 包
  • 下载固定版本、经校验和验证的 Syft 与 Grype 二进制;在所有交付物就绪后生成并做 schema 校验的发布级 CycloneDX SBOM
  • 强制使用仓库自有、无抑制规则的 Grype 配置,官方数据库更新最多重试三次,要求使用有效/激活的 schema-v6 数据库、新鲜度不超过 120 小时且无待更新项,并将机器可读的扫描/数据库/策略证据保留为工作流产物
  • 拒绝每个被扫描器侧忽略的匹配,然后在任何 attestation 或发布之前,对归类为 shipped/runtime 或 unknown-applicability 的 CISA KEV 或可修复 Critical 发现直接阻断;High、development-only 及无修复方案的 Critical 只报告不阻断,但仍保留在证据中
  • 通过actions/attest-build-provenance为全部12 个二进制生成 SLSA 构建来源 attestation(经 Sigstore 签名、记录于 Rekor)
  • 使用独立的官方actions/attestSBOM 路径,将 CycloneDX predicate 通过同一 GitHub OIDC/Sigstore 服务绑定到 12 个二进制和两个 npm tarball——这是清单类 attestation,不替代 SLSA 或 npm provenance
  • 创建 GitHub Release,附带全部二进制、SHA256 侧车文件、版本化 CycloneDX SBOM 及其 SHA256 侧车
  • 将@plannotator/opencode与@plannotator/pi-extension发布到 npm(带 provenance)

SBOM 范围与限制(重要事实边界)

公开 SBOM 是仓库锁定的构建输入与依赖的发布级 Syft 清单,文档明确"deliberately not described as exact binary runtime contents"。原因是:覆盖率测试发现 Bun standalone 可执行文件会隐藏打包的 JavaScript 依赖元数据,使其对 Syft 不可见;OpenCode tarball 同样不透明;Pi tarball 只能通过嵌套的 package-lock 文件暴露部分视图。这些范围与限制也内嵌在 CycloneDX 元数据中。

例外机制:VEX 而非宽松 ignore

当前没有活跃的生产例外文件。若未来某个发布基线确实需要例外,不允许添加宽松的 ignore 规则,必须:添加仓库评审过的 OpenVEX 文档,并显式通过PLANNOTATOR_RELEASE_VEX环境变量接入;每个 statement 必须精确匹配一个 package URL 与漏洞 ID,携带not_affected状态、OpenVEX justification、影响陈述、HTTPS 证据、所有者、创建日期与过期日期。策略测试会拒绝过期、畸形、宽泛及不匹配的记录。

不可变发布约束

仓库启用了 GitHub Immutable Releases:一旦推送v*标签并创建 Release,标签→提交、标签→资产的绑定就永久固定。不能通过删除再重建标签来"修复"糟糕的发布——只能发布新版本。Release Notes 正文仍可编辑(见步骤 5),其余一切均被锁定。

监控流水线

gh run list --workflow=release.yml --limit=1 gh run view <run-id> --log

需要验证的通过项:

  • 所有作业通过,包括release-security、attest、release、npm-publish
  • release-security-evidence记录了 Syft/Grype 版本、活动数据库的 schema/构建/校验和/更新状态、全部 Grype 匹配,以及ACCEPT策略决策
  • GitHub Release 已创建并附带全部二进制产物、SHA256 侧车、版本化plannotator-X.Y.Z-release-sbom.cdx.json及其.sha256侧车
  • npm 包发布成功:npm view @plannotator/opencode version与npm view @plannotator/pi-extension version

值得注意的是:PR 能证明生成、schema/sentinel 校验、数据库策略、Grype 评估、最小权限作业接线与全部报告产物;但 GitHub OIDC 签发、发布到 artifact-attestation 服务、最终 Release 资产发布只对真实符合条件的v*标签运行。因此在该安全控制落地后的首次发布,必须在调用发布完成之前完成一次有界的 tag-only 验证。

首次发布前,还需把 SBOM 范围/限制、Grype 策略、下载/校验和命令、README 中的两条 predicate 验证命令更新到文档站(SKILL.md 明确指出 canonical 文档源是 Mintlify 页面,而apps/marketing/src/content/docs/下的旧 Astro 文件只是 redirect-only/deprecated 副本,不是公开文档源)。

发布产物验证命令

tag=vX.Y.Z version="${tag#v}" gh release download "$tag" --pattern 'plannotator-linux-x64*' --pattern "plannotator-${version}-release-sbom.cdx.json*" --dir /tmp/plannotator-release-verify (cd /tmp/plannotator-release-verify && sha256sum --check plannotator-linux-x64.sha256) (cd /tmp/plannotator-release-verify && sha256sum --check "plannotator-${version}-release-sbom.cdx.json.sha256") gh attestation verify /tmp/plannotator-release-verify/plannotator-linux-x64 \ --repo backnotprop/plannotator \ --source-ref "refs/tags/$tag" \ --signer-workflow backnotprop/plannotator/.github/workflows/release.yml \ --predicate-type https://slsa.dev/provenance/v1 gh attestation verify /tmp/plannotator-release-verify/plannotator-linux-x64 \ --repo backnotprop/plannotator \ --source-ref "refs/tags/$tag" \ --signer-workflow backnotprop/plannotator/.github/workflows/release.yml \ --predicate-type https://cyclonedx.org/bom

进一步地,用gh attestation verify --format json --jq '.[0].verificationResult.statement.predicate'提取被 attest 的 CycloneDX predicate,用jq -S将它与下载的发布 SBOM 分别规范化后cmp比对;若下载了精确的已发布 tarball,可按同样方式验证一个 npm tarball subject。任何 tag-only 差异都应记录为发布阻断项,并通过发布新版本解决,而不是去变更不可变发布。

任一步骤失败,先调查日志并向用户报告,再决定是否重试。

替换 Release Notes

发布上线并验证通过后,用草拟的 notes 替换自动生成的 notes 正文:

gh release edit vX.Y.Z --notes-file RELEASE_NOTES_v<VERSION>.md

发布检查清单

SKILL.md 以清单收尾,这是每次发布前/后都必须过一遍的硬性核对项:

打标签前:

  • 7 个版本文件提升一致
  • Release Notes 已草拟并评审
  • bun run build:review成功
  • bun run build:hook成功
  • bun run build:opencode成功
  • bun run build:pi成功(或 pi 特有构建步骤)
  • 版本提升已提交
  • Pi parity gate 通过(imports、vendor.sh、dry-run pack)
  • 无陈旧构建产物(干净构建、无缓存问题——依赖变更时先运行bun install)
  • PR-safe 的release-security作业生成了 schema 有效、sentinel 完整的 SBOM,并以新数据库接受了 Grype 策略
  • 未暂存任何扫描器二进制、数据库、生成的 SBOM/报告、凭据或DO_NOT_COMMIT内容
  • 首个启用 SBOM 的发布:canonical 文档站的安装/验证页面包含 README 中的 SBOM 范围、策略、校验和、SLSA 与 CycloneDX 命令

打标签后:

  • 发布工作流完成,release-security、attest、release、npm-publish全部绿灯
  • GitHub Release 已创建并附带全部二进制、侧车、SBOM 与 SBOM 侧车
  • 一个原生二进制同时通过绑定到标签与签名工作流的显式 SLSA 与 CycloneDX predicate 检查
  • 下载的 SBOM 校验和通过,规范化 JSON 与被 attest 的 predicate 一致
  • release-security-evidence显示新鲜/活动数据库与接受的策略决策
  • npm 包以正确版本发布
  • 两个包仍可见 npm trusted-publishing provenance
  • Release Notes 已通过gh release edit替换

仓库内的证据支撑

本次发布流程并非孤立文档,而是与仓库现状严格咬合:

  • 版本号同步清单与仓库当前 7 个文件一一对应(均0.27.18),且apps/vscode-extension/package.json确实独立版本管理
  • 构建依赖顺序在根 package.json 的 scripts 中可直接验证:build:pi串联build:review与build:hook
  • Pi 的打包结构在 apps/pi-extension/package.json 中可见:files数组、prepublishOnly: cd ../.. && bun run build:pi、build 脚本中的 HTML 复制与bash vendor.sh
  • apps/pi-extension/vendor.sh 是 parity gate 第 2 步的直接审计对象,其// @generated — DO NOT EDIT注释与从packages/core/packages/shared的复制循环,解释了 Pi 为何以扁平generated/目录承载共享模块
  • .github/workflows/release.yml 是 Phase 4 标签触发流水线的落点,SKILL.md 中关于release-security、attest、release、npm-publish作业的说明与之对应
  • 三个历史 Release Notes 参考模板位于 .agents/skills/release/references/,可直接对照学习不同发布形态的写法

这套流程的核心理念是:版本号一次提升、构建严格有序、供应链证据完整留痕、社区贡献人人有份。无论是维护者亲自 cut 版本,还是 Agent 被要求"prep a release",遵循 SKILL.md 的四阶段与检查清单,都能得到可审计、可验证、对社区透明的发布结果。

【免费下载链接】plannotator

Annotate and review coding agent plans and code diffs visually, share with your team, send feedback to agents with one click.

项目地址:https://gitcode.com/gh_mirrors/pl/plannotator
点击查看免费下载

相关推荐

上一篇:Pearcleaner:macOS终极清理工具,彻底释放磁盘空间的完整指南
下一篇:CheatEngine-DMA插件:终极内存分析解决方案完全指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询