release-skill 0.8.1 → 0.9.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.
- 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 +31 -0
- package/INSTALL.md +14 -2
- package/INSTALL.zh-CN.md +12 -2
- package/README.md +28 -16
- package/README.zh-CN.md +23 -14
- package/adapters/claude/.claude-plugin/marketplace.json +1 -1
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/bin/release-skill-local-finish.mjs +4 -0
- package/adapters/claude/bin/release-skill.bundle.mjs +2416 -1320
- package/adapters/claude/schemas/release-plan.schema.json +40 -3
- package/adapters/claude/skills/release-finish/SKILL.md +65 -0
- package/adapters/claude/skills/release-verify/SKILL.md +6 -1
- package/adapters/codex/.codex-plugin/plugin.json +2 -2
- package/adapters/codex/bin/release-skill-local-finish.mjs +4 -0
- package/adapters/codex/bin/release-skill.bundle.mjs +2416 -1320
- package/adapters/codex/schemas/release-plan.schema.json +40 -3
- package/adapters/codex/skills/release-finish/SKILL.md +72 -0
- package/adapters/codex/skills/release-verify/SKILL.md +6 -1
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/bin/release-skill-local-finish.mjs +4 -0
- package/adapters/kimi/bin/release-skill.bundle.mjs +2416 -1320
- package/adapters/kimi/schemas/release-plan.schema.json +40 -3
- package/adapters/kimi/skills/release-finish/SKILL.md +72 -0
- package/adapters/kimi/skills/release-verify/SKILL.md +6 -1
- package/adapters/workbuddy/.codebuddy-plugin/plugin.json +1 -1
- package/adapters/workbuddy/bin/release-skill-local-finish.mjs +4 -0
- package/adapters/workbuddy/bin/release-skill.bundle.mjs +2416 -1320
- package/adapters/workbuddy/schemas/release-plan.schema.json +40 -3
- package/adapters/workbuddy/skills/release-finish/SKILL.md +65 -0
- package/adapters/workbuddy/skills/release-verify/SKILL.md +6 -1
- package/bin/release-skill-cli.mjs +126 -1
- package/bin/release-skill-local-finish.mjs +4 -0
- package/bin/release-skill.bundle.mjs +2416 -1320
- package/package.json +1 -1
- package/platform-manifest.json +30 -4
- package/schemas/release-plan.schema.json +40 -3
- package/skills/release-finish/SKILL.md +65 -0
- package/skills/release-verify/SKILL.md +6 -1
- package/skills-src/release-finish/SKILL.md +65 -0
- package/skills-src/release-verify/SKILL.md +6 -1
- package/src/commands/approve.mjs +14 -2
- package/src/commands/distribute.mjs +562 -321
- package/src/commands/post-release-local.mjs +611 -0
- package/src/commands/postverify.mjs +262 -155
- package/src/commands/prepare.mjs +67 -52
- package/src/commands/publish.mjs +11 -10
- package/src/commands/reconcile.mjs +11 -10
- package/src/commands/setup.mjs +26 -13
- package/src/commands/ship.mjs +45 -12
- package/src/commands/verify.mjs +19 -8
- package/src/core/adoption-assessment.mjs +0 -3
- package/src/core/approval.mjs +11 -8
- package/src/core/hooks.mjs +0 -16
- package/src/core/plan.mjs +19 -11
- package/src/core/postpublish-approval.mjs +12 -2
- package/src/core/postpublish-bundle.mjs +51 -13
- package/src/core/postpublish.mjs +146 -6
- package/src/core/preset-executor.mjs +53 -0
- package/src/core/proposal-inbox.mjs +91 -27
- package/src/core/recovery.mjs +27 -12
- package/src/producers/build-adapters.mjs +10 -1
|
@@ -17,9 +17,10 @@
|
|
|
17
17
|
"type": "integer",
|
|
18
18
|
"enum": [
|
|
19
19
|
1,
|
|
20
|
-
2
|
|
20
|
+
2,
|
|
21
|
+
3
|
|
21
22
|
],
|
|
22
|
-
"description": "Plan format and digest-scoping version. 1: legacy (every field except the top-level digest binds; commitTimestamp must equal createdAt). 2: T1.2 digest layering (record-layer fields status/createdAt/baseline/per-action status are excluded from the plan digest; commitTimestamp is derived from the HEAD commit committer date)."
|
|
23
|
+
"description": "Plan format and digest-scoping version. 1: legacy (every field except the top-level digest binds; commitTimestamp must equal createdAt). 2: T1.2 digest layering (record-layer fields status/createdAt/baseline/per-action status are excluded from the plan digest; commitTimestamp is derived from the HEAD commit committer date). 3: multi-release-unit postPublish v3 (postPublish is a declaration ARRAY, one entry per declaring unit in plan.units order, possibly empty; v3 inherits the v2 record-layer semantics and only changes the postPublish shape)."
|
|
23
24
|
},
|
|
24
25
|
"status": {
|
|
25
26
|
"type": "string",
|
|
@@ -1121,7 +1122,11 @@
|
|
|
1121
1122
|
}
|
|
1122
1123
|
},
|
|
1123
1124
|
"postPublish": {
|
|
1124
|
-
"
|
|
1125
|
+
"type": [
|
|
1126
|
+
"object",
|
|
1127
|
+
"array"
|
|
1128
|
+
],
|
|
1129
|
+
"description": "Frozen post-release distribution block. planVersion 1/2: a single declaration object, or absent (normalized to the empty array view at runtime). planVersion 3: a declaration ARRAY, one entry per declaring unit in plan.units order, possibly empty — never a single object, never absent. The exact allowed shape is enforced conditionally on planVersion (root allOf); readers must never guess the shape from the field value."
|
|
1125
1130
|
},
|
|
1126
1131
|
"digest": {
|
|
1127
1132
|
"type": "string",
|
|
@@ -1844,6 +1849,38 @@
|
|
|
1844
1849
|
}
|
|
1845
1850
|
},
|
|
1846
1851
|
"allOf": [
|
|
1852
|
+
{
|
|
1853
|
+
"if": {
|
|
1854
|
+
"properties": {
|
|
1855
|
+
"planVersion": {
|
|
1856
|
+
"const": 3
|
|
1857
|
+
}
|
|
1858
|
+
},
|
|
1859
|
+
"required": [
|
|
1860
|
+
"planVersion"
|
|
1861
|
+
]
|
|
1862
|
+
},
|
|
1863
|
+
"then": {
|
|
1864
|
+
"properties": {
|
|
1865
|
+
"postPublish": {
|
|
1866
|
+
"type": "array",
|
|
1867
|
+
"items": {
|
|
1868
|
+
"$ref": "#/definitions/planPostPublish"
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
},
|
|
1872
|
+
"required": [
|
|
1873
|
+
"postPublish"
|
|
1874
|
+
]
|
|
1875
|
+
},
|
|
1876
|
+
"else": {
|
|
1877
|
+
"properties": {
|
|
1878
|
+
"postPublish": {
|
|
1879
|
+
"$ref": "#/definitions/planPostPublish"
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
},
|
|
1847
1884
|
{
|
|
1848
1885
|
"if": {
|
|
1849
1886
|
"properties": {
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: release-finish
|
|
3
|
+
description: 发布达到 VERIFIED 后处理可选的本地收尾:按发布分支策略决定是否询问合并,并在用户确认后更新本机 Claude、Codex、Kimi、CodeBuddy/WorkBuddy 插件
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# release-finish
|
|
7
|
+
|
|
8
|
+
## 触发
|
|
9
|
+
|
|
10
|
+
发布刚达到 `VERIFIED`(已完成发布后验证),或用户要求处理发布后的分支合并、本机宿主插件更新。
|
|
11
|
+
|
|
12
|
+
## 边界
|
|
13
|
+
|
|
14
|
+
这是发布后的独立收尾,不属于 `prepare → approve → publish → verify` 状态机。它不能把本机更新结果写成新的发布状态,也不能因为本机更新失败而降低 `VERIFIED`。
|
|
15
|
+
|
|
16
|
+
默认只读取冻结计划和 verify run。没有用户明确同意,不合并分支,不更新插件,不接受 Kimi 的安装信任提示。
|
|
17
|
+
|
|
18
|
+
## 先生成收尾清单
|
|
19
|
+
|
|
20
|
+
从插件根执行:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
node "${CODEBUDDY_PLUGIN_ROOT}/bin/release-skill-local-finish.mjs" \
|
|
24
|
+
--plan <plan-path> \
|
|
25
|
+
--run <verified-run-path> \
|
|
26
|
+
--json
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
脚本只接受状态为 `VERIFIED`、且 `planDigest` 与冻结计划一致的 verify run。
|
|
30
|
+
|
|
31
|
+
## 主动询问
|
|
32
|
+
|
|
33
|
+
读取返回的 `merge` 和 `localHostUpdate`:
|
|
34
|
+
|
|
35
|
+
1. `merge.promptRequired=false` 时,发布工作流已经推进或初始化目标分支,不再询问合并。
|
|
36
|
+
2. `merge.promptRequired=true` 时,向用户说明尚未覆盖的发布分支,并询问是否需要合并。用户同意后,先只读核对源分支、目标分支、工作区状态和项目既有合并方式,再用明确的分支名执行;本脚本不猜分支,也不自动推送。
|
|
37
|
+
3. `localHostUpdate.promptRequired=true` 时,列出计划覆盖的宿主,询问是否更新本机插件。两个问题可以一次问完。
|
|
38
|
+
|
|
39
|
+
## 用户同意更新本机宿主
|
|
40
|
+
|
|
41
|
+
把用户选择的宿主和清单返回的精确 `planDigest` 传回脚本:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
node "${CODEBUDDY_PLUGIN_ROOT}/bin/release-skill-local-finish.mjs" \
|
|
45
|
+
--plan <plan-path> \
|
|
46
|
+
--run <verified-run-path> \
|
|
47
|
+
--update-local-hosts \
|
|
48
|
+
--hosts claude,codex,kimi,codebuddy,workbuddy \
|
|
49
|
+
--confirm-plan <planDigest> \
|
|
50
|
+
--json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
只传用户选择且计划声明的宿主。宿主 CLI 不存在时返回 `SKIPPED_NOT_INSTALLED`。各宿主按以下规则处理:
|
|
54
|
+
|
|
55
|
+
- Claude、Codex 绑定冻结的 Git 引用,并在安装后核对插件、市场、版本和市场检出提交。
|
|
56
|
+
- Kimi 先核对发布标签对应的提交,再通过受控的终端交互界面(TUI)安装,并读取本机安装根的版本、标签与修订号。
|
|
57
|
+
- CodeBuddy/WorkBuddy 的 CLI 不能精确绑定 Git 引用。本机已是目标提交时返回 `ALREADY_CURRENT`,否则返回 `MANUAL_REQUIRED`,不执行“更新到最新”。
|
|
58
|
+
|
|
59
|
+
任何宿主失败都保留其他宿主的实际结果,不回滚,也不把失败冒充成功。
|
|
60
|
+
|
|
61
|
+
完成后报告每个宿主的状态,并提醒用户重启已更新的宿主。
|
|
62
|
+
|
|
63
|
+
## 临时归属
|
|
64
|
+
|
|
65
|
+
本能力目前只服务发布后的本机收尾,因此保留在 release-skill。第二个技能族需要复用宿主更新或 TUI 驱动,或 Foundation 发布等价公共入口时,再把通用机制上收 Foundation并删除这里的通用部分。release-skill 只保留发布计划到宿主更新输入的领域映射。
|
|
@@ -42,7 +42,8 @@ verify 只接受 `PUBLISHED` 状态的源 run;`VERIFIED` 是终态,不会再
|
|
|
42
42
|
1. 确认有 `--run` 路径(必需),且源 run 状态为 PUBLISHED
|
|
43
43
|
2. 使用插件根相对路径运行 CLI;命令调用本身即授权执行已配置的 verification gate 和 smoke process
|
|
44
44
|
3. 检查 exit code 和结构化状态:`VERIFIED`(全部通过)/ 失败(具体错误)
|
|
45
|
-
4. 只有 `VERIFIED`
|
|
45
|
+
4. 只有 `VERIFIED` 才是发布 happy end
|
|
46
|
+
5. 达到 `VERIFIED` 后立即路由 `release-finish`:先生成只读收尾清单,再按清单主动询问分支合并和本机宿主插件更新;发布策略已包含分支动作时略过合并询问
|
|
46
47
|
|
|
47
48
|
## 确定性脚本调用
|
|
48
49
|
|
|
@@ -60,6 +61,10 @@ node "${CODEBUDDY_PLUGIN_ROOT}/bin/release-skill.mjs" verify --root <path> --pla
|
|
|
60
61
|
5. 对 Claude/Codex marketplace distribution 执行全新隔离消费者安装验证;收集 Kimi/CodeBuddy 的非阻塞 `manualFollowUps`
|
|
61
62
|
6. 全部通过 → `VERIFIED`
|
|
62
63
|
|
|
64
|
+
## 发布后收尾
|
|
65
|
+
|
|
66
|
+
`VERIFIED` 不代表要自动修改开发分支或本机宿主。进入 `release-finish` 后,只有用户明确同意,才执行对应的本地动作。本机插件更新失败不会改变发布终态。
|
|
67
|
+
|
|
63
68
|
## 烟雾测试
|
|
64
69
|
|
|
65
70
|
- 在 `os.tmpdir()` 创建隔离目录
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
3
4
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
4
5
|
import { execFile as execFileCb } from 'node:child_process';
|
|
5
6
|
import { promisify } from 'node:util';
|
|
@@ -36,7 +37,7 @@ registerPathRedactor(redactSensitivePaths);
|
|
|
36
37
|
|
|
37
38
|
const execFile = promisify(execFileCb);
|
|
38
39
|
|
|
39
|
-
const COMMANDS = new Set(['help', 'setup', 'assess', 'prepare', 'approve', 'publish', 'reconcile', 'verify', 'ship', 'attest', 'hooks', 'artifacts', 'docs', 'distribute', 'route', 'lineage']);
|
|
40
|
+
const COMMANDS = new Set(['help', 'setup', 'assess', 'prepare', 'approve', 'publish', 'reconcile', 'verify', 'ship', 'post-release', 'attest', 'hooks', 'artifacts', 'docs', 'distribute', 'route', 'lineage']);
|
|
40
41
|
|
|
41
42
|
/**
|
|
42
43
|
* Wait until writes already queued on a process output stream have reached
|
|
@@ -308,6 +309,8 @@ Commands:
|
|
|
308
309
|
verify Fresh remote and consumer verification; only this reaches VERIFIED
|
|
309
310
|
ship Resume one durable prepare -> approve -> publish -> verify flow; completes a parked
|
|
310
311
|
postVerify hook once its checkpoint approval is provided (--hook-approval)
|
|
312
|
+
post-release Inspect optional local finishing work after VERIFIED; update installed host plugins
|
|
313
|
+
only after exact plan confirmation
|
|
311
314
|
attest Legacy only: record a Kimi/CodeBuddy result for an old frozen plan
|
|
312
315
|
hooks Run declared development hooks and populate reusable receipts
|
|
313
316
|
artifacts Artifact status, inspect, update/apply, resolution, and diagnostics
|
|
@@ -360,6 +363,9 @@ Options:
|
|
|
360
363
|
--approve Approve the ship plan (boolean; plan digest is auto-resolved)
|
|
361
364
|
--hook-approval <path> Checkpoint approval for a requiresApproval postPublish hook (ship/distribute; repeatable)
|
|
362
365
|
--state <path> Override the durable ship state file
|
|
366
|
+
--update-local-hosts Update installed plugins for selected local hosts after VERIFIED
|
|
367
|
+
--hosts <ids> Comma-separated local hosts for post-release update (default: all declared)
|
|
368
|
+
--confirm-plan <digest> Confirm the exact VERIFIED plan before local host mutation
|
|
363
369
|
--no-hook-cache Force every prepare hook to run in full; neither read nor write the hook cache
|
|
364
370
|
--json Output results as JSON
|
|
365
371
|
--version Show version and exit
|
|
@@ -377,6 +383,7 @@ Safety:
|
|
|
377
383
|
- To ensure zero remote writes, disable hooks or audit them separately
|
|
378
384
|
- docs refresh --write rewrites only declared README managed regions and the current CHANGELOG entry after exact refreshDigest confirmation; it never commits, pushes, tags, publishes, or installs.
|
|
379
385
|
- publish requires explicit approval; plan digest is auto-read from the plan file
|
|
386
|
+
- post-release local host updates are optional local mutations and never change VERIFIED
|
|
380
387
|
- publish consumes frozen Git/npm artifacts, never the live workspace
|
|
381
388
|
- existing remote objects and uncertain checks stop for human intervention
|
|
382
389
|
- production-equivalent protocol sandbox is verified; a real remote canary is not
|
|
@@ -815,6 +822,19 @@ if (command === 'ship') {
|
|
|
815
822
|
console.log('then re-run: release-skill ship --root <root> --hook-approval <approval-record>');
|
|
816
823
|
}
|
|
817
824
|
}
|
|
825
|
+
if (result.status === 'VERIFIED' && result.postRelease) {
|
|
826
|
+
if (result.postRelease.status === 'UNAVAILABLE') {
|
|
827
|
+
console.warn(`Post-release checklist unavailable: ${result.postRelease.diagnostic?.message ?? 'unknown error'}`);
|
|
828
|
+
} else if (result.postRelease.merge.promptRequired) {
|
|
829
|
+
console.log('Post-release: ask whether to merge the remaining release branch.');
|
|
830
|
+
} else {
|
|
831
|
+
console.log('Post-release: branch advancement was already included; skip the merge question.');
|
|
832
|
+
}
|
|
833
|
+
if (result.postRelease.localHostUpdate?.promptRequired) {
|
|
834
|
+
console.log(`Post-release: ask whether to update local host plugins (${result.postRelease.localHostUpdate.hosts.join(', ')}).`);
|
|
835
|
+
console.log(`Post-release command: release-skill post-release --plan ${result.planPath} --run ${result.verifyRunPath}`);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
818
838
|
for (const followUp of result.manualFollowUps ?? []) {
|
|
819
839
|
console.log(`Manual follow-up [${followUp.platform}] ${followUp.plugin}: not verified by system`);
|
|
820
840
|
}
|
|
@@ -1178,6 +1198,91 @@ if (command === 'reconcile') {
|
|
|
1178
1198
|
}
|
|
1179
1199
|
}
|
|
1180
1200
|
|
|
1201
|
+
// --- Optional local finishing after VERIFIED ---
|
|
1202
|
+
if (command === 'post-release') {
|
|
1203
|
+
const value = (flag) => {
|
|
1204
|
+
const idx = args.indexOf(flag);
|
|
1205
|
+
return idx !== -1 && args[idx + 1] ? args[idx + 1] : undefined;
|
|
1206
|
+
};
|
|
1207
|
+
const planPath = value('--plan') ? resolve(value('--plan')) : undefined;
|
|
1208
|
+
const runPath = value('--run') ? resolve(value('--run')) : undefined;
|
|
1209
|
+
if (!planPath || !runPath) {
|
|
1210
|
+
const message = 'post-release requires --plan <path> and --run <verified-run-path>';
|
|
1211
|
+
if (hasJson) console.log(JSON.stringify({ error: 'MISSING_PARAMETERS', message, exitCode: 1 }));
|
|
1212
|
+
else console.error(`Error: ${message}`);
|
|
1213
|
+
await exitAfterFlush(1);
|
|
1214
|
+
}
|
|
1215
|
+
try {
|
|
1216
|
+
const {
|
|
1217
|
+
assertVerifiedReleaseRun,
|
|
1218
|
+
derivePostReleaseChecklist,
|
|
1219
|
+
updateLocalHostPlugins,
|
|
1220
|
+
} = await import('../src/commands/post-release-local.mjs');
|
|
1221
|
+
const { validatePlan } = await import('../src/core/plan.mjs');
|
|
1222
|
+
const {
|
|
1223
|
+
loadRun,
|
|
1224
|
+
resolveRunPath,
|
|
1225
|
+
validateRunLineage,
|
|
1226
|
+
} = await import('../src/core/run.mjs');
|
|
1227
|
+
const plan = JSON.parse(await readFile(planPath, 'utf8'));
|
|
1228
|
+
validatePlan(plan);
|
|
1229
|
+
const resolvedRunPath = await resolveRunPath(runPath);
|
|
1230
|
+
const runRecord = await loadRun(resolvedRunPath, {
|
|
1231
|
+
requireDigest: true,
|
|
1232
|
+
authorityPlanPath: planPath,
|
|
1233
|
+
});
|
|
1234
|
+
await validateRunLineage(runRecord, {
|
|
1235
|
+
plan,
|
|
1236
|
+
planPath,
|
|
1237
|
+
runPath: resolvedRunPath,
|
|
1238
|
+
production: Boolean(plan.production),
|
|
1239
|
+
});
|
|
1240
|
+
assertVerifiedReleaseRun(plan, runRecord);
|
|
1241
|
+
|
|
1242
|
+
const updateRequested = args.includes('--update-local-hosts');
|
|
1243
|
+
const selectedHosts = value('--hosts')
|
|
1244
|
+
?.split(',')
|
|
1245
|
+
.map((host) => host.trim())
|
|
1246
|
+
.filter(Boolean);
|
|
1247
|
+
const result = updateRequested
|
|
1248
|
+
? await updateLocalHostPlugins({
|
|
1249
|
+
plan,
|
|
1250
|
+
root: resolve(value('--root') ?? process.cwd()),
|
|
1251
|
+
confirmPlanDigest: value('--confirm-plan'),
|
|
1252
|
+
selectedHosts,
|
|
1253
|
+
})
|
|
1254
|
+
: derivePostReleaseChecklist(plan);
|
|
1255
|
+
|
|
1256
|
+
if (hasJson) {
|
|
1257
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1258
|
+
} else if (!updateRequested) {
|
|
1259
|
+
console.log(`Post-release status: ${result.status}`);
|
|
1260
|
+
if (result.merge.promptRequired) console.log('Ask whether the user wants to merge the remaining branch.');
|
|
1261
|
+
else console.log('Branch advancement was already included in the release workflow; skip the merge question.');
|
|
1262
|
+
if (result.localHostUpdate.promptRequired) {
|
|
1263
|
+
console.log(`Ask whether to update local host plugins: ${result.localHostUpdate.hosts.join(', ')}`);
|
|
1264
|
+
}
|
|
1265
|
+
} else {
|
|
1266
|
+
console.log(`Local host update: ${result.status}`);
|
|
1267
|
+
for (const entry of result.results) {
|
|
1268
|
+
console.log(` ${entry.host}/${entry.unitId}: ${entry.status}${entry.version ? ` (${entry.version})` : ''}`);
|
|
1269
|
+
}
|
|
1270
|
+
console.log('The release remains VERIFIED; restart updated hosts before using the new plugin bytes.');
|
|
1271
|
+
}
|
|
1272
|
+
const success = !updateRequested || ['UPDATED', 'ALREADY_CURRENT', 'NO_APPLICABLE_HOSTS'].includes(result.status);
|
|
1273
|
+
await exitAfterFlush(success ? 0 : 1);
|
|
1274
|
+
} catch (err) {
|
|
1275
|
+
if (hasJson) {
|
|
1276
|
+
console.log(JSON.stringify({
|
|
1277
|
+
error: err.code ?? 'POST_RELEASE_FAILED',
|
|
1278
|
+
message: err.message,
|
|
1279
|
+
exitCode: err.exitCode ?? 1,
|
|
1280
|
+
}));
|
|
1281
|
+
} else console.error(`Error: ${err.message}`);
|
|
1282
|
+
await exitAfterFlush(err.exitCode ?? 1);
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1181
1286
|
// --- Verify command routing ---
|
|
1182
1287
|
if (command === 'verify') {
|
|
1183
1288
|
|
|
@@ -1221,6 +1326,18 @@ if (command === 'verify') {
|
|
|
1221
1326
|
root,
|
|
1222
1327
|
verificationGatesAuthorized,
|
|
1223
1328
|
});
|
|
1329
|
+
if (result.status === 'VERIFIED') {
|
|
1330
|
+
const {
|
|
1331
|
+
derivePostReleaseChecklist,
|
|
1332
|
+
unavailablePostReleaseChecklist,
|
|
1333
|
+
} = await import('../src/commands/post-release-local.mjs');
|
|
1334
|
+
const plan = JSON.parse(await readFile(planPath, 'utf8'));
|
|
1335
|
+
try {
|
|
1336
|
+
result.postRelease = derivePostReleaseChecklist(plan);
|
|
1337
|
+
} catch (error) {
|
|
1338
|
+
result.postRelease = unavailablePostReleaseChecklist(plan, error);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1224
1341
|
|
|
1225
1342
|
if (hasJson) {
|
|
1226
1343
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -1237,6 +1354,14 @@ if (command === 'verify') {
|
|
|
1237
1354
|
console.log(`Baseline advance: ${result.baselineAdvance.committed ? 'advanced and committed' : 'advanced (uncommitted — commit .release-skill/project.yaml manually)'}`);
|
|
1238
1355
|
}
|
|
1239
1356
|
}
|
|
1357
|
+
if (result.postRelease?.status === 'UNAVAILABLE') {
|
|
1358
|
+
console.warn(`Post-release checklist unavailable: ${result.postRelease.diagnostic?.message ?? 'unknown error'}`);
|
|
1359
|
+
} else if (result.postRelease?.merge.promptRequired) {
|
|
1360
|
+
console.log('Post-release: ask whether to merge the remaining branch.');
|
|
1361
|
+
}
|
|
1362
|
+
if (result.postRelease?.localHostUpdate.promptRequired) {
|
|
1363
|
+
console.log(`Post-release: ask whether to update local host plugins (${result.postRelease.localHostUpdate.hosts.join(', ')}).`);
|
|
1364
|
+
}
|
|
1240
1365
|
}
|
|
1241
1366
|
|
|
1242
1367
|
await exitAfterFlush(result.status === 'VERIFIED' ? 0 : 1);
|