release-skill 0.5.1 → 0.6.1

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 (100) 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 +27 -0
  7. package/INSTALL.md +2 -2
  8. package/INSTALL.zh-CN.md +2 -2
  9. package/README.md +15 -14
  10. package/README.zh-CN.md +16 -15
  11. package/adapters/claude/.claude-plugin/marketplace.json +1 -1
  12. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  13. package/adapters/claude/bin/release-skill.bundle.mjs +3779 -769
  14. package/adapters/claude/schemas/.render-manifest.json +6 -6
  15. package/adapters/claude/schemas/release-plan.schema.json +401 -2
  16. package/adapters/claude/schemas/release-project.schema.json +299 -0
  17. package/adapters/claude/schemas/release-run.schema.json +59 -6
  18. package/adapters/claude/skills/release-config/SKILL.md +140 -0
  19. package/adapters/claude/skills/release-docs/SKILL.md +106 -0
  20. package/adapters/claude/skills/release-help/SKILL.md +39 -0
  21. package/adapters/claude/skills/release-marketplace/SKILL.md +147 -0
  22. package/adapters/claude/skills/release-publish/SKILL.md +25 -6
  23. package/adapters/claude/skills/release-verify/SKILL.md +10 -0
  24. package/adapters/codex/.codex-plugin/plugin.json +2 -2
  25. package/adapters/codex/bin/release-skill.bundle.mjs +3779 -769
  26. package/adapters/codex/schemas/.render-manifest.json +6 -6
  27. package/adapters/codex/schemas/release-plan.schema.json +401 -2
  28. package/adapters/codex/schemas/release-project.schema.json +299 -0
  29. package/adapters/codex/schemas/release-run.schema.json +59 -6
  30. package/adapters/codex/skills/release-config/SKILL.md +147 -0
  31. package/adapters/codex/skills/release-docs/SKILL.md +113 -0
  32. package/adapters/codex/skills/release-help/SKILL.md +39 -0
  33. package/adapters/codex/skills/release-marketplace/SKILL.md +154 -0
  34. package/adapters/codex/skills/release-publish/SKILL.md +25 -6
  35. package/adapters/codex/skills/release-verify/SKILL.md +10 -0
  36. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  37. package/adapters/kimi/bin/release-skill.bundle.mjs +3779 -769
  38. package/adapters/kimi/schemas/.render-manifest.json +6 -6
  39. package/adapters/kimi/schemas/release-plan.schema.json +401 -2
  40. package/adapters/kimi/schemas/release-project.schema.json +299 -0
  41. package/adapters/kimi/schemas/release-run.schema.json +59 -6
  42. package/adapters/kimi/skills/release-config/SKILL.md +147 -0
  43. package/adapters/kimi/skills/release-docs/SKILL.md +113 -0
  44. package/adapters/kimi/skills/release-help/SKILL.md +39 -0
  45. package/adapters/kimi/skills/release-marketplace/SKILL.md +154 -0
  46. package/adapters/kimi/skills/release-publish/SKILL.md +25 -6
  47. package/adapters/kimi/skills/release-verify/SKILL.md +10 -0
  48. package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
  49. package/adapters/workbuddy/bin/release-skill.bundle.mjs +3779 -769
  50. package/adapters/workbuddy/schemas/.render-manifest.json +6 -6
  51. package/adapters/workbuddy/schemas/release-plan.schema.json +401 -2
  52. package/adapters/workbuddy/schemas/release-project.schema.json +299 -0
  53. package/adapters/workbuddy/schemas/release-run.schema.json +59 -6
  54. package/adapters/workbuddy/skills/release-config/SKILL.md +140 -0
  55. package/adapters/workbuddy/skills/release-docs/SKILL.md +106 -0
  56. package/adapters/workbuddy/skills/release-help/SKILL.md +39 -0
  57. package/adapters/workbuddy/skills/release-marketplace/SKILL.md +147 -0
  58. package/adapters/workbuddy/skills/release-publish/SKILL.md +25 -6
  59. package/adapters/workbuddy/skills/release-verify/SKILL.md +10 -0
  60. package/bin/release-skill-cli.mjs +246 -7
  61. package/bin/release-skill.bundle.mjs +3779 -769
  62. package/package.json +3 -2
  63. package/platform-manifest.json +359 -0
  64. package/references/.render-manifest.json +9 -9
  65. package/references/02-project-config.md +35 -0
  66. package/references/05-evidence-and-errors.md +45 -0
  67. package/references/06-adapter-contract.md +13 -0
  68. package/schemas/.render-manifest.json +6 -6
  69. package/schemas/release-plan.schema.json +401 -2
  70. package/schemas/release-project.schema.json +299 -0
  71. package/schemas/release-run.schema.json +59 -6
  72. package/scripts/build-bundle.mjs +11 -2
  73. package/scripts/sync-public-files.mjs +4 -0
  74. package/skills/release-config/SKILL.md +140 -0
  75. package/skills/release-docs/SKILL.md +106 -0
  76. package/skills/release-help/SKILL.md +39 -0
  77. package/skills/release-marketplace/SKILL.md +147 -0
  78. package/skills/release-publish/SKILL.md +25 -6
  79. package/skills/release-verify/SKILL.md +10 -0
  80. package/skills-src/release-config/SKILL.md +140 -0
  81. package/skills-src/release-docs/SKILL.md +106 -0
  82. package/skills-src/release-help/SKILL.md +39 -0
  83. package/skills-src/release-marketplace/SKILL.md +147 -0
  84. package/skills-src/release-publish/SKILL.md +25 -6
  85. package/skills-src/release-verify/SKILL.md +10 -0
  86. package/src/adapters/contract.mjs +5 -0
  87. package/src/adapters/distribute-git.mjs +625 -0
  88. package/src/commands/distribute.mjs +1078 -0
  89. package/src/commands/lineage.mjs +616 -0
  90. package/src/commands/prepare.mjs +548 -83
  91. package/src/commands/route.mjs +686 -0
  92. package/src/commands/ship.mjs +45 -1
  93. package/src/commands/verify.mjs +198 -0
  94. package/src/core/baseline-advance.mjs +185 -0
  95. package/src/core/bundle-freshness.mjs +236 -0
  96. package/src/core/checkpoints.mjs +25 -0
  97. package/src/core/errors.mjs +2 -0
  98. package/src/core/frozen-marker.mjs +97 -0
  99. package/src/core/hooks.mjs +12 -1
  100. package/src/core/postpublish.mjs +315 -0
