release-skill 0.1.1 → 0.1.3

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 (60) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +2 -2
  4. package/CHANGELOG.md +60 -0
  5. package/INSTALL.md +179 -5
  6. package/INSTALL.zh-CN.md +320 -0
  7. package/README.md +347 -67
  8. package/README.zh-CN.md +318 -59
  9. package/adapters/claude/.claude-plugin/marketplace.json +1 -1
  10. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  11. package/adapters/claude/skills/release-help/SKILL.md +7 -4
  12. package/adapters/claude/skills/release-prepare/SKILL.md +11 -1
  13. package/adapters/claude/skills/release-publish/SKILL.md +6 -3
  14. package/adapters/claude/skills/release-reconcile/SKILL.md +1 -1
  15. package/adapters/claude/skills/release-setup/SKILL.md +111 -0
  16. package/adapters/claude/skills/release-verify/SKILL.md +5 -2
  17. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  18. package/adapters/codex/skills/release-help/SKILL.md +7 -4
  19. package/adapters/codex/skills/release-prepare/SKILL.md +11 -1
  20. package/adapters/codex/skills/release-publish/SKILL.md +6 -3
  21. package/adapters/codex/skills/release-reconcile/SKILL.md +1 -1
  22. package/adapters/codex/skills/release-setup/SKILL.md +111 -0
  23. package/adapters/codex/skills/release-verify/SKILL.md +5 -2
  24. package/bin/release-skill.mjs +65 -9
  25. package/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  26. package/native/safe-write/prebuilds.json +22 -2
  27. package/native/safe-write/src/safe_write.cc +11 -2
  28. package/package.json +3 -1
  29. package/references/02-project-config.md +54 -3
  30. package/references/05-evidence-and-errors.md +6 -2
  31. package/schemas/release-plan.schema.json +550 -65
  32. package/schemas/release-project.schema.json +398 -29
  33. package/schemas/release-run.schema.json +165 -18
  34. package/skills/release-help/SKILL.md +7 -4
  35. package/skills/release-prepare/SKILL.md +11 -1
  36. package/skills/release-publish/SKILL.md +6 -3
  37. package/skills/release-reconcile/SKILL.md +1 -1
  38. package/skills/release-setup/SKILL.md +111 -0
  39. package/skills/release-verify/SKILL.md +5 -2
  40. package/skills-src/release-help/SKILL.md +7 -4
  41. package/skills-src/release-prepare/SKILL.md +11 -1
  42. package/skills-src/release-publish/SKILL.md +6 -3
  43. package/skills-src/release-reconcile/SKILL.md +1 -1
  44. package/skills-src/release-setup/SKILL.md +111 -0
  45. package/skills-src/release-verify/SKILL.md +5 -2
  46. package/src/adapters/contract.mjs +3 -0
  47. package/src/adapters/git-github.mjs +84 -2
  48. package/src/adapters/plugin-marketplace.mjs +65 -21
  49. package/src/adapters/push-snapshot.mjs +84 -17
  50. package/src/commands/prepare.mjs +223 -20
  51. package/src/commands/publish.mjs +45 -0
  52. package/src/commands/reconcile.mjs +152 -0
  53. package/src/commands/setup.mjs +886 -0
  54. package/src/commands/verify.mjs +122 -26
  55. package/src/core/config.mjs +34 -0
  56. package/src/core/errors.mjs +4 -0
  57. package/src/core/plan.mjs +123 -0
  58. package/src/core/previous-public-baseline.mjs +21 -1
  59. package/src/core/verification-gates.mjs +451 -0
  60. package/src/snapshot/frozen.mjs +89 -5
package/README.zh-CN.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # release-skill
2
2
 
3
- [English](README.md)
3
+ [English](README.md) · 安装指南:[中文](INSTALL.zh-CN.md) / [English](INSTALL.md)
4
4
 
5
5
  面向 Claude Code 和 Codex 的发布准备工具,完整保留人工维护的文件内容。
6
6
 
@@ -9,23 +9,21 @@ release-skill 帮助维护者回答三个问题:准备发布什么、还有哪
9
9
  最后一步重新生成 README、重新打包活动工作区或覆盖人工内容。
10
10
 
11
11
  <!-- release-skill:capability:external-write-boundary -->
12
- > **当前边界:** `assess`、离线 `prepare`,以及冻结 Git branch/tag、GitHub
13
- > Release、npm tarball、Claude/Codex 插件市场消费者安装验证已通过生产等价协议沙箱:
14
- > 测试运行真实 release-skill CLI 和冻结制品,Git 目标是本地 bare remote,`gh`、
15
- > `npm`、Claude、Codex 是协议级 fake;另有隔离的本地探针调用已安装的
16
- > Claude/Codex CLI,但没有访问真实 marketplace 或生产 API。这些测试没有提供
17
- > OS 级网络隔离。我们尚未替你执行真实生产 canary;
18
- > 第一次真实发布仍应作为受监控 canary。真实 API、认证、权限、限流和最终一致性
19
- > 不属于该沙箱证明范围。`prepare --online` 观察前序公开基线(bound 模式),
20
- > 漂移或不可观察时失败关闭;远端唯一性检查延后到 `publish` 全局预检完成。
12
+ > **当前边界:** v0.1.1 已完成 GitHub 与 npm 的真实生产发布,并从冻结 Git ref
13
+ > 完成精确 npm 安装及 Claude/Codex 消费者安装验证。同一工作流还通过了本地
14
+ > 生产等价协议套件:测试运行真实 release-skill CLI 和冻结制品,Git 目标是本地
15
+ > bare remote,`gh`、`npm`、Claude、Codex 使用协议级 fake。该套件没有提供 OS 级
16
+ > 网络隔离,也不能证明其他项目的认证、权限、限流和最终一致性行为与本次发布相同;
17
+ > 每个项目的第一次生产发布仍应作为受监控 canary。`prepare --online` 观察 bound
18
+ > 前序公开基线,漂移或不可观察时失败关闭;远端唯一性检查在 `publish` 全局预检执行。
21
19
 
