release-skill 0.1.5 → 0.1.6

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 (67) 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 +77 -0
  5. package/INSTALL.md +81 -1
  6. package/INSTALL.zh-CN.md +69 -1
  7. package/README.md +223 -8
  8. package/README.zh-CN.md +180 -8
  9. package/adapters/claude/.claude-plugin/marketplace.json +1 -1
  10. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  11. package/adapters/claude/bin/release-skill.bundle.mjs +14182 -10017
  12. package/adapters/claude/bin/release-skill.mjs +24 -4
  13. package/adapters/claude/native/safe-write/binding.gyp +2 -1
  14. package/adapters/claude/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  15. package/adapters/claude/native/safe-write/prebuilds.json +1 -1
  16. package/adapters/claude/schemas/.render-manifest.json +10 -10
  17. package/adapters/claude/schemas/release-project.schema.json +118 -0
  18. package/adapters/claude/skills/release-help/SKILL.md +21 -0
  19. package/adapters/claude/skills/release-prepare/SKILL.md +17 -6
  20. package/adapters/claude/skills/release-publish/SKILL.md +3 -1
  21. package/adapters/claude/skills/release-reconcile/SKILL.md +1 -1
  22. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  23. package/adapters/codex/bin/release-skill.bundle.mjs +14182 -10017
  24. package/adapters/codex/bin/release-skill.mjs +24 -4
  25. package/adapters/codex/native/safe-write/binding.gyp +2 -1
  26. package/adapters/codex/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  27. package/adapters/codex/native/safe-write/prebuilds.json +1 -1
  28. package/adapters/codex/schemas/.render-manifest.json +10 -10
  29. package/adapters/codex/schemas/release-project.schema.json +118 -0
  30. package/adapters/codex/skills/release-help/SKILL.md +21 -0
  31. package/adapters/codex/skills/release-prepare/SKILL.md +17 -6
  32. package/adapters/codex/skills/release-publish/SKILL.md +3 -1
  33. package/adapters/codex/skills/release-reconcile/SKILL.md +1 -1
  34. package/bin/release-skill-cli.mjs +163 -4
  35. package/bin/release-skill.bundle.mjs +14182 -10017
  36. package/bin/release-skill.mjs +24 -4
  37. package/native/safe-write/binding.gyp +2 -1
  38. package/native/safe-write/prebuilds/darwin-arm64/safe_write.node +0 -0
  39. package/native/safe-write/prebuilds.json +1 -1
  40. package/package.json +2 -2
  41. package/references/.render-manifest.json +4 -4
  42. package/references/02-project-config.md +24 -0
  43. package/references/05-evidence-and-errors.md +5 -0
  44. package/schemas/.render-manifest.json +10 -10
  45. package/schemas/release-project.schema.json +118 -0
  46. package/scripts/build-bundle.mjs +15 -2
  47. package/skills/release-help/SKILL.md +21 -0
  48. package/skills/release-prepare/SKILL.md +17 -6
  49. package/skills/release-publish/SKILL.md +3 -1
  50. package/skills/release-reconcile/SKILL.md +1 -1
  51. package/skills-src/release-help/SKILL.md +21 -0
  52. package/skills-src/release-prepare/SKILL.md +17 -6
  53. package/skills-src/release-publish/SKILL.md +3 -1
  54. package/skills-src/release-reconcile/SKILL.md +1 -1
  55. package/src/artifacts/transaction-journal.mjs +1126 -105
  56. package/src/artifacts/transaction.mjs +313 -130
  57. package/src/commands/docs.mjs +332 -0
  58. package/src/commands/prepare.mjs +316 -17
  59. package/src/core/errors.mjs +64 -2
  60. package/src/core/redact.mjs +206 -0
  61. package/src/docs/changelog-renderer.mjs +853 -0
  62. package/src/docs/config.mjs +337 -0
  63. package/src/docs/notes-loader.mjs +432 -0
  64. package/src/docs/notes.mjs +553 -0
  65. package/src/docs/readme-renderer.mjs +647 -0
  66. package/src/docs/refresh-planner.mjs +542 -0
  67. package/src/docs/refresh-service.mjs +675 -0
@@ -9,7 +9,7 @@
9
9
  {
10
10
  "name": "release-skill",
11
11
  "source": "./",
12
- "version": "0.1.5",
12
+ "version": "0.1.6",
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.5",
3
+ "version": "0.1.6",
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.5",
3
+ "version": "0.1.6",
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.5.",
22
+ "Prepare a release plan for version 0.1.6.",
23
23
  "Help me understand the release workflow."
24
24
  ]
25
25
  }