@@ -613,6 +613,9 @@
613
613
  },
614
614
  "releaseDocuments": {
615
615
  "$ref": "#/definitions/releaseDocuments"
616
+ },
617
+ "postPublish": {
618
+ "$ref": "#/definitions/postPublish"
616
619
  }
617
620
  },
618
621
  "allOf": [
@@ -870,9 +873,305 @@
870
873
  },
871
874
  "uniqueItems": true,
872
875
  "description": "Root-relative globs declaring the hook's full input set (source, scripts, config, lockfiles). The cache key fingerprints the content of every matched file; a glob that matches nothing fails closed. Must cover ALL inputs or the cache can return a false hit."
876
+ },
877
+ "testSelection": {
878
+ "type": "string",
879
+ "enum": [
880
+ "full",
881
+ "incremental"
882
+ ],
883
+ "description": "Only meaningful for the test hook: which test selection the hook command runs. Absence or 'full' means the hook runs the full suite, which prepare's built-in full-test freeze gate requires before the plan digest is computed. 'incremental' is reserved for a future preflight mode and is rejected at freeze time ('incremental selection is not allowed at freeze time'). Built-in gate; cannot be disabled by project overlays."
873
884
  }
874
885
  }
875
886
  },
887
+ "postPublish": {
888
+ "type": "object",
889
+ "description": "发布后分发声明:materialize 钩子从冻结 tag 工作树物化载荷,targets 将载荷镜像或渲染市场索引推送到独立 git 远端。分发在 publish 之后由 distribute 命令执行,时序契约禁止读取工作区状态。",
890
+ "required": [
891
+ "materialize",
892
+ "targets",
893
+ "commitIdentity"
894
+ ],
895
+ "additionalProperties": false,
896
+ "properties": {
897
+ "materialize": {
898
+ "$ref": "#/definitions/postPublishMaterialize"
899
+ },
900
+ "targets": {
901
+ "type": "array",
902
+ "minItems": 1,
903
+ "items": {
904
+ "$ref": "#/definitions/postPublishTarget"
905
+ }
906
+ },
907
+ "commitIdentity": {
908
+ "type": "object",
909
+ "description": "分发仓库提交者身份(bot 身份),通过 git -c user.name/-c user.email 注入,绝不读取或修改全局 git 配置",
910
+ "required": [
911
+ "name",
912
+ "email"
913
+ ],
914
+ "additionalProperties": false,
915
+ "properties": {
916
+ "name": {
917
+ "type": "string",
918
+ "minLength": 1
919
+ },
920
+ "email": {
921
+ "type": "string",
922
+ "minLength": 1
923
+ }
924
+ }
925
+ },
926
+ "steps": {
927
+ "type": "array",
928
+ "description": "物化之后、推送之前按序执行的只读检查步骤;任一步失败即 fail-closed",
929
+ "items": {
930
+ "$ref": "#/definitions/postPublishStep"
931
+ }
932
+ },
933
+ "assertMainVersionAhead": {
934
+ "type": "boolean",
935
+ "description": "分发前校验主干版本源仍领先于目标版本,防止在已推进的主干上分发旧版本"
936
+ }
937
+ }
938
+ },
939
+ "postPublishMaterialize": {
940
+ "type": "object",
941
+ "description": "载荷物化钩子:executable+参数数组(禁止 shell 字符串),stdout 中 outputMarker 行之后为载荷目录路径;可选 requireReport 对 stdout 首个 JSON 对象做字段断言",
942
+ "required": [
943
+ "command",
944
+ "outputMarker"
945
+ ],
946
+ "additionalProperties": false,
947
+ "properties": {
948
+ "command": {
949
+ "type": "array",
950
+ "minItems": 1,
951
+ "items": {
952
+ "type": "string"
953
+ }
954
+ },
955
+ "cwd": {
956
+ "type": "string",
957
+ "pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$"
958
+ },
959
+ "timeoutMs": {
960
+ "type": "integer",
961
+ "minimum": 1000,
962
+ "maximum": 7200000
963
+ },
964
+ "envAllowlist": {
965
+ "type": "array",
966
+ "items": {
967
+ "type": "string",
968
+ "pattern": "^(?!.*(?:TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL))[A-Z_][A-Z0-9_]*$"
969
+ },
970
+ "uniqueItems": true
971
+ },
972
+ "outputMarker": {
973
+ "type": "string",
974
+ "minLength": 1,
975
+ "description": "stdout 中标识载荷目录路径的前缀标记(如 \"isolated dir kept: \")"
976
+ },
977
+ "requireReport": {
978
+ "type": "object",
979
+ "required": [
980
+ "parse"
981
+ ],
982
+ "additionalProperties": false,
983
+ "properties": {
984
+ "parse": {
985
+ "const": "stdout-first-json",
986
+ "description": "解析 stdout 中第一个完整 JSON 对象作为报告"
987
+ },
988
+ "equals": {
989
+ "type": "object",
990
+ "description": "报告字段等值断言;任一字段缺失或不等即 fail-closed"
991
+ }
992
+ }
993
+ }
994
+ }
995
+ },
996
+ "postPublishStep": {
997
+ "type": "object",
998
+ "description": "物化后按序执行的检查步骤;executable+参数数组(禁止 shell 字符串)",
999
+ "required": [
1000
+ "name",
1001
+ "command"
1002
+ ],
1003
+ "additionalProperties": false,
1004
+ "properties": {
1005
+ "name": {
1006
+ "type": "string",
1007
+ "pattern": "^[a-z0-9][a-z0-9._-]*$"
1008
+ },
1009
+ "command": {
1010
+ "type": "array",
1011
+ "minItems": 1,
1012
+ "items": {
1013
+ "type": "string"
1014
+ }
1015
+ },
1016
+ "cwd": {
1017
+ "type": "string",
1018
+ "pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$"
1019
+ },
1020
+ "timeoutMs": {
1021
+ "type": "integer",
1022
+ "minimum": 1000,
1023
+ "maximum": 7200000
1024
+ },
1025
+ "envAllowlist": {
1026
+ "type": "array",
1027
+ "items": {
1028
+ "type": "string",
1029
+ "pattern": "^(?!.*(?:TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL))[A-Z_][A-Z0-9_]*$"
1030
+ },
1031
+ "uniqueItems": true
1032
+ }
1033
+ }
1034
+ },
1035
+ "postPublishTarget": {
1036
+ "type": "object",
1037
+ "description": "分发目标 git 远端:payload-mirror 镜像载荷,marketplace-index 渲染市场索引清单;dependsOn 语义(引用、无环)在运行时 fail-closed 校验",
1038
+ "required": [
1039
+ "id",
1040
+ "kind",
1041
+ "remoteUrl",
1042
+ "visibility",
1043
+ "branch"
1044
+ ],
1045
+ "additionalProperties": false,
1046
+ "properties": {
1047
+ "id": {
1048
+ "type": "string",
1049
+ "pattern": "^[a-z0-9][a-z0-9._-]*$"
1050
+ },
1051
+ "kind": {
1052
+ "type": "string",
1053
+ "enum": [
1054
+ "payload-mirror",
1055
+ "marketplace-index"
1056
+ ]
1057
+ },
1058
+ "remoteUrl": {
1059
+ "type": "string",
1060
+ "pattern": "^(?:https?|file)://.+\\.git$",
1061
+ "description": "仅允许 http(s) 或 file(测试传输)且以 .git 结尾的远端 URL"
1062
+ },
1063
+ "visibility": {
1064
+ "type": "string",
1065
+ "enum": [
1066
+ "internal",
1067
+ "public"
1068
+ ]
1069
+ },
1070
+ "branch": {
1071
+ "type": "string",
1072
+ "pattern": "^[A-Za-z0-9][A-Za-z0-9._/-]*$"
1073
+ },
1074
+ "dependsOn": {
1075
+ "type": "string",
1076
+ "pattern": "^[a-z0-9][a-z0-9._-]*$",
1077
+ "description": "消费另一目标(须为 payload-mirror)推送后的 commit sha;运行时校验引用存在且无环"
1078
+ },
1079
+ "marketplace": {
1080
+ "type": "object",
1081
+ "description": "marketplace-index 目标必填:渲染 .claude-plugin/marketplace.json 所用的市场元数据",
1082
+ "required": [
1083
+ "form",
1084
+ "name",
1085
+ "owner"
1086
+ ],
1087
+ "additionalProperties": false,
1088
+ "properties": {
1089
+ "form": {
1090
+ "type": "string",
1091
+ "enum": [
1092
+ "github",
1093
+ "url"
1094
+ ]
1095
+ },
1096
+ "name": {
1097
+ "type": "string",
1098
+ "minLength": 1
1099
+ },
1100
+ "owner": {
1101
+ "type": "string",
1102
+ "minLength": 1
1103
+ },
1104
+ "sourceRepo": {
1105
+ "type": "string",
1106
+ "pattern": "^[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+$",
1107
+ "description": "可选 owner/repo;github form 缺省时以 owner/name 组装"
1108
+ }
1109
+ }
1110
+ },
1111
+ "staticFiles": {
1112
+ "type": "array",
1113
+ "description": "随目标一起写入的静态文件(from 为源仓库相对路径,to 为目标仓库相对路径)",
1114
+ "items": {
1115
+ "type": "object",
1116
+ "required": [
1117
+ "from",
1118
+ "to"
1119
+ ],
1120
+ "additionalProperties": false,
1121
+ "properties": {
1122
+ "from": {
1123
+ "type": "string",
1124
+ "minLength": 1,
1125
+ "pattern": "^(?!/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(/|$))(?!\\.$)(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/$).*$"
1126
+ },
1127
+ "to": {
1128
+ "type": "string",
1129
+ "minLength": 1,
1130
+ "pattern": "^(?!/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(/|$))(?!\\.$)(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/$).*$"
1131
+ }
1132
+ }
1133
+ }
1134
+ }
1135
+ },
1136
+ "allOf": [
1137
+ {
1138
+ "if": {
1139
+ "properties": {
1140
+ "kind": {
1141
+ "const": "marketplace-index"
1142
+ }
1143
+ },
1144
+ "required": [
1145
+ "kind"
1146
+ ]
1147
+ },
1148
+ "then": {
1149
+ "required": [
1150
+ "marketplace"
1151
+ ]
1152
+ }
1153
+ },
1154
+ {
1155
+ "if": {
1156
+ "properties": {
1157
+ "kind": {
1158
+ "const": "payload-mirror"
1159
+ }
1160
+ },
1161
+ "required": [
1162
+ "kind"
1163
+ ]
1164
+ },
1165
+ "then": {
1166
+ "not": {
1167
+ "required": [
1168
+ "marketplace"
1169
+ ]
1170
+ }
1171
+ }
1172
+ }
1173
+ ]
1174
+ },
876
1175
  "releaseDocuments": {
877
1176
  "type": "object",
878
1177
  "description": "Optional configuration-driven multilingual release-document refresh for one release unit. Absence preserves legacy behaviour. Lexical layer only; runtime path, locale-membership and collision checks apply additionally.",
@@ -41,7 +41,9 @@
41
41
  "PUBLISHED",
42
42
  "VERIFIED",
43
43
  "PARTIAL",
44
- "BLOCKED"
44
+ "BLOCKED",
45
+ "DISTRIBUTING",
46
+ "DISTRIBUTED"
45
47
  ],
