release-skill 0.2.3 → 0.2.4

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.
Files changed (53) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codebuddy-plugin/plugin.json +1 -1
  4. package/.codex-plugin/plugin.json +2 -2
  5. package/.kimi-plugin/plugin.json +1 -1
  6. package/CHANGELOG.md +22 -0
  7. package/CONTRIBUTING.md +27 -0
  8. package/INSTALL.md +95 -139
  9. package/INSTALL.zh-CN.md +70 -121
  10. package/README.md +264 -913
  11. package/README.zh-CN.md +222 -535
  12. package/adapters/claude/.claude-plugin/marketplace.json +1 -1
  13. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  14. package/adapters/claude/bin/release-skill.bundle.mjs +19054 -17573
  15. package/adapters/claude/schemas/release-plan.schema.json +137 -0
  16. package/adapters/claude/schemas/release-project.schema.json +93 -0
  17. package/adapters/claude/schemas/release-run.schema.json +70 -2
  18. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  19. package/adapters/codex/bin/release-skill.bundle.mjs +19054 -17573
  20. package/adapters/codex/schemas/release-plan.schema.json +137 -0
  21. package/adapters/codex/schemas/release-project.schema.json +93 -0
  22. package/adapters/codex/schemas/release-run.schema.json +70 -2
  23. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  24. package/adapters/kimi/bin/release-skill.bundle.mjs +19054 -17573
  25. package/adapters/kimi/schemas/release-plan.schema.json +137 -0
  26. package/adapters/kimi/schemas/release-project.schema.json +93 -0
  27. package/adapters/kimi/schemas/release-run.schema.json +70 -2
  28. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
  29. package/adapters/workbuddy/bin/release-skill.bundle.mjs +19054 -17573
  30. package/adapters/workbuddy/schemas/release-plan.schema.json +137 -0
  31. package/adapters/workbuddy/schemas/release-project.schema.json +93 -0
  32. package/adapters/workbuddy/schemas/release-run.schema.json +70 -2
  33. package/bin/release-skill.bundle.mjs +19054 -17573
  34. package/package.json +1 -1
  35. package/schemas/release-plan.schema.json +137 -0
  36. package/schemas/release-project.schema.json +93 -0
  37. package/schemas/release-run.schema.json +70 -2
  38. package/src/adapters/plugin-marketplace.mjs +1190 -435
  39. package/src/commands/prepare.mjs +380 -40
  40. package/src/commands/publish.mjs +107 -75
  41. package/src/commands/reconcile.mjs +92 -327
  42. package/src/commands/setup.mjs +148 -20
  43. package/src/commands/verify.mjs +304 -20
  44. package/src/core/baseline.mjs +8 -1
  45. package/src/core/checkpoints.mjs +50 -7
  46. package/src/core/config.mjs +15 -0
  47. package/src/core/errors.mjs +2 -0
  48. package/src/core/installation-contract.mjs +341 -0
  49. package/src/core/plan.mjs +129 -6
  50. package/src/platforms/codebuddy.mjs +193 -280
  51. package/src/platforms/codex.mjs +369 -0
  52. package/src/platforms/kimi.mjs +164 -119
  53. package/src/platforms/registry.mjs +24 -6
package/README.zh-CN.md CHANGED
@@ -2,34 +2,37 @@
2
2
 
3
3
  [English](README.md) · 安装指南:[中文](INSTALL.zh-CN.md) / [English](INSTALL.md)
4
4
 
5
- <!-- release-skill:release-version: 0.2.3 -->
6
- 面向 Claude Code、Codex 和 Kimi Code 的发布准备工具,完整保留人工维护的文件内容。
5
+ <!-- release-skill:release-version: 0.2.4 -->
6
+ 面向 Claude Code、CodeBuddy、WorkBuddy、Codex 和 Kimi Code 的发布准备工具,完整保留人工维护的文件内容。
7
7
 
8
- release-skill 帮助维护者回答三个问题:准备发布什么、还有哪些检查未通过、最终发布的内容是什么。它先冻结并供人工审阅,再从同一份冻结产物发布,不会在最后一步重新生成 README、重新打包当前工作区或覆盖人工内容。
8
+ release-skill 帮助维护者回答三个问题:准备发布什么、还有哪些检查未通过、最终发布的内容是什么。它不重新生成、也不回写项目源文件。`prepare` 把每个配置的公开文件复制到隔离快照并验证字节——先冻结并供人工审阅,再从同一份冻结产物发布。`setup` 只显示确定性的 `compactSummary` 审阅视图,完整报告保留在临时会话目录中。
9
9
 
10
10
  <!-- release-skill:managed:start id=latest-release -->
11
- **0.2.3** (2026-07-26)
11
+ **0.2.4** (2026-07-28)
12
12
 
13
- v0.2.3 是修复版本,解决 v0.2.2 中发现的平台验证、公共生成物和文档问题。本版本收敛平台事实源、修复消费端门禁映射错误并加强证明验证。
13
+ v0.2.4 是文档与市场来源整改版本。将默认市场来源纠正为 bundled-family 仓库(ifoohoo/release-skill),消除过时的 v0.1.9 残留,改善 README 双语一致性与导航,并强化版本漂移的防复发门禁。
14
14
 
15
15
  **变更**
16
16
 
17
- - **版本同步到 0.2.3**:所有插件清单(9个文件)、package.json、INSTALL.md、INSTALL.zh-CN.md、README.md README.zh-CN.md 已更新。
17
+ - **默认市场来源纠正**:所有安装文档现使用 bundled-family 仓库 `ifoohoo/release-skill`,而非外部市场 `ifoohoo/artifact-skill-set`。Claude Code 安装命令改为 `/plugin marketplace add ifoohoo/release-skill`,安装名为 `release-skill@release-skill`。
18
+ - **README 结构优化**:中英文 README 均增加目录、文档导航章节,并重组章节流程(快速开始移至保存契约之前)。相较此前显著缩短。
19
+ - **定位句补全**:README 和根工作区 README 现列出所有支持平台(Claude Code、CodeBuddy、WorkBuddy、Codex、Kimi Code)。
20
+ - **防复发门禁扩展**:`sync-version.mjs` TEXT_TARGETS 现覆盖中英文 README 的 safe-first-command 版本陈述,防止未来 v0.1.9 类漂移。
18
21
 
19
22
  **修复**
20
23
 
21
- - **CodeBuddy marketplace-install 分发映射**:`verify.mjs` 现在正确将 `codebuddy-marketplace-install` 映射到 `codebuddy-plugin` distribution(之前错误回落到 `kimi-plugin`)。codebuddy `fixedEnv` 现在只使用 `HOME`,不再包含 `KIMI_CODE_HOME`。
22
- - **移除未知消费端回落**:`plugin-marketplace.mjs` 现在对未注册的消费端平台抛出明确错误,而非静默回落到 Kimi 配置。错误消息包含未知消费端标识和已注册平台列表。
23
- - **CodeBuddy 证明基线排除**:`.release-skill/codebuddy-attestations/` 现在正确排除在工作区基线摘要计算之外,防止在发布生命周期中写入 codebuddy 证明文件时产生自漂移。
24
- - **CodeBuddy 清单 skills 字段支持数组**:`normalizeCodeBuddySkillsRel()` 现在同时支持字符串和单元素数组形式的 `skills` 字段,与真实 CodeBuddy 验证器期望的形状一致。根 `.codebuddy-plugin/plugin.json` 现在使用数组形式。
25
- - **CLI 通道证明路径验证**:`validateCodeBuddyAttestation()` 现在验证 CLI 通道的 `installPath` 以已知的 `.codebuddy/plugins/marketplaces/<marketplace>/plugins/<plugin>` 段尾结尾,关闭路径逃逸缺口。
24
+ - **消除 v0.1.9 残留**:两个 README safe-first-command 块现正确引用当前版本(之前停留在 v0.1.9)。
25
+ - **移除易漂移计数**:将 'All four plugin hosts' / '四种插件宿主' 替换为 'All supported plugin hosts' / '各插件宿主'。
26
+ - **根 README 边界修正**:明确 README/INSTALL/CHANGELOG 是人工维护的源文件,references/schemas/adapters/skills 是生成产物。
27
+ - **CONTRIBUTING 更新**:新增'不要直接编辑生成物'章节,说明 references/、schemas/、adapters/、skills/ 的权威来源和再生命令。
28
+ - **AGENTS.md 语言规则调整**:治理规则文件可使用英文;面向用户的文档仍使用中文。
26
29
  <!-- release-skill:managed:end id=latest-release -->
27
30
 
28
31
  <!-- release-skill:capability:external-write-boundary -->
29
- > **当前边界:** v0.2.3 是当前发布版本(v0.2.2 曾处于已发布状态,后因平台验证收敛修复而更新)。
32
+ > **当前边界:** v0.2.4 是当前发布版本(v0.2.2 曾处于已发布状态,后因平台验证收敛修复而更新)。
30
33
  > v0.1.1 已完成 GitHub 与 npm 的