package/CHANGELOG.md CHANGED
@@ -1,10 +1,86 @@
1
1
  # Changelog
2
2
 
3
+ <!-- release-skill:changelog:start version=0.1.6 locale=en baseline=sha256:6b45d1aa912b32c9c00a616661ae3e2a9536e5ff85a7c0cf82b846a3ffb6c1d3 -->
4
+ ## [0.1.6] - 2026-07-22
5
+
6
+ v0.1.6 is a release-preparation snapshot that closes the release-docs automation loop. A single structured release-notes source drives deterministic, multilingual CHANGELOG and README refresh behind a two-phase, digest-bound write protocol and a prepare-time documentation freshness gate, while terminal transaction receipts are bounded and the CLI lifecycle, path safety, and error-output redaction are hardened.
7
+
8
+ ### Added
9
+
10
+ - **Structured release-notes-driven document refresh (`docs refresh`)**: a single
11
+ structured release-notes source (`release-notes/0.1.6.yaml`) now drives
12
+ deterministic, multilingual refresh of the managed CHANGELOG and README
13
+ regions. Refresh runs as a two-phase protocol: a read-only planning phase
14
+ renders every candidate and freezes an `inputDigest` (binding the canonical
15
+ notes and the notes-source bytes) plus a `refreshDigest` (binding the protocol
16
+ version, unit, version, configuration projection, and per-file old/new
17
+ digests), and a separate write phase commits the changed targets only when all
18
+ three authorizations are present (`--write`, an exact `--confirm-refresh
19
+ <refreshDigest>` match, and `--ack-local-document-write`). The write phase
20
+ re-plans under the exclusive lock; a diverging digest converges to
21
+ `RELEASE_DOCS_REFRESH_STALE` with zero writes, and a clean plan is a zero-write
22
+ no-op. A prepare-time documentation freshness gate makes version drift between
23
+ the package version and the public docs fail closed before a release plan is
24
+ frozen.
25
+ - **Bounded terminal transaction receipts with recovery safety**: terminal
26
+ (committed / rolled-back) transactions now persist a summary-only receipt
27
+ instead of full payload, capped at 256 KB per receipt
28
+ (`TERMINAL_RECEIPT_SIZE_CAP`), under a retention cap of 50 terminal records
29
+ (`DEFAULT_TRANSACTION_RETENTION_MAX`). Retention pruning only ever removes
30
+ terminal records and never prunes `RECOVERY_CONFLICT` records or any
31
+ non-terminal (recovery-relevant) record, so recovery evidence is preserved even
32
+ when the count cap is reached; a retention failure never aborts an in-flight
33
+ commit.
34
+ - **Strict `docs refresh` parameter validation (fail closed)**: the `docs`
35
+ command validates every parameter before invoking the refresh service, so
36
+ precise stable parameter errors surface even without project configuration or a
37
+ safe-fs backend. The `--flag=value` equals form routes through exactly the same
38
+ validation as the space-separated form; duplicated flags fail closed with
39
+ `DUPLICATE_PARAMETER` before any service call, config read, lock, or
40
+ transaction; and bare positional arguments and single-dash flags (such as `-w`)
41
+ are rejected as unrecognized. Write-authorization flags supplied without
42
+ `--write`, or `--write` without its full authorizations, fail closed with
43
+ precise reasons rather than silently proceeding.
44
+
45
+ ### Fixed
46
+
47
+ - **Bundle entry lifecycle settles with real exit codes**: the self-contained
48
+ bundle now owns the command lifecycle. Its entry awaits command completion and
49
+ exits with the real business exit code for success, business errors, handled
50
+ async rejections, and unknown commands, so the launcher no longer leaves an
51
+ unsettled top-level await (Node exit code 13). When the bundle is missing or
52
+ cannot be evaluated, the launcher fails closed with static text only and never
53
+ interpolates machine-specific paths, usernames, or host layout, because
54
+ module-load failure messages carry absolute paths.
55
+ - **Fail-closed path canonicalization with stable diagnostics**: artifact path
56
+ canonicalization requires POSIX separators and rejects absolute paths in POSIX
57
+ (`/`), Windows drive-letter, and UNC spellings, along with traversal, Windows
58
+ reserved device names, and colons, failing closed with `PATH_UNSAFE` rather
59
+ than normalizing an unsafe spelling into a different public path. Error-output
60
+ redaction now distinguishes real filesystem paths from strict RFC 6901 JSON
61
+ Pointer diagnostic coordinates (such as `/units/0/version`): absolute
62
+ POSIX/Windows/UNC paths collapse to a stable `<redacted-path>` placeholder
63
+ while diagnostic pointers are preserved verbatim, keeping failures diagnosable
64
+ without leaking host paths.
65
+ - **Self public-boundary redaction**: the centralized redaction authority
66
+ (`core/redact.mjs`) now closes the self public boundary so runtime error
67
+ outputs and detail structures never carry the release-skill workspace's own
68
+ absolute path, nor the macOS `Users`, Linux home, macOS `private`/`var` alias,
69
+ temp, or CI checkout realms. Redaction runs fail-closed through the
70
+ `ReleaseError` choke point: any two-or-more-segment `/`-led token that is not a
71
+ strict diagnostic JSON Pointer is replaced with `<redacted-path>`, so
72
+ self-releasing never leaks private filesystem layout into public outputs.
73
+ <!-- release-skill:changelog:end version=0.1.6 locale=en -->
74
+
75
+
3
76
  All notable changes to the `release-skill` plugin will be documented in this