22
20
  <!-- release-skill:capability:safe-first-command -->
23
- > **v0.1.1 发布候选:** 在 `npm view release-skill version` 返回 `0.1.1` 前,
24
- > 使用下方源码 checkout 命令,不要假设 npm 命令已经存在。
21
+ > **v0.1.1 已完成真实生产发布与验证。** npm 安装的 CLI 是受支持的用户入口;
22
+ > 源码 checkout 保留为开发/贡献者路径。
25
23
  >
26
24
  > **第一条命令:**
27
- > - npm 已发布:`release-skill help`
28
- > - 当前发布候选:`node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" help`
25
+ > - npm 安装:`npm install -g release-skill` → `release-skill help`
26
+ > - 源码 checkout:`node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" help`
29
27
 
30
28
  <!-- release-skill:maturity:v0.1-boundary -->
31
29
  <!-- release-skill:maturity:boundary -->
@@ -60,11 +58,7 @@ release-skill 不重新生成、也不回写项目源文件。`prepare` 从当
60
58
  - Git 2.30+
61
59
  - 至少已有一个提交的目标 Git 仓库
62
60
 
63
- > **v0.1.1 发布候选:** 生产发布完成前,npm registry 可能返回 404,本轮审阅
64
- > 请使用下方源码 checkout。只有当 `npm view release-skill version` 返回 `0.1.1`
65
- > 后,npm 安装的 CLI 才是受支持的用户入口;源码 checkout 仅作为开发回退。
66
-
67
- **从 npm 安装(v0.1.1 发布后受支持):**
61
+ **从 npm 安装(推荐):**
68
62
 
69
63
  ```bash
70
64
  npm install -g release-skill
@@ -82,7 +76,7 @@ npx release-skill help
82
76
  release-skill help
83
77
  ```
84
78
 
85
- **开发安装(从源码 checkout):**
79
+ **开发安装(贡献者回退,从源码 checkout):**
86
80
 
87
81
  设置源码路径并安装依赖:
88
82
 
@@ -94,8 +88,6 @@ npm exec --yes pnpm@10.17.1 -- install --frozen-lockfile
94
88
 
95
89
  然后通过 `node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs"` 调用 CLI。
96
90
 
97
- 在目标项目创建 `.release-skill/project.yaml`:
98
-
99
91
  先保护本地运行数据,避免把计划、审批和冻结制品提交进仓库:
100
92
 
101
93
  ```gitignore
@@ -103,7 +95,135 @@ npm exec --yes pnpm@10.17.1 -- install --frozen-lockfile
103
95
  !.release-skill/project.yaml
104
96
  ```
105
97
 