31
34
  > 真实生产发布,是首次生产验证的历史里程碑,并从冻结 Git ref 完成精确 npm
32
- > 安装及 Claude/Codex 消费者安装验证;“当前发布版本”与“首次生产验证里程碑”
35
+ > 安装及 Claude/Codex 消费者安装验证;"当前发布版本"与"首次生产验证里程碑"
33
36
  > 是两个不同的事实,不得混写成同一含义。同一工作流还通过了本地
34
37
  > 生产等价协议套件:测试运行真实 release-skill CLI 和冻结制品,Git 目标是
35
38
  > 本地 bare remote,`gh`、`npm`、Claude、Codex 使用协议级 fake。该套件没有
@@ -39,7 +42,7 @@ v0.2.3 是修复版本,解决 v0.2.2 中发现的平台验证、公共生成
39
42
  > 远端唯一性检查在 `publish` 全局预检执行。
40
43
 
41
44
  <!-- release-skill:capability:safe-first-command -->
42
- > **生产路径自 v0.1.1 里程碑起已完成真实生产验证;v0.1.9 是当前发布版本。**
45
+ > **生产路径自 v0.1.1 里程碑起已完成真实生产验证;v0.2.4 是当前发布版本。**
43
46
  > npm 安装的 CLI 是受支持的用户入口;源码 checkout 保留为开发/贡献者路径。
44
47
  >
45
48
  > **第一条命令:**
@@ -53,55 +56,26 @@ v0.2.3 是修复版本,解决 v0.2.2 中发现的平台验证、公共生成
53
56
  > --confirm-production <planDigest>`;`bound` 前序公开基线必须使用
54
57
  > `prepare --online --production`。没有摘要确认就不会预检或写远端。
55
58
 
56
- ## 发布工作流概览
59
+ ## 目录
57
60
 
58
- release-skill 把发布生命周期建模为一个严格状态机,让每个阶段都有明确的进入和退出条件,且任何阶段都不能跳过。规范定义见 `references/01-state-machine.md`。
59
-
60
- ```text
61
- DISCOVERED -> ASSESSED -> PREPARED -> APPROVED -> PUBLISHING -> PUBLISHED -> VERIFIED
62
- 异常态:NEEDS_INPUT / BLOCKED / PARTIAL
63
- ```
64
-
65
- 每个 CLI 命令对应一次状态转换:
66
-
67
- - `help` 检查环境;`setup` 发现项目,并在摘要确认后仅首次创建配置。
68
- - `assess` 执行只读就绪度评估(`DISCOVERED -> ASSESSED`)。
69
- - `prepare` 运行验证门、冻结一份不可变发布计划,并把配置的公开文件复制进隔离快照(`ASSESSED -> PREPARED`)。它只写入 `.release-skill/` 目录,从不触碰远端服务。
70
- - `approve` 记录人工批准,绑定到计划摘要并带 24 小时有效期(`PREPARED -> APPROVED`)。计划一旦变化,批准自动失效。
71
- - `publish` 按顺序执行外部写操作检查点(`APPROVED -> PUBLISHING -> PUBLISHED`)。
72
- - `reconcile` 从 `PARTIAL` 恢复;`verify` 在全新隔离环境完成消费者安装验证(`PUBLISHED -> VERIFIED`)。
73
-
74
- `PUBLISHED` **不是**终态。只有全新运行的 `verify` 确认远端状态和精确消费者安装都与冻结计划一致时,才会到达 `VERIFIED`。
75
-
76
- **发布检查点顺序。** `publish` 先对所有动作做只读全局预检,再按固定顺序执行并观察:公开快照 branch → 签名/可追溯 tag → npm 发布 → GitHub Release → 配置的 Claude/Codex 插件市场安装 → 运行记录。任一步骤失败都会停止后续检查点并使运行进入 `PARTIAL`。系统绝不自动删除远端 tag、不 unpublish 包、不从头重跑;`reconcile` 查询实际远端状态,跳过已一致的步骤,只重试安全且未完成的动作,远端冲突则交由人工决策。
77
-
78
- ## 为什么人工修改的 README 不会丢失
79
-
80
- release-skill 不重新生成、也不回写项目源文件。`prepare` 从当前工作区把每个公开文件复制到隔离的本地快照,并验证复制前后的字节。README 的 slogan、示例、正文、格式,以及后续任何人工修改都会作为完整文件被保留。
81
-
82
- - 后续 prepare 重新读取当前文件,不会从模板重建。
83
- - 快照必须与源文件逐字节一致。
84
- - 计划变化会产生新的 digest,旧批准不能授权新内容。
85
- - prepare 后再改源文件,publish 会因 baseline 变化在远端写入前停止。保留修改的正确方式是重新 prepare、重新审阅并重新 approve。
86
- - 冻结制品被篡改时,publish 会因 snapshot/tarball/Git object 摘要不符停止。
87
- - 远端 branch、tag、Release 或 npm 版本冲突时交给人工;系统不 force、不覆盖。
88
- - 只有 `publicFiles` 明确列出的文件会被复制;需要发布的翻译 README、图片、演示文件和链接文档都要显式加入配置。
89
- - 发布只冻结当前真相:`prepare` 不会刷新或重写人工文档。维护者必须先更新 README、INSTALL 与 CHANGELOG(包括必须与 `package.json` 版本一致的机器可读 `release-skill:release-version` 标记,以及当前包版本的正式 CHANGELOG 标题),再 prepare、审阅和批准。任一文档版本标记或 CHANGELOG 当前版本条目漂移时,发布前门禁失败关闭。
90
-
91
- 保护规则只有一句话:**复制当前事实,冻结已审阅事实,不重写人工事实。**
61
+ - [快速开始](#快速开始)
62
+ - [发布工作流](#发布工作流)
63
+ - [文档导航](#文档导航)
64
+ - [Skills](#skills)
65
+ - [平台分发](#平台分发)
66
+ - [许可证](#许可证)
92
67
 
93
68
  ## 快速开始
94
69
 
95
- ### 安装 / 前置条件
70
+ ### 安装
96
71
 
97
- - Node.js 22+
98
- - Git 2.30+
99
- - 至少已有一个提交的目标 Git 仓库
72
+ - Node.js 22+、Git 2.30+、至少已有一个提交的目标 Git 仓库。
100
73
 
101
- **从 npm 安装(推荐):**
74
+ **npm(推荐):**
102
75
 
103
76
  ```bash
104
77
  npm install -g release-skill
78
+ release-skill help
105
79
  ```
106
80
 
107
81
  或免安装直接运行:
@@ -110,214 +84,179 @@ npm install -g release-skill
110
84
  npx release-skill help
111
85
  ```
112
86
 
113
- **验证安装:**
114
-
115
- ```bash
116
- release-skill help
117
- ```
118
-
119
- **安装为插件(Claude Code / CodeBuddy / WorkBuddy / Codex / Kimi Code):**
87
+ **插件(Claude Code / CodeBuddy / WorkBuddy / Codex):**
120
88
 
121
- 四种插件宿主都从统一市场 `ifoohoo/artifact-skill-set` 安装——以 Claude
122
- Code 会话为例:
89
+ Claude Code、CodeBuddy、WorkBuddy 和 Codex 从 bundled-family 市场
90
+ `ifoohoo/release-skill` 安装:
123
91
 
124
92
  ```
125
- /plugin marketplace add ifoohoo/artifact-skill-set
126
- /plugin install release-skill@artifact-skill-set
93
+ /plugin marketplace add ifoohoo/release-skill
94
+ /plugin install release-skill@release-skill
127
95
  ```
128
96
 
129
- `ifoohoo/artifact-skill-set` 是一个**外部独立市场**:插件仓库只含 plugin
130
- 清单,marketplace 索引集中于外部市场仓库。当发布单元的插件 distribution 声明
131
- `marketplaceRepo` 时,`prepare --online --production` 会冻结外部市场 HEAD
132
- (Codex commit sha——强冻结;Claude 钉默认分支名——弱冻结),并以本单元自身
133
- 冻结快照整树校验安装载荷。**发布时序:** 须先发布外部市场索引——其条目版本须
134
- 等于目标发布版本——之后 `prepare` 才能冻结到含该条目的市场 sha。各平台完整命令
135
- 见 [INSTALL.zh-CN.md](INSTALL.zh-CN.md),契约与进阶直接仓库安装方式见
136
- `references/06-adapter-contract.md` §2.3/§2.4。
97
+ > **前置条件:GitHub 访问。** `owner/repo` 简写会让 Claude Code 通过 SSH 克隆。
98
+ > 如不使用 SSH,可传完整 HTTPS 地址——
99
+ > `/plugin marketplace add https://github.com/ifoohoo/release-skill`——
100
+ > 或设置 `CLAUDE_CODE_PLUGIN_PREFER_HTTPS=1`。
137
101
 