46
48
  "description": "Current status of the run"
47
49
  },
@@ -52,7 +54,8 @@
52
54
  "prepare",
53
55
  "publish",
54
56
  "reconcile",
55
- "verify"
57
+ "verify",
58
+ "distribute"
56
59
  ],
57
60
  "description": "The command that initiated this run"
58
61
  },
@@ -128,7 +131,9 @@
128
131
  "codex-marketplace-install",
129
132
  "kimi-marketplace-install",
130
133
  "codebuddy-marketplace-install",
131
- "set-default-branch"
134
+ "set-default-branch",
135
+ "distribute-probe",
136
+ "distribute-mirror"
132
137
  ],
133
138
  "description": "Type of external action"
134
139
  },
@@ -143,9 +148,10 @@
143
148
  "deferred",
144
149
  "PASSED_AUTOMATIC",
145
150
  "PASSED_MANUAL",
146
- "NOT_REQUIRED_UNCHANGED"
151
+ "NOT_REQUIRED_UNCHANGED",
152
+ "NO_CHANGE"
147
153
  ],
148
- "description": "Result status of this checkpoint (uncertain = started, result unknown; deferred = marketplace action postponed to verify phase; PASSED_AUTOMATIC/PASSED_MANUAL/NOT_REQUIRED_UNCHANGED 为验证阶段专用状态)"
154
+ "description": "Result status of this checkpoint (uncertain = started, result unknown; deferred = marketplace action postponed to verify phase; PASSED_AUTOMATIC/PASSED_MANUAL/NOT_REQUIRED_UNCHANGED 为验证阶段专用状态; NO_CHANGE = distribute 目标暂存差异为空,未产生 commit/tag/push)"
149
155
  },