106
- 然后创建配置;npm 的可见性必须显式选择,不能依赖工具猜测:
98
+ ### 首次接入:先发现,再由人工定稿
99
+
100
+ 项目尚无配置时,先运行只读 setup。它会扫描包、插件清单、Git remote、旧版
101
+ `public-release.json` 和质量脚本,列出发布单元、tag、分支、前序公开基线及验证
102
+ gate 候选,但不会读取 README 正文作为指令,也不会自动选择或执行脚本:
103
+
104
+ ```bash
105
+ release-skill setup --root /absolute/path/to/my-project --json
106
+ ```
107
+
108
+ `NEEDS_INPUT` 和 `LOCAL_ONLY_DETECTED` 会按设计返回退出码 2:它们表示仍需人工决策,
109
+ 不是内部崩溃。自动化应读取 JSON 的 `status`,不要把 setup 的所有非零退出码都当作
110
+ 工具故障。
111
+
112
+ 审阅候选后,人工创建 answers JSON,其中 `projectConfig` 是完整配置,
113
+ `selectedGateIds` 与其中 `verificationGates[].id` 必须精确一致;不需要个性化 gate
114
+ 时显式使用空数组。带 answers 再 dry-run 一次,确认它绑定的新 `setupDigest`,最后
115
+ 才允许首次创建配置:
116
+
117
+ ```json
118
+ {
119
+ "projectConfig": {
120
+ "apiVersion": "release-skill/v1",
121
+ "kind": "ReleaseProject",
122
+ "project": { "name": "my-project", "defaultBranch": "main" },
123
+ "releaseUnits": [{
124
+ "id": "my-project",
125
+ "source": ".",
126
+ "publicRepo": "owner/my-project",
127
+ "version": { "source": "package.json", "tagTemplate": "v{version}" },
128
+ "distributions": [{
129
+ "type": "npm",
130
+ "package": "my-project",
131
+ "access": "public",
132
+ "provenance": false,
133
+ "tag": "latest",
134
+ "registry": "https://registry.npmjs.org",
135
+ "publisher": "my-npm-username"
136
+ }],
137
+ "publicFiles": [
138
+ { "from": "README.md", "to": "README.md", "mode": "preserve" },
139
+ { "from": "package.json", "to": "package.json", "mode": "preserve" }
140
+ ],
141
+ "requiredPublicFiles": ["README.md", "package.json"],
142
+ "previousPublicBaseline": { "mode": "none" },
143
+ "production": {
144
+ "branchTemplate": "release/{tag}",
145
+ "branchStrategy": "create-release-branch"
146
+ }
147
+ }]
148
+ },
149
+ "selectedGateIds": []
150
+ }
151
+ ```
152
+
153
+ 这是完整的 schema 形状,不是项目事实的权威答案。仓库、渠道、基线与公开文件
154
+ 都必须替换为本项目经审阅的事实;只有确认不存在任何历史公开版本时才可使用
155
+ `mode: none`。
156
+
157
+ 如果要选择一个 dry-run 已报告的 gate,保留同一份完整 `projectConfig`,在其中增加
158
+ 顶层 `verificationGates`,并让外层 `selectedGateIds` 完全一致。例如 dry-run 已
159
+ 报告 `my-project-script-test` 时:
160
+
161
+ ```json
162
+ {
163
+ "projectConfig": {
164
+ "apiVersion": "release-skill/v1",
165
+ "kind": "ReleaseProject",
166
+ "project": { "name": "my-project", "defaultBranch": "main" },
167
+ "releaseUnits": [{
168
+ "id": "my-project",
169
+ "source": ".",
170
+ "publicRepo": "owner/my-project",
171
+ "version": { "source": "package.json", "tagTemplate": "v{version}" },
172
+ "distributions": [{
173
+ "type": "npm",
174
+ "package": "my-project",
175
+ "access": "public",
176
+ "provenance": false,
177
+ "tag": "latest",
178
+ "registry": "https://registry.npmjs.org",
179
+ "publisher": "my-npm-username"
180
+ }],
181
+ "publicFiles": [
182
+ { "from": "package.json", "to": "package.json", "mode": "preserve" }
183
+ ],
184
+ "requiredPublicFiles": ["package.json"],
185
+ "previousPublicBaseline": { "mode": "none" },
186
+ "production": {
187
+ "branchTemplate": "release/{tag}",
188
+ "branchStrategy": "create-release-branch"
189
+ }
190
+ }],
191
+ "verificationGates": [{
192
+ "id": "my-project-script-test",
193
+ "phase": "snapshot-verify",
194
+ "scope": { "unit": "my-project" },
195
+ "command": ["node", "-e", "const p=require('./package.json');if(!p.name)process.exit(1)"],
196
+ "cwd": ".",
197
+ "timeoutMs": 30000,
198
+ "envAllowlist": []
199
+ }]
200
+ },
201
+ "selectedGateIds": ["my-project-script-test"]
202
+ }
203
+ ```
204
+
205
+ id 必须复制自当前 `gateCandidates`,不得自创。示例命令只依赖公开快照中的
206
+ `package.json`。如果改用项目脚本,该脚本及其全部依赖必须包含在 `publicFiles` 中;
207
+ snapshot gate 看不到父工作空间的测试、开发依赖或 `node_modules`,除非它们本来就是
208
+ 显式公开内容。
209
+
210
+ ```bash
211
+ release-skill setup --root /absolute/path/to/my-project \
212
+ --answers /absolute/path/to/setup-answers.json --json
213
+ release-skill setup --root /absolute/path/to/my-project \
214
+ --answers /absolute/path/to/setup-answers.json \
215
+ --write --confirm-setup <setupDigest> --json
216
+ ```
217
+
218
+ setup 只会原子创建不存在的 `.release-skill/project.yaml`。v0.1.3 的 create-once
219
+ 写入使用随包提供、带摘要登记的 `darwin-arm64` 原生预构建;
220
+ 不支持的平台会以 `SAFE_WRITE_UNAVAILABLE` 失败关闭,不会退回存在路径竞态的写法。
221
+ 已有配置返回 `ALREADY_CONFIGURED`/`CONFIG_EXISTS`,后续由人工增量编辑;README、slogan、
222
+ CHANGELOG 和业务脚本不会被生成或覆盖。没有远端渠道时会返回
223
+ `LOCAL_ONLY_DETECTED`,表示生产渠道仍需人工建立或明确放弃。
224
+
225
+ 下面是人工配置的最小示例;npm 可见性、公开文件边界和远端目标必须显式选择,
226
+ 不能依赖工具猜测:
107
227
 
108
228
  ```yaml
109
229
  apiVersion: release-skill/v1
@@ -151,6 +271,7 @@ releaseUnits:
151
271
  # status: READY
152
272
  production:
153
273
  branchTemplate: release/{tag}
274
+ branchStrategy: create-release-branch
154
275
  releaseTitleTemplate: "{unit} {version}"
155
276
  releaseNotes: "人工维护的发布说明"
156
277
  ```
@@ -177,6 +298,55 @@ diff unavailable。发生漂移时先停止发布,由人工取得并审阅真
177
298
  把 `previousPublicBaseline` 重新绑定到人工接受的不可变 `repo`/`ref`/`commit`,再运行
178
299
  新的 `prepare --online --production`、审阅和 approve。
179
300
 
