release-skill 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codebuddy-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +2 -2
- package/.kimi-plugin/plugin.json +1 -1
- package/CHANGELOG.md +23 -0
- package/CONTRIBUTING.md +1 -1
- package/INSTALL.md +47 -2
- package/INSTALL.zh-CN.md +29 -2
- package/README.md +126 -9
- package/README.zh-CN.md +108 -9
- package/adapters/claude/.claude-plugin/marketplace.json +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/claude/schemas/.render-manifest.json +10 -6
- package/adapters/claude/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/claude/schemas/release-plan.schema.json +65 -1
- package/adapters/claude/schemas/release-project.schema.json +73 -1
- package/adapters/claude/schemas/release-run.schema.json +11 -6
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/codex/schemas/.render-manifest.json +10 -6
- package/adapters/codex/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/codex/schemas/release-plan.schema.json +65 -1
- package/adapters/codex/schemas/release-project.schema.json +73 -1
- package/adapters/codex/schemas/release-run.schema.json +11 -6
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/kimi/schemas/.render-manifest.json +10 -6
- package/adapters/kimi/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/kimi/schemas/release-plan.schema.json +65 -1
- package/adapters/kimi/schemas/release-project.schema.json +73 -1
- package/adapters/kimi/schemas/release-run.schema.json +11 -6
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +6408 -1654
- package/adapters/workbuddy/schemas/.render-manifest.json +10 -6
- package/adapters/workbuddy/schemas/postpublish-approval-record.schema.json +47 -0
- package/adapters/workbuddy/schemas/release-plan.schema.json +65 -1
- package/adapters/workbuddy/schemas/release-project.schema.json +73 -1
- package/adapters/workbuddy/schemas/release-run.schema.json +11 -6
- package/bin/release-skill-cli.mjs +181 -3
- package/bin/release-skill.bundle.mjs +6408 -1654
- package/package.json +2 -1
- package/platform-manifest.json +4 -4
- package/references/.render-manifest.json +5 -5
- package/references/01-state-machine.md +22 -2
- package/schemas/.render-manifest.json +10 -6
- package/schemas/postpublish-approval-record.schema.json +47 -0
- package/schemas/release-plan.schema.json +65 -1
- package/schemas/release-project.schema.json +73 -1
- package/schemas/release-run.schema.json +11 -6
- package/src/commands/approve.mjs +167 -1
- package/src/commands/distribute.mjs +411 -33
- package/src/commands/postverify.mjs +734 -0
- package/src/commands/prepare.mjs +280 -42
- package/src/commands/setup.mjs +715 -0
- package/src/commands/ship.mjs +152 -5
- package/src/commands/verify.mjs +92 -15
- package/src/core/approval.mjs +93 -68
- package/src/core/bounded-output.mjs +46 -0
- package/src/core/derived-artifact-gates.mjs +258 -0
- package/src/core/docs-refresh-preset.mjs +167 -0
- package/src/core/errors.mjs +4 -0
- package/src/core/hooks.mjs +28 -0
- package/src/core/marketplace-registry-entry.mjs +174 -0
- package/src/core/notify-handoff.mjs +76 -0
- package/src/core/postpublish-approval.mjs +110 -0
- package/src/core/postpublish.mjs +424 -7
- package/src/core/preset-executor.mjs +156 -0
- package/src/core/preset-gitwrite.mjs +463 -0
- package/src/core/presets.mjs +706 -0
- package/src/core/proposal-inbox.mjs +630 -0
- package/src/core/run.mjs +91 -6
|
@@ -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": "
|
|
26
|
-
"bytes":
|
|
29
|
+
"digest": "517ac9b1d92d2bf348497ee0e79c9e474a4c60e6ed8ba77830948716d143dfa2",
|
|
30
|
+
"bytes": 49369
|
|
27
31
|
},
|
|
28
32
|
"release-project.schema.json": {
|
|
29
|
-
"digest": "
|
|
30
|
-
"bytes":
|
|
33
|
+
"digest": "d38649d1dc9b1dbc643f4e2c98fd18d111090e9ce221c9c61fa50245f6c4c232",
|
|
34
|
+
"bytes": 45715
|
|
31
35
|
},
|
|
32
36
|
"release-run.schema.json": {
|
|
33
|
-
"digest": "
|
|
34
|
-
"bytes":
|
|
37
|
+
"digest": "a605db801d6994d657049431ad453233974bd10610b7b447b196136bb0692866",
|
|
38
|
+
"bytes": 17847
|
|
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
|
+
}
|
|
@@ -1307,7 +1307,6 @@
|
|
|
1307
1307
|
"description": "冻结的发布后分发块:声明本身 + tag/tagCommit/unitId/payloadSource 绑定。整体参与 plan digest(planVersion 2 记录层剥离不包含该块),任何配置变更都会改变 planDigest。tagCommit 仅在 prepare 能冻结 create-tag 预期 commit 时存在(production 资产);缺省时 distribute fail-closed。",
|
|
1308
1308
|
"required": [
|
|
1309
1309
|
"materialize",
|
|
1310
|
-
"targets",
|
|
1311
1310
|
"commitIdentity",
|
|
1312
1311
|
"tag",
|
|
1313
1312
|
"unitId",
|
|
@@ -1325,6 +1324,13 @@
|
|
|
1325
1324
|
"$ref": "#/definitions/planPostPublishTarget"
|
|
1326
1325
|
}
|
|
1327
1326
|
},
|
|
1327
|
+
"hooks": {
|
|
1328
|
+
"type": "array",
|
|
1329
|
+
"description": "冻结的发布后钩子声明(v0.6.3 R1);随整块参与 plan digest",
|
|
1330
|
+
"items": {
|
|
1331
|
+
"$ref": "#/definitions/planPostPublishHook"
|
|
1332
|
+
}
|
|
1333
|
+
},
|
|
1328
1334
|
"commitIdentity": {
|
|
1329
1335
|
"type": "object",
|
|
1330
1336
|
"required": [
|
|
@@ -1373,6 +1379,64 @@
|
|
|
1373
1379
|
}
|
|
1374
1380
|
}
|
|
1375
1381
|
},
|
|
1382
|
+
"planPostPublishHook": {
|
|
1383
|
+
"type": "object",
|
|
1384
|
+
"description": "冻结的发布后钩子声明项(v0.6.3 R1):preset 与 command 运行时互斥;phase 缺省 distribute;blocksVerified 缺省 true 且仅 preset 可声明 false",
|
|
1385
|
+
"required": [
|
|
1386
|
+
"id"
|
|
1387
|
+
],
|
|
1388
|
+
"additionalProperties": false,
|
|
1389
|
+
"properties": {
|
|
1390
|
+
"id": {
|
|
1391
|
+
"type": "string",
|
|
1392
|
+
"pattern": "^[a-z0-9][a-z0-9._-]*$"
|
|
1393
|
+
},
|
|
1394
|
+
"preset": {
|
|
1395
|
+
"type": "string",
|
|
1396
|
+
"pattern": "^[a-z0-9][a-z0-9._-]*$"
|
|
1397
|
+
},
|
|
1398
|
+
"command": {
|
|
1399
|
+
"type": "array",
|
|
1400
|
+
"minItems": 1,
|
|
1401
|
+
"items": {
|
|
1402
|
+
"type": "string"
|
|
1403
|
+
}
|
|
1404
|
+
},
|
|
1405
|
+
"phase": {
|
|
1406
|
+
"type": "string",
|
|
1407
|
+
"enum": [
|
|
1408
|
+
"distribute",
|
|
1409
|
+
"postVerify"
|
|
1410
|
+
]
|
|
1411
|
+
},
|
|
1412
|
+
"config": {
|
|
1413
|
+
"type": "object"
|
|
1414
|
+
},
|
|
1415
|
+
"cwd": {
|
|
1416
|
+
"type": "string",
|
|
1417
|
+
"pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$"
|
|
1418
|
+
},
|
|
1419
|
+
"timeoutMs": {
|
|
1420
|
+
"type": "integer",
|
|
1421
|
+
"minimum": 1000,
|
|
1422
|
+
"maximum": 7200000
|
|
1423
|
+
},
|
|
1424
|
+
"envAllowlist": {
|
|
1425
|
+
"type": "array",
|
|
1426
|
+
"items": {
|
|
1427
|
+
"type": "string",
|
|
1428
|
+
"pattern": "^(?!.*(?:TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL))[A-Z_][A-Z0-9_]*$"
|
|
1429
|
+
},
|
|
1430
|
+
"uniqueItems": true
|
|
1431
|
+
},
|
|
1432
|
+
"requiresApproval": {
|
|
1433
|
+
"type": "boolean"
|
|
1434
|
+
},
|
|
1435
|
+
"blocksVerified": {
|
|
1436
|
+
"type": "boolean"
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
},
|
|
1376
1440
|
"planPostPublishMaterialize": {
|
|
1377
1441
|
"type": "object",
|
|
1378
1442
|
"required": [
|
|
@@ -889,7 +889,6 @@
|
|
|
889
889
|
"description": "发布后分发声明:materialize 钩子从冻结 tag 工作树物化载荷,targets 将载荷镜像或渲染市场索引推送到独立 git 远端。分发在 publish 之后由 distribute 命令执行,时序契约禁止读取工作区状态。",
|
|
890
890
|
"required": [
|
|
891
891
|
"materialize",
|
|
892
|
-
"targets",
|
|
893
892
|
"commitIdentity"
|
|
894
893
|
],
|
|
895
894
|
"additionalProperties": false,
|
|
@@ -904,6 +903,13 @@
|
|
|
904
903
|
"$ref": "#/definitions/postPublishTarget"
|
|
905
904
|
}
|
|
906
905
|
},
|
|
906
|
+
"hooks": {
|
|
907
|
+
"type": "array",
|
|
908
|
+
"description": "发布后钩子声明(v0.6.3 R1):每项为命名 preset(+config)或自定义 command 钩子(executable+参数数组,禁止 shell 字符串)。schema 层只校验形状;preset 与 command 互斥、preset 注册表归属等语义在运行时 fail-closed 校验(POSTPUBLISH_HOOK_INVALID)",
|
|
909
|
+
"items": {
|
|
910
|
+
"$ref": "#/definitions/postPublishHook"
|
|
911
|
+
}
|
|
912
|
+
},
|
|
907
913
|
"commitIdentity": {
|
|
908
914
|
"type": "object",
|
|
909
915
|
"description": "分发仓库提交者身份(bot 身份),通过 git -c user.name/-c user.email 注入,绝不读取或修改全局 git 配置",
|
|
@@ -936,6 +942,72 @@
|
|
|
936
942
|
}
|
|
937
943
|
}
|
|
938
944
|
},
|
|
945
|
+
"postPublishHook": {
|
|
946
|
+
"type": "object",
|
|
947
|
+
"description": "发布后钩子声明项:preset(命名预设 + config)与 command(自定义命令)在运行时互斥校验;phase 缺省为 distribute(VERIFIED 之前执行),postVerify 在 verify 通过后作为独立 run 执行(R3);blocksVerified 缺省 true,仅 preset 可声明 false",
|
|
948
|
+
"required": [
|
|
949
|
+
"id"
|
|
950
|
+
],
|
|
951
|
+
"additionalProperties": false,
|
|
952
|
+
"properties": {
|
|
953
|
+
"id": {
|
|
954
|
+
"type": "string",
|
|
955
|
+
"pattern": "^[a-z0-9][a-z0-9._-]*$"
|
|
956
|
+
},
|
|
957
|
+
"preset": {
|
|
958
|
+
"type": "string",
|
|
959
|
+
"pattern": "^[a-z0-9][a-z0-9._-]*$",
|
|
960
|
+
"description": "预设注册表中的预设名(R2 起);R1 无注册表,任何 preset 引用在运行时 fail-closed"
|
|
961
|
+
},
|
|
962
|
+
"command": {
|
|
963
|
+
"type": "array",
|
|
964
|
+
"minItems": 1,
|
|
965
|
+
"items": {
|
|
966
|
+
"type": "string"
|
|
967
|
+
},
|
|
968
|
+
"description": "executable+参数数组(禁止 shell 字符串);在冻结 tag 工作树中执行"
|
|
969
|
+
},
|
|
970
|
+
"phase": {
|
|
971
|
+
"type": "string",
|
|
972
|
+
"enum": [
|
|
973
|
+
"distribute",
|
|
974
|
+
"postVerify"
|
|
975
|
+
],
|
|
976
|
+
"description": "执行阶段;缺省 distribute"
|
|
977
|
+
},
|
|
978
|
+
"config": {
|
|
979
|
+
"type": "object",
|
|
980
|
+
"description": "preset 钩子的配置对象;语义由预设注册表校验(R2 起)"
|
|
981
|
+
},
|
|
982
|
+
"cwd": {
|
|
983
|
+
"type": "string",
|
|
984
|
+
"pattern": "^(?:\\.$|(?!\\/)(?!\\.\\/)(?!.*\\\\)(?!.*:)(?!\\.\\.(?:\\/|$))(?!.*\\/\\.\\.\\/)(?!.*\\/\\.\\.$)(?!.*\\/\\.\\/)(?!.*\\/\\/)(?!.*\\0)(?!.*\\/\\.$)(?!.*\\/\\/$)(?!.*\\/$).*)$",
|
|
985
|
+
"description": "command 钩子执行目录(相对冻结 tag 工作树);preset 钩子禁止声明(运行时 fail-closed)"
|
|
986
|
+
},
|
|
987
|
+
"timeoutMs": {
|
|
988
|
+
"type": "integer",
|
|
989
|
+
"minimum": 1000,
|
|
990
|
+
"maximum": 7200000
|
|
991
|
+
},
|
|
992
|
+
"envAllowlist": {
|
|
993
|
+
"type": "array",
|
|
994
|
+
"items": {
|
|
995
|
+
"type": "string",
|
|
996
|
+
"pattern": "^(?!.*(?:TOKEN|SECRET|PASSWORD|PASSPHRASE|API_KEY|CREDENTIAL))[A-Z_][A-Z0-9_]*$"
|
|
997
|
+
},
|
|
998
|
+
"uniqueItems": true,
|
|
999
|
+
"description": "允许透传给钩子进程的环境变量白名单;TOKEN/SECRET 等敏感子串在 schema 层即被拒绝"
|
|
1000
|
+
},
|
|
1001
|
+
"requiresApproval": {
|
|
1002
|
+
"type": "boolean",
|
|
1003
|
+
"description": "执行前需要 checkpoint 级批准(绑定 planDigest + hookId);public-write preset 缺省 true"
|
|
1004
|
+
},
|
|
1005
|
+
"blocksVerified": {
|
|
1006
|
+
"type": "boolean",
|
|
1007
|
+
"description": "失败时是否阻断 VERIFIED;缺省 true;仅 preset 可声明 false(运行时 fail-closed 校验)"
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
},
|
|
939
1011
|
"postPublishMaterialize": {
|
|
940
1012
|
"type": "object",
|
|
941
1013
|
"description": "载荷物化钩子:executable+参数数组(禁止 shell 字符串),stdout 中 outputMarker 行之后为载荷目录路径;可选 requireReport 对 stdout 首个 JSON 对象做字段断言",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"PARTIAL",
|
|
44
44
|
"BLOCKED",
|
|
45
45
|
"DISTRIBUTING",
|
|
46
|
-
"DISTRIBUTED"
|
|
46
|
+
"DISTRIBUTED",
|
|
47
|
+
"NEEDS_INPUT"
|
|
47
48
|
],
|
|
48
49
|
"description": "Current status of the run"
|
|
49
50
|
},
|
|
@@ -55,7 +56,8 @@
|
|
|
55
56
|
"publish",
|
|
56
57
|
"reconcile",
|
|
57
58
|
"verify",
|
|
58
|
-
"distribute"
|
|
59
|
+
"distribute",
|
|
60
|
+
"postverify"
|
|
59
61
|
],
|
|
60
62
|
"description": "The command that initiated this run"
|
|
61
63
|
},
|
|
@@ -133,7 +135,8 @@
|
|
|
133
135
|
"codebuddy-marketplace-install",
|
|
134
136
|
"set-default-branch",
|
|
135
137
|
"distribute-probe",
|
|
136
|
-
"distribute-mirror"
|
|
138
|
+
"distribute-mirror",
|
|
139
|
+
"postpublish-hook"
|
|
137
140
|
],
|
|
138
141
|
"description": "Type of external action"
|
|
139
142
|
},
|
|
@@ -149,9 +152,10 @@
|
|
|
149
152
|
"PASSED_AUTOMATIC",
|
|
150
153
|
"PASSED_MANUAL",
|
|
151
154
|
"NOT_REQUIRED_UNCHANGED",
|
|
152
|
-
"NO_CHANGE"
|
|
155
|
+
"NO_CHANGE",
|
|
156
|
+
"AWAITING_APPROVAL"
|
|
153
157
|
],
|
|
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)"
|
|
158
|
+
"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; AWAITING_APPROVAL = requiresApproval postPublish hook 尚无 checkpoint 批准,v0.6.3 R1)"
|
|
155
159
|
},
|
|
156
160
|
"preObserve": {
|
|
157
161
|
"type": "string",
|
|
@@ -621,7 +625,8 @@
|
|
|
621
625
|
"enum": [
|
|
622
626
|
"reconcile",
|
|
623
627
|
"verify",
|
|
624
|
-
"distribute"
|
|
628
|
+
"distribute",
|
|
629
|
+
"postverify"
|
|
625
630
|
]
|
|
626
631
|
}
|
|
627
632
|
},
|
|
@@ -237,7 +237,8 @@ Commands:
|
|
|
237
237
|
publish Publish frozen GitHub/npm artifacts after approval
|
|
238
238
|
reconcile Resume PARTIAL state from evidence; conflicts require a human
|
|
239
239
|
verify Fresh remote and consumer verification; only this reaches VERIFIED
|
|
240
|
-
ship Resume one durable prepare -> approve -> publish -> verify flow
|
|
240
|
+
ship Resume one durable prepare -> approve -> publish -> verify flow; completes a parked
|
|
241
|
+
postVerify hook once its checkpoint approval is provided (--hook-approval)
|
|
241
242
|
attest Legacy only: record a Kimi/CodeBuddy result for an old frozen plan
|
|
242
243
|
hooks Run declared development hooks and populate reusable receipts
|
|
243
244
|
artifacts Artifact status, inspect, update/apply, resolution, and diagnostics
|
|
@@ -249,7 +250,8 @@ Commands:
|
|
|
249
250
|
Options:
|
|
250
251
|
--root <path> Project root directory (default: cwd)
|
|
251
252
|
--plan <path> Path to the release plan file
|
|
252
|
-
--run <path> Path to the release run file
|
|
253
|
+
--run <path> Path to the release run file, or a run directory whose release-run.json
|
|
254
|
+
is resolved automatically (required for reconcile/verify)
|
|
253
255
|
--approval <path> Path to the approval record
|
|
254
256
|
--production Prepare immutable Git/npm production artifacts
|
|
255
257
|
--output <path> Override prepare/approve output path (non-production only)
|
|
@@ -264,6 +266,12 @@ Options:
|
|
|
264
266
|
--answers <path> Human-reviewed setup answers JSON
|
|
265
267
|
--write Create an absent project.yaml during setup; never overwrites
|
|
266
268
|
--confirm-setup <digest> Confirm exact setup facts and answers before create
|
|
269
|
+
--discover-downstream Read-only discovery of downstream candidates (git remotes, marketplace/docs
|
|
270
|
+
clues, artifact-graph.config.yaml, foundation profile). Never writes
|
|
271
|
+
--propose-hooks Produce postPublish hook declaration drafts; with --write and exact --confirm-setup,
|
|
272
|
+
performs an append-only hooks edit of an existing config (create-once is untouched)
|
|
273
|
+
--select-hooks <ids> Comma-separated proposal ids to adopt (propose-hooks mode)
|
|
274
|
+
--foundation-profile <path> Explicit foundation postPublish profile JSON (proposal input only; never auto-applied)
|
|
267
275
|
--unit <id> Release unit whose declared release documents are refreshed (docs refresh)
|
|
268
276
|
--confirm-refresh <sha256:...> Confirm the exact dry-run refreshDigest before any document write
|
|
269
277
|
--ack-local-document-write Acknowledge the explicit local release-document write (docs refresh --write)
|
|
@@ -274,6 +282,7 @@ Options:
|
|
|
274
282
|
--install-path <path> Actual managed plugin path when closure verification requires it
|
|
275
283
|
--install-channel <desktop|cli> CodeBuddy installation channel when required
|
|
276
284
|
--approve Approve the ship plan (boolean; plan digest is auto-resolved)
|
|
285
|
+
--hook-approval <path> Checkpoint approval for a requiresApproval postPublish hook (ship/distribute; repeatable)
|
|
277
286
|
--state <path> Override the durable ship state file
|
|
278
287
|
--no-hook-cache Force every prepare hook to run in full; neither read nor write the hook cache
|
|
279
288
|
--json Output results as JSON
|
|
@@ -467,6 +476,59 @@ if (command === 'setup') {
|
|
|
467
476
|
? args[confirmationIdx + 1]
|
|
468
477
|
: undefined;
|
|
469
478
|
const write = args.includes('--write');
|
|
479
|
+
|
|
480
|
+
// R5 — downstream discovery + postPublish hook proposal (guided config) and
|
|
481
|
+
// the independent incremental-proposal mode for existing projects. These
|
|
482
|
+
// modes are read-only until --write + exact --confirm-setup, and the write is
|
|
483
|
+
// an append-only hooks edit; they never touch the create-once setup path.
|
|
484
|
+
const discoverDownstreamMode = args.includes('--discover-downstream');
|
|
485
|
+
const proposeHooksMode = args.includes('--propose-hooks');
|
|
486
|
+
if (discoverDownstreamMode || proposeHooksMode) {
|
|
487
|
+
const flagValue = (flag) => {
|
|
488
|
+
const idx = args.indexOf(flag);
|
|
489
|
+
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
490
|
+
};
|
|
491
|
+
const foundationProfilePath = flagValue('--foundation-profile');
|
|
492
|
+
const unitId = flagValue('--unit');
|
|
493
|
+
const selectRaw = flagValue('--select-hooks');
|
|
494
|
+
const selectedHookIds = selectRaw
|
|
495
|
+
? selectRaw.split(',').map((item) => item.trim()).filter(Boolean)
|
|
496
|
+
: undefined;
|
|
497
|
+
try {
|
|
498
|
+
const setupModule = await import('../src/commands/setup.mjs');
|
|
499
|
+
const report = discoverDownstreamMode
|
|
500
|
+
? await setupModule.discoverDownstream({ root, foundationProfilePath })
|
|
501
|
+
: await setupModule.proposePostPublishHooks({
|
|
502
|
+
root, write, confirmSetup, selectedHookIds, foundationProfilePath, unitId,
|
|
503
|
+
});
|
|
504
|
+
if (hasJson) {
|
|
505
|
+
console.log(JSON.stringify(report, null, 2));
|
|
506
|
+
} else {
|
|
507
|
+
console.log(`Status: ${report.status ?? report.mode}`);
|
|
508
|
+
if (report.setupDigest) console.log(`Setup digest: ${report.setupDigest}`);
|
|
509
|
+
if (report.hookProposals) {
|
|
510
|
+
console.log(`Hook proposals: ${report.hookProposals.map((p) => p.id).join(', ') || '(none)'}`);
|
|
511
|
+
}
|
|
512
|
+
if (report.configPath) console.log(`Config: ${report.configPath}`);
|
|
513
|
+
if (report.next) console.log(`Next: ${report.next}`);
|
|
514
|
+
}
|
|
515
|
+
const okStatuses = ['HOOKS_PROPOSAL_READY', 'HOOKS_APPENDED', 'HOOKS_NO_CHANGE', 'postpublish-discovery'];
|
|
516
|
+
process.exit(okStatuses.includes(report.status ?? report.mode) ? 0 : 2);
|
|
517
|
+
} catch (err) {
|
|
518
|
+
if (hasJson) {
|
|
519
|
+
console.log(JSON.stringify({
|
|
520
|
+
error: err.code ?? 'UNKNOWN_ERROR',
|
|
521
|
+
message: err.message,
|
|
522
|
+
details: err.details ?? {},
|
|
523
|
+
exitCode: err.exitCode ?? 1,
|
|
524
|
+
}));
|
|
525
|
+
} else {
|
|
526
|
+
console.error(`Error: ${err.message}`);
|
|
527
|
+
}
|
|
528
|
+
process.exit(err.exitCode ?? 1);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
470
532
|
try {
|
|
471
533
|
const { setupProject } = await import('../src/commands/setup.mjs');
|
|
472
534
|
const report = await setupProject({ root, answersPath, write, confirmSetup });
|
|
@@ -575,6 +637,16 @@ if (command === 'ship') {
|
|
|
575
637
|
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
576
638
|
};
|
|
577
639
|
const root = resolve(value('--root') ?? process.cwd());
|
|
640
|
+
// Repeatable --hook-approval <path>: checkpoint approvals for
|
|
641
|
+
// requiresApproval postPublish hooks (same convention as distribute;
|
|
642
|
+
// review major-1 — without this the ship flow can never complete a
|
|
643
|
+
// parked AWAITING_APPROVAL postVerify hook).
|
|
644
|
+
const postpublishApprovalPaths = [];
|
|
645
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
646
|
+
if (args[i] === '--hook-approval' && args[i + 1]) {
|
|
647
|
+
postpublishApprovalPaths.push(resolve(args[i + 1]));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
578
650
|
try {
|
|
579
651
|
const [
|
|
580
652
|
{ advanceShip },
|
|
@@ -582,6 +654,7 @@ if (command === 'ship') {
|
|
|
582
654
|
{ createNpmAdapter },
|
|
583
655
|
{ createPluginMarketplaceAdapter },
|
|
584
656
|
{ createPushSnapshotAdapter },
|
|
657
|
+
{ createDistributeGitAdapter },
|
|
585
658
|
{ createAdapterRegistry },
|
|
586
659
|
] = await Promise.all([
|
|
587
660
|
import('../src/commands/ship.mjs'),
|
|
@@ -589,13 +662,17 @@ if (command === 'ship') {
|
|
|
589
662
|
import('../src/adapters/npm.mjs'),
|
|
590
663
|
import('../src/adapters/plugin-marketplace.mjs'),
|
|
591
664
|
import('../src/adapters/push-snapshot.mjs'),
|
|
665
|
+
import('../src/adapters/distribute-git.mjs'),
|
|
592
666
|
import('../src/adapters/contract.mjs'),
|
|
593
667
|
]);
|
|
668
|
+
// v0.6.3 R1: ship auto-routes into the distribute saga; the registry must
|
|
669
|
+
// carry the distribute-git adapter or that production path fails closed.
|
|
594
670
|
const adapterRegistry = createAdapterRegistry([
|
|
595
671
|
createGitGithubAdapter(),
|
|
596
672
|
createNpmAdapter(),
|
|
597
673
|
createPluginMarketplaceAdapter(),
|
|
598
674
|
createPushSnapshotAdapter(),
|
|
675
|
+
createDistributeGitAdapter(),
|
|
599
676
|
]);
|
|
600
677
|
const result = await advanceShip({
|
|
601
678
|
root,
|
|
@@ -605,15 +682,27 @@ if (command === 'ship') {
|
|
|
605
682
|
planApprovalDigest: value('--approve-plan'),
|
|
606
683
|
actor: value('--actor'),
|
|
607
684
|
adapterRegistry,
|
|
685
|
+
...(postpublishApprovalPaths.length > 0 ? { postpublishApprovalPaths } : {}),
|
|
608
686
|
});
|
|
609
687
|
if (hasJson) {
|
|
610
688
|
console.log(JSON.stringify(result, null, 2));
|
|
611
689
|
} else {
|
|
612
690
|
console.log(`Ship status: ${result.status}`);
|
|
613
691
|
console.log(`State: ${result.statePath}`);
|
|
692
|
+
for (const warning of result.warnings ?? []) {
|
|
693
|
+
console.log(`Warning [${warning.code}] ${warning.message}`);
|
|
694
|
+
}
|
|
614
695
|
if (result.planDigest && result.status === 'NEEDS_PLAN_APPROVAL') {
|
|
615
696
|
console.log(`Approve plan: ship --approve --actor <person>`);
|
|
616
697
|
}
|
|
698
|
+
if (result.postVerify) {
|
|
699
|
+
console.log(`PostVerify: ${result.postVerify.status}${result.postVerify.runPath ? ` (run: ${result.postVerify.runPath})` : ''}`);
|
|
700
|
+
if (['NEEDS_INPUT', 'PARTIAL', 'BLOCKED', 'FAILED'].includes(result.postVerify.status)) {
|
|
701
|
+
console.log('PostVerify incomplete: re-run release-skill ship to retry non-gated hooks (no approval needed for them).');
|
|
702
|
+
console.log('For requiresApproval hooks, mint a checkpoint approval (release-skill approve --plan <plan> --hook <hookId> --actor <person>)');
|
|
703
|
+
console.log('then re-run: release-skill ship --root <root> --hook-approval <approval-record>');
|
|
704
|
+
}
|
|
705
|
+
}
|
|
617
706
|
for (const followUp of result.manualFollowUps ?? []) {
|
|
618
707
|
console.log(`Manual follow-up [${followUp.platform}] ${followUp.plugin}: not verified by system`);
|
|
619
708
|
}
|
|
@@ -757,6 +846,7 @@ if (command === 'prepare') {
|
|
|
757
846
|
unitId: action.unitId,
|
|
758
847
|
})),
|
|
759
848
|
warnings: result.warnings,
|
|
849
|
+
nextSteps: result.nextSteps ?? [],
|
|
760
850
|
}, null, 2));
|
|
761
851
|
} else {
|
|
762
852
|
for (const warning of result.warnings) {
|
|
@@ -765,6 +855,9 @@ if (command === 'prepare') {
|
|
|
765
855
|
console.log(`Plan frozen at: ${result.planPath}`);
|
|
766
856
|
console.log(`Plan digest: ${result.planDigest}`);
|
|
767
857
|
console.log(`Evidence: ${result.evidenceDir}`);
|
|
858
|
+
for (const step of result.nextSteps ?? []) {
|
|
859
|
+
console.log(`Next [${step.code}] ${step.message}`);
|
|
860
|
+
}
|
|
768
861
|
if (plan.workflowKind && plan.workflowKind !== 'full') {
|
|
769
862
|
console.log(`Workflow: ${plan.workflowKind}`);
|
|
770
863
|
}
|
|
@@ -804,6 +897,10 @@ if (command === 'approve') {
|
|
|
804
897
|
const actor = actorIdx !== -1 && args[actorIdx + 1] ? args[actorIdx + 1] : undefined;
|
|
805
898
|
const outputIdx = args.indexOf('--output');
|
|
806
899
|
const outputPath = outputIdx !== -1 && args[outputIdx + 1] ? resolve(args[outputIdx + 1]) : undefined;
|
|
900
|
+
const hookIdx = args.indexOf('--hook');
|
|
901
|
+
const hookId = hookIdx !== -1 && args[hookIdx + 1] ? args[hookIdx + 1] : undefined;
|
|
902
|
+
const runIdIdx = args.indexOf('--run-id');
|
|
903
|
+
const runId = runIdIdx !== -1 && args[runIdIdx + 1] ? args[runIdIdx + 1] : undefined;
|
|
807
904
|
|
|
808
905
|
if (!planPath || !actor) {
|
|
809
906
|
const msg = 'approve requires --plan <path> and --actor <name>';
|
|
@@ -815,6 +912,44 @@ if (command === 'approve') {
|
|
|
815
912
|
process.exit(1);
|
|
816
913
|
}
|
|
817
914
|
|
|
915
|
+
// --- Checkpoint-level postPublish hook approval (v0.6.3 R1, review N-6) ---
|
|
916
|
+
if (hookId) {
|
|
917
|
+
try {
|
|
918
|
+
const { approvePostPublishHook } = await import('../src/commands/approve.mjs');
|
|
919
|
+
const record = await approvePostPublishHook({
|
|
920
|
+
planPath: resolve(planPath),
|
|
921
|
+
hookId,
|
|
922
|
+
actor,
|
|
923
|
+
...(runId ? { runId } : {}),
|
|
924
|
+
});
|
|
925
|
+
if (hasJson) {
|
|
926
|
+
console.log(JSON.stringify(record, null, 2));
|
|
927
|
+
} else {
|
|
928
|
+
console.log(`Checkpoint approval for postPublish hook "${record.hookId}" by ${record.actor}`);
|
|
929
|
+
console.log(`Approval record: ${record.approvalPath}`);
|
|
930
|
+
console.log(`Approved at: ${record.approvedAt}`);
|
|
931
|
+
console.log(`Expires at: ${record.expiresAt}`);
|
|
932
|
+
console.log('Approved hook (normalized entry summary):');
|
|
933
|
+
const summary = record.hookSummary ?? {};
|
|
934
|
+
for (const [key, value] of Object.entries(summary)) {
|
|
935
|
+
console.log(` ${key}: ${typeof value === 'object' ? JSON.stringify(value) : value}`);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
process.exit(0);
|
|
939
|
+
} catch (err) {
|
|
940
|
+
if (hasJson) {
|
|
941
|
+
console.log(JSON.stringify({
|
|
942
|
+
error: err.code ?? 'UNKNOWN_ERROR',
|
|
943
|
+
message: err.message,
|
|
944
|
+
exitCode: err.exitCode ?? 1,
|
|
945
|
+
}));
|
|
946
|
+
} else {
|
|
947
|
+
console.error(`Error: ${err.message}`);
|
|
948
|
+
}
|
|
949
|
+
process.exit(err.exitCode ?? 1);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
|
|
818
953
|
try {
|
|
819
954
|
const { approvePlan } = await import('../src/commands/approve.mjs');
|
|
820
955
|
const { computePlanDigest } = await import('../src/core/plan.mjs');
|
|
@@ -1259,7 +1394,41 @@ if (command === 'distribute') {
|
|
|
1259
1394
|
const approvalPath = value('--approval');
|
|
1260
1395
|
const runPath = value('--run');
|
|
1261
1396
|
const dryRun = args.includes('--dry-run');
|
|
1397
|
+
// Repeatable --hook-approval <path>: checkpoint approvals for
|
|
1398
|
+
// requiresApproval postPublish hooks (v0.6.3 R1).
|
|
1399
|
+
const postpublishApprovalPaths = [];
|
|
1400
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
1401
|
+
if (args[i] === '--hook-approval' && args[i + 1]) {
|
|
1402
|
+
postpublishApprovalPaths.push(resolve(args[i + 1]));
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1262
1405
|
|
|
1406
|
+
// R2: enumerate the postPublish preset registry (ships with the bundle).
|
|
1407
|
+
// Read-only; needs no --plan/--run, so it short-circuits parameter checks.
|
|
1408
|
+
if (args.includes('--list-presets')) {
|
|
1409
|
+
const { listPostPublishPresets } = await import('../src/core/presets.mjs');
|
|
1410
|
+
const presets = listPostPublishPresets();
|
|
1411
|
+
if (hasJson) {
|
|
1412
|
+
console.log(JSON.stringify({ command: 'distribute', presets }, null, 2));
|
|
1413
|
+
} else {
|
|
1414
|
+
console.log('postPublish presets:');
|
|
1415
|
+
for (const preset of presets) {
|
|
1416
|
+
const status = preset.implemented ? 'implemented' : 'reserved (behavior lands in a later release)';
|
|
1417
|
+
console.log(` ${preset.name}`);
|
|
1418
|
+
console.log(` description: ${preset.description}`);
|
|
1419
|
+
console.log(` requiresApproval default: ${preset.defaultRequiresApproval}`);
|
|
1420
|
+
if (preset.requiresApprovalNote) {
|
|
1421
|
+
console.log(` requiresApproval note: ${preset.requiresApprovalNote}`);
|
|
1422
|
+
}
|
|
1423
|
+
if (preset.targetsFormOnly) {
|
|
1424
|
+
console.log(' declaration form: targets-form only (declare under postPublish.targets, not postPublish.hooks)');
|
|
1425
|
+
}
|
|
1426
|
+
console.log(` write-downstream: ${preset.writeDownstream}; target optional: ${preset.targetOptional}; status: ${status}`);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
process.exit(0);
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1263
1432
|
// Handle --help explicitly
|
|
1264
1433
|
if (args.includes('--help')) {
|
|
1265
1434
|
const helpText = `Distribute command: Distributes frozen artifacts to post-publish targets
|
|
@@ -1271,7 +1440,9 @@ Options:
|
|
|
1271
1440
|
--plan Path to the release plan file (required)
|
|
1272
1441
|
--run Path to the release run file (required)
|
|
1273
1442
|
--approval Path to the approval record (optional but recommended)
|
|
1443
|
+
--hook-approval <path> Checkpoint approval for a requiresApproval postPublish hook (repeatable)
|
|
1274
1444
|
--dry-run Preview distribution steps without executing (default: false)
|
|
1445
|
+
--list-presets Enumerate the postPublish preset registry (no plan/run needed)
|
|
1275
1446
|
|
|
1276
1447
|
Description:
|
|
1277
1448
|
After PUBLISHED state, distributes to configured postPublish targets:
|
|
@@ -1288,9 +1459,11 @@ Description:
|
|
|
1288
1459
|
'--plan': 'Path to the release plan file (required)',
|
|
1289
1460
|
'--run': 'Path to the release run file (required)',
|
|
1290
1461
|
'--approval': 'Path to the approval record (optional but recommended)',
|
|
1462
|
+
'--hook-approval': 'Checkpoint approval for a requiresApproval postPublish hook (repeatable)',
|
|
1291
1463
|
'--dry-run': 'Preview distribution steps without executing (default: false)',
|
|
1464
|
+
'--list-presets': 'Enumerate the postPublish preset registry (no plan/run needed)',
|
|
1292
1465
|
},
|
|
1293
|
-
|
|
1466
|
+
details: 'After PUBLISHED state, distributes to configured postPublish targets: git mirrors + marketplace index updates. Requires plan.postPublish config. Reconciles PARTIAL runs.',
|
|
1294
1467
|
}, null, 2));
|
|
1295
1468
|
} else {
|
|
1296
1469
|
console.log(helpText);
|
|
@@ -1314,13 +1487,17 @@ Description:
|
|
|
1314
1487
|
const { createNpmAdapter } = await import('../src/adapters/npm.mjs');
|
|
1315
1488
|
const { createPluginMarketplaceAdapter } = await import('../src/adapters/plugin-marketplace.mjs');
|
|
1316
1489
|
const { createPushSnapshotAdapter } = await import('../src/adapters/push-snapshot.mjs');
|
|
1490
|
+
const { createDistributeGitAdapter } = await import('../src/adapters/distribute-git.mjs');
|
|
1317
1491
|
const { createAdapterRegistry } = await import('../src/adapters/contract.mjs');
|
|
1318
1492
|
|
|
1493
|
+
// v0.6.3 R1: the distribute saga executes through the distribute-git
|
|
1494
|
+
// adapter; without this registration the production path fails closed.
|
|
1319
1495
|
const registry = createAdapterRegistry([
|
|
1320
1496
|
createGitGithubAdapter(),
|
|
1321
1497
|
createNpmAdapter(),
|
|
1322
1498
|
createPluginMarketplaceAdapter(),
|
|
1323
1499
|
createPushSnapshotAdapter(),
|
|
1500
|
+
createDistributeGitAdapter(),
|
|
1324
1501
|
]);
|
|
1325
1502
|
|
|
1326
1503
|
const result = await distributeRelease({
|
|
@@ -1330,6 +1507,7 @@ Description:
|
|
|
1330
1507
|
root,
|
|
1331
1508
|
dryRun,
|
|
1332
1509
|
planPath,
|
|
1510
|
+
...(postpublishApprovalPaths.length > 0 ? { postpublishApprovalPaths } : {}),
|
|
1333
1511
|
});
|
|
1334
1512
|
|
|
1335
1513
|
if (hasJson) {
|