150
156
  "preObserve": {
151
157
  "type": "string",
@@ -206,6 +212,7 @@
206
212
  "GATE_FAILED",
207
213
  "AUTH_MISSING",
208
214
  "REMOTE_CONFLICT",
215
+ "REMOTE_UNAVAILABLE",
209
216
  "HOOK_TIMEOUT",
210
217
  "PARTIAL_RELEASE",
211
218
  "POST_PUBLISH_VERIFY_FAILED"
@@ -223,6 +230,51 @@
223
230
  "phase": {
224
231
  "type": "string",
225
232
  "description": "Phase identifier for deferred checkpoints (e.g. post-publish-verification)"
233
+ },
234
+ "remoteUrl": {
235
+ "type": "string",
236
+ "description": "distribute 目标远端 URL"
237
+ },
238
+ "branch": {
239
+ "type": "string",
240
+ "description": "distribute 目标分支"
241
+ },
242
+ "tag": {
243
+ "type": "string",
244
+ "description": "distribute 分发 tag"
245
+ },
246
+ "tagCommit": {
247
+ "type": "string",
248
+ "pattern": "^[a-f0-9]{40}$",
249
+ "description": "冻结的 create-tag 预期 commit"
250
+ },
251
+ "previousHead": {
252
+ "type": "string",
253
+ "pattern": "^[a-f0-9]{40}$",
254
+ "description": "执行前目标分支 tip"
255
+ },
256
+ "pushedCommit": {
257
+ "type": "string",
258
+ "pattern": "^[a-f0-9]{40}$",
259
+ "description": "实际推送的 commit(与 ls-remote 交叉核对)"
260
+ },
261
+ "mode": {
262
+ "type": "string",
263
+ "enum": [
264
+ "pushed",
265
+ "no-change",
266
+ "dry-run"
267
+ ],
268
+ "description": "distribute 执行模式"
269
+ },
270
+ "executor": {
271
+ "type": "string",
272
+ "description": "执行者标识"
273
+ },
274
+ "payloadFileCount": {
275
+ "type": "integer",
276
+ "minimum": 0,
277
+ "description": "写入目标的载荷文件数"
226
278
  }
227
279
  }