301
+ 分支策略也必须符合真实仓库语义:
302
+
303
+ - `create-release-branch`:创建不存在的独立发布分支;同名分支存在即停止。
304
+ - `advance-existing-branch`:在 `previousPublicBaseline` 精确提交上创建单父提交,
305
+ 只允许普通 fast-forward push;远端并发漂移时交由人工。
306
+ - `initialize-default-branch`:受控创建不存在的标准分支;只有显式配置
307
+ `setAsDefaultBranch` 和 `expectedCurrentDefaultBranch` 时,默认分支切换才成为
308
+ 计划中可批准、可观察、可 reconcile 的独立动作。
309
+
310
+ 三种策略的最小配置如下:
311
+
312
+ ```yaml
313
+ # 新建不可变 release 分支;目标必须不存在。
314
+ previousPublicBaseline: { mode: none } # 仅限真正的首次公开发布
315
+ production:
316
+ branchTemplate: release/{tag}
317
+ branchStrategy: create-release-branch
318
+ ```
319
+
320
+ ```yaml
321
+ # 推进 main;绑定的 ref 必须与目标分支精确一致。
322
+ previousPublicBaseline:
323
+ mode: bound
324
+ repo: owner/my-project
325
+ ref: refs/heads/main
326
+ commit: 0123456789abcdef0123456789abcdef01234567
327
+ production:
328
+ branchTemplate: main
329
+ branchStrategy: advance-existing-branch
330
+ ```
331
+
332
+ ```yaml
333
+ # 一次性创建尚不存在的 main,并显式切换默认分支。
334
+ previousPublicBaseline:
335
+ mode: bound
336
+ repo: owner/my-project
337
+ ref: refs/heads/old-public-branch
338
+ commit: 0123456789abcdef0123456789abcdef01234567
339
+ production:
340
+ branchTemplate: main
341
+ branchStrategy: initialize-default-branch
342
+ setAsDefaultBranch: true
343
+ expectedCurrentDefaultBranch: old-public-branch
344
+ ```
345
+
346
+ 后两种策略必须运行 `prepare --online --production`。如果观察到的分支、commit、
347
+ 目标不存在性或当前默认分支与预期不符,先停止并审阅真实远端状态,再人工更新权威
348
+ 源文件/配置;禁止 force push 或弱化基线。
349
+
180
350
  这只是解释机制的本地示例,不是完整的 npm 发布清单。真实发布前必须枚举全部
181
351
  公开运行时代码、可执行文件、类型声明、图片和链接文档。monorepo 应把 `source`
182
352
  设为 `packages/my-plugin` 之类的子目录;每个 `from` 仍相对工作空间根,例如
@@ -188,47 +358,68 @@ diff unavailable。发生漂移时先停止发布,由人工取得并审阅真
188
358
 
189
359
  ### 主流程
190
360
 
191
- 按以下顺序执行。步骤 1–3 是安全默认(只读或仅本地);步骤 48 是需要显式
361
+ 按以下顺序执行。步骤 1–4 是安全默认(只读或仅本地);步骤 59 是需要显式
192
362
  人工门禁的生产发布。
193
363
 
194
364
  ```bash
195
- # 当前 v0.1.1 发布候选:
196
- CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
365
+ # npm 安装的 CLI(推荐):
366
+ CLI=(release-skill)
197
367
  PROJECT=/absolute/path/to/my-project
198
- # npm view 已返回 0.1.1 且安装完成后:
199
- # CLI=(release-skill)
368
+ ACTOR=your-name
369
+ # 开发回退(源码 checkout):
370
+ # CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
200
371
  ```
201
372
 
202
- npm 生产发布验证完成前,源码 checkout 是候选默认入口;发布验证完成后,
203
- npm 安装入口才是受支持的用户默认路径。
373
+ v0.1.1 生产发布验证完成后,npm 安装的 CLI 是受支持的用户入口;
374
+ 源码 checkout 保留为开发/贡献者路径。
204
375
 
205
376
  1. **环境检查:**
206
377
  ```bash
207
378
  "${CLI[@]}" help
208
379
  ```
209
- 2. **就绪评估(只读):**
380
+ 2. **首次接入(仅缺少配置时,只读):**
381
+ ```bash
382
+ "${CLI[@]}" setup --root "$PROJECT" --json
383
+ ```
384
+ 按上文完成 answers 和精确 `setupDigest` 确认;配置已存在时跳过。
385
+ 3. **就绪评估(只读):**
210
386
  ```bash
211
387
  "${CLI[@]}" assess --root "$PROJECT" --offline --json
212
388
  ```
213
- 3. **本地快照与计划冻结:**
389
+ 4. **本地快照与计划冻结:**
214
390
  ```bash
215
- "${CLI[@]}" prepare --root "$PROJECT" --offline --json
391
+ "${CLI[@]}" prepare --root "$PROJECT" --offline \
392
+ --acknowledge-hook-side-effects \
393
+ --acknowledge-gate-side-effects --json
216
394
  ```
217
- 4. **人工审阅:** 检查返回的 `planPath`、`externalActions`、
395
+ 只有项目配置没有对应 hook snapshot gate 时,才省略相应授权参数。授权前
396
+ 必须审阅可执行文件、参数、工作目录和副作用,不能把授权参数当固定样板。
397
+ 5. **人工审阅:** 检查返回的 `planPath`、`externalActions`、
218
398
  `units[].targetVersion` 和 `planDigest`。每个发布单元的快照位于