138
- **开发安装(贡献者回退,从源码 checkout):**
102
+ **Kimi Code:** Kimi Code 没有市场安装接口,需手动安装并钉死到特定 release
103
+ tag——见 [INSTALL.zh-CN.md](INSTALL.zh-CN.md#安装为-kimi-code-插件)。
139
104
 
140
- ```bash
141
- export RELEASE_SKILL_HOME=/absolute/path/to/release-skill
142
- cd "$RELEASE_SKILL_HOME"
143
- npm exec --yes pnpm@10.17.1 -- install --frozen-lockfile
144
- ```
145
-
146
- 然后通过 `node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs"` 调用 CLI。
147
-
148
- 先保护本地运行数据,避免把计划、审批和冻结制品提交进仓库:
149
-
150
- ```gitignore
151
- .release-skill/*
152
- !.release-skill/project.yaml
153
- ```
105
+ CodeBuddy、Codex 和 Kimi Code 的完整命令见 [INSTALL.zh-CN.md](INSTALL.zh-CN.md)。
154
106
 
155
- ### 首次接入
107
+ ### 主流程
156
108
 
157
- `setup` 默认只读。把完整报告写入临时文件,只查看确定性的 `compactSummary`(紧凑摘要):
109
+ 按以下顺序执行。步骤 1-4 是安全默认(只读或仅本地);步骤 5-9 需要显式人工门禁。
158
110
 
159
111
  ```bash
112
+ CLI=(release-skill) # 或:CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
160
113
  PROJECT=/absolute/path/to/my-project
161
- SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
162
- REPORT="$SETUP_SESSION/discovery.json"
163
- ANSWERS="$SETUP_SESSION/answers.json"
164
- BOUND_REPORT="$SETUP_SESSION/bound.json"
165
- printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
166
-
167
- release-skill setup --root "$PROJECT" --json > "$REPORT" || test "$?" -eq 2
168
- node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary){console.error("compactSummary missing");process.exit(2)}process.stdout.write(JSON.stringify(r.compactSummary,null,2)+"\n")' "$REPORT"
114
+ ACTOR=your-name
169
115
  ```
170
116
 
171
- `NEEDS_INPUT` `LOCAL_ONLY_DETECTED` 按设计返回退出码 2。若 `proposalConflicts` 非空,必须停止自动路径,由人工修正冲突的仓库或映射权威事实后重新运行 setup,不得猜测选边。
117
+ 1. **help** 环境检查:
118
+ ```bash
119
+ "${CLI[@]}" help
120
+ ```
121
+ 2. **setup** — 首次接入(只读发现,然后 create-once 配置):
122
+ ```bash
123
+ SETUP_SESSION="$(mktemp -d "${TMPDIR:-/tmp}/release-setup.XXXXXX")"
124
+ REPORT="$SETUP_SESSION/discovery.json"
125
+ ANSWERS="$SETUP_SESSION/answers.json"
126
+ printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
127
+ "${CLI[@]}" setup --root "$PROJECT" --json > "$REPORT" || test "$?" -eq 2
128
+ ```
129
+ 若 `proposalConflicts` 非空,必须停止并由人工修正冲突的仓库或映射权威。无冲突时
130
+ 机械提取 `recommendedAnswers`(不得手写完整 answers):
131
+ ```bash
132
+ SETUP_SESSION='<上一步打印的会话目录绝对路径>'
133
+ node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if((r.proposalConflicts??[]).length){console.error("proposal conflicts require human resolution");process.exit(2)}if(!r.recommendedAnswers){console.error("recommendedAnswers missing");process.exit(2)}fs.writeFileSync(process.argv[2],JSON.stringify(r.recommendedAnswers,null,2)+"\n",{flag:"wx",mode:0o600})' "$REPORT" "$ANSWERS"
134
+ ```
135
+ 确认绑定后的 `setupDigest` 一次,然后创建配置:
136
+ ```bash
137
+ SETUP_SESSION='<会话目录绝对路径>'
138
+ PROJECT='<项目绝对路径>'
139
+ ANSWERS="$SETUP_SESSION/answers.json"
140
+ CREATED_REPORT="$SETUP_SESSION/created.json"
141
+ POST_REPORT="$SETUP_SESSION/post-setup.json"
142
+ ASSESS_REPORT="$SETUP_SESSION/assess.json"
143
+ "${CLI[@]}" setup --root "$PROJECT" --answers "$ANSWERS" \
144
+ --write --confirm-setup <已确认的setupDigest> --json > "$CREATED_REPORT"
145
+ "${CLI[@]}" setup --root "$PROJECT" --json > "$POST_REPORT"
146
+ set +e
147
+ "${CLI[@]}" assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
148
+ ASSESS_EXIT=$?
149
+ set -e
150
+ [ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
151
+ node -e 'const fs=require("node:fs");const [c,p,a]=process.argv.slice(1).map(x=>JSON.parse(fs.readFileSync(x,"utf8")));if(c.status!=="CONFIG_CREATED"||p.status!=="ALREADY_CONFIGURED"||!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){process.exit(2)}' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
152
+ node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
153
+ ```
154
+ 写入必须返回 `CONFIG_CREATED`,下一次 setup 必须返回 `ALREADY_CONFIGURED`。
155
+ 已有配置永不重新生成,后续只做经审阅的增量编辑。发现的脚本标记为
156
+ `SIDE_EFFECTS_UNPROVEN`。只有在人工审阅之后才添加项目专属 hook 或 gate:
157
+ 编辑 `projectConfig.hooks`,或编辑 `verificationGates` 并把同一个 id 加入
158
+ `selectedGateIds`,然后重新运行绑定 dry-run。配置已存在时跳过。
159
+ 完整多步流程见 [INSTALL.zh-CN.md](INSTALL.zh-CN.md#首次接入)。
160
+ 3. **assess** — 只读就绪评估:
161
+ ```bash
162
+ "${CLI[@]}" assess --root "$PROJECT" --offline --json
163
+ ```
164
+ 4. **prepare** — 本地快照与计划冻结:
165
+ ```bash
166
+ "${CLI[@]}" prepare --root "$PROJECT" --offline \
167
+ --acknowledge-hook-side-effects \
168
+ --acknowledge-gate-side-effects --json
169
+ ```
170
+ 只有项目配置没有对应 hook 或 snapshot gate 时,才省略相应授权参数。授权前必须审阅可执行文件、参数、工作目录和副作用,不能把授权参数当固定样板。
171
+ 5. **人工审阅:** 检查 `planPath`、`externalActions`、`targetVersion` 和 `planDigest`。
172
+ 6. **prepare --production** — 冻结生产计划:
173
+ ```bash
174
+ PLAN_JSON=$("${CLI[@]}" prepare --root "$PROJECT" --online --production \
175
+ --acknowledge-hook-side-effects \
176
+ --acknowledge-gate-side-effects --json)
177
+ PLAN_PATH=$(printf '%s\n' "$PLAN_JSON" | jq -r '.planPath')
178
+ PLAN_DIGEST=$(printf '%s\n' "$PLAN_JSON" | jq -r '.planDigest')
179
+ ```
180
+ 7. **approve** — 人工批准(24 小时有效期):
181
+ ```bash
182
+ APPROVAL_JSON=$("${CLI[@]}" approve --plan "$PLAN_PATH" \
183
+ --digest "$PLAN_DIGEST" --actor "$ACTOR" --json)
184
+ APPROVAL_PATH=$(printf '%s\n' "$APPROVAL_JSON" | jq -r '.approvalPath')
185
+ ```
186
+ 8. **publish** — 远端写入开始:
187
+ ```bash
188
+ PUBLISH_JSON=$("${CLI[@]}" publish --root "$PROJECT" \
189
+ --plan "$PLAN_PATH" --approval "$APPROVAL_PATH" \
190
+ --confirm-production "$PLAN_DIGEST" --json)
191
+ PUBLISH_RUN_PATH=$(printf '%s\n' "$PUBLISH_JSON" | jq -r '.runPath')
192
+ ```
193
+ `PUBLISHED` **不是**终态。
194
+ 9. **verify** — 消费者安装检查:
195
+ ```bash
196
+ "${CLI[@]}" verify --root "$PROJECT" \
197
+ --plan "$PLAN_PATH" --run "$PUBLISH_RUN_PATH" \
198
+ --acknowledge-gate-side-effects --json
199
+ ```
172
200
 
173
- 没有冲突时,机械提取机器提案:
201
+ 示例需要 `jq`。没有 jq 时,直接复制返回的 JSON 字段;不要把尖括号占位符当作 shell 语法。
174
202
 
175
- ```bash
176
- SETUP_SESSION='/上一步打印的会话目录绝对路径'
177
- PROJECT='/上一步打印的项目绝对路径'
178
- REPORT="$SETUP_SESSION/discovery.json"
179
- ANSWERS="$SETUP_SESSION/answers.json"
180
- BOUND_REPORT="$SETUP_SESSION/bound.json"
181
- node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if((r.proposalConflicts??[]).length){console.error("proposal conflicts require human resolution");process.exit(2)}if(!r.recommendedAnswers){console.error("recommendedAnswers missing");process.exit(2)}fs.writeFileSync(process.argv[2],JSON.stringify(r.recommendedAnswers,null,2)+"\n",{flag:"wx",mode:0o600})' "$REPORT" "$ANSWERS"
182
-
183
- release-skill setup --root "$PROJECT" --answers "$ANSWERS" --json > "$BOUND_REPORT"
184
- node -e 'const fs=require("node:fs");const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8"));if(!r.compactSummary||!r.setupDigest){console.error("bound setup report incomplete");process.exit(2)}process.stdout.write(JSON.stringify({compactSummary:r.compactSummary,setupDigest:r.setupDigest},null,2)+"\n")' "$BOUND_REPORT"
185
- printf 'SETUP_SESSION=%s\nPROJECT=%s\n' "$SETUP_SESSION" "$PROJECT"
186
- ```
203
+ ### PARTIAL 恢复与 reconcile
187
204
 
188
- 只审阅这份绑定摘要和精确摘要值,并由用户确认一次。确认后使用其字面量首次创建配置:
205
+ 当 `publish` 在部分检查点成功但在其他检查点失败时,运行进入 `PARTIAL` 状态。**不要从头重跑,也不要删除远端状态。**
189
206
 
190
207
  ```bash
191
- SETUP_SESSION=<上一步打印的会话目录绝对路径>
192
- PROJECT=<上一步打印的项目绝对路径>
193
- ANSWERS="$SETUP_SESSION/answers.json"
194
- CREATED_REPORT="$SETUP_SESSION/created.json"
195
- POST_REPORT="$SETUP_SESSION/post-setup.json"
196
- ASSESS_REPORT="$SETUP_SESSION/assess.json"
197
- release-skill setup --root "$PROJECT" --answers "$ANSWERS" \
198
- --write --confirm-setup <已确认的 setupDigest> --json > "$CREATED_REPORT"
199
- release-skill setup --root "$PROJECT" --json > "$POST_REPORT"
200
- set +e
201
- release-skill assess --root "$PROJECT" --offline --json > "$ASSESS_REPORT"
202
- ASSESS_EXIT=$?
203
- set -e
204
- [ "$ASSESS_EXIT" -eq 0 ] || [ "$ASSESS_EXIT" -eq 1 ] || exit "$ASSESS_EXIT"
205
- node -e 'const fs=require("node:fs");const [c,p,a]=process.argv.slice(1).map(x=>JSON.parse(fs.readFileSync(x,"utf8")));if(c.status!=="CONFIG_CREATED"||p.status!=="ALREADY_CONFIGURED"||!["ASSESSED","NEEDS_INPUT","BLOCKED"].includes(a.status)){process.exit(2)}process.stdout.write(JSON.stringify({created:c.status,postSetup:p.status,assessment:{status:a.status,summary:a.summary,gapCount:(a.gaps??[]).length,blockingCodes:(a.gaps??[]).filter(g=>g.severity==="error").map(g=>g.code)}},null,2)+"\n")' "$CREATED_REPORT" "$POST_REPORT" "$ASSESS_REPORT"
206
- node -e 'require("node:fs").rmSync(process.argv[1],{recursive:true,force:false})' "$SETUP_SESSION"
208
+ RECONCILE_JSON=$("${CLI[@]}" reconcile --root "$PROJECT" \
209
+ --run "$PUBLISH_RUN_PATH" \
210
+ --plan "$PLAN_PATH" \
211
+ --approval "$APPROVAL_PATH" \
212
+ --confirm-production "$PLAN_DIGEST" --json)
213
+ RECONCILE_RUN_PATH=$(printf '%s\n' "$RECONCILE_JSON" | jq -r '.runPath')
214
+ "${CLI[@]}" verify --root "$PROJECT" \
215
+ --plan "$PLAN_PATH" --run "$RECONCILE_RUN_PATH" \
216
+ --acknowledge-gate-side-effects --json
207
217
  ```
208
218
 
209
- 写入必须返回 `CONFIG_CREATED`,下一次 setup 必须返回 `ALREADY_CONFIGURED`。已有配置永不重新生成,后续只做经审阅的增量编辑。发现的解释器/包管理器脚本标记为 `SIDE_EFFECTS_UNPROVEN`,不会被自动选中。只有在人工审阅之后才添加项目专属的 hook 或 gate:编辑 `projectConfig.hooks`,或编辑 `verificationGates` 并把同一个 id 加入 `selectedGateIds`,然后重新运行绑定 dry-run。人工维护的文件保持 `mode: preserve`;只有明确的跨单元共享来源才使用 `sourceScope: workspace`。
219
+ `reconcile` 查询实际远端状态,跳过已一致步骤,只重试安全未完成的动作。远端冲突需人工决策。reconcile 成功只返回 `PUBLISHED`,不返回 `VERIFIED`。
210
220
 
211
- #### 进阶:schema 参考——并非首次接入路径
221
+ ## 发布工作流
212
222
 
213
- 下面的 wrapper 仅用于说明 schema。正常 setup 路径中不要手工编写它;按上文机械提取 `recommendedAnswers`。
223
+ release-skill 把发布生命周期建模为严格状态机(规范定义见 `references/01-state-machine.md`):
214
224
 
215
- ```json
216
- {
217
- "projectConfig": {
218
- "apiVersion": "release-skill/v1",
219
- "kind": "ReleaseProject",
220
- "project": { "name": "my-project", "defaultBranch": "main" },
221
- "releaseUnits": [{
222
- "id": "my-project",
223
- "source": ".",
224
- "publicRepo": "owner/my-project",
225
- "version": { "source": "package.json", "tagTemplate": "v{version}" },
226
- "distributions": [{
227
- "type": "npm",
228
- "package": "my-project",
229
- "access": "public",
230
- "provenance": false,
231
- "tag": "latest",
232
- "registry": "https://registry.npmjs.org",
233
- "publisher": "my-npm-username"
234
- }],
235
- "publicFiles": [
236
- { "from": "README.md", "to": "README.md", "mode": "preserve" },
237
- { "from": "package.json", "to": "package.json", "mode": "preserve" }
238
- ],
239
- "requiredPublicFiles": ["README.md", "package.json"],
240
- "previousPublicBaseline": { "mode": "none" },
241
- "production": {
242
- "branchTemplate": "release/{tag}",
243
- "branchStrategy": "create-release-branch"
244
- }
245
- }]
246
- },
247
- "selectedGateIds": []
248
- }
225
+ ```text
226
+ DISCOVERED -> ASSESSED -> PREPARED -> APPROVED -> PUBLISHING -> PUBLISHED -> VERIFIED
227
+ 异常态:NEEDS_INPUT / BLOCKED / PARTIAL
249
228
  ```
250
229
 
251
- 这只是 schema 参考,不是接入模板。正常 setup 必须使用机器提案。`mode: none` 仅在不存在任何公开版本时有效。
230
+ 每个 CLI 命令对应一次状态转换。`PUBLISHED` **不是**终态——只有全新运行的 `verify` 确认远端状态和消费者安装与冻结计划一致时,才到达 `VERIFIED`。
252
231
 
253
- 下面的参考展示经人工审阅的 gate `selectedGateIds` 之间的精确关系。该关系只能作为对提取出的机器提案的增量编辑来应用:
232
+ **保存契约:** release-skill 不重新生成或回写项目源文件。`prepare` 把每个配置的公开文件复制到隔离快照并验证字节。后续 prepare 重新读取当前文件,不会从模板重建。只有 `publicFiles` 列出的文件会被复制。`prepare` 不会刷新或重写人工文档——维护者先更新 README、INSTALL 和 CHANGELOG,再 prepare、审阅和批准。
254
233
 
255
- ```json
256
- {
257
- "projectConfig": {
258
- "apiVersion": "release-skill/v1",
259
- "kind": "ReleaseProject",
260
- "project": { "name": "my-project", "defaultBranch": "main" },
261
- "releaseUnits": [{
262
- "id": "my-project",
263
- "source": ".",
264
- "publicRepo": "owner/my-project",
265
- "version": { "source": "package.json", "tagTemplate": "v{version}" },
266
- "distributions": [{
267
- "type": "npm",
268
- "package": "my-project",
269
- "access": "public",
270
- "provenance": false,
271
- "tag": "latest",
272
- "registry": "https://registry.npmjs.org",
273
- "publisher": "my-npm-username"
274
- }],
275
- "publicFiles": [
276
- { "from": "package.json", "to": "package.json", "mode": "preserve" }
277
- ],
278
- "requiredPublicFiles": ["package.json"],
279
- "previousPublicBaseline": { "mode": "none" },
280
- "production": {
281
- "branchTemplate": "release/{tag}",
282
- "branchStrategy": "create-release-branch"
283
- }
284
- }],
285
- "verificationGates": [{
286
- "id": "my-project-script-test",
287
- "phase": "snapshot-verify",
288
- "scope": { "unit": "my-project" },
289
- "command": ["node", "-e", "const p=require('./package.json');if(!p.name)process.exit(1)"],
290
- "cwd": ".",
291
- "timeoutMs": 30000,
292
- "envAllowlist": []
293
- }]
294
- },
295
- "selectedGateIds": ["my-project-script-test"]
296
- }
297
- ```
234
+ **写入安全:** `setup` 默认只读(摘要确认后仅首次创建配置)。`prepare` 只写 `.release-skill/`。`publish` 是生产写入入口,需要同时提供批准和当前计划摘要。项目 hook 和 gate 是已确认的本地进程,没有操作系统沙箱。
298
235
 
299
- id 必须从当前 `gateCandidates` 复制,不得臆造。示例命令在公开快照内自包含。项目脚本只有在脚本本身及其全部依赖都包含在 `publicFiles` 中时才有效;snapshot gate 看不到父工作区的测试、开发依赖或 `node_modules`,除非它们被显式公开。
236
+ ## 文档导航
300
237
 
301
- ```bash
302
- release-skill setup --root /absolute/path/to/my-project \
303
- --answers /absolute/path/to/setup-answers.json --json
304
- release-skill setup --root /absolute/path/to/my-project \
305
- --answers /absolute/path/to/setup-answers.json \
306
- --write --confirm-setup <setupDigest> --json
307
- ```
238
+ | 文档 | 说明 |
239
+ |---|---|
240
+ | [INSTALL.md](INSTALL.md) / [INSTALL.zh-CN.md](INSTALL.zh-CN.md) | 完整安装指南:npm、插件、源码 checkout、setup 流程、分支策略 |
241
+ | [CHANGELOG.md](CHANGELOG.md) | 发布历史 |
242
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | 贡献指南(含生成产物规则) |
243
+ | [SECURITY.md](SECURITY.md) | 安全策略 |
244
+ | `references/01-state-machine.md` | 规范状态机定义 |
245
+ | `references/02-project-config.md` | 项目配置 schema 参考 |
246
+ | `references/05-evidence-and-errors.md` | 证据格式和错误码 |
247
+ | `references/06-adapter-contract.md` | 适配器和市场契约详情 |
248
+ | [GitHub Issues](https://github.com/ifoohoo/release-skill/issues) | 问题报告和功能请求 |
308
249
 
309
- Setup 只原子创建缺失的 `.release-skill/project.yaml`。这一 create-once 步骤使用 v0.1.3 起随包发布、经 digest 登记的 `darwin-arm64` 原生预编译产物;不支持的平台以 `SAFE_WRITE_UNAVAILABLE` 失败关闭,不会回退到基于路径的写入。`ALREADY_CONFIGURED`/`CONFIG_EXISTS` 表示现有文件仍由人工所有,只能增量编辑。README、slogan、CHANGELOG 和业务脚本永不被生成或覆盖。没有远端渠道的项目会报告 `LOCAL_ONLY_DETECTED`,而不是虚构生产支持。
250
+ ## 配置
310
251
 
311
- 以下是一个最小的人工编写配置。npm 可见性、公开文件边界和远端目标都必须显式声明:
252
+ 最小人工编写配置(完整 schema 和 setup 流程见 [INSTALL.zh-CN.md](INSTALL.zh-CN.md)):
312
253
 
313
254
  ```yaml
314
255
  apiVersion: release-skill/v1
315
256
  kind: ReleaseProject
316
-
317
257
  project:
318
258
  name: my-project
319
259
  defaultBranch: main
320
-
321
260
  releaseUnits:
322
261
  - id: my-project
323
262
  source: .
@@ -332,165 +271,23 @@ releaseUnits:
332
271
  - from: package.json
333
272
  to: package.json
334
273
  mode: preserve
335
- - from: LICENSE
336
- to: LICENSE
337
- mode: preserve
338
- requiredPublicFiles: [README.md, LICENSE, package.json]
274
+ requiredPublicFiles: [README.md, package.json]
339
275
  previousPublicBaseline:
340
- mode: none # 首次发布:不存在更早的公开版本
276
+ mode: none
341
277
  distributions:
342
278
  - type: npm
343
279
  package: my-project
344
- access: public # 或 restricted;选择真实的包策略
345
- provenance: false # 只有在 CI/OIDC 配置完成后才使用 true
280
+ access: public
281
+ provenance: false
346
282
  tag: latest
347
283
  registry: https://registry.npmjs.org
348
284
  publisher: my-npm-username
349
- # 可选:CLI smoke 验证。配置 smokeBin 后,verify 会在隔离目录
350
- # 安装该包并运行指定二进制。不配置 smokeBin 时,verify 只确认
351
- # 安装与 name/version。
352
- # smokeBin: my-project
353
- # smokeArgs: [help, --json]
354
- # smokeExpectedJson:
355
- # command: help
356
- # status: READY
357
285
  production:
358
286
  branchTemplate: release/{tag}
359
287
  branchStrategy: create-release-branch
360
- releaseTitleTemplate: "{unit} {version}"
361
- releaseNotes: "人工维护的发布说明"
362
288
  ```
363
289
 
364
- 每个发布单元都必须声明其前序公开基线。只有当你确认不存在更早的公开版本时才使用 `mode: none`。对于已有公开仓库,绑定精确的不可变 ref commit:
365
-
366
- ```yaml
367
- previousPublicBaseline:
368
- mode: bound
369
- repo: owner/my-project
370
- ref: release/v0.9.0
371
- commit: 0123456789abcdef0123456789abcdef01234567
372
- ```
373
-
374
- `none` 不是绕过冲突检查的手段:publish 仍会在任何写入前检查目标 branch、tag、GitHub Release 与 npm 版本的唯一性。bound 模式的生产 prepare 必须在线运行,以便观察 ref 到 commit 的映射。默认观察器不下载远端文件内容,因此它报告映射差异并标记内容差异不可用。发生漂移时停止,由人工选择 `merge`、`adopt` 或 `reject`。先获取并审阅真实远端 commit;工具不会下载或合并其文件。`merge` 在人工所有的来源中保留本地与远端双方修改;`adopt` 把审阅过的远端字节复制进该来源;`reject` 在调查或修正远端/ref 期间停止本次发布;永远不要为了绕过漂移而改回 `mode: none`。`merge` 或 `adopt` 之后,把 `previousPublicBaseline` 重新绑定到已接受的不可变 `repo`/`ref`/`commit`,再运行新的 `prepare --online --production`、审阅并批准。
375
-
376
- 分支策略应与真实仓库匹配(`create-release-branch`、`advance-existing-branch`、`initialize-default-branch`);三种策略的最小配置示例见[英文 README](README.md)。
377
-
378
- ### 主流程
379
-
380
- 按以下顺序执行。步骤 1–4 是安全默认(只读或仅本地);步骤 5–9 是需要显式人工门禁的生产发布。
381
-
382
- ```bash
383
- # npm 安装的 CLI(推荐):
384
- CLI=(release-skill)
385
- PROJECT=/absolute/path/to/my-project
386
- ACTOR=your-name
387
- # 开发回退(源码 checkout):
388
- # CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
389
- ```
390
-
391
- 1. **环境检查:**
392
- ```bash
393
- "${CLI[@]}" help
394
- ```
395
- 2. **首次接入(仅缺少配置时,只读):**
396
- ```bash
397
- "${CLI[@]}" setup --root "$PROJECT" --json
398
- ```
399
- 按上文机械提取 `compactSummary` 与 `recommendedAnswers`,只确认一次绑定后的 `setupDigest`;配置已存在时跳过。
400
- 3. **就绪评估(只读):**
401
- ```bash
402
- "${CLI[@]}" assess --root "$PROJECT" --offline --json
403
- ```
404
- 4. **本地快照与计划冻结:**
405
- ```bash
406
- "${CLI[@]}" prepare --root "$PROJECT" --offline \
407
- --acknowledge-hook-side-effects \
408
- --acknowledge-gate-side-effects --json
409
- ```
410
- 只有项目配置没有对应 hook 或 snapshot gate 时,才省略相应授权参数。授权前必须审阅可执行文件、参数、工作目录和副作用,不能把授权参数当固定样板。
411
- 5. **人工审阅:** 检查返回的 `planPath`、`externalActions`、`units[].targetVersion` 和 `planDigest`。每个发布单元的快照位于 `<evidenceDir>/snapshots/<unit-id>/`。
412
- 6. **生产计划冻结:**
413
- ```bash
414
- PRODUCTION_JSON=$("${CLI[@]}" prepare --root "$PROJECT" --online --production \
415
- --acknowledge-hook-side-effects \
416
- --acknowledge-gate-side-effects --json)
417
- printf '%s\n' "$PRODUCTION_JSON" | jq .
418
- PLAN_PATH=$(printf '%s\n' "$PRODUCTION_JSON" | jq -r '.planPath')
419
- PLAN_DIGEST=$(printf '%s\n' "$PRODUCTION_JSON" | jq -r '.planDigest')
420
- ```
421
- 同样,只省略配置不需要的授权,并在授权前逐项审阅项目进程。`prepare --json` 返回的生产权威 `planPath` 指向 `<项目>/.release-skill/plans/<planDigest>.json`,后续必须始终沿用这个返回值。`.release-skill/release-plan.json` 只是可变便利副本,不得传给生产 approve/publish/reconcile。
422
- 7. **批准:**
423
- ```bash
424
- APPROVAL_JSON=$("${CLI[@]}" approve --plan "$PLAN_PATH" \
425
- --digest "$PLAN_DIGEST" --actor "$ACTOR" --json)
426
- printf '%s\n' "$APPROVAL_JSON" | jq .
427
- APPROVAL_PATH=$(printf '%s\n' "$APPROVAL_JSON" | jq -r '.approvalPath')
428
- ```
429
- 批准 24 小时失效;`--actor` 只是未经认证的本地审计标签。后续必须使用返回的 immutable `approvalPath` 和 `expiresAt`。
430
- 8. **发布(从此开始写远端):**
431
- ```bash
432
- PUBLISH_JSON=$("${CLI[@]}" publish --root "$PROJECT" \
433
- --plan "$PLAN_PATH" --approval "$APPROVAL_PATH" \
434
- --confirm-production "$PLAN_DIGEST" --json)
435
- printf '%s\n' "$PUBLISH_JSON" | jq .
436
- PUBLISH_RUN_PATH=$(printf '%s\n' "$PUBLISH_JSON" | jq -r '.runPath')
437
- ```
438
- 保存返回的 `runPath`。`PUBLISHED` **不是**终态。
439
- 9. **验证(消费者安装检查):**
440
- ```bash
441
- "${CLI[@]}" verify --root "$PROJECT" \
442
- --plan "$PLAN_PATH" --run "$PUBLISH_RUN_PATH" \
443
- --acknowledge-gate-side-effects --json
444
- ```
445
- 只有计划既没有 consumer gate,也没有 npm `smokeBin` 时才省略授权。
446
-
447
- 生产 prepare 会把每个公开快照封存为独立 Git commit/tree,并为 npm 单元生成固定 tarball。`publish` 先对所有动作做只读预检,再按“公开快照 branch → tag → npm → GitHub Release → Claude/Codex 插件市场安装”执行并逐项观察。Kimi Code 没有可脚本化的安装接口,其检查点**失败关闭**:`publish` 在完成自动化写入后落入 `PARTIAL`,并产出版本钉死的手动安装要求。操作者随后用 requirement 给出的隔离 `KIMI_CODE_HOME` 启动 Kimi Code,运行钉死的 `/plugins install <release-tag URL>`,把可信证明(同时绑定冻结**计划**摘要与快照**载荷**摘要)写入按计划摘要命名的目录 `.release-skill/kimi-attestations/<planDigest>/<plugin>/`,再运行 `reconcile`(→ `PUBLISHED`)与 `verify`(→ `VERIFIED`);两者都从同一稳定位置读取证明。安装到日常 `~/.kimi-code` 不被接受。完整流程与证明 JSON 字段见 `INSTALL.zh-CN.md`。`verify` 在隔离目录安装每一个精确 npm `package@version`;配置 `smokeBin` 后还会运行 CLI 并校验输出。只有全部证据与冻结计划一致才进入 `VERIFIED`。默认分支名由每个 unit 的 `production.branchTemplate` 配置;同名远端对象存在时停止,交由人工判断。
448
-
449
- ### 发布文档刷新(可选)
450
-
451
- 发布单元可以声明 `releaseDocuments`,用一份结构化双语说明源确定性刷新 README 受管区域和 CHANGELOG 当前版本条目。核心 CLI 完全离线运行:不联网、不调用大模型、不自动翻译;只改写声明过的受管区域、唯一版本标记的机器值和 CHANGELOG 当前版本受管条目,区域外字节逐字保留。`prepare` 只检查新鲜度,不写工作树。
452
-
453
- ```yaml
454
- # .release-skill/project.yaml(发布单元片段)
455
- releaseUnits:
456
- - id: my-project
457
- source: .
458
- releaseDocuments:
459
- notesSource: release-notes/{version}.yaml
460
- locales: [en, zh-CN]
461
- changelogs:
462
- - path: CHANGELOG.md
463
- locale: en
464
- readmes:
465
- - path: README.md
466
- locale: en
467
- regions: [latest-release]
468
- versionMarkers:
469
- - id: current-version
470
- pattern: '<!-- release-skill:version -->v{version}<!-- /release-skill:version -->'
471
- - path: README.zh-CN.md
472
- locale: zh-CN
473
- regions: [latest-release]
474
- ```
475
-
476
- 1. **只读演练:**
477
- ```bash
478
- "${CLI[@]}" docs refresh --root "$PROJECT" --unit my-project --json
479
- ```
480
- 2. **摘要确认的本地写入(仅在用户明确授权“本地发布文档写入”后执行):**
481
- ```bash
482
- "${CLI[@]}" docs refresh --root "$PROJECT" --unit my-project \
483
- --write --confirm-refresh <refreshDigest> \
484
- --ack-local-document-write --json
485
- ```
486
-
487
- 该授权只覆盖声明的本地发布文档目标,不是 hook、Git 提交、push、publish 或安装的授权:维护者必须审阅刷新结果并提交,然后重新 `prepare`。
488
-
489
- ### 父工作空间 + npm 子单元 + 插件子单元
490
-
491
- 当 monorepo 从不同目录同时产出 npm 包和 Claude/Codex/Kimi Code 插件时,应定义独立的发布单元。只有当某个单元确实以 manifest、marketplace 和 entry Skill 的形式发布插件时,才为其添加插件分发:
492
-
493
- 这里的 `project` 是父工作空间的编排容器,不是公开发布单元。如果工作区根目录也发布自己的仓库或包,再添加一个 `source: .` 的发布单元。`version.source` 相对于该发布单元的 `source` 目录解析(`version.source` is resolved relative to that release unit's `source` directory):因此 `source: packages/app` 的单元写裸 `package.json`,而不是 `packages/app/package.json`。
290
+ `version.source` 相对于该发布单元的 `source` 目录解析(`version.source` is resolved relative to that release unit's `source` directory)。monorepo 中 npm 和插件分开发布时定义多个发布单元:
494
291
 
495
292
  ```yaml
496
293
  apiVersion: release-skill/v1
@@ -498,7 +295,6 @@ kind: ReleaseProject
498
295
  project:
499
296
  name: my-workspace
500
297
  defaultBranch: main
501
-
502
298
  releaseUnits:
503
299
  - id: my-app
504
300
  source: packages/app
@@ -514,28 +310,16 @@ releaseUnits:
514
310
  tag: latest
515
311
  registry: https://registry.npmjs.org
516
312
  publisher: my-npm-username
517
- smokeBin: my-app
518
- smokeArgs: [help, --json]
519
- smokeExpectedJson:
520
- command: help
521
- status: READY
522
313
  publicFiles:
523
- - from: packages/app/README.md
524
- to: README.md
525
- mode: preserve
526
314
  - from: packages/app/package.json
527
315
  to: package.json
528
316
  mode: preserve
529
- - from: packages/app/LICENSE
530
- to: LICENSE
531
- mode: preserve
532
- requiredPublicFiles: [README.md, package.json, LICENSE]
317
+ requiredPublicFiles: [package.json]
533
318
  previousPublicBaseline:
534
319
  mode: none
535
320
  production:
536
321
  branchTemplate: release/{tag}
537
- releaseTitleTemplate: "{unit} {version}"
538
-
322
+ branchStrategy: create-release-branch
539
323
  - id: my-plugin
540
324
  source: packages/plugin
541
325
  publicRepo: owner/my-plugin
@@ -543,114 +327,63 @@ releaseUnits:
543
327
  source: package.json
544
328
  tagTemplate: my-plugin-v{version}
545
329
  distributions:
546
- # 只有当单元确实发布插件时才声明插件消费者。
547
- # CLI smoke 是独立的;只有当插件包同时暴露 CLI 二进制时才声明 smokeBin。
548
330
  - type: claude-plugin
549
331
  plugin: my-plugin
550
332
  marketplace: my-plugin
551
333
  entrySkill: my-plugin-help
552
- timeoutMs: 300000 # 可选;范围 30000-900000;默认 300000
553
- - type: codex-plugin
554
- plugin: my-plugin
555
- marketplace: my-plugin
556
- entrySkill: my-plugin-help
557
- timeoutMs: 300000 # 可选;范围 30000-900000;默认 300000
558
- - type: kimi-plugin
559
- plugin: my-plugin
560
- entrySkill: my-plugin-help
561
- timeoutMs: 300000 # 可选;范围 30000-900000;默认 300000(Kimi 无安装命令;仅约束只读验证)
334
+ marketplaceSourceType: bundled-family
562
335
  publicFiles:
563
- - from: packages/plugin/.claude-plugin/plugin.json
564
- to: .claude-plugin/plugin.json
565
- mode: preserve
566
- - from: packages/plugin/.claude-plugin/marketplace.json
567
- to: .claude-plugin/marketplace.json
568
- mode: preserve
569
- - from: packages/plugin/.codex-plugin/plugin.json
570
- to: .codex-plugin/plugin.json
571
- mode: preserve
572
- - from: packages/plugin/.kimi-plugin/plugin.json
573
- to: .kimi-plugin/plugin.json
574
- mode: preserve
575
- - from: packages/plugin/.agents/plugins/marketplace.json
576
- to: .agents/plugins/marketplace.json
577
- mode: preserve
578
- - from: packages/plugin/skills/my-plugin-help/SKILL.md
579
- to: skills/my-plugin-help/SKILL.md
580
- mode: preserve
581
- - from: packages/plugin/README.md
582
- to: README.md
583
- mode: preserve
584
336
  - from: packages/plugin/package.json
585
337
  to: package.json
586
338
  mode: preserve
587
- - from: packages/plugin/LICENSE
588
- to: LICENSE
589
- mode: preserve
590
- requiredPublicFiles:
591
- - .claude-plugin/plugin.json
592
- - .claude-plugin/marketplace.json
593
- - .codex-plugin/plugin.json
594
- - .kimi-plugin/plugin.json
595
- - .agents/plugins/marketplace.json
596
- - skills/my-plugin-help/SKILL.md
597
- - README.md
598
- - package.json
599
- - LICENSE
339
+ requiredPublicFiles: [package.json]
600
340
  previousPublicBaseline:
601
341
  mode: none
602
342
  production:
603
343
  branchTemplate: release/{tag}
604
- releaseTitleTemplate: "{unit} {version}"
344
+ branchStrategy: create-release-branch
605
345
  ```
606
346
 
607
- 每个插件单元**必须**列出其 Claude/Codex/Kimi Code `plugin.json`、Claude/Codex 的 `marketplace.json`(Kimi Code 没有 marketplace 清单)、entry Skill 以及全部必需公开文件。CLI smoke(`smokeBin`)对插件单元是可选的,只适用于发布的 npm 包暴露 CLI 二进制的情况。
608
-
609
- 插件分发可以声明 `timeoutMs`(范围 30,000–900,000 ms;默认 300,000 ms),用于 marketplace add、插件安装与插件列表命令的子进程超时。真实网络下这些命令可能需要 40–105 秒;默认 300 秒超时可以避免误报 `PARTIAL`。解析后的值会冻结进计划,并随其他动作参数一起批准。没有 `timeoutMs` 的旧计划在执行时按 300,000 ms 兼容处理。
610
-
611
- ### PARTIAL 恢复与 reconcile
612
-
613
- 当 `publish` 在部分检查点成功但在其他检查点失败时,运行进入 `PARTIAL` 状态。**不要从头重跑,也不要删除远端状态。**
614
-
615
- 使用 `reconcile` 检查实际远端状态,跳过已一致的步骤,安全重试未完成的动作:
347
+ 在提取出的 `recommendedAnswers` 中添加 gate:编辑 `verificationGates` 并在 `selectedGateIds` 中绑定同一 id:
616
348
 
617
- ```bash
618
- RECONCILE_JSON=$("${CLI[@]}" reconcile --root "$PROJECT" \
619
- --run "$PUBLISH_RUN_PATH" \
620
- --plan "$PLAN_PATH" \
621
- --approval "$APPROVAL_PATH" \
622
- --confirm-production "$PLAN_DIGEST" --json)
623
- printf '%s\n' "$RECONCILE_JSON" | jq .
624
- RECONCILE_RUN_PATH=$(printf '%s\n' "$RECONCILE_JSON" | jq -r '.runPath')
625
- "${CLI[@]}" verify --root "$PROJECT" \
626
- --plan "$PLAN_PATH" --run "$RECONCILE_RUN_PATH" \
627
- --acknowledge-gate-side-effects --json
349
+ ```json
350
+ {
351
+ "projectConfig": {
352
+ "apiVersion": "release-skill/v1",
353
+ "kind": "ReleaseProject",
354
+ "project": { "name": "my-project", "defaultBranch": "main" },
355
+ "releaseUnits": [{
356
+ "id": "my-project",
357
+ "source": ".",
358
+ "publicRepo": "owner/my-project",
359
+ "version": { "source": "package.json", "tagTemplate": "v{version}" },
360
+ "distributions": [{
361
+ "type": "npm", "package": "my-project", "access": "public",
362
+ "provenance": false, "tag": "latest",
363
+ "registry": "https://registry.npmjs.org", "publisher": "my-npm-username"
364
+ }],
365
+ "publicFiles": [{ "from": "package.json", "to": "package.json", "mode": "preserve" }],
366
+ "requiredPublicFiles": ["package.json"],
367
+ "previousPublicBaseline": { "mode": "none" },
368
+ "production": { "branchTemplate": "release/{tag}", "branchStrategy": "create-release-branch" }
369
+ }],
370
+ "verificationGates": [{
371
+ "id": "my-project-script-test",
372
+ "phase": "snapshot-verify",
373
+ "scope": { "unit": "my-project" },
374
+ "command": ["node", "-e", "const p=require('./package.json');if(!p.name)process.exit(1)"],
375
+ "cwd": ".",
376
+ "timeoutMs": 30000,
377
+ "envAllowlist": []
378
+ }]
379
+ },
380
+ "selectedGateIds": ["my-project-script-test"]
381
+ }
628
382
  ```
629
383
 
630
- reconcile 成功只返回 `PUBLISHED`,不会返回 `VERIFIED`;只有全新运行的 verify 可以产生终态 `VERIFIED`。
631
-
632
- ## 已验收能力
633
-
634
- - 验证项目配置和发布单元;
635
- - `assess` 在不修改项目的前提下报告就绪度;
636
- - 把配置的公开文件复制到隔离快照;
637
- - 只读发现首次接入候选,经精确 `setupDigest` 确认后仅首次创建配置;
638
- - 在冻结快照副本和精确消费者安装根运行经人工选择的项目 gate;
639
- - 检查必需文件、路径安全、精确字节/权限和明显泄漏;
640
- - 记录 Git/工作区身份,冻结绑定 digest 的发布计划;
641
- - 用计划摘要、有效期和显式 action allowlist 绑定人工批准;
642
- - 从冻结 Git object 和 npm tarball 发布,并核对远端 commit/tree/tag/integrity;
643
- - 从冻结 Git ref 安装配置的 Claude/Codex 插件,证明入口 Skill 和安装载荷摘要;对 Kimi Code(无可脚本化安装接口)产出版本钉死的手动安装要求,仅依据绑定到冻结计划摘要的可信证明来确认入口 Skill 和载荷摘要;
644
- - 为 Claude/Codex distribution 支持外部独立市场(`marketplaceRepo`):`prepare --online --production` 冻结外部市场 HEAD(Codex commit sha / Claude 默认分支名),校验该 sha 处的市场索引条目,并以本单元自身冻结快照整树校验安装载荷(`external-marketplace-v1`),安装侧 CLI list 观察在版本漂移时失败关闭;
645
- - 随 Claude/Codex/Kimi 适配器一并提供生成的自包含 CodeBuddy/WorkBuddy 适配器(`adapters/workbuddy/`,清单 `.codebuddy-plugin/plugin.json`,技能以 `${CODEBUDDY_PLUGIN_ROOT}` 渲染);因 codebuddy CLI 无法钉死冻结 ref 而无自动化 marketplace 安装检查点,故产出手动安装要求,仅依据绑定到冻结计划摘要的可信证明来确认入口 Skill 和载荷摘要;
646
- - 明确区分 `PUBLISHED`(外写完成)与 `VERIFIED`(远端和消费者安装证据完成);
647
- - 中途失败停止后续动作,记录独立 run;不修改冻结 plan,不自动撤销已成功动作。
648
-
649
- ## 个性化验证:hook 与 gate
650
-
651
- `hooks.docs/build/test/typecheck/lint` 在冻结前运行,适合确实需要生成源文件或依赖父工作区的步骤。它们可能修改项目或访问网络,prepare 必须显式传入 `--acknowledge-hook-side-effects`。
384
+ ### hook gate
652
385
 
653
- 每个 hook 都是一个对象,`command` 是可执行文件/参数数组,不是 shell 字符串(`command` is an executable/argument array, not a shell string)。每个 hook 还声明 `cwd`、`timeoutMs` 和 `envAllowlist`:
386
+ `hooks.docs/build/test/typecheck/lint` 在快照冻结前运行。每个 hook 是一个对象——`command` 是可执行文件/参数数组,不是 shell 字符串(`command` is an executable/argument array, not a shell string):
654
387
 
655
388
  ```yaml
656
389
  hooks:
@@ -666,63 +399,7 @@ hooks:
666
399
  envAllowlist: []
667
400
  ```
668
401
 
669
- `verificationGates` 是更适合发布校准的受控扩展点:
670
-
671
- ```yaml
672
- verificationGates:
673
- - id: package-contract
674
- phase: snapshot-verify
675
- scope: { unit: my-project }
676
- command:
677
- - node
678
- - -e
679
- - "const p=require('./package.json'); if (!p.name) process.exit(1)"
680
- cwd: .
681
- timeoutMs: 120000
682
- envAllowlist: [CI]
683
- ```
684
-
685
- `snapshot-verify` 在冻结公开快照的一次性可写副本中执行;`consumer-verify` 在精确 npm/Claude/Codex/Kimi Code 隔离安装根执行。两者都使用命令数组而非 shell 字符串,定义和结果会进入摘要证据,并要求 prepare/verify 显式传入 `--acknowledge-gate-side-effects`。
686
-
687
- push、tag、默认分支修改、GitHub Release 和 npm publish 不能放进 hook/gate,只能由冻结计划的受控动作执行。
688
-
689
- ## 当前不会做什么
690
-
691
- <!-- release-skill:capability:unsupported-scope -->
692
- - 不自动生成 README,不覆盖项目源文件;
693
- - 不自动合并冲突,也不要求回滚工作流;
694
- - 不声称已经替项目完成真实生产 canary;
695
- - `prepare --online` 只观察 bound 前序基线;目标唯一性由 publish 全局预检完成;
696
- - 不覆盖已有 branch/tag/Release,不 unpublish npm;
697
- - 不提供自动化 CodeBuddy/WorkBuddy marketplace 安装检查点——codebuddy CLI 无法钉死冻结 ref,安装为手动步骤,经与 Kimi Code 相同的可信证明闭环确认;
698
- - 不承诺 Windows 或广泛的跨平台原生写入;
699
- - 不会隐藏地 commit、push、打 tag、创建 Release 或发布包。
700
-
701
- ### 写入安全
702
-
703
- `setup` 默认只读,写入只允许精确摘要确认后首次创建配置。`assess` 默认只读。`prepare` 会在 `.release-skill/` 下写本地文件,但不会写项目源文件或远端服务。如果配置了 hook,它就是任意本地进程,必须使用 `--acknowledge-hook-side-effects` 明确授权;gate 同样需要 `--acknowledge-gate-side-effects`。
704
-
705
- `publish` 是唯一生产外写入口,必须同时提供 approval 和当前 plan digest。
706
-
707
- ### 失败时怎么办
708
-
709
- | 结果 | 下一步 |
710
- |---|---|
711
- | `NEEDS_INPUT` | 补齐 setup 列出的仓库、tag、渠道、基线和 gate 人工决策。 |
712
- | `LOCAL_ONLY_DETECTED` | 决定建立远端渠道或仅保留本地配置设计;不得冒充生产就绪。 |
713
- | `SETUP_DIGEST_MISMATCH` | 项目事实或 answers 已变化;重新 dry-run、审阅并确认新摘要。 |
714
- | `CONFIG_EXISTS` | setup 不覆盖已有配置;运行 assess 后人工增量修改。 |
715
- | `SAFE_WRITE_UNAVAILABLE` | 当前平台不支持自动 create-once;保留只读报告,由人工首次创建经审阅的配置。 |
716
- | `CONFIG_INVALID` | 修正 `.release-skill/project.yaml`,重新运行 `assess`。 |
717
- | `PUBLIC_FILE_MISSING` | 添加或修正配置中的公开文件。 |
718
- | `FORBIDDEN_CONTENT_DETECTED` | 移除泄漏或私有内容,再次 prepare。 |
719
- | `SNAPSHOT_FIDELITY_FAILED` | 检查源文件和快照路径,重新运行 `prepare`。 |
720
- | `BASELINE_CHANGED` | 保留人工修改,重新 prepare、审阅和 approve。 |
721
- | `prepare` 阶段 `GATE_FAILED` | 修复 snapshot gate 或冻结公开制品,再生成一份新 plan。 |
722
- | `verify` 阶段 `GATE_FAILED` | 若是消费者环境失败,修复环境后从同一 `PUBLISHED` run 重跑 verify;若是已发布制品缺陷,发布新的补丁版本。 |
723
- | `PARTIAL` | 不重跑整套发布、不删除远端;审阅返回的 `runPath` 并运行 `reconcile`。 |
724
- | `PUBLISHED` | 运行 `verify --plan <planPath> --run <publishRunPath>`;此时还不是终态。 |
725
- | `VERIFIED` | 远端状态、精确 npm 安装和插件消费者安装都与冻结计划一致。 |
402
+ hook 仅在人工审阅后、以 `--acknowledge-hook-side-effects` 显式授权后运行。gate 是发布校准的受控扩展点(见 `references/02-project-config.md`)。
726
403
 
727
404
  ## Skills
728
405
 
@@ -736,7 +413,7 @@ push、tag、默认分支修改、GitHub Release 和 npm publish 不能放进 ho
736
413
 
737
414
  ## 平台分发
738
415
 
739
- 同一个确定性核心引擎通过 build-only 适配器闭包分发到多个目标。发布单元用 `distributions` 声明要发布给谁;每种分发类型对应一个具体产物:
416
+ 同一个确定性核心引擎通过 build-only 适配器闭包分发到多个目标。发布单元用 `distributions` 声明要发布给谁:
740
417
 
741
418
  | `distributions` 类型 | 物理产物 | 安装方式 |
742
419
  |---|---|---|
@@ -744,9 +421,19 @@ push、tag、默认分支修改、GitHub Release 和 npm publish 不能放进 ho
744
421
  | `claude-plugin` | `adapters/claude/` 下的自包含闭包 | 自动化 marketplace 检查点 |
745
422
  | `codex-plugin` | `adapters/codex/` 下的自包含闭包 | 自动化 marketplace 检查点 |
746
423
  | `kimi-plugin` | 自包含闭包(无可脚本化安装接口) | 手动,需可信证明 |
747
- | `codebuddy-plugin` | 生成的 `adapters/workbuddy/`,带 `.codebuddy-plugin/plugin.json`(codebuddy CLI 无法钉死冻结 ref) | 手动,需可信证明 |
424
+ | `codebuddy-plugin` | 生成的 `adapters/workbuddy/`,带 `.codebuddy-plugin/plugin.json` | 手动,需可信证明 |
748
425
 
749
- 每个适配器闭包都自带一份 CLI bundle、skills 和 schemas 的副本,安装后无需外部依赖即可运行。Claude/Codex 的 marketplace 安装检查点是自动化的(preflight、execute、observe、verify);Kimi Code 检查点失败关闭,并产出版本钉死的手动安装要求;CodeBuddy/WorkBuddy 检查点同样失败关闭——因 codebuddy CLI 无法钉死冻结 ref 而无自动化安装检查点——并产出经绑定冻结计划摘要的可信证明确认的手动安装要求。
426
+ 每个适配器闭包都自带 CLI、skills 和 schemas 副本,安装后无需外部依赖即可运行。Claude/Codex 验证是自动化的;Kimi Code CodeBuddy/WorkBuddy 需要绑定冻结计划摘要的可信证明。
427
+
428
+ <!-- release-skill:capability:unsupported-scope -->
429
+ - 不自动生成 README,不覆盖项目源文件;
430
+ - 不自动合并冲突,也不要求回滚工作流;
431
+ - 不声称已经替项目完成真实生产 canary,不声称已完成真实插件市场验证;
432
+ - `prepare --online` 只观察 bound 前序基线;目标唯一性由 publish 全局预检完成;
433
+ - 不覆盖已有 branch/tag/Release,不 unpublish npm;
434
+ - 不提供自动化 CodeBuddy/WorkBuddy marketplace 安装检查点——codebuddy CLI 无法钉死冻结 ref,安装为手动步骤,经与 Kimi Code 相同的可信证明闭环确认;
435
+ - 不承诺 Windows 或广泛的跨平台原生写入;
436
+ - 不会隐藏地 commit、push、打 tag、创建 Release 或发布包。
750
437
 
751
438
  ## 许可证
752
439