228
280
  }
@@ -568,7 +620,8 @@
568
620
  "command": {
569
621
  "enum": [
570
622
  "reconcile",
571
- "verify"
623
+ "verify",
624
+ "distribute"
572
625
  ]
573
626
  }
574
627
  },
@@ -21,6 +21,7 @@ import { readFile, writeFile, mkdir } from 'node:fs/promises';
21
21
  import { existsSync, readFileSync } from 'node:fs';
22
22
  import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
23
23
  import { createHash } from 'node:crypto';
24
+ import { computeBundleSourceDigest } from '../src/core/bundle-freshness.mjs';
24
25
 
25
26
  const CHECK_MODE = process.argv.includes('--check');
26
27
 
@@ -38,7 +39,12 @@ const OUTFILE = join(PKG_ROOT, 'bin', 'release-skill.bundle.mjs');
38
39
  // dependency: the Claude and Codex adapter closures ship the bundle at a
39
40
  // different depth with no package.json next to it, while the npm closure does.
40
41
  // Reading package.json here (build input) keeps the output deterministic.
41
- function buildBanner(pkgIdentity) {
42
+ //
43
+ // __bundleSourceDigest is the build-time digest of the bundle's source inputs
44
+ // (src/, skills-src/, bin/release-skill-cli.mjs, package.json — algorithm in
45
+ // src/core/bundle-freshness.mjs). prepare's BUNDLE_STALE gate recomputes the
46
+ // digest and fails closed on any mismatch (2026-08-18 investigation §4.2).
47
+ function buildBanner(pkgIdentity, sourceDigest) {
42
48
  return `\
43
49
  // --- release-skill bundle (deterministic build) ---
44
50
  // Compute package root from the bundle's own file location (import.meta.url).
@@ -51,6 +57,8 @@ const __bundlePkgRoot = __bundleResolve(__bundleDirname(__bundleFileURLToPath(im
51
57
  const __bundleRealRequire = __bundleCreateRequire(import.meta.url);
52
58
  // Package identity injected at build time — closure-independent --version probe.
53
59
  const __bundlePkg = Object.freeze(${JSON.stringify(pkgIdentity)});
60
+ // Build-time source digest for the BUNDLE_STALE freshness gate (see above).
61
+ const __bundleSourceDigest = "${sourceDigest}";
54
62
  `;
55
63
  }
56
64
 
@@ -164,7 +172,8 @@ async function buildBundle() {
164
172
  }
165
173
 
166
174
  const pkgJson = JSON.parse(await readFile(join(PKG_ROOT, 'package.json'), 'utf-8'));
167
- const banner = buildBanner({ name: pkgJson.name, version: pkgJson.version });
175
+ const sourceDigest = await computeBundleSourceDigest(PKG_ROOT);
176
+ const banner = buildBanner({ name: pkgJson.name, version: pkgJson.version }, sourceDigest);
168
177
 
169
178
  const identity = Object.freeze({ name: pkgJson.name, version: pkgJson.version });
170
179
 
@@ -232,6 +232,9 @@ async function collectEntries(packageRoot) {
232
232
  // a distribution artifact; the shipped bundle
233
233
  // inlines the adopted capability — matches the npm
234
234
  // pack closure contract)
235
+ // - .release-skill/ (local release runtime state — runs, plans, locks;
236
+ // not in the package.json files whitelist, so it is
237
+ // never part of the npm pack closure)
235
238
  const baseFiles = allFiles.filter((f) => {
236
239
  if (f.startsWith('adapters/')) return false;
237
240
  if (f.startsWith('test/')) return false;
@@ -240,6 +243,7 @@ async function collectEntries(packageRoot) {
240
243
  if (f.startsWith('native/') && f.includes('/build/')) return false;
241
244
  if (f.startsWith('scripts/')) return false;
242
245
  if (f.startsWith('vendor/')) return false;
246
+ if (f.startsWith('.release-skill/')) return false;
243
247
  return true;
244
248
  });
245
249
 
@@ -0,0 +1,140 @@
1
+ ---
2
+ name: release-config
3
+ description: "Config-only workflow profile: route confirms config-only diff, assess with schema validation, prepare --workflow config (code-class gates trimmed), workflowDecision records publish path (public bytes unchanged → no publish path; changed → lightchain prepare→approve→publish→verify)"
4
+ ---
5
+
6
+ # release-config
7
+
8
+ ## 触发
9
+
10
+ 用户询问或执行纯配置变更的发布流程。包含 `.release-skill/project.yaml`、配置 schema 等配置文件的修改,且无代码、文档或 marketplace 变更。
11
+
12
+ ## 当前状态
13
+
14
+ `release-config` 是工作流配置文件 (§4) 定义的独立工作流之一,专门处理仅配置变更的场景。它遵循简化生命周期,专注于配置验证和发布路径决策分支。
15
+
16
+ **机械实现**: `prepare --workflow config` 确定性地裁剪代码类门禁(H5),并比较当前
17
+ per-unit `snapshotDigest` 与最新冻结 plan——公开字节未变 → `publishPath:
18
+ 'no-publish-needed'`(externalActions 被移除,无 publish 路径);字节变化或无对比
19
+ plan → `publishPath: 'publish-needed'`(fail-safe)。决策以 `workflowDecision` 绑定
20
+ 进 plan digest,不可篡改。**不存在** `NO_PUBLISH_NEEDED`/`REPORTED` 虚构状态:
21
+ prepare 的真实输出是 plan 内的 `workflowDecision`。
22
+
23
+ **边界**: 跳过代码类 gates(declared hooks、snapshot-verify gates、source-authority
24
+ closure、skill-resource-closure)。保留 baseline/snapshots/plan freeze/docs
25
+ freshness。consumer-verify 仅在触发生效发布时参与。
26
+
27
+ ## 职责与边界
28
+
29
+ - **步骤① diff 确认 config-only**: 调用 `release-skill route` command 确认仅有配置变更
30
+ - **步骤② assess with schema validation**: 执行配置结构验证、schema 检查、contract 一致性
31
+ - **步骤③ prepare --workflow config**: 本地 freeze 检查,生成只读计划;输出 `workflowDecision`
32
+ - **步骤④ decision branch**(来自 plan.workflowDecision):
33
+ - 场景 A:`publishPath === 'no-publish-needed'`(公开字节未变化)→ 记录决策并结束,
34
+ 无 publish 路径,不运行 approve/publish/verify
35
+ - 场景 B:`publishPath === 'publish-needed'`(公开 surface 变化或不可判定)→ 运行
36
+ 轻链 (approve→publish→verify)
37
+
38
+ **授权边界**: 命令调用本身即授权执行配置的 hooks/gates。config-only 工作流的远程写操作受标准 approval 机制约束,不 bypass 安全 gate。
39
+
40
+ **阶段通过规则**:
41
+ - 场景 A: prepare 输出 `workflowDecision.decision === 'public-bytes-unchanged'`(无 publish 路径)
42
+ - 场景 B: `status === 'VERIFIED'` + CLI exit code 0
43
+
44
+ ## 正向执行路径
45
+
46
+ 1. 运行 `release-skill route --root <path> --json` 获取 diff 分类
47
+ 2. 若推荐 `workflowKind === 'config-only'`,则使用本技能
48
+ 3. 执行步骤②:运行 `release-skill assess --root <path> --offline --json` 进行 schema validation
49
+ 4. 执行步骤③:运行 `release-skill prepare --offline --workflow config --target-version <ver> --json`
50
+ 5. 读取输出中的 `workflowDecision`:
51
+ - **A**: `publishPath === 'no-publish-needed'` → 记录决策(plan 已冻结,无
52
+ externalActions),结束。无需 approve/publish/verify
53
+ - **B**: `publishPath === 'publish-needed'` → 继续 approve → publish → verify 链条
54
+ 6. (场景 B 续) 执行步骤⑥:运行 `release-skill approve --plan <path> --actor <name>`
55
+ 7. (场景 B 续) 执行步骤⑦:运行 `release-skill publish --plan <path> --approval <path>`
56
+ 8. (场景 B 续) 执行步骤⑧:运行 `release-skill verify --plan <path> --run <path>`
57
+
58
+ ## 确定性脚本调用
59
+
60
+ ```bash
61
+ # Step 1: Diff classification confirmation (config-only)
62
+ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" route --root <path> --json
63
+
64
+ # Step 2: Assess with schema validation
65
+ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" assess --root <path> --offline --json
66
+
67
+ # Step 3: Prepare --workflow config (local freeze + publish-path decision)
68
+ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" prepare --offline \
69
+ --workflow config --target-version <version> --json
70
+ # Output (JSON): { workflowKind: 'config',
71
+ # workflowDecision: { decision: 'public-bytes-unchanged'|'public-bytes-changed'|'indeterminable',
72
+ # publishPath: 'no-publish-needed'|'publish-needed', comparedPlan: '<digest>.json' } }
73
+
74
+ # Decision Branch A (no-publish-needed): plan frozen with zero externalActions;
75
+ # the decision is bound into the plan digest. No publish commands run.
76
+
77
+ # Decision Branch B (publish-needed): light chain execution
78
+ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" approve \
79
+ --plan <path> --actor <person-name>
80
+ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" publish \
81
+ --plan <path> --approval <path>
82
+ node "${CLAUDE_PLUGIN_ROOT}/bin/release-skill.mjs" verify \
83
+ --plan <path> --run <path> --json
84
+ ```
85
+
86
+ ## 故障路由
87
+
88
+ | 场景 | 状态 | 处理 |
89
+ |------|------|------|
90
+ | 非纯配置变更(mixed=true) | full-happy-end | 路由到 `release-skill ship` 完整工作流 |
91
+ | schema validation 失败 | CONFIG_SCHEMA_INVALID | 修正 project.yaml 或 schemas 结构错误后重试 step② |
92
+ | contract verification 失败 | CONFIG_CONFLICT | 解决配置冲突后重试 step② |
93
+ | prepare 检测到基线漂移 | BASELINE_DRIFT_DETECTED | 人工审查 drift 后决定是否继续或回滚 |
94
+ | workflowDecision 不可判定(无对比 plan) | indeterminable | fail-safe 到 publish-needed,走场景 B |
95
+ | approval expired | APPROVAL_EXPIRED | 重新执行 approve,digest 必须匹配 |
96
+ | remote conflict at publish | REMOTE_CONFLICT | 人工决策:force override 或 cancel |
97
+
98
+ ## 决策树 (Step 4)
99
+
100
+ ```
101
+ ┌─────────────────────────────────────────┐
102
+ │ prepare --workflow config completed │
103
+ └──────────────────┬──────────────────────┘
104
+
105
+ ┌──────────┴──────────┐
106
+ │ │
107
+ ▼ ▼
108
+ ┌───────────────┐ ┌───────────────────┐
109
+ │ public bytes │ │ public bytes │
110
+ │ unchanged │ │ changed / │
111
+ │ (or no plan │ │ indeterminable │
112
+ │ → fail-safe │ │ │
113
+ │ → publish │ │ │
114
+ │ needed) │ │ │
115
+ └───────┬───────┘ └────────┬──────────┘
116
+ │ │
117
+ ▼ ▼
118
+ ┌───────────────┐ ┌───────────────────┐
119
+ │ no-publish │ │ light chain │
120
+ │ needed: │ │ approve→publish │
121
+ │ decision │ │ →verify │
122
+ │ recorded in │ │ │
123
+ │ plan digest │ │ │
124
+ └───────────────┘ └───────────────────┘
125
+ ```
126
+
127
+ ## 与其他工作流的关系
128
+
129
+ - **docs-only**: 纯文档变更时使用 `release-docs`
130
+ - **marketplace-only**: 仅 marketplace 变更时使用独立工作流
131
+ - **full-happy-end**: 混合变更(code+config+docs)时降级到此完整路径
132
+
133
+ ## 关联技能
134
+
135
+ - `release-skill route`: 快速入门决策路由(§4.3)
136
+ - `release-assess`: 配置 schema/contract 验证入口
137
+ - `release-prepare`: 离线冻结检查(`--workflow config` 输出 publish-path 决策)
138
+ - `release-approve`: Plan approval(仅场景 B)
139
+ - `release-publish`: 制品发布(仅在 public surface 变化时执行)
140
+ - `release-verify`: 消费者验证(场景 B 的最终验证门)