219
- `<evidenceDir>/snapshots/<unit-id>/`。命令只在 `.release-skill/` 下写入本地数据。
220
- 5. **生产计划冻结:**
399
+ `<evidenceDir>/snapshots/<unit-id>/`。release-skill 自身只把数据写入
400
+ `.release-skill/`;获得授权的项目 hook/gate 是无沙箱进程,可能写入其他位置或
401
+ 访问网络。
402
+ 6. **生产计划冻结:**
221
403
  ```bash
222
- "${CLI[@]}" prepare --root "$PROJECT" --online --production --json
404
+ PRODUCTION_JSON=$("${CLI[@]}" prepare --root "$PROJECT" --online --production \
405
+ --acknowledge-hook-side-effects \
406
+ --acknowledge-gate-side-effects --json)
407
+ printf '%s\n' "$PRODUCTION_JSON" | jq .
408
+ PLAN_PATH=$(printf '%s\n' "$PRODUCTION_JSON" | jq -r '.planPath')
409
+ PLAN_DIGEST=$(printf '%s\n' "$PRODUCTION_JSON" | jq -r '.planDigest')
223
410
  ```
411
+ 同样,只省略配置不需要的授权,并在授权前逐项审阅项目进程。
224
412
  审阅新 plan 的 externalActions、npm access/provenance/tag、branch/tag 和冻结摘要。
225
413
  `prepare --json` 返回的生产权威 `planPath` 指向
226
414
  `<项目>/.release-skill/plans/<planDigest>.json`,后续必须始终沿用这个返回值。
227
415
  `.release-skill/release-plan.json` 只是可变便利副本,不得传给生产
228
416
  approve/publish/reconcile。
229
- 6. **批准:**
417
+ 7. **批准:**
230
418
  ```bash
231
- "${CLI[@]}" approve --plan <planPath> --digest <planDigest> --actor <name> --json
419
+ APPROVAL_JSON=$("${CLI[@]}" approve --plan "$PLAN_PATH" \
420
+ --digest "$PLAN_DIGEST" --actor "$ACTOR" --json)
421
+ printf '%s\n' "$APPROVAL_JSON" | jq .
422
+ APPROVAL_PATH=$(printf '%s\n' "$APPROVAL_JSON" | jq -r '.approvalPath')
232
423
  ```
233
424
  返回的生产权威 `approvalPath` 指向
234
425
  `<项目>/.release-skill/approvals/<planDigest>/<approvalDigest>.json`。
@@ -236,22 +427,30 @@ npm 安装入口才是受支持的用户默认路径。
236
427
  副本,不得传给生产 publish/reconcile。批准 24 小时失效;PARTIAL 恢复可为同一
237
428
  plan 重新批准,同时逐字节保留全部旧批准。后续必须使用返回的 immutable
238
429
  `approvalPath` 和 `expiresAt`。
239
- 7. **发布(从此开始写远端):**
430
+ 8. **发布(从此开始写远端):**
240
431
  ```bash
241
- "${CLI[@]}" publish --root "$PROJECT" \
242
- --plan <planPath> --approval <approvalPath> \
243
- --confirm-production <planDigest> --json
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')
244
437
  ```
245
438
  保存返回的 `runPath`。`PUBLISHED` **不是**终态。
246
- 8. **验证(消费者安装检查):**
439
+ 9. **验证(消费者安装检查):**
247
440
  ```bash
248
441
  "${CLI[@]}" verify --root "$PROJECT" \
249
- --plan <planPath> --run <publishRunPath> --json
442
+ --plan "$PLAN_PATH" --run "$PUBLISH_RUN_PATH" \
443
+ --acknowledge-gate-side-effects --json
250
444
  ```
445
+ 只有计划既没有 consumer gate,也没有 npm `smokeBin` 时才省略授权。两者都会
446
+ 执行已安装的项目代码,而且没有操作系统或网络沙箱。
447
+
448
+ 以上返回值交接示例依赖 `jq`。没有 `jq` 时必须从 JSON 原样复制这四个字段;不要把
449
+ 文档其他位置的尖括号标签直接当作 shell 语法。
251
450
 
252
451
  生产 prepare 会把每个公开快照封存为独立 Git commit/tree,并为 npm 单元生成固定
253
452
  tarball。`publish` 先对所有动作做只读预检,再按“公开快照 branch → tag → npm →
254
- GitHub Release → Claude/Codex marketplace 安装”执行并逐项观察。`verify` 在隔离目录
453
+ GitHub Release → Claude/Codex 插件市场(marketplace)安装”执行并逐项观察。`verify` 在隔离目录
255
454
  安装每一个精确 npm `package@version`;配置 `smokeBin` 后还会运行 CLI 并校验输出。
256
455
  只有全部证据与冻结计划一致才进入 `VERIFIED`。真实发布前运行 `gh auth login`、
257
456
  `gh auth setup-git` 和 `npm login`,同时确认 Git HTTPS credential 能访问目标仓库。
@@ -382,17 +581,23 @@ unpublish 已发布的包)。
382
581
  使用 `reconcile` 检查实际远端状态,跳过已一致的步骤,安全重试未完成的动作:
383
582
 
384
583
  ```bash
385
- "${CLI[@]}" reconcile --root "$PROJECT" \
386
- --run <publishRunPath> \
387
- --plan <planPath> \
388
- --approval <approvalPath> \
389
- --confirm-production <planDigest> \
390
- --json
584
+ RECONCILE_JSON=$("${CLI[@]}" reconcile --root "$PROJECT" \
585
+ --run "$PUBLISH_RUN_PATH" \
586
+ --plan "$PLAN_PATH" \
587
+ --approval "$APPROVAL_PATH" \
588
+ --confirm-production "$PLAN_DIGEST" --json)
589
+ printf '%s\n' "$RECONCILE_JSON" | jq .
590
+ RECONCILE_RUN_PATH=$(printf '%s\n' "$RECONCILE_JSON" | jq -r '.runPath')
391
591
  # 保存 reconcile 返回的新 runPath,再执行全新的安装验证。
392
592
  "${CLI[@]}" verify --root "$PROJECT" \
393
- --plan <planPath> --run <reconcileRunPath> --json
593
+ --plan "$PLAN_PATH" --run "$RECONCILE_RUN_PATH" \
594
+ --acknowledge-gate-side-effects --json
394
595
  ```
