release-skill 0.6.2 → 0.7.0

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 (112) 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 +48 -0
  7. package/CONTRIBUTING.md +1 -1
  8. package/INSTALL.md +47 -2
  9. package/INSTALL.zh-CN.md +29 -2
  10. package/README.md +137 -12
  11. package/README.zh-CN.md +110 -9
  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/error-codes.json +1 -1
  15. package/adapters/claude/bin/kernel-protocol.json +1 -1
  16. package/adapters/claude/bin/license-texts/Apache-2.0.txt +201 -0
  17. package/adapters/claude/bin/license-texts/MIT.txt +21 -0
  18. package/adapters/claude/bin/registry.json +64 -1
  19. package/adapters/claude/bin/release-skill.bundle.mjs +50570 -42208
  20. package/adapters/claude/bin/rules.json +1 -1
  21. package/adapters/claude/schemas/.render-manifest.json +10 -6
  22. package/adapters/claude/schemas/postpublish-approval-record.schema.json +47 -0
  23. package/adapters/claude/schemas/release-plan.schema.json +200 -4
  24. package/adapters/claude/schemas/release-project.schema.json +86 -5
  25. package/adapters/claude/schemas/release-run.schema.json +11 -6
  26. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  27. package/adapters/codex/bin/error-codes.json +1 -1
  28. package/adapters/codex/bin/kernel-protocol.json +1 -1
  29. package/adapters/codex/bin/license-texts/Apache-2.0.txt +201 -0
  30. package/adapters/codex/bin/license-texts/MIT.txt +21 -0
  31. package/adapters/codex/bin/registry.json +64 -1
  32. package/adapters/codex/bin/release-skill.bundle.mjs +50570 -42208
  33. package/adapters/codex/bin/rules.json +1 -1
  34. package/adapters/codex/schemas/.render-manifest.json +10 -6
  35. package/adapters/codex/schemas/postpublish-approval-record.schema.json +47 -0
  36. package/adapters/codex/schemas/release-plan.schema.json +200 -4
  37. package/adapters/codex/schemas/release-project.schema.json +86 -5
  38. package/adapters/codex/schemas/release-run.schema.json +11 -6
  39. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  40. package/adapters/kimi/bin/error-codes.json +1 -1
  41. package/adapters/kimi/bin/kernel-protocol.json +1 -1
  42. package/adapters/kimi/bin/license-texts/Apache-2.0.txt +201 -0
  43. package/adapters/kimi/bin/license-texts/MIT.txt +21 -0
  44. package/adapters/kimi/bin/registry.json +64 -1
  45. package/adapters/kimi/bin/release-skill.bundle.mjs +50570 -42208
  46. package/adapters/kimi/bin/rules.json +1 -1
  47. package/adapters/kimi/schemas/.render-manifest.json +10 -6
  48. package/adapters/kimi/schemas/postpublish-approval-record.schema.json +47 -0
  49. package/adapters/kimi/schemas/release-plan.schema.json +200 -4
  50. package/adapters/kimi/schemas/release-project.schema.json +86 -5
  51. package/adapters/kimi/schemas/release-run.schema.json +11 -6
  52. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
  53. package/adapters/workbuddy/bin/error-codes.json +1 -1
  54. package/adapters/workbuddy/bin/kernel-protocol.json +1 -1
  55. package/adapters/workbuddy/bin/license-texts/Apache-2.0.txt +201 -0
  56. package/adapters/workbuddy/bin/license-texts/MIT.txt +21 -0
  57. package/adapters/workbuddy/bin/registry.json +64 -1
  58. package/adapters/workbuddy/bin/release-skill.bundle.mjs +50570 -42208
  59. package/adapters/workbuddy/bin/rules.json +1 -1
  60. package/adapters/workbuddy/schemas/.render-manifest.json +10 -6
  61. package/adapters/workbuddy/schemas/postpublish-approval-record.schema.json +47 -0
  62. package/adapters/workbuddy/schemas/release-plan.schema.json +200 -4
  63. package/adapters/workbuddy/schemas/release-project.schema.json +86 -5
  64. package/adapters/workbuddy/schemas/release-run.schema.json +11 -6
  65. package/bin/error-codes.json +1 -1
  66. package/bin/kernel-protocol.json +1 -1
  67. package/bin/license-texts/Apache-2.0.txt +201 -0
  68. package/bin/license-texts/MIT.txt +21 -0
  69. package/bin/registry.json +64 -1
  70. package/bin/release-skill-cli.mjs +187 -9
  71. package/bin/release-skill.bundle.mjs +50570 -42208
  72. package/bin/rules.json +1 -1
  73. package/package.json +6 -4
  74. package/platform-manifest.json +4 -4
  75. package/references/.render-manifest.json +5 -5
  76. package/references/01-state-machine.md +22 -2
  77. package/references/02-project-config.md +1 -1
  78. package/references/06-adapter-contract.md +6 -3
  79. package/schemas/.render-manifest.json +10 -6
  80. package/schemas/postpublish-approval-record.schema.json +47 -0
  81. package/schemas/release-plan.schema.json +200 -4
  82. package/schemas/release-project.schema.json +86 -5
  83. package/schemas/release-run.schema.json +11 -6
  84. package/src/adapters/distribute-git.mjs +17 -11
  85. package/src/commands/approve.mjs +163 -1
  86. package/src/commands/distribute.mjs +649 -89
  87. package/src/commands/postverify.mjs +808 -0
  88. package/src/commands/prepare.mjs +456 -45
  89. package/src/commands/setup.mjs +715 -0
  90. package/src/commands/ship.mjs +152 -5
  91. package/src/commands/verify.mjs +92 -15
  92. package/src/core/approval.mjs +93 -68
  93. package/src/core/bounded-output.mjs +46 -0
  94. package/src/core/derived-artifact-gates.mjs +258 -0
  95. package/src/core/docs-refresh-preset.mjs +171 -0
  96. package/src/core/errors.mjs +4 -0
  97. package/src/core/evidence.mjs +8 -1
  98. package/src/core/git-url-policy.mjs +214 -0
  99. package/src/core/hooks.mjs +28 -0
  100. package/src/core/marketplace-registry-entry.mjs +175 -0
  101. package/src/core/notify-handoff.mjs +76 -0
  102. package/src/core/postpublish-approval.mjs +241 -0
  103. package/src/core/postpublish-bundle.mjs +342 -0
  104. package/src/core/postpublish-projection.mjs +210 -0
  105. package/src/core/postpublish.mjs +449 -25
  106. package/src/core/preset-executor.mjs +175 -0
  107. package/src/core/preset-gitwrite.mjs +484 -0
  108. package/src/core/presets.mjs +754 -0
  109. package/src/core/proposal-inbox.mjs +646 -0
  110. package/src/core/redact.mjs +16 -3
  111. package/src/core/run.mjs +91 -6
  112. package/src/producers/build-adapters.mjs +28 -14