4
77
  file. The format is based on [Keep a Changelog](https://keepachangelog.com/).
5
78
 
79
+ <!-- release-skill:changelog:start version=0.1.5 locale=en baseline=sha256:72d222ff63008de63edcf20c89626fa18748e6cb39e54263e861b8f0c9669026 -->
6
80
  ## [0.1.5] - 2026-07-21
7
81
 
82
+ Claude and Codex marketplace installs now use an explicit, configurable timeout frozen into the release plan.
83
+
8
84
  ### Added
9
85
 
10
86
  - **Explicit marketplace install timeout (`timeoutMs`)**: Claude and Codex
@@ -29,6 +105,7 @@ file. The format is based on [Keep a Changelog](https://keepachangelog.com/).
29
105
  distribution and verified through injected-executor tests. Invalid values
30
106
  (non-integer, non-finite, out-of-range) fail closed rather than being
31
107
  silently clamped.
108
+ <!-- release-skill:changelog:end version=0.1.5 locale=en -->
32
109
 
33
110
  ## [0.1.4] - 2026-07-19
34
111
 
package/INSTALL.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [简体中文](INSTALL.zh-CN.md)
4
4
 
5
- <!-- release-skill:release-version: 0.1.5 -->
5
+ <!-- release-skill:release-version: 0.1.6 -->
6
6
  ## Prerequisites
7
7
 
8
8
  - Node.js 22.0.0 or later
@@ -300,6 +300,86 @@ guarantee that a custom command will not modify files or access the network.
300
300
  Never register Git push, tag, default-branch changes, GitHub Releases, or npm
301
301
  publish as a hook/gate; those are controlled plan actions.
302
302
 
303
+ ### Advanced: release-document refresh (optional)
304
+
305
+ A release unit can declare `releaseDocuments` so one structured notes source
306
+ deterministically refreshes its managed README regions and the current
307
+ CHANGELOG entry. The command runs offline: it does not use the network, does
308
+ not call any large language model, and does not auto-translate. It only
309
+ rewrites declared managed regions, the unique version marker's machine
310
+ value, and the current CHANGELOG managed entry; every other byte is
311
+ preserved. `prepare` only checks freshness and never writes the working
312
+ tree.
313
+
314
+ ```yaml
315
+ # Release unit fragment in .release-skill/project.yaml
316
+ releaseUnits:
317
+ - id: my-project
318
+ source: .
319
+ releaseDocuments:
320
+ notesSource: release-notes/{version}.yaml
321
+ locales: [en, zh-CN]
322
+ changelogs:
323
+ - path: CHANGELOG.md
324
+ locale: en
325
+ readmes:
326
+ - path: README.md
327
+ locale: en
328
+ regions: [latest-release]
329
+ versionMarkers:
330
+ - id: current-version
331
+ pattern: '<!-- release-skill:version -->v{version}<!-- /release-skill:version -->'
332
+ - path: README.zh-CN.md
333
+ locale: zh-CN
334
+ regions: [latest-release]
335
+ ```
336
+
337
+ `notesSource` and every target path are relative to the release unit root;
338
+ `versionMarkers[].pattern` must match the README's existing unique version
339
+ marker exactly, and the refresh replaces only the machine version value.
340
+ The notes source lives under the release unit root; its `version` must
341
+ equal the resolved unit version, every configured locale appears exactly
342
+ once with a non-empty summary and at least one change category, and YAML
343
+ aliases, duplicate keys, unknown fields, and locale fallback all fail
344
+ closed:
345
+
346
+ ```yaml
347
+ # release-notes/0.1.6.yaml
348
+ version: 0.1.6
349
+ date: 2026-07-21
350
+ locales:
351
+ en:
352
+ summary: Deterministic multilingual release-document refresh.
353
+ changes:
354
+ added:
355
+ - Refresh managed README regions and changelogs from one source.
356
+ zh-CN:
357
+ summary: 从同一说明源确定性刷新多语种发布文档。
358
+ changes:
359
+ added:
360
+ - 自动刷新 README 受管区域和 CHANGELOG。
361
+ ```
362
+
363
+ Drill first (read-only), then write only with all three bindings:
364
+
365
+ ```bash
366
+ "${CLI[@]}" docs refresh --root <your-project> --unit my-project --json
367
+ "${CLI[@]}" docs refresh --root <your-project> --unit my-project \
368
+ --write --confirm-refresh <refreshDigest> --ack-local-document-write --json
369
+ ```
370
+
371
+ `refreshDigest` binds the canonical notes object, the configuration
372
+ projection, and the sorted per-file old/new digests — never time, absolute
373
+ paths, or display text. A mismatched digest fails closed with
374
+ `RELEASE_DOCS_REFRESH_STALE` and writes nothing; an unchanged candidate
375
+ reports `clean` and writes nothing either. This authorization covers only
376
+ the declared local document targets; it does not authorize hooks, commits,
377
+ pushes, publishes, or installs. When `prepare` reports `RELEASE_DOCS_STALE`,
378
+ recover by running the drill, reviewing the listed files and locales,
379
+ performing the confirmed local write, reviewing and committing the result,
380
+ and rerunning `prepare`. See the README release-document refresh section
381
+ for the full contract.
382
+
303
383
  ### Production branch strategy
304
384
 
305
385
  Every production unit selects one explicit strategy:
package/INSTALL.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](INSTALL.md)
4
4
 
5
- <!-- release-skill:release-version: 0.1.5 -->
5
+ <!-- release-skill:release-version: 0.1.6 -->
6
6
  ## 前置条件
7
7
 
8
8
  - Node.js 22.0.0 或更高版本
@@ -278,6 +278,74 @@ release-skill 约束其输入与证据,但无法保证自定义命令不修改
278
278
  禁止把 Git push、tag、默认分支修改、GitHub Release 或 npm publish 注册为
279
279
  hook/gate,它们只能由受控的计划动作完成。
280
280
 
281
+ ### 进阶:发布文档刷新(可选)
282
+
283
+ 发布单元可以声明 `releaseDocuments`,用一份结构化说明源确定性刷新 README 受管
284
+ 区域和 CHANGELOG 当前版本条目。该命令离线运行:不联网、不调用大模型、不自动
285
+ 翻译;只改写声明过的受管区域、唯一版本标记的机器值和 CHANGELOG 当前版本受管
286
+ 条目,其他字节全部保留。`prepare` 只检查新鲜度,不写工作树。
287
+
288
+ ```yaml
289
+ # .release-skill/project.yaml 的发布单元片段
290
+ releaseUnits:
291
+ - id: my-project
292
+ source: .
293
+ releaseDocuments:
294
+ notesSource: release-notes/{version}.yaml
295
+ locales: [en, zh-CN]
296
+ changelogs:
297
+ - path: CHANGELOG.md
298
+ locale: en
299
+ readmes:
300
+ - path: README.md
301
+ locale: en
302
+ regions: [latest-release]
303
+ versionMarkers:
304
+ - id: current-version
305
+ pattern: '<!-- release-skill:version -->v{version}<!-- /release-skill:version -->'
306
+ - path: README.zh-CN.md
307
+ locale: zh-CN
308
+ regions: [latest-release]
309
+ ```
310
+
311
+ `notesSource` 和所有目标路径均相对发布单元根;`versionMarkers[].pattern` 必须与
312
+ README 现有唯一版本标记精确匹配,刷新只替换机器版本值。说明源位于发布单元根
313
+ 下,`version` 必须与解析出的单元版本一致,每个配置语种恰好出现一次且 summary
314
+ 非空、至少一个变更类别有条目;YAML alias、重复键、未知字段和语种回退均失败
315
+ 关闭:
316
+
317
+ ```yaml
318
+ # release-notes/0.1.6.yaml
319
+ version: 0.1.6
320
+ date: 2026-07-21
321
+ locales:
322
+ en:
323
+ summary: Deterministic multilingual release-document refresh.
324
+ changes:
325
+ added:
326
+ - Refresh managed README regions and changelogs from one source.
327
+ zh-CN:
328
+ summary: 从同一说明源确定性刷新多语种发布文档。
329
+ changes:
330
+ added:
331
+ - 自动刷新 README 受管区域和 CHANGELOG。
332
+ ```
333
+
334
+ 先只读演练,确认后再带三项绑定写入:
335
+
336
+ ```bash
337
+ "${CLI[@]}" docs refresh --root <your-project> --unit my-project --json
338
+ "${CLI[@]}" docs refresh --root <your-project> --unit my-project \
339
+ --write --confirm-refresh <refreshDigest> --ack-local-document-write --json
340
+ ```
341
+
342
+ `refreshDigest` 绑定规范说明对象、配置投影和按路径排序的逐文件新旧摘要,不绑定
343
+ 时间、绝对路径或展示文本。摘要不匹配以 `RELEASE_DOCS_REFRESH_STALE` 失败关闭且
344
+ 零写入;候选无变化时返回 `clean` 同样零写入。该授权只覆盖声明的本地文档目标,
345
+ 不是 hook、提交、push、publish 或安装的授权。`prepare` 报告 `RELEASE_DOCS_STALE`
346
+ 时,按“运行演练 → 审阅文件与语种 → 确认本地写入 → 审阅并提交 → 重新 prepare”
347
+ 恢复。完整契约见 README 的发布文档刷新章节。
348
+
281
349
  ### 生产分支策略
282
350
 
283
351
  每个生产发布单元显式选择一种策略:
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [简体中文](README.zh-CN.md) · Installation: [English](INSTALL.md) / [简体中文](INSTALL.zh-CN.md)
4
4
 
5
- <!-- release-skill:release-version: 0.1.5 -->
5
+ <!-- release-skill:release-version: 0.1.6 -->
6
6
  Release preparation for Claude Code and Codex, with human-edited files kept intact.
7
7
 
8
8
  release-skill helps a maintainer answer three questions: what will be released,
@@ -10,9 +10,83 @@ which checks still fail, and which exact bytes will reach users. It freezes the
10
10
  reviewed artifacts first and publishes those same artifacts later; it does not
11
11
  regenerate a README or re-pack the live workspace at the last step.
12
12
 
13
+ <!-- release-skill:managed:start id=latest-release -->
14
+ **0.1.6** (2026-07-22)
15
+
16
+ v0.1.6 is a release-preparation snapshot that closes the release-docs automation loop. A single structured release-notes source drives deterministic, multilingual CHANGELOG and README refresh behind a two-phase, digest-bound write protocol and a prepare-time documentation freshness gate, while terminal transaction receipts are bounded and the CLI lifecycle, path safety, and error-output redaction are hardened.
17
+
18
+ **Added**
19
+
20
+ - **Structured release-notes-driven document refresh (`docs refresh`)**: a single
21
+ structured release-notes source (`release-notes/0.1.6.yaml`) now drives
22
+ deterministic, multilingual refresh of the managed CHANGELOG and README
23
+ regions. Refresh runs as a two-phase protocol: a read-only planning phase
24
+ renders every candidate and freezes an `inputDigest` (binding the canonical
25
+ notes and the notes-source bytes) plus a `refreshDigest` (binding the protocol
26
+ version, unit, version, configuration projection, and per-file old/new
27
+ digests), and a separate write phase commits the changed targets only when all
28
+ three authorizations are present (`--write`, an exact `--confirm-refresh
29
+ <refreshDigest>` match, and `--ack-local-document-write`). The write phase
30
+ re-plans under the exclusive lock; a diverging digest converges to
31
+ `RELEASE_DOCS_REFRESH_STALE` with zero writes, and a clean plan is a zero-write
32
+ no-op. A prepare-time documentation freshness gate makes version drift between
33
+ the package version and the public docs fail closed before a release plan is
34
+ frozen.
35
+ - **Bounded terminal transaction receipts with recovery safety**: terminal
36
+ (committed / rolled-back) transactions now persist a summary-only receipt
37
+ instead of full payload, capped at 256 KB per receipt
38
+ (`TERMINAL_RECEIPT_SIZE_CAP`), under a retention cap of 50 terminal records
39
+ (`DEFAULT_TRANSACTION_RETENTION_MAX`). Retention pruning only ever removes
40
+ terminal records and never prunes `RECOVERY_CONFLICT` records or any
41
+ non-terminal (recovery-relevant) record, so recovery evidence is preserved even
42
+ when the count cap is reached; a retention failure never aborts an in-flight
43
+ commit.
44
+ - **Strict `docs refresh` parameter validation (fail closed)**: the `docs`
45
+ command validates every parameter before invoking the refresh service, so
46
+ precise stable parameter errors surface even without project configuration or a
47
+ safe-fs backend. The `--flag=value` equals form routes through exactly the same
48
+ validation as the space-separated form; duplicated flags fail closed with
49
+ `DUPLICATE_PARAMETER` before any service call, config read, lock, or
50
+ transaction; and bare positional arguments and single-dash flags (such as `-w`)
51
+ are rejected as unrecognized. Write-authorization flags supplied without
52
+ `--write`, or `--write` without its full authorizations, fail closed with
53
+ precise reasons rather than silently proceeding.
54
+
55
+ **Fixed**
56
+
57
+ - **Bundle entry lifecycle settles with real exit codes**: the self-contained
58
+ bundle now owns the command lifecycle. Its entry awaits command completion and
59
+ exits with the real business exit code for success, business errors, handled
60
+ async rejections, and unknown commands, so the launcher no longer leaves an
61
+ unsettled top-level await (Node exit code 13). When the bundle is missing or
62
+ cannot be evaluated, the launcher fails closed with static text only and never
63
+ interpolates machine-specific paths, usernames, or host layout, because
64
+ module-load failure messages carry absolute paths.
65
+ - **Fail-closed path canonicalization with stable diagnostics**: artifact path
66
+ canonicalization requires POSIX separators and rejects absolute paths in POSIX
67
+ (`/`), Windows drive-letter, and UNC spellings, along with traversal, Windows
68
+ reserved device names, and colons, failing closed with `PATH_UNSAFE` rather
69
+ than normalizing an unsafe spelling into a different public path. Error-output
70
+ redaction now distinguishes real filesystem paths from strict RFC 6901 JSON
71
+ Pointer diagnostic coordinates (such as `/units/0/version`): absolute
72
+ POSIX/Windows/UNC paths collapse to a stable `<redacted-path>` placeholder
73
+ while diagnostic pointers are preserved verbatim, keeping failures diagnosable
74
+ without leaking host paths.
75
+ - **Self public-boundary redaction**: the centralized redaction authority
76
+ (`core/redact.mjs`) now closes the self public boundary so runtime error
77
+ outputs and detail structures never carry the release-skill workspace's own
78
+ absolute path, nor the macOS `Users`, Linux home, macOS `private`/`var` alias,
79
+ temp, or CI checkout realms. Redaction runs fail-closed through the
80
+ `ReleaseError` choke point: any two-or-more-segment `/`-led token that is not a
81
+ strict diagnostic JSON Pointer is replaced with `<redacted-path>`, so
82
+ self-releasing never leaks private filesystem layout into public outputs.
83
+ <!-- release-skill:managed:end id=latest-release -->
84
+
13
85
  <!-- release-skill:capability:external-write-boundary -->
14
- > **Current boundary:** v0.1.5 is the current release. v0.1.1 completed a real production release
15
- > to GitHub and npm the first production-verified milestone — followed by
86
+ > **Current boundary:** v0.1.6 is the current release (v0.1.5 previously held
87
+ > this status after completing real production verification).
88
+ > v0.1.1 completed a real production release to GitHub and npm — the first
89
+ > production-verified milestone — followed by
16
90
  > exact npm installation and Claude/Codex consumer installation verification
17
91
  > from the frozen Git ref; "current release" and "first production-verified
18
92
  > milestone" are two distinct facts and must not be conflated. The same
@@ -27,7 +101,7 @@ regenerate a README or re-pack the live workspace at the last step.
27
101
  > publish global preflight.
28
102
 
29
103
  <!-- release-skill:capability:safe-first-command -->
30
- > **Production path verified since the v0.1.1 milestone; v0.1.5 is the current
104
+ > **Production path verified since the v0.1.1 milestone; v0.1.6 is the current
31
105
  > release.** The npm-installed CLI is the supported user entry. Source checkout
32
106
  > is the development/contributor fallback.
33
107
  >
@@ -73,6 +147,10 @@ truth, and never rewrite human truth.**
73
147
 
74
148
  ## Quick start
75
149
 
150
+ Every read-only step below keeps potentially large reports in temporary files
151
+ and surfaces only the deterministic `compactSummary` review view; the summary
152
+ is a review aid, never a substitute for the bound digest authorization.
153
+
76
154
  ### Install / requirements
77
155
 
78
156
  - Node.js 22+
@@ -490,7 +568,9 @@ publication. The source checkout remains the development/contributor fallback.
490
568
  `units[].targetVersion`, and `planDigest`. Each unit's snapshot is under
491
569
  `<evidenceDir>/snapshots/<unit-id>/`. The release-skill pipeline writes its
492
570
  own data under `.release-skill/`; acknowledged project hooks and gates are
493
- unsandboxed processes and may write elsewhere or access the network.
571
+ arbitrary project processes without an operating-system sandbox and may
572
+ write elsewhere, access the network, and read any credentials, tokens,
573
+ keys, and environment variables accessible to the current account.
494
574
  6. **Production plan freeze:**
495
575
  ```bash
496
576
  PRODUCTION_JSON=$("${CLI[@]}" prepare --root "$PROJECT" --online --production \
@@ -521,7 +601,11 @@ publication. The source checkout remains the development/contributor fallback.
521
601
  publish/reconcile. Approval expires after 24
522
602
  hours; a PARTIAL recovery may create a new approval for the same plan while
523
603
  preserving every earlier approval byte-for-byte. Use the returned
524
- `approvalPath` and `expiresAt` as authority.
604
+ `approvalPath` and `expiresAt` as authority. `--actor` is only an
605
+ unauthenticated local audit label: release-skill performs no identity
606
+ authentication and provides no digital signature, so it cannot prove that
607
+ a real human actually approved — it only records the identity the operator
608
+ self-reports.
525
609
  8. **Publish (remote writes start here):**
526
610
  ```bash
527
611
  PUBLISH_JSON=$("${CLI[@]}" publish --root "$PROJECT" \
@@ -557,6 +641,110 @@ Before a real release run `gh auth login`, `gh auth setup-git`, and
557
641
  Version branches default to `release/<tag>` and can be configured per unit with
558
642
  `production.branchTemplate`; any existing remote object stops for human review.
559
643
 
644
+ ### Release-document refresh (optional)
645
+
646
+ A release unit can declare `releaseDocuments` so one structured, bilingual
647
+ notes source deterministically refreshes the managed README regions and the
648
+ current CHANGELOG entry. The core CLI runs entirely offline: it does not use
649
+ the network, does not call any large language model, and does not
650
+ auto-translate. It only rewrites the declared managed regions, the unique
651
+ version marker's machine value, and the current CHANGELOG managed entry;
652
+ every byte outside those regions is preserved verbatim. `prepare` only
653
+ checks freshness and never writes the working tree.
654
+
655
+ ```yaml
656
+ # .release-skill/project.yaml (release unit fragment)
657
+ releaseUnits:
658
+ - id: my-project
659
+ source: .
660
+ releaseDocuments:
661
+ notesSource: release-notes/{version}.yaml
662
+ locales: [en, zh-CN]
663
+ changelogs:
664
+ - path: CHANGELOG.md
665
+ locale: en
666
+ readmes:
667
+ - path: README.md
668
+ locale: en
669
+ regions: [latest-release]
670
+ versionMarkers:
671
+ - id: current-version
672
+ pattern: '<!-- release-skill:version -->v{version}<!-- /release-skill:version -->'
673
+ - path: README.zh-CN.md
674
+ locale: zh-CN
675
+ regions: [latest-release]
676
+ ```
677
+
678
+ `notesSource` and every target path are relative to the release unit root.
679
+ `versionMarkers[].pattern` must match the README's existing unique version
680
+ marker exactly, with `{version}` standing in for the machine value; the
681
+ refresh replaces only that value (zero or multiple matches fail closed).
682
+
683
+ ```yaml
684
+ # release-notes/0.1.6.yaml (structured notes source)
685
+ version: 0.1.6
686
+ date: 2026-07-21
687
+ locales:
688
+ en:
689
+ summary: Deterministic multilingual release-document refresh.
690
+ changes:
691
+ added:
692
+ - Refresh managed README regions and changelogs from one source.
693
+ upgradeNotes: Review and commit refreshed documents before prepare.
694
+ zh-CN:
695
+ summary: 从同一说明源确定性刷新多语种发布文档。
696
+ changes:
697
+ added:
698
+ - 自动刷新 README 受管区域和 CHANGELOG。
699
+ upgradeNotes: prepare 前审阅并提交刷新结果。
700
+ ```
701
+
702
+ `version` must exactly equal the resolved unit version; every configured
703
+ locale appears exactly once with a non-empty `summary` and at least one
704
+ change under `security`, `breaking`, `added`, `changed`, `deprecated`,
705
+ `removed`, or `fixed`. YAML aliases, duplicate keys, unknown fields, and
706
+ locale fallback all fail closed.
707
+
708
+ 1. **Read-only drill:**
709
+ ```bash
710
+ "${CLI[@]}" docs refresh --root "$PROJECT" --unit my-project --json
711
+ ```
712
+ Prints `status` (`changes` or `clean`), per-file relative `path`,
713
+ `locale`, `kind`, old/new digests, the unit `version`, `locales`,
714
+ `inputDigest`, and `refreshDigest` — a binding over the protocol
715
+ version, the unit, the canonical notes object, the configuration
716
+ projection, and the sorted per-file old/new digests. It never binds
717
+ time, absolute paths, or display text. `nextCommand.argv` carries the
718
+ exact write command.
719
+ 2. **Digest-confirmed local write (only after explicit human authorization
720
+ of the local release-document write):**
721
+ ```bash
722
+ "${CLI[@]}" docs refresh --root "$PROJECT" --unit my-project \
723
+ --write --confirm-refresh <refreshDigest> \
724
+ --ack-local-document-write --json
725
+ ```
726
+ All three bindings are required; a mismatched digest fails closed with
727
+ `RELEASE_DOCS_REFRESH_STALE` and writes nothing. When the candidate is
728
+ unchanged the drill reports `clean` and the write performs zero writes.
729
+ All targets commit as one transaction; a successful write is followed
730
+ by a re-drill that must return `clean`.
731
+
732
+ This authorization covers only the declared local document targets. It is
733
+ not authorization for hooks, Git commits, pushes, publishes, or installs:
734
+ a maintainer must review the refreshed documents, commit them, and rerun
735
+ `prepare` — the new bytes change the snapshot, workspace digest, and plan
736
+ digest, so an earlier approval cannot authorize the refreshed plan.
737
+
738
+ When configured documents drift, `prepare` fails closed with
739
+ `RELEASE_DOCS_STALE` before hooks, baseline, snapshot, remote checks, and
740
+ plan freeze. Recovery: run the drill, review the shown files/locales/
741
+ version/digest, authorize and perform the local write, review and commit
742
+ the result, then rerun `prepare`. `RELEASE_DOCS_INVALID` (bad
743
+ configuration or notes data), `RELEASE_DOCS_TRANSLATION_MISSING` (a
744
+ configured locale absent), and `RELEASE_DOCS_CONFLICT` (unmanaged
745
+ same-version content or marker damage) each require fixing the source or
746
+ target first; never widen the write scope to resolve them.
747
+
560
748
  ### Parent workspace with npm + plugin sub-units
561
749
 
562
750
  When a monorepo produces both an npm package and a Claude/Codex plugin from
@@ -567,6 +755,10 @@ and entry Skill:
567
755
  Here `project` is the parent workspace's orchestration container, not a public
568
756
  release unit. If the workspace root also publishes its own repository or
569
757
  package, add another release unit with `source: .`.
758
+ `version.source` is resolved relative to that release unit's `source` directory
759
+ (`version.source` 相对于该发布单元的 `source` 目录解析): a unit with
760
+ `source: packages/app` therefore writes plain `package.json`, not
761
+ `packages/app/package.json`.
570
762
 
571
763
  ```yaml
572
764
  apiVersion: release-skill/v1
@@ -580,7 +772,7 @@ releaseUnits:
580
772
  source: packages/app
581
773
  publicRepo: owner/my-app
582
774
  version:
583
- source: packages/app/package.json
775
+ source: package.json
584
776
  tagTemplate: my-app-v{version}
585
777
  distributions:
586
778
  - type: npm
@@ -616,7 +808,7 @@ releaseUnits:
616
808
  source: packages/plugin
617
809
  publicRepo: owner/my-plugin
618
810
  version:
619
- source: packages/plugin/package.json
811
+ source: package.json
620
812
  tagTemplate: my-plugin-v{version}
621
813
  distributions:
622
814
  # Declare plugin consumers only when the unit ships a plugin.
@@ -750,6 +942,29 @@ them only for work that genuinely needs the parent workspace or generates
750
942
  source files. They can modify files or access the network, so prepare requires
751
943
  `--acknowledge-hook-side-effects`.
752
944
 
945
+ Each hook is an object, never a bare command list.
946
+ `command` is an executable/argument array, not a shell string
947
+ (`command` 是可执行文件/参数数组,不是 shell 字符串). Each hook also declares
948
+ `cwd`, `timeoutMs`, and `envAllowlist`:
949
+
950
+ ```yaml
951
+ hooks:
952
+ build:
953
+ command: [node, scripts/build.mjs]
954
+ cwd: .
955
+ timeoutMs: 120000
956
+ envAllowlist: [CI]
957
+ test:
958
+ command: [node, --test, test/]
959
+ cwd: .
960
+ timeoutMs: 300000
961
+ envAllowlist: []
962
+ ```
963
+
964
+ Hooks still run only after human review of every configured executable,
965
+ argument, working directory, and side effect, and only with
966
+ `prepare --acknowledge-hook-side-effects`.
967
+
753
968
  `verificationGates` are the controlled extension point for release calibration:
754
969
 
755
970
  ```yaml