395
596
 
597
+ 只有冻结计划既没有 consumer gate,也没有 npm `smokeBin` 时才省略 verify 授权。
598
+ 以上变量沿用主流程从 JSON 提取的精确值;如果恢复期间批准已过期,应为同一个不可变
599
+ 计划重新批准,并在 reconcile 前替换 `APPROVAL_PATH`。
600
+
396
601
  `reconcile` 查询实际远端状态(Git refs、npm 版本、GitHub Release、
397
602
  marketplace 安装),跳过证据已匹配冻结计划的步骤,只重试安全且未完成的
398
603
  步骤。远端冲突(例如意外的 tag 或 npm 版本)需要人工判断,无法自动解决。
@@ -404,6 +609,8 @@ reconcile 成功只返回 `PUBLISHED`,不会返回 `VERIFIED`;只有全新
404
609
  - 验证项目配置和发布单元;
405
610
  - `assess` 在不修改项目的前提下报告就绪度;
406
611
  - 把配置的公开文件复制到隔离快照;
612
+ - 只读发现首次接入候选,经精确 `setupDigest` 确认后仅首次创建配置;
613
+ - 在冻结快照副本和精确消费者安装根运行经人工选择的项目 gate;
407
614
  - 检查必需文件、路径安全、精确字节/权限和明显泄漏;
408
615
  - 记录 Git/工作区身份,冻结绑定 digest 的发布计划;
409
616
  - 用计划摘要、有效期和显式 action allowlist 绑定人工批准;
@@ -412,6 +619,47 @@ reconcile 成功只返回 `PUBLISHED`,不会返回 `VERIFIED`;只有全新
412
619
  - 明确区分 `PUBLISHED`(外写完成)与 `VERIFIED`(远端和消费者安装证据完成);
413
620
  - 中途失败停止后续动作,记录独立 run;不修改冻结 plan,不自动撤销已成功动作。
414
621
 
622
+ ## 个性化验证:hook 与 gate
623
+
624
+ `hooks.docs/build/test/typecheck/lint` 在冻结前运行,适合确实需要生成源文件或依赖
625
+ 父工作区的步骤。它们可能修改项目或访问网络,prepare 必须显式传入
626
+ `--acknowledge-hook-side-effects`。
627
+
628
+ `verificationGates` 是更适合发布校准的受控扩展点:
629
+
630
+ ```yaml
631
+ verificationGates:
632
+ - id: package-contract
633
+ phase: snapshot-verify
634
+ scope: { unit: my-project }
635
+ command:
636
+ - node
637
+ - -e
638
+ - "const p=require('./package.json'); if (!p.name) process.exit(1)"
639
+ cwd: .
640
+ timeoutMs: 120000
641
+ envAllowlist: [CI]
642
+ - id: installed-help
643
+ phase: consumer-verify
644
+ scope: { unit: my-project, distribution: npm }
645
+ command: [node, scripts/check-installed-help.mjs]
646
+ cwd: .
647
+ timeoutMs: 30000
648
+ envAllowlist: []
649
+ expectedJson: { status: READY }
650
+ ```
651
+
652
+ snapshot 示例刻意设计为自包含,只读取已映射的公开文件。若替换成项目脚本,该脚本
653
+ 及其全部依赖必须存在于冻结公开快照;consumer 脚本也必须存在于精确安装的发行物。
654
+ gate 不能借用父工作空间中的测试、开发依赖或 `node_modules`。
655
+
656
+ `snapshot-verify` 在冻结公开快照的一次性可写副本中执行;`consumer-verify` 在精确
657
+ npm/Claude/Codex 隔离安装根执行。两者都使用命令数组而非 shell 字符串,定义和
658
+ 结果会进入摘要证据,并要求 prepare/verify 显式传入
659
+ `--acknowledge-gate-side-effects`。gate 仍是无网络沙箱的项目进程,release-skill
660
+ 无法保证它不会写文件或访问网络。push、tag、默认分支切换、GitHub Release 和
661
+ npm publish 不能放进 hook/gate,只能由冻结计划的受控动作执行。
662
+
415
663
  ## 当前不会做什么
416
664
 
417
665
  <!-- release-skill:capability:unsupported-scope -->
@@ -420,28 +668,38 @@ reconcile 成功只返回 `PUBLISHED`,不会返回 `VERIFIED`;只有全新
420
668
  - 不声称已经替项目完成真实生产 canary;
421
669
  - `prepare --online` 只观察 bound 前序基线的 ref→commit 映射;目标唯一性由
422
670
  publish 全局预检完成;
423
- - force push,不覆盖已有 branch/tag/Release,不 unpublish npm
671
+ - 不覆盖已有 branch/tag/Release,不 unpublish npm;新建 ref 仅使用
672
+ `--force-with-lease=<ref>:` 作为“目标必须不存在”的原子比较并设置断言,推进已有
673
+ 分支使用普通非 force push;
424
674
  - 不承诺 Windows 或广泛的跨平台原生写入;
425
675
  - 不会隐藏地 commit、push、打 tag、创建 Release 或发布包。
426
676
 