package/bin/rules.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "kind": "skill-family.contracts.rules",
4
- "contractsVersion": "1.5.0",
4
+ "contractsVersion": "1.7.0",
5
5
  "budget": {
6
6
  "firstVersionMax": 20,
7
7
  "absoluteMax": 30,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "release-skill",
3
- "version": "0.6.2",
3
+ "version": "0.7.0",
4
4
  "description": "Safe preparation and frozen GitHub/npm production publishing with full happy end verification",
5
5
  "author": {
6
6
  "name": "广州市风荷科技有限公司"
@@ -65,6 +65,7 @@
65
65
  "sync:public-files:check": "node scripts/sync-public-files.mjs --check",
66
66
  "build:adapters": "node scripts/build-adapters.mjs",
67
67
  "build:adapters:check": "node scripts/build-adapters.mjs --check",
68
+ "build:adapters:apply": "node scripts/build-adapters.mjs --apply",
68
69
  "build:bundle": "node scripts/build-bundle.mjs",
69
70
  "build:bundle:check": "node scripts/build-bundle.mjs --check",
70
71
  "native:build": "node-gyp rebuild --directory native/safe-write",
@@ -77,8 +78,9 @@
77
78
  "ajv-formats": "3.0.1",
78
79
  "libnpmpublish": "11.1.0",
79
80
  "npm-registry-fetch": "18.0.2",
80
- "skill-family-contracts": "0.5.0",
81
- "skill-family-harness-node": "0.5.0",
81
+ "skill-family-contracts": "0.8.0",
82
+ "skill-family-engineering-kit": "0.8.0",
83
+ "skill-family-harness-node": "0.8.0",
82
84
  "yaml": "2.9.0"
83
85
  },
84
86
  "devDependencies": {
@@ -86,7 +88,7 @@
86
88
  "node-gyp": "12.3.0"
87
89
  },
88
90
  "engines": {
89
- "node": ">=22.0.0"
91
+ "node": ">=22.22.2 <23"
90
92
  },
91
93
  "keywords": [
92
94
  "release",
@@ -2,11 +2,11 @@
2
2
  "schemaVersion": "1.0.0",
3
3
  "platformId": "release-skill",
4
4
  "platformName": "release-skill Plugin Platform",
5
- "version": "0.6.0",
5
+ "version": "0.7.0",
6
6
  "logicalRoot": "skills-src/",
7
- "logicalRootDigest": "6d504094e1bf7d38beb6d886ff48ea442e7563b6061a7145a14c2d71a60292f5",
8
- "projectionDigest": "2ca5c5d0b71e10622911426d3abf9c0dfae72237ee6001d4eaaada90acb7a0d7",
9
- "projectionId": "release-skill:platform:0.6.0",
7
+ "logicalRootDigest": "3767fc36f42ca561f5e839cea7b7e5bc16d08c47867b5bd6086f25efd0cb0f06",
8
+ "projectionDigest": "419f7f9601015459956e10aae74f42240ab2ac248238ff7494f3e761643d1749",
9
+ "projectionId": "release-skill:platform:0.7.0",
10
10
  "manifestRequired": true,
11
11
  "projectionSources": {
12
12
  "skills-src-root": {
@@ -1,13 +1,13 @@
1
1
  {
2
- "source": "references",
2
+ "source": "standards",
3
3
  "files": {
4
4
  "00-target-state.md": {
5
5
  "digest": "d66f8c33b2df2bbcb235ce123f786c18c19b3a797197495793d9af566618099d",
6
6
  "bytes": 6335
7
7
  },
8
8
  "01-state-machine.md": {
9
- "digest": "4698e3763f76774798e269ae163fcf87ba8ca358a9638c5bff693f5921455f9f",
10
- "bytes": 9114
9
+ "digest": "711265e093be13f582ac8be89c391eff79ac22f56c25b91d1ccaef31856ef269",
10
+ "bytes": 12086
11
11
  },
12
12
  "02-project-config.md": {
13
13
  "digest": "f866490d5897c2baf38fd3a6770964c052bea4418f034b75965ecfe49c2f4387",
@@ -22,8 +22,8 @@
22
22
  "bytes": 4682
23
23
  },
24
24
  "05-evidence-and-errors.md": {
25
- "digest": "3df7644a6db614ee5f67689834f97227752834cf6c27762dee66650675c34168",
26
- "bytes": 11592
25
+ "digest": "f1352256e3b9e2c96c1aa6689fa921a909ab41f80832c5a3356a10590b640929",
26
+ "bytes": 12014
27
27
  },
28
28
  "06-adapter-contract.md": {
29
29
  "digest": "4b1ec9ba843345df47c1d133a8bf1aa644bf12a4ecf760cb1d566a43f1e9a9d2",
@@ -6,7 +6,7 @@
6
6
 
7
7
  ## 1. 状态定义
8
8
 
9
- 发布生命周期包含 7 个主状态和 3 个异常状态,共计 10 个状态。
9
+ 发布生命周期包含 9 个主状态和 3 个异常状态,共计 12 个状态。
10
10
 
11
11
  ### 1.1 主状态
12
12
 
@@ -18,6 +18,8 @@
18
18
  | **APPROVED** | 人工审阅并批准了冻结的发布计划 | 批准记录绑定到发布计划 hash,且未过期 |
19
19
  | **PUBLISHING** | 外部写操作正在按检查点依次执行 | `publish` 命令读取已批准计划并开始执行 |
20
20
  | **PUBLISHED** | 所有发布检查点均已成功完成 | 最后一个检查点的 `observe` 验证通过 |
21
+ | **DISTRIBUTING** | 发布后分发正在执行:载荷物化、目标镜像推送与 distribute 阶段 postPublish hooks 按检查点依次进行 | 计划声明 `postPublish`(targets 或 hooks),`ship` 路由到 `distribute` 并通过全部安全门后开始执行 |
22
+ | **DISTRIBUTED** | 分发完成:全部目标与 distribute 阶段 hooks 成功(或远端已一致而幂等跳过) | `distribute` run 无失败且无待批准检查点 |
21
23
  | **VERIFIED** | 发布后验证全部通过 | `verify` 命令在全新环境中完成安装、调用、泄漏审计和远端一致性校验 |
22
24
 
23
25
  ### 1.2 异常状态
@@ -48,7 +50,15 @@
48
50
  | PUBLISHING | PUBLISHED | 所有检查点成功 |
49
51
  | PUBLISHING | PARTIAL | 至少一个检查点成功但后续失败 |
50
52
  | PUBLISHING | BLOCKED | 外部服务阻断且无法继续 |
51
- | PUBLISHED | VERIFIED | `verify` 的远端、npm、Claude/Codex 等自动化检查全部通过;新计划中的 Kimi/CodeBuddy 人工安装任务不由系统核验且不阻塞该状态 |
53
+ | PUBLISHED | DISTRIBUTING | 计划声明 `postPublish`(targets 或 hooks),`ship` 路由到 `distribute` 开始执行 |
54
+ | PUBLISHED | VERIFIED | 无 `postPublish` 声明时,`verify` 的远端、npm、Claude/Codex 等自动化检查全部通过(Kimi/CodeBuddy 人工安装任务不由系统核验且不阻塞);声明了 `postPublish` 时必须先经 DISTRIBUTING/DISTRIBUTED 门禁 |
55
+ | DISTRIBUTING | DISTRIBUTED | 全部目标与 distribute 阶段 hooks 成功(或远端已一致幂等跳过),且无待批准检查点 |
56
+ | DISTRIBUTING | PARTIAL | 至少一个外部 checkpoint 已成功后,目标/hooks 失败或存在待批准 checkpoint |
57
+ | DISTRIBUTING | NEEDS_INPUT | `requiresApproval` hook 缺少 checkpoint 级批准,且尚无任何外部副作用 |
58
+ | DISTRIBUTING | BLOCKED | 零外部写入落地且安全门或 hook 失败(失败关闭) |
59
+ | DISTRIBUTED | VERIFIED | `verify` 的 distribute 门禁通过:存在 DISTRIBUTED(或经 `blocksVerified:false` 合法豁免的 PARTIAL)分发 run,且安装/远端校验全部通过 |
60
+ | NEEDS_INPUT | DISTRIBUTING | checkpoint 批准补齐后重跑 `distribute` |
61
+ | PARTIAL | DISTRIBUTING | `distribute` 重跑即 reconcile:跳过已一致目标,仅重跑安全未完成项 |
52
62
  | PUBLISHED | POST_PUBLISH_VERIFY_FAILED | 发布后验证失败(保留 PUBLISHED 事实但标记验证失败) |
53
63
  | NEEDS_INPUT | DISCOVERED | 用户提供输入后重新开始评估 |
54
64
  | NEEDS_INPUT | ASSESSED | 用户提供输入后恢复评估 |
@@ -66,6 +76,14 @@
66
76
  - APPROVED -> PREPARED:当 plan digest、目标版本或已批准 action 列表变化时,批准自动失效。planVersion 2 计划的 digest 只绑定信任边界(冻结产物身份、动作列表、目标版本、配置摘要),工作区基线(Git tree hash、workspace digest)是记录层审计数据,不使批准失效;planVersion 1(旧版)计划维持旧规则,Git tree hash 与 workspace digest 变化同样使批准失效。
67
77
  - PUBLISHING -> PARTIAL:当任一检查点成功后下一检查点失败时,自动计算 PARTIAL 状态。
68
78
 
79
+ ### 2.2 分发阶段与 postVerify 阶段(v0.6.3)
80
+
81
+ postPublish hooks 分两个阶段,各自对应独立的 distribute run:
82
+
83
+ - **distribute 阶段**(默认 `phase: distribute`):在 DISTRIBUTING 中执行,载荷只能来自冻结 tagCommit 的 detached worktree(时序契约)。全部目标与 distribute 阶段 hooks 成功后进入 DISTRIBUTED;`verify` 在到达 VERIFIED 前检查 distribute 门禁——存在未 SUCCEEDED 且未经 `blocksVerified: false` 合法豁免的 hook 时不得 VERIFIED。NEEDS_INPUT/BLOCKED 不得静默转 VERIFIED(承袭治理规则)。
84
+ - **postVerify 阶段**(`phase: postVerify`):主 run VERIFIED 后由 ship/verify 路由触发,产出独立的 distribute run(复用现有 run 记录与 checkpoint 机制);失败即该 run PARTIAL、reconcile 可续。主 run 的 VERIFIED 不回退,但 postVerify run 的失败必须以证据显著记录,绝不静默。
85
+ - **checkpoint 级批准**:`requiresApproval: true` 的 hook 执行前需要绑定 `(planDigest, hookId)` 的独立批准记录(24h 过期、5 分钟时钟偏移容忍)。批准未获时:尚无外部 checkpoint 成功 → checkpoint 标记 `AWAITING_APPROVAL`、run 进 NEEDS_INPUT;已有外部 checkpoint 成功 → run 保持 PARTIAL。
86
+
69
87
  ---
70
88
 
71
89
  ## 3. 禁止转换
@@ -84,6 +102,8 @@
84
102
  | APPROVED -> VERIFIED | 不能跳过发布直接验证 |
85
103
  | APPROVED -> PUBLISHED | 不能跳过发布执行直接到已发布 |
86
104
  | PUBLISHING -> VERIFIED | 发布完成后必须先到 PUBLISHED |
105
+ | DISTRIBUTING -> VERIFIED | 分发必须先达 DISTRIBUTED 再经 verify distribute 门禁 |
106
+ | DISTRIBUTING -> APPROVED | 分发进行中不能回退到批准 |
87
107
  | PUBLISHING -> APPROVED | 发布进行中不能回退到批准 |
88
108
  | PUBLISHING -> PREPARED | 发布进行中不能回退到准备 |
89
109
  | PUBLISHED -> PUBLISHING | 已发布的不能重新发布同一计划 |
@@ -103,7 +103,7 @@ postPublish: # 可选;发布后分发配置(W2 closure)
103
103
  email: <string> # RFC 5322 valid
104
104
  payloadDir: <string> # 相对路径
105
105
  dryRun?: boolean # 可选;只本地执行
106
- materialize?: { # 可选;分发前钩子
106
+ materialize?: { # 可选;缺省时载荷由冻结 publicFiles 经 Foundation 托管投影物化
107
107
  command: <string> # 可执行文件
108
108
  args: [<string>] # 参数数组,禁止 shell 字符串
109
109
  outputMarker?: <string> # 输出标记,用于验证
@@ -170,12 +170,14 @@ marketplace install action 的安装侧载荷校验以 action 参数 `payloadCon
170
170
  1. 发布计划已冻结且 schema 验证通过。
171
171
  2. 发布计划摘要与批准记录中的摘要匹配。
172
172
  3. 批准记录存在且未超过 24 小时有效期。
173
- 4. Git tree hash 与批准记录中的匹配。
173
+ 4. 工作区基线按 `planVersion` 分叉校验(与 `01-state-machine.md` §4.4 及根 `AGENTS.md` 的 Release Authorization 语义一致):
174
+ - **planVersion 1(旧版)计划**:继续绑定基线——Git tree hash(及 workspace digest)必须与批准记录中的匹配;批准后基线变化即使批准失效,硬失败(`BASELINE_CHANGED`)。
175
+ - **planVersion 2 计划**:digest 只绑定信任边界(冻结产物身份:git commit/tree、manifestDigest、npm tarball 摘要;外部动作列表;目标版本;配置摘要)。工作区基线(tree hash、workspace digest)是记录层审计数据:不参与 digest、不使批准失效;publish/reconcile 检测到基线漂移时记录 warning 级证据事件并继续执行,产物身份与完整性由外部写之前的冻结产物复验保证。
174
176
  5. 目标版本与批准记录中的匹配。
175
177
  6. 远端无冲突状态(preflight 通过)。
176
178
  7. `context.externalWritesAuthorized === true`。
177
179
 
178
- 任一条件不满足时,execute 返回对应错误码(`AUTH_MISSING`、`BASELINE_CHANGED`、`REMOTE_CONFLICT` 等)并拒绝执行。
180
+ 任一条件不满足时,execute 返回对应错误码(`AUTH_MISSING`、`BASELINE_CHANGED`(仅 planVersion 1)、`REMOTE_CONFLICT` 等)并拒绝执行。
179
181
 
180
182
  ### 3.2 批准记录结构
181
183
 
@@ -195,6 +197,7 @@ marketplace install action 的安装侧载荷校验以 action 参数 `payloadCon
195
197
 
196
198
  - `approvedActions` 不得包含通配符。
197
199
  - `expiresAt` 不得晚于 `approvedAt` + 24 小时。
200
+ - `baseline` 的约束力按 `planVersion` 分叉(见 §3.1 条件 4):planVersion 1 计划中它是批准绑定字段;planVersion 2 计划中它只是记录层审计数据,不使批准失效。
198
201
 
199
202
  ---
200
203
 
@@ -234,7 +237,7 @@ marketplace install action 的安装侧载荷校验以 action 参数 `payloadCon
234
237
  1. 重新验证发布计划 schema。
235
238
  2. 重新验证发布计划摘要。
236
239
  3. 检查批准记录是否过期。
237
- 4. 检查 Git tree hash 是否变化。
240
+ 4. planVersion 分叉复验工作区基线:planVersion 1 计划基线变化即失败(`BASELINE_CHANGED`);planVersion 2 计划基线漂移仅记录 warning 级证据事件并继续,产物身份由外部写之前的冻结产物复验保证。
238
241
  5. 执行远程 preflight。
239
242
  6. 按批准的操作列表顺序执行每个检查点。
240
243
  7. 每个检查点:preflight -> execute -> observe -> 记录。
@@ -21,17 +21,21 @@
21
21
  "digest": "b7e14522a5aba818cab191545f23d2323be0e4c80566e9d3e4da576103a00490",
22
22
  "bytes": 2390
23
23
  },
24
+ "postpublish-approval-record.schema.json": {
25
+ "digest": "e365c9e9f5aa189ca6788e68dbedfa718aa120f2c197534417c21e019b9a29a4",
26
+ "bytes": 1744
27
+ },
24
28
  "release-plan.schema.json": {
25
- "digest": "5e988a5301b89b3d3260154ffae12669af0e4d6ec7f9db8c44df21037ea0eaf6",
26
- "bytes": 46948
29
+ "digest": "48b7755dfbeee88ccf78c3200000ab2f5dd06db42bc7b423aed0f81a91cc0418",
30
+ "bytes": 54672
27
31
  },
28
32
  "release-project.schema.json": {
29
- "digest": "546e05845cd83a3b1db0a54036f9555081420337e9df961d783d2d2630800ef7",
30
- "bytes": 41898
33
+ "digest": "cc2061799c3a0dd6daea940148e3497b7a4ae8cafb987bf51de7c34c1fed921d",
34
+ "bytes": 46932
31
35
  },
32
36
  "release-run.schema.json": {
33
- "digest": "6dd239c59f7045df11d13d6ba2027610d3c55c27a6af5bc87676b0eaad9600fd",
34
- "bytes": 17663
37
+ "digest": "9755a8caa58dd02509ac8e6f869aec5e74d8ae3f7339a3f944977bfad7b729ad",
38
+ "bytes": 17897
35
39
  }
36
40
  }
37
41
  }
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://release-skill.dev/schemas/postpublish-approval-record/v1",
4
+ "title": "PostPublish Hook Approval Record",
5
+ "description": "Schema for checkpoint-level approval of a requiresApproval postPublish hook (v0.6.3 R1, design §2.7 ruling 2). Binds the approval to (planDigest, hookId); the plan-level approval-record schema is untouched. runId is audit-only and never participates in binding or validation semantics.",
6
+ "type": "object",
7
+ "required": [
8
+ "planDigest",
9
+ "hookId",
10
+ "actor",
11
+ "approvedAt",
12
+ "expiresAt"
13
+ ],
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "planDigest": {
17
+ "type": "string",
18
+ "pattern": "^[a-f0-9]{64}$",
19
+ "description": "SHA-256 digest of the frozen release plan whose postPublish hooks block this approval binds to"
20
+ },
21
+ "hookId": {
22
+ "type": "string",
23
+ "pattern": "^[a-z0-9][a-z0-9._-]*$",
24
+ "description": "id of the requiresApproval postPublish hook being approved (must be declared in the frozen plan)"
25
+ },
26
+ "actor": {
27
+ "type": "string",
28
+ "minLength": 1,
29
+ "description": "Identity of the approver"
30
+ },
31
+ "approvedAt": {
32
+ "type": "string",
33
+ "format": "date-time",
34
+ "description": "ISO 8601 timestamp when approval was granted"
35
+ },
36
+ "expiresAt": {
37
+ "type": "string",
38
+ "format": "date-time",
39
+ "description": "ISO 8601 timestamp when approval expires (max 24h after approvedAt; 5-minute clock skew tolerated at validation)"
40
+ },
41
+ "runId": {
42
+ "type": "string",
43
+ "minLength": 1,
44
+ "description": "Audit-only identifier of the distribute run present when approval was granted; never a binding"
45
+ }
46
+ }
47
+ }
@@ -1304,10 +1304,8 @@
1304
1304
  },
1305
1305
  "planPostPublish": {
1306
1306
  "type": "object",
1307
- "description": "冻结的发布后分发块:声明本身 + tag/tagCommit/unitId/payloadSource 绑定。整体参与 plan digest(planVersion 2 记录层剥离不包含该块),任何配置变更都会改变 planDigest。tagCommit 仅在 prepare 能冻结 create-tag 预期 commit 时存在(production 资产);缺省时 distribute fail-closed。",
1307
+ "description": "冻结的发布后分发块:声明本身 + tag/tagCommit/unitId/payloadSource 绑定。整体参与 plan digest(planVersion 2 记录层剥离不包含该块),任何配置变更都会改变 planDigest。tagCommit 仅在 prepare 能冻结 create-tag 预期 commit 时存在(production 资产);缺省时 distribute fail-closed。materialize 钩子自 T6 起可选:载荷物化要么由消费者 materialize 钩子完成,要么由冻结 executionBundle.publicFiles 经 Foundation Engineering Kit 托管投影完成(两者至少其一,见 anyOf)。",
1308
1308
  "required": [
1309
- "materialize",
1310
- "targets",
1311
1309
  "commitIdentity",
1312
1310
  "tag",
1313
1311
  "unitId",
@@ -1325,6 +1323,13 @@
1325
1323
  "$ref": "#/definitions/planPostPublishTarget"
1326
1324
  }
1327
1325
  },
1326
+ "hooks": {
1327
+ "type": "array",
1328
+ "description": "冻结的发布后钩子声明(v0.6.3 R1);随整块参与 plan digest",
1329
+ "items": {
1330
+ "$ref": "#/definitions/planPostPublishHook"
1331
+ }
1332
+ },
1328
1333
  "commitIdentity": {
1329
1334
  "type": "object",
1330
1335
  "required": [
@@ -1370,6 +1375,197 @@
1370
1375
  "payloadSource": {
1371
1376
  "const": "tag-worktree",
1372
1377
  "description": "时序契约:载荷只能来自 tagCommit 处的 detached worktree,绝不读取工作区状态"
1378
+ },
1379
+ "executionBundle": {
1380
+ "type": "object",
1381
+ "description": "冻结的私有执行包(F-01/T1):closure 直接采用 Foundation computeResourceClosure() 的返回(排序、去重、受收容读取与摘要均由 Foundation 完成),publicFiles 是从发布单元投影的公开映射。计划是该执行包的唯一事实源:随整个 plan digest 绑定,不维护平行 manifest,也不另造 bundle digest。字节写入计划权威 .release-skill 的 postpublish-bundles/<closure.digest>/<resource.path>;distribute/postVerify 在任何 hook/外部写之前经 Foundation 严格复验并重算闭包,任何不一致即失败。",
1382
+ "required": [
1383
+ "foundationMechanism",
1384
+ "closure",
1385
+ "publicFiles"
1386
+ ],
1387
+ "additionalProperties": false,
1388
+ "properties": {
1389
+ "foundationMechanism": {
1390
+ "const": "foundation.harness.resource-closure"
1391
+ },
1392
+ "closure": {
1393
+ "type": "object",
1394
+ "description": "Foundation skill-family.resource-closure(schemaVersion 1)原样冻结",
1395
+ "required": [
1396
+ "schemaVersion",
1397
+ "kind",
1398
+ "digestAlgorithm",
1399
+ "digest",
1400
+ "resources"
1401
+ ],
1402
+ "additionalProperties": false,
1403
+ "properties": {
1404
+ "schemaVersion": {
1405
+ "const": 1
1406
+ },
1407
+ "kind": {
1408
+ "const": "skill-family.resource-closure"
1409
+ },
1410
+ "digestAlgorithm": {
1411
+ "const": "sha256"
1412
+ },
1413
+ "digest": {
1414
+ "type": "string",
1415
+ "pattern": "^[a-f0-9]{64}$"
1416
+ },
1417
+ "resources": {
1418
+ "type": "array",
1419
+ "items": {
1420
+ "type": "object",
1421
+ "required": [
1422
+ "path",
1423
+ "role",
1424
+ "exists",
1425
+ "sha256"
1426
+ ],
1427
+ "additionalProperties": false,
1428
+ "properties": {
1429
+ "path": {
1430
+ "type": "string",
1431
+ "minLength": 1,
1432
+ "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*\\\\).+$"
1433
+ },
1434
+ "role": {
1435
+ "const": "input",
1436
+ "description": "私有执行输入只有 input 资源;output 角色不属于执行包"
1437
+ },
1438
+ "exists": {
1439
+ "const": true
1440
+ },
1441
+ "sha256": {
1442
+ "type": "string",
1443
+ "pattern": "^[a-f0-9]{64}$"
1444
+ }
1445
+ }
1446
+ }
1447
+ }
1448
+ }
1449
+ },
1450
+ "publicFiles": {
1451
+ "type": "array",
1452
+ "description": "从已通过 schema 与运行时校验的发布单元投影进冻结计划的公开映射(T6 托管投影输入)",
1453
+ "items": {
1454
+ "type": "object",
1455
+ "required": [
1456
+ "from",
1457
+ "to",
1458
+ "mode"
1459
+ ],
1460
+ "additionalProperties": false,
1461
+ "properties": {
1462
+ "sourceScope": {
1463
+ "type": "string",
1464
+ "enum": [
1465
+ "unit",
1466
+ "workspace"
1467
+ ]
1468
+ },
1469
+ "from": {
1470
+ "type": "string",
1471
+ "minLength": 1,
1472
+ "pattern": "^(?!/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(/|$))(?!\\.$)(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/$).*$"
1473
+ },
1474
+ "to": {
1475
+ "type": "string",
1476
+ "minLength": 1,
1477
+ "pattern": "^(?!/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(/|$))(?!\\.$)(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/$).*$"
1478
+ },
1479
+ "mode": {
1480
+ "type": "string",
1481
+ "enum": [
1482
+ "preserve"
1483
+ ]
1484
+ }
1485
+ }
1486
+ }
1487
+ }
1488
+ }
1489
+ }
1490
+ },
1491
+ "anyOf": [
1492
+ {
1493
+ "required": [
1494
+ "materialize"
1495
+ ]
1496
+ },
1497
+ {
1498
+ "description": "无 materialize 钩子时,冻结的 executionBundle.publicFiles 必须非空:载荷由 Foundation 托管投影物化(F-06/T6)",
1499
+ "required": [
1500
+ "executionBundle"
1501
+ ],
1502
+ "properties": {
1503
+ "executionBundle": {
1504
+ "properties": {
1505
+ "publicFiles": {
1506
+ "minItems": 1
1507
+ }
1508
+ }
1509
+ }
1510
+ }
1511
+ }
1512
+ ]
1513
+ },
1514
+ "planPostPublishHook": {
1515
+ "type": "object",
1516
+ "description": "冻结的发布后钩子声明项(v0.6.3 R1):preset 与 command 运行时互斥;phase 缺省 distribute;blocksVerified 缺省 true 且仅 preset 可声明 false",
1517
+ "required": [
1518
+ "id"
1519
+ ],
1520
+ "additionalProperties": false,
1521
+ "properties": {
1522
+ "id": {
1523
+ "type": "string",
1524
+ "pattern": "^[a-z0-9][a-z0-9._-]*$"
1525
+ },
1526
+ "preset": {
1527
+ "type": "string",
1528
+ "pattern": "^[a-z0-9][a-z0-9._-]*$"
1529
+ },
1530
+ "command": {
1531
+ "type": "array",
1532
+ "minItems": 1,
1533
+ "items": {
1534
+ "type": "string"
1535
+ }
1536
+ },
1537
+ "phase": {
1538
+ "type": "string",
1539
+ "enum": [
1540
+ "distribute",
1541
+ "postVerify"
1542
+ ]
1543
+ },
1544
+ "config": {
1545
+ "type": "object"
1546
+ },
1547
+ "cwd": {
1548
+ "type": "string",
1549
+ "pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$"
1550
+ },
1551
+ "timeoutMs": {
1552
+ "type": "integer",
1553
+ "minimum": 1000,
1554
+ "maximum": 7200000
1555
+ },
1556
+ "envAllowlist": {
1557
+ "type": "array",
1558
+ "items": {
1559
+ "type": "string",
1560
+ "pattern": "^(?!.*(?:TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL))[A-Z_][A-Z0-9_]*$"
1561
+ },
1562
+ "uniqueItems": true
1563
+ },
1564
+ "requiresApproval": {
1565
+ "type": "boolean"
1566
+ },
1567
+ "blocksVerified": {
1568
+ "type": "boolean"
1373
1569
  }
1374
1570
  }
1375
1571
  },
@@ -1488,7 +1684,7 @@
1488
1684
  },
1489
1685
  "remoteUrl": {
1490
1686
  "type": "string",
1491
- "pattern": "^(?:https?|file)://.+\\.git$"
1687
+ "pattern": "^(?:https?|file)://[^@]+\\.git$"
1492
1688
  },
1493
1689
  "visibility": {
1494
1690
  "type": "string",
@@ -886,10 +886,8 @@
886
886
  },
887
887
  "postPublish": {
888
888
  "type": "object",
889
- "description": "发布后分发声明:materialize 钩子从冻结 tag 工作树物化载荷,targets 将载荷镜像或渲染市场索引推送到独立 git 远端。分发在 publish 之后由 distribute 命令执行,时序契约禁止读取工作区状态。",
889
+ "description": "发布后分发声明:载荷要么由 materialize 钩子从冻结 tag 工作树物化,要么(省略 materialize 时)由冻结的 publicFiles 映射经 Foundation Engineering Kit 托管投影物化(F-06/T6);targets 将载荷镜像或渲染市场索引推送到独立 git 远端。分发在 publish 之后由 distribute 命令执行,时序契约禁止读取工作区状态。",
890
890
  "required": [
891
- "materialize",
892
- "targets",
893
891
  "commitIdentity"
894
892
  ],
895
893
  "additionalProperties": false,
@@ -904,6 +902,13 @@
904
902
  "$ref": "#/definitions/postPublishTarget"
905
903
  }
906
904
  },
905
+ "hooks": {
906
+ "type": "array",
907
+ "description": "发布后钩子声明(v0.6.3 R1):每项为命名 preset(+config)或自定义 command 钩子(executable+参数数组,禁止 shell 字符串)。schema 层只校验形状;preset 与 command 互斥、preset 注册表归属等语义在运行时 fail-closed 校验(POSTPUBLISH_HOOK_INVALID)",
908
+ "items": {
909
+ "$ref": "#/definitions/postPublishHook"
910
+ }
911
+ },
907
912
  "commitIdentity": {
908
913
  "type": "object",
909
914
  "description": "分发仓库提交者身份(bot 身份),通过 git -c user.name/-c user.email 注入,绝不读取或修改全局 git 配置",
@@ -933,6 +938,82 @@
933
938
  "assertMainVersionAhead": {
934
939
  "type": "boolean",
935
940
  "description": "分发前校验主干版本源仍领先于目标版本,防止在已推进的主干上分发旧版本"
941
+ },
942
+ "executionFiles": {
943
+ "type": "array",
944
+ "description": "私有执行输入闭世界清单(F-01):仅列出发布后命令需要、但冻结 tag 中不存在的父工作区领域文件;辅助文件(helper)必须显式列入,执行时不做任何临时发现。每个路径经 Foundation 路径分类与受收容读取;列表排序去重后随计划冻结为 executionBundle.closure,字节发布到计划权威 .release-skill 下的摘要寻址目录。tag 中已有的文件继续由 tagCommit 绑定,不得在此声明(执行包不得覆盖 tag 文件)。路径语法只由 schema 做第一层形状检查,最终以运行时 Foundation 分类为准。",
945
+ "items": {
946
+ "type": "string",
947
+ "minLength": 1,
948
+ "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*\\\\).+$"
949
+ },
950
+ "uniqueItems": true
951
+ }
952
+ }
953
+ },
954
+ "postPublishHook": {
955
+ "type": "object",
956
+ "description": "发布后钩子声明项:preset(命名预设 + config)与 command(自定义命令)在运行时互斥校验;phase 缺省为 distribute(VERIFIED 之前执行),postVerify 在 verify 通过后作为独立 run 执行(R3);blocksVerified 缺省 true,仅 preset 可声明 false",
957
+ "required": [
958
+ "id"
959
+ ],
960
+ "additionalProperties": false,
961
+ "properties": {
962
+ "id": {
963
+ "type": "string",
964
+ "pattern": "^[a-z0-9][a-z0-9._-]*$"
965
+ },
966
+ "preset": {
967
+ "type": "string",
968
+ "pattern": "^[a-z0-9][a-z0-9._-]*$",
969
+ "description": "预设注册表中的预设名(R2 起);R1 无注册表,任何 preset 引用在运行时 fail-closed"
970
+ },
971
+ "command": {
972
+ "type": "array",
973
+ "minItems": 1,
974
+ "items": {
975
+ "type": "string"
976
+ },
977
+ "description": "executable+参数数组(禁止 shell 字符串);在冻结 tag 工作树中执行"
978
+ },
979
+ "phase": {
980
+ "type": "string",
981
+ "enum": [
982
+ "distribute",
983
+ "postVerify"
984
+ ],
985
+ "description": "执行阶段;缺省 distribute"
986
+ },
987
+ "config": {
988
+ "type": "object",
989
+ "description": "preset 钩子的配置对象;语义由预设注册表校验(R2 起)"
990
+ },
991
+ "cwd": {
992
+ "type": "string",
993
+ "pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$",
994
+ "description": "command 钩子执行目录(相对冻结 tag 工作树);preset 钩子禁止声明(运行时 fail-closed)"
995
+ },
996
+ "timeoutMs": {
997
+ "type": "integer",
998
+ "minimum": 1000,
999
+ "maximum": 7200000
1000
+ },
1001
+ "envAllowlist": {
1002
+ "type": "array",
1003
+ "items": {
1004
+ "type": "string",
1005
+ "pattern": "^(?!.*(?:TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL))[A-Z_][A-Z0-9_]*$"
1006
+ },
1007
+ "uniqueItems": true,
1008
+ "description": "允许透传给钩子进程的环境变量白名单;TOKEN/SECRET 等敏感子串在 schema 层即被拒绝"
1009
+ },
1010
+ "requiresApproval": {
1011
+ "type": "boolean",
1012
+ "description": "执行前需要 checkpoint 级批准(绑定 planDigest + hookId);public-write preset 缺省 true"
1013
+ },
1014
+ "blocksVerified": {
1015
+ "type": "boolean",
1016
+ "description": "失败时是否阻断 VERIFIED;缺省 true;仅 preset 可声明 false(运行时 fail-closed 校验)"
936
1017
  }
937
1018
  }
938
1019
  },
@@ -1057,8 +1138,8 @@
1057
1138
  },
1058
1139
  "remoteUrl": {
1059
1140
  "type": "string",
1060
- "pattern": "^(?:https?|file)://.+\\.git$",
1061
- "description": "仅允许 http(s) 或 file(测试传输)且以 .git 结尾的远端 URL"
1141
+ "pattern": "^(?:https?|file)://[^@]+\\.git$",
1142
+ "description": "仅允许 http(s) 或 file(测试传输)且以 .git 结尾的远端 URL;禁止任何 userinfo(user:password@)形态——凭证只属于宿主 git credential helper。schema 只是第一道门,运行时 Git URL 策略(new URL 解析)是最终权威"
1062
1143
  },
1063
1144
  "visibility": {
1064
1145
  "type": "string",