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
@@ -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"
@@ -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"
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "defaultPrompt": [
21
21
  "Assess this project for release readiness.",
22
- "Prepare a release plan for version 0.1.1.",
22
+ "Prepare a release plan for version 0.1.3.",
23
23
  "Help me understand the release workflow."
24
24
  ]
25
25
  }
package/CHANGELOG.md CHANGED
@@ -3,6 +3,66 @@
3
3
  All notable changes to the `release-skill` plugin will be documented in this
4
4
  file. The format is based on [Keep a Changelog](https://keepachangelog.com/).
5
5
 
6
+ ## [0.1.3] - 2026-07-19
7
+
8
+ > `0.1.2` was an internal release candidate and was never published to npm or
9
+ > GitHub Releases. Its fixes are included here; `0.1.3` is the next public
10
+ > release after `0.1.1`.
11
+
12
+ ### Added
13
+
14
+ - **Create-once first-use setup**: `release-skill setup` performs deterministic,
15
+ read-only discovery of packages, plugin manifests, Git remotes, legacy
16
+ `public-release.json`, public-file hints, and project quality scripts. It
17
+ reports `NEEDS_INPUT` or `LOCAL_ONLY_DETECTED` honestly and writes only an
18
+ absent `.release-skill/project.yaml` after answers and the exact
19
+ `setupDigest` are confirmed.
20
+ - **Discoverable `release-setup` skill**: Claude and Codex adapters now guide
21
+ users through candidate review, explicit gate selection, fact-drift handling,
22
+ and the safe handoff to `release-assess` without regenerating human content.
23
+ - **Project verification gates**: `snapshot-verify` runs selected commands in a
24
+ disposable writable copy of the frozen public snapshot;
25
+ `consumer-verify` runs after an exact isolated npm/Claude/Codex installation.
26
+ Gate definitions, exact execution-input digests, and bounded output digests
27
+ are frozen into plan/run evidence.
28
+ - **Identity-bound create-once setup**: the final facts/answers digest and
29
+ config bytes are bound immediately before a directory-handle-relative,
30
+ no-follow create. v0.1.3 ships a digest-registered `darwin-arm64` prebuild;
31
+ unsupported platforms fail closed instead of using pathname writes.
32
+ - **Explicit production branch strategies**: projects can create an immutable
33
+ release branch, fast-forward an existing branch from an exact bound baseline,
34
+ or initialize an absent standard branch and make a separately approved,
35
+ observable, reconcilable default-branch change.
36
+
37
+ ### Changed
38
+
39
+ - Existing `public-release.json` snapshot commands are surfaced only as
40
+ migration candidates. Discovery never grants execution authority; gate and
41
+ legacy-hook side effects still require separate explicit acknowledgements.
42
+ - Compatibility configurations for artifact-graph, flow-architect, loop-agent,
43
+ and agent-method-registry now bind real tag/channel/baseline semantics and
44
+ project-owned verification behavior. glaf4-test is represented as local-only
45
+ instead of receiving an invented remote channel.
46
+ - README and installation guidance now begin with safe setup, explain the three
47
+ branch strategies, and distinguish pre-freeze hooks from frozen-snapshot and
48
+ installed-consumer gates.
49
+
50
+ ### Fixed
51
+
52
+ - **GitHub CLI Release-missing plain text compatibility**: `gh release view`
53
+ returns plain text `release not found` when the target release does not
54
+ exist; the previous implementation only recognized an HTTP 404 exit code.
55
+ The adapter now maps that specific plain text to a missing-release
56
+ decision without misclassifying `repository not found` or permission
57
+ errors as a target release absence.
58
+ - **Plugin consumer install verification transport semantics**: frozen
59
+ snapshots are sealed as read-only, but Git and plugin installation
60
+ transport restores owner write permission on extraction. Verification
61
+ now normalizes ordinary write permission from transport semantics and
62
+ continues to strictly verify path, type, content, size, and executable
63
+ intent. The frozen source digest is still compared against the plan and
64
+ must not be back-filled from observed results.
65
+
6
66
  ## [0.1.1] - 2026-07-18
7
67
 
8
68
  ### Fixed
package/INSTALL.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Installation Guide
2
2
 
3
+ [简体中文](INSTALL.zh-CN.md)
4
+
3
5
  ## Prerequisites
4
6
 
5
7
  - Node.js 22.0.0 or later
@@ -7,9 +9,9 @@
7
9
 
8
10
  ## Install from npm (recommended)
9
11
 
10
- This repository is currently preparing the v0.1.1 release. Use the npm path
11
- only after `npm view release-skill version` returns `0.1.1` (or newer). Before
12
- that publication is verified, use the source checkout instructions below.
12
+ v0.1.1 is published and verified. For a newer source candidate such as v0.1.3,
13
+ use the npm path only after `npm view release-skill version` returns that exact
14
+ version; before then, use the source checkout instructions below.
13
15
 
14
16
  ```bash
15
17
  npm install -g release-skill
@@ -61,7 +63,89 @@ instructions above; do not mix the two entry paths in one run.
61
63
  "${CLI[@]}" help
62
64
  ```
63
65
 
64
- To check if your project is ready for release governance:
66
+ If `.release-skill/project.yaml` is absent, discover first-use facts and
67
+ candidates without writing files:
68
+
69
+ ```bash
70
+ "${CLI[@]}" setup --root /path/to/your/project --json
71
+ ```
72
+
73
+ `NEEDS_INPUT` and `LOCAL_ONLY_DETECTED` intentionally return exit code 2. They
74
+ are decision states, not an internal crash; automation should inspect the JSON
75
+ `status`.
76
+
77
+ Review release units, legacy `public-release.json` migration hints, tags,
78
+ branch strategies, previous-public-baseline decisions, and gate candidates.
79
+ Setup never executes a discovered script automatically. Provide a complete
80
+ answers JSON, dry-run again to obtain the digest that binds current facts and
81
+ answers, then create the configuration exactly once:
82
+
83
+ ```json
84
+ {
85
+ "projectConfig": {
86
+ "apiVersion": "release-skill/v1",
87
+ "kind": "ReleaseProject",
88
+ "project": { "name": "my-project", "defaultBranch": "main" },
89
+ "releaseUnits": [{
90
+ "id": "my-project",
91
+ "source": ".",
92
+ "publicRepo": "owner/my-project",
93
+ "version": { "source": "package.json", "tagTemplate": "v{version}" },
94
+ "distributions": [{
95
+ "type": "npm",
96
+ "package": "my-project",
97
+ "access": "public",
98
+ "provenance": false,
99
+ "tag": "latest",
100
+ "registry": "https://registry.npmjs.org",
101
+ "publisher": "my-npm-username"
102
+ }],
103
+ "publicFiles": [
104
+ { "from": "README.md", "to": "README.md", "mode": "preserve" },
105
+ { "from": "package.json", "to": "package.json", "mode": "preserve" }
106
+ ],
107
+ "requiredPublicFiles": ["README.md", "package.json"],
108
+ "previousPublicBaseline": { "mode": "none" },
109
+ "production": {
110
+ "branchTemplate": "release/{tag}",
111
+ "branchStrategy": "create-release-branch"
112
+ }
113
+ }]
114
+ },
115
+ "selectedGateIds": []
116
+ }
117
+ ```
118
+
119
+ The wrapper is complete, but its values are examples. Replace every repository,
120
+ channel, baseline, and public-file decision with reviewed project facts; use
121
+ `mode: none` only when no public version exists.
122
+
123
+ When selecting a reported gate, add the complete gate definition to
124
+ `projectConfig.verificationGates` and copy its id into `selectedGateIds`. The
125
+ id must come from the current `gateCandidates`. A snapshot-gate command and all
126
+ of its dependencies must be present in `publicFiles`; it cannot see tests,
127
+ development dependencies, or `node_modules` that exist only in the parent
128
+ workspace. The full [README setup section](README.md#first-use-discover-then-let-a-human-finalize)
129
+ contains complete no-gate and one-gate answers examples.
130
+
131
+ ```bash
132
+ "${CLI[@]}" setup --root /path/to/your/project \
133
+ --answers /path/to/setup-answers.json --json
134
+ "${CLI[@]}" setup --root /path/to/your/project \
135
+ --answers /path/to/setup-answers.json \
136
+ --write --confirm-setup <setupDigest> --json
137
+ ```
138
+
139
+ An existing config is never regenerated or overwritten. A project with no
140
+ discoverable GitHub/npm channel reports `LOCAL_ONLY_DETECTED` rather than
141
+ claiming production readiness.
142
+
143
+ The automatic create-once write uses the digest-registered `darwin-arm64`
144
+ native prebuild shipped in v0.1.3. Other platforms fail closed with
145
+ `SAFE_WRITE_UNAVAILABLE`; keep the dry-run report and create the reviewed file
146
+ manually instead of enabling an unsafe pathname fallback.
147
+
148
+ After the config exists, check release readiness:
65
149
 
66
150
  ```bash
67
151
  "${CLI[@]}" assess --root /path/to/your/project --offline --json
@@ -139,12 +223,100 @@ hooks:
139
223
  build:
140
224
  command: [npm, run, build]
141
225
  test:
142
- command: [npm, test]
226
+ command:
227
+ - node
228
+ - -e
229
+ - "const p=require('./package.json'); if (!p.name) process.exit(1)"
143
230
  ```
144
231
 
145
232
  See the [full README](README.md) for hook parameter constraints and safety
146
233
  requirements.
147
234
 
235
+ ### Advanced: verification gates (optional)
236
+
237
+ Use a `snapshot-verify` gate for checks that should run against a disposable
238
+ writable copy of the frozen public snapshot. Use `consumer-verify` for commands
239
+ that must run from an exact isolated npm/Claude/Codex installation root. Gate
240
+ commands are executable arrays, not shell strings, and must declare unit,
241
+ distribution when applicable, cwd, timeout, and environment allowlist.
242
+
243
+ ```yaml
244
+ verificationGates:
245
+ - id: package-contract
246
+ phase: snapshot-verify
247
+ scope: { unit: my-project }
248
+ command: [node, -e, "const p=require('./package.json');if(!p.name)process.exit(1)"]
249
+ cwd: .
250
+ timeoutMs: 30000
251
+ envAllowlist: []
252
+ ```
253
+
254
+ This self-contained example reads only a mapped public file. A replacement
255
+ script and every dependency it needs must exist in the frozen public snapshot;
256
+ the gate cannot borrow tests, development dependencies, or `node_modules` from
257
+ the parent workspace.
258
+
259
+ Prepare and verify require `--acknowledge-gate-side-effects` whenever their
260
+ planned phase contains gates. Hooks and gates are project processes without a
261
+ network sandbox; release-skill limits their inputs and evidence but cannot
262
+ guarantee that a custom command will not modify files or access the network.
263
+ Never register Git push, tag, default-branch changes, GitHub Releases, or npm
264
+ publish as a hook/gate; those are controlled plan actions.
265
+
266
+ ### Production branch strategy
267
+
268
+ Every production unit selects one explicit strategy:
269
+
270
+ - `create-release-branch` creates an absent immutable release branch;
271
+ - `advance-existing-branch` fast-forwards an existing branch from the exact
272
+ bound public baseline using an ordinary non-force push;
273
+ - `initialize-default-branch` creates an absent standard branch and may add an
274
+ explicit default-branch action only when `setAsDefaultBranch` and
275
+ `expectedCurrentDefaultBranch` are both reviewed.
276
+
277
+ Remote drift, a non-fast-forward update, or an unexpected default branch stops
278
+ for human intervention. No strategy overwrites remote history. Create-only refs
279
+ use `--force-with-lease=<ref>:` solely as an atomic absence assertion; advancing
280
+ an existing branch uses an ordinary non-force push.
281
+
282
+ ```yaml
283
+ # create-release-branch: target must be absent
284
+ previousPublicBaseline: { mode: none } # true first public release only
285
+ production:
286
+ branchTemplate: release/{tag}
287
+ branchStrategy: create-release-branch
288
+ ```
289
+
290
+ ```yaml
291
+ # advance-existing-branch: ref must exactly equal refs/heads/<target>
292
+ previousPublicBaseline:
293
+ mode: bound
294
+ repo: owner/my-project
295
+ ref: refs/heads/main
296
+ commit: 0123456789abcdef0123456789abcdef01234567
297
+ production:
298
+ branchTemplate: main
299
+ branchStrategy: advance-existing-branch
300
+ ```
301
+
302
+ ```yaml
303
+ # initialize-default-branch: main must be absent; current default must match
304
+ previousPublicBaseline:
305
+ mode: bound
306
+ repo: owner/my-project
307
+ ref: refs/heads/old-public-branch
308
+ commit: 0123456789abcdef0123456789abcdef01234567
309
+ production:
310
+ branchTemplate: main
311
+ branchStrategy: initialize-default-branch
312
+ setAsDefaultBranch: true
313
+ expectedCurrentDefaultBranch: old-public-branch
314
+ ```
315
+
316
+ The last two strategies require online production prepare. Any mismatch stops
317
+ for review; update the human-owned config only after inspecting real remote
318
+ state, and never force-push or weaken the baseline.
319
+
148
320
  ## Protect Human-Owned Content
149
321
 
150
322
  README text, slogans, examples, layout, and other manually curated source files
@@ -167,6 +339,8 @@ When an existing public copy has drifted, choose explicitly:
167
339
  ## Next Steps
168
340
 
169
341
  - Read the [full README](README.md) for the complete workflow guide.
342
+ - Run `"${CLI[@]}" setup --root <your-project> --json` when the project has no
343
+ configuration; keep its default dry-run behavior until human decisions are complete.
170
344
  - Run `"${CLI[@]}" assess --root <your-project> --offline` to evaluate your project's release readiness.
171
345
  - Run `"${CLI[@]}" prepare --root <your-project> --offline` (release-skill pipeline writes
172
346
  locally only; user-configured hooks may perform remote operations) to generate
@@ -0,0 +1,320 @@
1
+ # 安装指南
2
+
3
+ [English](INSTALL.md)
4
+
5
+ ## 前置条件
6
+
7
+ - Node.js 22.0.0 或更高版本
8
+ - Git 2.30 或更高版本
9
+
10
+ ## 从 npm 安装(推荐)
11
+
12
+ v0.1.1 已公开发布并完成验证。对于 v0.1.3 这样的更新源码候选,只有当
13
+ `npm view release-skill version` 返回该精确版本后才使用 npm 安装;在此之前请使用
14
+ 下文的源码检出方式。
15
+
16
+ ```bash
17
+ npm install -g release-skill
18
+ CLI=(release-skill)
19
+ ```
20
+
21
+ 也可以不安装,直接运行:
22
+
23
+ ```bash
24
+ npx release-skill help
25
+ ```
26
+
27
+ 验证安装:
28
+
29
+ ```bash
30
+ release-skill --version
31
+ release-skill help
32
+ ```
33
+
34
+ 输出中应包含版本号和可用命令列表。
35
+
36
+ ## 开发安装(本地源码)
37
+
38
+ 用于开发或尚未公开发布的源码候选:
39
+
40
+ ```bash
41
+ export RELEASE_SKILL_HOME=/absolute/path/to/release-skill
42
+ cd "$RELEASE_SKILL_HOME"
43
+ npm exec --yes pnpm@10.17.1 -- install --frozen-lockfile
44
+ ```
45
+
46
+ 通过以下数组调用命令行工具:
47
+
48
+ ```bash
49
+ CLI=(node "$RELEASE_SKILL_HOME/packages/release-skill/bin/release-skill.mjs")
50
+ "${CLI[@]}" help
51
+ ```
52
+
53
+ 当 `npm view release-skill version` 已确认目标版本公开并安装后,等价的 npm 入口是
54
+ `CLI=(release-skill)`。同一次运行不要混用 npm 与源码入口。
55
+
56
+ ## 首次运行
57
+
58
+ 最安全的首条命令始终是 `help`。它完全在本地运行,不写入文件:
59
+
60
+ ```bash
61
+ "${CLI[@]}" help
62
+ ```
63
+
64
+ 如果项目尚无 `.release-skill/project.yaml`,先只读发现事实和候选:
65
+
66
+ ```bash
67
+ "${CLI[@]}" setup --root /path/to/your/project --json
68
+ ```
69
+
70
+ `NEEDS_INPUT` 和 `LOCAL_ONLY_DETECTED` 按设计返回退出码 2。它们表示待人工决策,不是
71
+ 内部崩溃;自动化应读取 JSON 的 `status`。
72
+
73
+ 人工审阅发布单元、旧 `public-release.json` 迁移提示、tag、分支策略、前序公开基线
74
+ 和 gate 候选。setup 不会自动执行发现到的脚本。建立完整 answers JSON,再运行一次
75
+ dry-run(只读试运行),取得同时绑定当前事实与人工答案的摘要,然后只创建一次配置:
76
+
77
+ ```json
78
+ {
79
+ "projectConfig": {
80
+ "apiVersion": "release-skill/v1",
81
+ "kind": "ReleaseProject",
82
+ "project": { "name": "my-project", "defaultBranch": "main" },
83
+ "releaseUnits": [{
84
+ "id": "my-project",
85
+ "source": ".",
86
+ "publicRepo": "owner/my-project",
87
+ "version": { "source": "package.json", "tagTemplate": "v{version}" },
88
+ "distributions": [{
89
+ "type": "npm",
90
+ "package": "my-project",
91
+ "access": "public",
92
+ "provenance": false,
93
+ "tag": "latest",
94
+ "registry": "https://registry.npmjs.org",
95
+ "publisher": "my-npm-username"
96
+ }],
97
+ "publicFiles": [
98
+ { "from": "README.md", "to": "README.md", "mode": "preserve" },
99
+ { "from": "package.json", "to": "package.json", "mode": "preserve" }
100
+ ],
101
+ "requiredPublicFiles": ["README.md", "package.json"],
102
+ "previousPublicBaseline": { "mode": "none" },
103
+ "production": {
104
+ "branchTemplate": "release/{tag}",
105
+ "branchStrategy": "create-release-branch"
106
+ }
107
+ }]
108
+ },
109
+ "selectedGateIds": []
110
+ }
111
+ ```
112
+
113
+ 这个外壳完整,但其中的值只是示例。仓库、渠道、基线与公开文件都必须替换为本项目
114
+ 经审阅的事实;只有确认不存在历史公开版本时才可使用 `mode: none`。
115
+
116
+ 选择已报告的 gate 时,把完整定义加入 `projectConfig.verificationGates`,并把同一 id
117
+ 复制进 `selectedGateIds`。id 必须来自当前 `gateCandidates`。snapshot gate 命令及
118
+ 全部依赖必须包含在 `publicFiles`;它看不到仅存在于父工作空间的测试、开发依赖或
119
+ `node_modules`。完整的无 gate 与单 gate answers 示例见
120
+ [README 首次接入章节](README.zh-CN.md#首次接入先发现再由人工定稿)。
121
+
122
+ ```bash
123
+ "${CLI[@]}" setup --root /path/to/your/project \
124
+ --answers /path/to/setup-answers.json --json
125
+ "${CLI[@]}" setup --root /path/to/your/project \
126
+ --answers /path/to/setup-answers.json \
127
+ --write --confirm-setup <setupDigest> --json
128
+ ```
129
+
130
+ 已有配置永远不会被重新生成或覆盖。无法发现 GitHub/npm 渠道的项目返回
131
+ `LOCAL_ONLY_DETECTED`,不会冒充生产就绪。
132
+
133
+ 自动 create-once 写入使用 v0.1.3 随包提供、带摘要登记的 `darwin-arm64` 原生预构建。
134
+ 其他平台以 `SAFE_WRITE_UNAVAILABLE` 失败关闭;此时保留只读报告,由人工首次创建经审阅
135
+ 的文件,不得启用不安全的路径写入兜底。
136
+
137
+ 配置存在后,检查发布就绪度:
138
+
139
+ ```bash
140
+ "${CLI[@]}" assess --root /path/to/your/project --offline --json
141
+ ```
142
+
143
+ 该命令只读地检查项目结构、配置、文档和供应链;未显式传入 `--output` 时不写报告,
144
+ 也不运行项目 hook。
145
+
146
+ `prepare` 不同:它在目标项目的 `.release-skill/` 下写入发布工件,并可能运行已配置
147
+ hook。hook 是无沙箱的任意进程,可能写到项目外、访问凭据、使用网络或执行远端写入。
148
+ 授予 `--acknowledge-hook-side-effects` 前必须审阅可执行文件、参数和工作目录。
149
+
150
+ Git 仓库应保留人工配置,同时忽略生成的权威文件和证据:
151
+
152
+ ```gitignore
153
+ .release-skill/*
154
+ !.release-skill/project.yaml
155
+ ```
156
+
157
+ ## 项目配置
158
+
159
+ 在项目根目录创建 `.release-skill/project.yaml`。以下是单包项目的最小示例:
160
+
161
+ ```yaml
162
+ apiVersion: release-skill/v1
163
+ kind: ReleaseProject
164
+
165
+ project:
166
+ name: my-project
167
+ defaultBranch: main
168
+
169
+ releaseUnits:
170
+ - id: my-project
171
+ source: .
172
+ publicRepo: owner/my-project
173
+ version:
174
+ source: package.json
175
+ tagTemplate: v{version}
176
+ distributions:
177
+ - type: npm
178
+ package: my-project
179
+ access: public
180
+ provenance: false
181
+ tag: latest
182
+ registry: https://registry.npmjs.org
183
+ publisher: my-npm-username
184
+ publicFiles:
185
+ - from: README.md
186
+ to: README.md
187
+ mode: preserve
188
+ - from: package.json
189
+ to: package.json
190
+ mode: preserve
191
+ - from: LICENSE
192
+ to: LICENSE
193
+ mode: preserve
194
+ requiredPublicFiles: [README.md, package.json, LICENSE]
195
+ previousPublicBaseline:
196
+ mode: none # 仅限已确认不存在历史公开版本
197
+ ```
198
+
199
+ ### 进阶:hook(可选)
200
+
201
+ hook 是可选的任意本地进程。prepare 使用 hook 时必须显式授予
202
+ `--acknowledge-hook-side-effects`:
203
+
204
+ ```yaml
205
+ hooks:
206
+ build:
207
+ command: [npm, run, build]
208
+ test:
209
+ command:
210
+ - node
211
+ - -e
212
+ - "const p=require('./package.json'); if (!p.name) process.exit(1)"
213
+ ```
214
+
215
+ 参数约束和安全要求见[完整 README](README.zh-CN.md)。
216
+
217
+ ### 进阶:验证 gate(可选)
218
+
219
+ `snapshot-verify` 用于冻结公开快照的一次性可写副本;`consumer-verify` 用于精确且
220
+ 隔离安装后的 npm/Claude/Codex 根目录。gate 使用可执行文件数组而不是 shell 字符串,
221
+ 并声明 unit、必要时的 distribution、cwd、超时和环境变量白名单。
222
+
223
+ ```yaml
224
+ verificationGates:
225
+ - id: package-contract
226
+ phase: snapshot-verify
227
+ scope: { unit: my-project }
228
+ command: [node, -e, "const p=require('./package.json');if(!p.name)process.exit(1)"]
229
+ cwd: .
230
+ timeoutMs: 30000
231
+ envAllowlist: []
232
+ ```
233
+
234
+ 这个自包含示例只读取已映射的公开文件。若替换成项目脚本,该脚本及全部依赖必须
235
+ 存在于冻结公开快照;gate 不能借用父工作空间中的测试、开发依赖或 `node_modules`。
236
+
237
+ 当计划的当前阶段包含 gate 时,prepare 或 verify 必须传入
238
+ `--acknowledge-gate-side-effects`。hook/gate 都是无网络沙箱的项目进程;
239
+ release-skill 约束其输入与证据,但无法保证自定义命令不修改文件或不访问网络。
240
+ 禁止把 Git push、tag、默认分支修改、GitHub Release 或 npm publish 注册为
241
+ hook/gate,它们只能由受控的计划动作完成。
242
+
243
+ ### 生产分支策略
244
+
245
+ 每个生产发布单元显式选择一种策略:
246
+
247
+ - `create-release-branch`:创建此前不存在且不可变的 release 分支;
248
+ - `advance-existing-branch`:从精确绑定的公开基线用普通非 force push 快进已有分支;
249
+ - `initialize-default-branch`:创建不存在的标准分支;只有同时审阅
250
+ `setAsDefaultBranch` 与 `expectedCurrentDefaultBranch` 后,计划才可增加显式默认分支动作。
251
+
252
+ 远端漂移、非快进或默认分支不符合预期时必须停止并由人工介入。所有策略都禁止覆盖
253
+ 远端历史。新建 ref 仅使用 `--force-with-lease=<ref>:` 作为“目标必须不存在”的原子
254
+ 断言;推进已有分支使用普通非 force push。
255
+
256
+ ```yaml
257
+ # create-release-branch:目标分支必须不存在
258
+ previousPublicBaseline: { mode: none } # 仅限真正的首次公开发布
259
+ production:
260
+ branchTemplate: release/{tag}
261
+ branchStrategy: create-release-branch
262
+ ```
263
+
264
+ ```yaml
265
+ # advance-existing-branch:ref 必须精确等于 refs/heads/<目标分支>
266
+ previousPublicBaseline:
267
+ mode: bound
268
+ repo: owner/my-project
269
+ ref: refs/heads/main
270
+ commit: 0123456789abcdef0123456789abcdef01234567
271
+ production:
272
+ branchTemplate: main
273
+ branchStrategy: advance-existing-branch
274
+ ```
275
+
276
+ ```yaml
277
+ # initialize-default-branch:main 必须不存在,当前默认分支必须符合预期
278
+ previousPublicBaseline:
279
+ mode: bound
280
+ repo: owner/my-project
281
+ ref: refs/heads/old-public-branch
282
+ commit: 0123456789abcdef0123456789abcdef01234567
283
+ production:
284
+ branchTemplate: main
285
+ branchStrategy: initialize-default-branch
286
+ setAsDefaultBranch: true
287
+ expectedCurrentDefaultBranch: old-public-branch
288
+ ```
289
+
290
+ 后两种策略必须在线执行 production prepare。任何不一致都应停止并审阅;只有检查
291
+ 真实远端状态后才能人工更新权威配置,禁止 force push 或弱化基线。
292
+
293
+ ## 保护人工维护内容
294
+
295
+ README 文案、slogan、示例、排版及其他人工源文件始终是权威。release-skill 只按
296
+ `publicFiles` 映射做快照,不重新生成或覆盖源 README。每次人工编辑后重新 prepare,
297
+ 并批准新的不可变计划;不得编辑冻结快照或复用旧批准绕过变化。
298
+
299
+ 如果已有公开副本发生漂移,显式选择:
300
+
301
+ - **merge(合并)**:比较真实远端内容,把接受的改动合并回人工源文件,然后把
302
+ `previousPublicBaseline` 绑定到精确不可变的 `repo`/`ref`/`commit`,再 prepare;
303
+ - **adopt(采纳)**:接受远端为新的事实来源,先带回人工源文件,再更新同一基线绑定;
304
+ - **reject(拒绝)**:停止并调查。不得改成 `mode: none` 绕过漂移或唯一性检查。
305
+
306
+ ## 下一步
307
+
308
+ - 阅读[完整中文 README](README.zh-CN.md)了解整个工作流。
309
+ - 缺少配置时运行 `"${CLI[@]}" setup --root <your-project> --json`,在人工决策完成前
310
+ 保持默认 dry-run。
311
+ - 运行 `"${CLI[@]}" assess --root <your-project> --offline` 检查发布就绪度。
312
+ - 运行 `"${CLI[@]}" prepare --root <your-project> --offline` 生成发布计划;
313
+ release-skill 自身只做本地写入,但项目 hook 可能执行远端操作。
314
+ - 生产前为每个 unit 配置 `previousPublicBaseline`。已有公开版本必须使用
315
+ `mode: bound`,绑定精确 `repo`、`ref` 和 `commit`,再运行
316
+ `"${CLI[@]}" prepare --root <your-project> --online --production`。默认观察器只证明
317
+ ref 到 commit 的映射,不下载远端内容;目标 branch/tag/Release/npm 唯一性由
318
+ publish 全局预检在任何 execute 前检查。
319
+ - 生产命令只使用 `prepare --json` 返回的不可变 `planPath`,以及 `approve --json`
320
+ 返回的不可变 `approvalPath`。可变的 latest 别名不能作为生产权威。