427
677
  ### 写入安全
428
678
 
429
- `assess` 默认只读,只有显式指定报告输出时才写报告。`prepare` 会在
679
+ `setup` 默认只读,写入只允许精确摘要确认后首次创建配置。`assess` 默认只读,
680
+ 只有显式指定报告输出时才写报告。`prepare` 会在
430
681
  `.release-skill/` 下写本地文件,但不会写项目源文件或远端服务。如果配置了
431
682
  hook,它就是任意本地进程,必须使用 `--acknowledge-hook-side-effects` 明确授权;
432
- hook 可能自行产生文件系统或网络副作用。`publish` 是唯一生产外写入口,必须同时
683
+ gate 同样是项目进程,必须使用 `--acknowledge-gate-side-effects` 明确授权。它们
684
+ 可能自行产生文件系统或网络副作用。`publish` 是唯一生产外写入口,必须同时
433
685
  提供 approval 和当前 plan digest。最小安全演练应省略 hook,并在本地沙箱目标运行。
434
686
 
435
687
  ### 失败时怎么办
436
688
 
437
689
  | 结果 | 下一步 |
438
690
  |---|---|
691
+ | `NEEDS_INPUT` | 补齐 setup 列出的仓库、tag、渠道、基线和 gate 人工决策。 |
692
+ | `LOCAL_ONLY_DETECTED` | 决定建立远端渠道或仅保留本地配置设计;不得冒充生产就绪。 |
693
+ | `SETUP_DIGEST_MISMATCH` | 项目事实或 answers 已变化;重新 dry-run、审阅并确认新摘要。 |
694
+ | `CONFIG_EXISTS` | setup 不覆盖已有配置;运行 assess 后人工增量修改。 |
695
+ | `SAFE_WRITE_UNAVAILABLE` | 当前平台不支持自动 create-once;保留只读报告,由人工首次创建经审阅的配置,且不得覆盖已有文件。 |
439
696
  | `CONFIG_INVALID` | 修正 `.release-skill/project.yaml`,重新运行 `assess`。 |
440
697
  | `PUBLIC_FILE_MISSING` | 添加或修正配置中的公开文件。 |
441
698
  | `FORBIDDEN_CONTENT_DETECTED` | 移除泄漏或私有内容,再次 prepare。 |
442
699
  | `SNAPSHOT_FIDELITY_FAILED` | 检查源文件和快照路径,重新运行 `prepare`。 |
443
700
  | `BASELINE_CHANGED` | 保留人工修改,重新 prepare、审阅和 approve。 |
444
- | `GATE_FAILED` | 检查冻结制品、认证、远端唯一性或生产摘要确认。 |
701
+ | `prepare` 阶段 `GATE_FAILED` | 修复 snapshot gate 或冻结公开制品,再生成一份新 plan;失败 plan 不得批准。 |
702
+ | `verify` 阶段 `GATE_FAILED` | 若是消费者环境失败,修复环境后从同一 `PUBLISHED` run 重跑 verify;若是已发布制品缺陷,发布新的补丁版本,不覆盖旧制品。 |
445
703
  | `PARTIAL` | 不重跑整套发布、不删除远端;审阅返回的 `runPath` 并运行 `reconcile`(见上文)。 |
446
704
  | `PUBLISHED` | 运行 `verify --plan <planPath> --run <publishRunPath>`;此时还不是终态。 |
447
705
  | `VERIFIED` | 远端状态、精确 npm 安装和插件消费者安装都与冻结计划一致。 |
@@ -449,14 +707,15 @@ hook 可能自行产生文件系统或网络副作用。`publish` 是唯一生
449
707
  ## Skills
450
708
 
451
709
  - `release-help`:环境检查和下一步引导。
710
+ - `release-setup`:首次接入的只读发现、人工校准和 create-once 配置创建。
452
711
  - `release-assess`:只读发布就绪度报告。
453
712
  - `release-prepare`:本地快照和可审阅发布计划。
454
713
  - `release-publish`:经批准、摘要确认的冻结 GitHub+npm 发布。
455
714
  - `release-reconcile`:基于证据恢复 PARTIAL;冲突时人工介入。
456
715
  - `release-verify`:发布后验证;只有 `VERIFIED` 才是 happy end。
457
716
 
458
- 冲突默认仍由人工介入。v0.1.1 发布前使用上面的源码 CLI;registry 验证通过后,
459
- 受支持的用户入口是 npm 安装的 `release-skill` CLI
717
+ 冲突默认仍由人工介入。v0.1.1 生产发布后,受支持的用户入口是 npm 安装的
718
+ `release-skill` CLI;源码 checkout 保留为开发/贡献者路径。
460
719
 
461
720
  ## 许可证
462
721
 
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "release-skill",
11
11
  "source": "./",
12
- "version": "0.1.1",
12
+ "version": "0.1.3",
13
13
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification"
14
14
  }
15
15
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "release-skill contributors"
@@ -12,21 +12,21 @@ description: "Discoverable entry point for release-skill: dependency and environ
12
12
  ## 职责
13
13
 
14
14
  - 依赖和环境检查:Node.js >= 22、Git 决定本地准备就绪度;npm/gh 另行决定生产依赖就绪度
15
- - 能力说明:安全默认路径是 `help → assess → prepare --offline`;已有公开版本的生产闭环是显式的 `prepare --online --production → approve → publish → verify`
15
+ - 能力说明:缺少配置时走 `help → setup → assess`;已有配置的安全默认路径是 `help assess → prepare --offline`;已有公开版本的生产闭环是显式的 `prepare --online --production → approve → publish → verify`
16
16
  - 最小示例:展示从 release-help 到 release-assess 的最短路径
17
17
  - 只读诊断:运行 dry-run 检查,不修改任何文件
18
18
  - 故障引导:根据错误码指向对应的修复 Skill
19
19
 
20
20
  **阶段通过规则**: `status` 与 `readiness.localPreparation.status` 只判断本地 help/assess/prepare;其充要条件是 `READY` 且 exit code 为 0。`missingRequired` 列出缺失的 Node/Git。生产发布必须另外读取 `readiness.productionPublish`:缺少 npm/gh 时为 `NOT_READY`,依赖存在时仍是 `AUTH_CHECK_REQUIRED`,因为 help 不访问网络、不验证认证。Agent 无权把本地就绪解释为生产就绪。
21
21
 
22
- **边界**: help 不修改文件系统、不执行外部写操作、不生成发布计划。优先探测 PATH 上的全局安装命令 `release-skill`,不可用时回退到源码路径。每个 unit 必须配置 `previousPublicBaseline`:首次发布且确认无前序版本用 none,已有版本用 bound + repo/ref/commit;none 不是绕过 publish 唯一性预检的开关。GitHub/npmClaude/Codex marketplace 隔离安装、精确 npm 安装 smoke 与最终 VERIFIED 已通过真实 release-skill CLI + 本地 bare Git + fake gh/npm/Claude/Codex 的生产等价协议沙箱;另有隔离的已安装消费者 CLI 探针。测试未做 OS 级禁网,也未访问真实 marketplace;真实认证/API canary 尚未执行。
22
+ **边界**: help 不修改文件系统、不执行外部写操作、不生成发布计划。优先探测 PATH 上的全局安装命令 `release-skill`,不可用时回退到源码路径。每个 unit 必须配置 `previousPublicBaseline`:首次发布且确认无前序版本用 none,已有版本用 bound + repo/ref/commit;none 不是绕过 publish 唯一性预检的开关。v0.1.1 已完成 GitHub/npm 真实生产发布、冻结 Git ref 的 Claude/Codex 消费者安装、精确 npm 安装 smoke 与最终 VERIFIED;生产等价本地协议套件继续覆盖 fake gh/npm/Claude/Codex 和本地 bare Git。测试未做 OS 级禁网,且一次成功发布不能证明其他项目的认证、权限、限流或最终一致性行为;每个项目的首次生产发布仍应作为受监控 canary
23
23
 
24
24
  ## 正向执行路径
25
25
 
26
26
  1. 若 `npm view release-skill version` 已返回当前支持版本,探测 PATH 全局安装并运行 `release-skill help --json`
27
27
  2. registry 尚未发布当前版本或 PATH 不可用时,回退到源码路径:设置 `RELEASE_SKILL_HOME` 并运行 `node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" help --json`
28
28
  3. 检查 `readiness.localPreparation`;需要生产发布时再检查 `readiness.productionPublish`
29
- 4. 若环境就绪,运行 `release-assess` 识别项目拓扑
29
+ 4. 若环境就绪且缺少 `.release-skill/project.yaml`,先路由 `release-setup`;配置已存在才运行 `release-assess`
30
30
  5. 默认在审阅本地计划和快照后停止;只有用户明确要求且完成摘要审批时才路由到 `release-publish`
31
31
 
32
32
  ## 确定性脚本调用
@@ -34,11 +34,13 @@ description: "Discoverable entry point for release-skill: dependency and environ
34
34
  ```bash
35
35
  # 已确认 registry 存在当前版本后,从 npm 全局安装(推荐)
36
36
  release-skill help --json # PATH 全局安装
37
+ release-skill setup --root <path> --json # 首次接入,只读发现
37
38
  release-skill assess --root <path> --offline --json # PATH 全局安装
38
39
 
39
40
  # 从源码 checkout 运行
40
41
  RELEASE_SKILL_HOME=/path/to/release-skill
41
42
  node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" help --json
43
+ node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" setup --root <path> --json
42
44
  node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" assess --root <path> --offline --json
43
45
  ```
44
46
 
@@ -51,7 +53,8 @@ node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs" assess -
51
53
  | pnpm 未安装 | 不影响本地准备;仅出现在 recommendations 中 |
52
54
  | npm/gh 未安装 | 本地准备仍可就绪,但 `readiness.productionPublish.status` 为 `NOT_READY` |
53
55
  | npm/gh 已安装 | 生产状态仍为 `AUTH_CHECK_REQUIRED`;发布前验证 `gh auth`、Git HTTPS credential 和 npm auth |
54
- | CLI 入口不存在 | 先检查 registry 是否已有当前支持版本;存在则安装 `npm install -g release-skill`,尚未发布则设置 `RELEASE_SKILL_HOME` 使用源码路径 |
56
+ | CLI 入口不存在 | 安装 `npm install -g release-skill`;无法使用 npm 时设置 `RELEASE_SKILL_HOME` 使用源码路径 |
57
+ | 项目配置不存在 | 路由 `release-setup`,默认只读;不得直接生成或覆盖 README/配置 |
55
58
  | assess 失败 | 运行 `node "$RELEASE_SKILL_HOME/..." assess --offline --json` 获取详情 |
56
59
  | 请求生产发布 | 已有公开版本先调用 `release-prepare --online --production` 观察 bound 基线;人工审阅后再路由 `release-publish` |
57
60