@fitlab-ai/agent-infra 0.9.14 → 0.10.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 (354) hide show
  1. package/README.md +10 -0
  2. package/README.zh-CN.md +10 -0
  3. package/bin/internal-cli.sh +45 -0
  4. package/dist/bin/internal-cli.js +93 -30
  5. package/dist/lib/agent-clients/adapters/codex-lifecycle/capability-store.js +165 -27
  6. package/dist/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.js +9 -4
  7. package/dist/lib/agent-clients/adapters/codex-lifecycle/store.js +43 -3
  8. package/dist/lib/defaults.json +103 -103
  9. package/dist/lib/fs/durable-write.js +39 -0
  10. package/dist/lib/fs/file-lock.js +111 -0
  11. package/dist/lib/host-control/audit.js +19 -0
  12. package/dist/lib/host-control/client.js +142 -0
  13. package/dist/lib/host-control/command.js +49 -0
  14. package/dist/lib/host-control/path.js +160 -0
  15. package/dist/lib/host-control/secure-fs.js +140 -0
  16. package/dist/lib/host-control/server.js +159 -0
  17. package/dist/lib/host-control/service.js +112 -0
  18. package/dist/lib/init.js +11 -2
  19. package/dist/lib/internal/cli-route-inventory.js +4 -2
  20. package/dist/lib/internal/codex-lifecycle.js +6 -6
  21. package/dist/lib/internal/demo-promotion.js +322 -0
  22. package/dist/lib/internal/demo-transcript.js +454 -0
  23. package/dist/lib/internal/host-control.js +28 -0
  24. package/dist/lib/internal/manual-validation.js +331 -0
  25. package/dist/lib/internal/platform-pr.js +18 -4
  26. package/dist/lib/internal/release-workflow.js +63 -84
  27. package/dist/lib/internal/sandbox-control.js +149 -2
  28. package/dist/lib/internal/task-artifact.js +16 -263
  29. package/dist/lib/internal/task-create.js +6 -5
  30. package/dist/lib/internal/task-event.js +37 -37
  31. package/dist/lib/internal/task-lifecycle.js +2 -2
  32. package/dist/lib/internal/task-operation-registry.js +101 -4
  33. package/dist/lib/internal/task-review.js +11 -56
  34. package/dist/lib/internal/task-validate.js +30 -10
  35. package/dist/lib/owned-path.js +33 -0
  36. package/dist/lib/platform/check-status.js +11 -0
  37. package/dist/lib/platform/comment-safety.js +4 -1
  38. package/dist/lib/platform/completion-backfill.js +1 -1
  39. package/dist/lib/platform/github-data.js +241 -0
  40. package/dist/lib/platform/github-provider.js +15 -20
  41. package/dist/lib/platform/issue-comments.js +18 -12
  42. package/dist/lib/platform/issues.js +2 -180
  43. package/dist/lib/platform/pr-change-report.js +5 -4
  44. package/dist/lib/platform/pr-checks.js +12 -65
  45. package/dist/lib/platform/pr-summary.js +117 -33
  46. package/dist/lib/platform/pull-requests.js +5 -108
  47. package/dist/lib/platform/snapshots.js +2 -0
  48. package/dist/lib/platform/task-identities.js +2 -9
  49. package/dist/lib/platform/verification-sync.js +132 -143
  50. package/dist/lib/pr-review/evidence-grading.js +4 -8
  51. package/dist/lib/release/workflow.js +1 -1
  52. package/dist/lib/sandbox/commands/create.js +7 -2
  53. package/dist/lib/sandbox/commands/rm.js +19 -1511
  54. package/dist/lib/sandbox/control/audit.js +203 -0
  55. package/dist/lib/sandbox/control/client.js +93 -54
  56. package/dist/lib/sandbox/control/executor.js +129 -65
  57. package/dist/lib/sandbox/control/finalization-response.js +27 -0
  58. package/dist/lib/sandbox/control/identity-sentinel.js +107 -0
  59. package/dist/lib/sandbox/control/lifecycle.js +36 -2
  60. package/dist/lib/sandbox/control/native-file-lock.js +6 -98
  61. package/dist/lib/sandbox/control/protocol.js +55 -4
  62. package/dist/lib/sandbox/control/server.js +518 -127
  63. package/dist/lib/sandbox/control/state.js +64 -0
  64. package/dist/lib/sandbox/control/task-workflow.js +74 -0
  65. package/dist/lib/sandbox/control/workflow-executor.js +89 -0
  66. package/dist/lib/sandbox/index.js +1 -2
  67. package/dist/lib/sandbox/recovery.js +28 -4
  68. package/dist/lib/sandbox/removal.js +822 -0
  69. package/dist/lib/sandbox/task-cleanup.js +217 -0
  70. package/dist/lib/sandbox/workspace-identity.js +17 -1
  71. package/dist/lib/sandbox/workspace-view.js +13 -14
  72. package/dist/lib/task/activity-intent.js +2 -1
  73. package/dist/lib/task/activity-log.js +30 -24
  74. package/dist/lib/task/artifact-command.js +79 -0
  75. package/dist/lib/task/artifact-lifecycle.js +30 -28
  76. package/dist/lib/task/artifact-name.js +36 -0
  77. package/dist/lib/task/artifact-operations.js +29 -289
  78. package/dist/lib/task/artifact-receipts.js +3 -15
  79. package/dist/lib/task/artifact-recovery.js +430 -0
  80. package/dist/lib/task/artifact-repair-intent.js +134 -29
  81. package/dist/lib/task/artifact-schema.js +6 -14
  82. package/dist/lib/task/capabilities.js +12 -19
  83. package/dist/lib/task/codex-orchestration.js +71 -25
  84. package/dist/lib/task/commit-identity.js +28 -0
  85. package/dist/lib/task/commit-operation.js +33 -20
  86. package/dist/lib/task/control-authority.js +403 -6
  87. package/dist/lib/task/control-recovery.js +140 -0
  88. package/dist/lib/task/create-service.js +1 -8
  89. package/dist/lib/task/create.js +62 -9
  90. package/dist/lib/task/decision-details.js +2 -46
  91. package/dist/lib/task/delegation-receipts.js +64 -3
  92. package/dist/lib/task/events.js +275 -22
  93. package/dist/lib/task/finalization-state.js +9 -0
  94. package/dist/lib/task/human-override.js +8 -14
  95. package/dist/lib/task/implementation-inputs.js +3 -3
  96. package/dist/lib/task/intermediate-cleanup.js +441 -0
  97. package/dist/lib/task/invalidation.js +18 -65
  98. package/dist/lib/task/ledger-intents.js +7 -22
  99. package/dist/lib/task/ledger.js +1 -3
  100. package/dist/lib/task/lifecycle-recovery.js +549 -0
  101. package/dist/lib/task/lifecycle.js +31 -4
  102. package/dist/lib/task/local-artifact-finalization.js +197 -197
  103. package/dist/lib/task/manual-validation-completion.js +26 -0
  104. package/dist/lib/task/manual-validation-evidence.js +130 -0
  105. package/dist/lib/task/manual-validation-receipt.js +105 -0
  106. package/dist/lib/task/manual-validation-shared.js +40 -0
  107. package/dist/lib/task/manual-validation-transaction.js +243 -0
  108. package/dist/lib/task/markdown.js +47 -0
  109. package/dist/lib/task/orchestration.js +66 -19
  110. package/dist/lib/task/pr-delivery-fact.js +12 -56
  111. package/dist/lib/task/qualification-audit.js +20 -34
  112. package/dist/lib/task/recovery-warning.js +19 -0
  113. package/dist/lib/task/review-artifacts.js +2 -18
  114. package/dist/lib/task/review-command.js +26 -0
  115. package/dist/lib/task/review-finalization.js +175 -216
  116. package/dist/lib/task/review-fingerprint.js +2 -2
  117. package/dist/lib/task/sections.js +34 -56
  118. package/dist/lib/task/short-id.js +15 -7
  119. package/dist/lib/task/task-execution-lock.js +1 -1
  120. package/dist/lib/task/verification-engine.js +119 -337
  121. package/dist/lib/task/verification.js +1 -1
  122. package/dist/lib/task/workflow-command.js +16 -0
  123. package/dist/lib/task/workflow-warning-intents.js +0 -16
  124. package/dist/lib/task/workflow-warnings.js +28 -2
  125. package/dist/lib/update.js +2 -0
  126. package/dist/lib/version.js +1 -11
  127. package/dist/lifecycle-build-manifest.json +3 -3
  128. package/lib/agent-clients/adapters/codex-lifecycle/capability-store.ts +223 -33
  129. package/lib/agent-clients/adapters/codex-lifecycle/sandbox-controller.ts +10 -4
  130. package/lib/agent-clients/adapters/codex-lifecycle/store.ts +55 -3
  131. package/lib/fs/durable-write.ts +30 -0
  132. package/lib/fs/file-lock.ts +113 -0
  133. package/lib/host-control/audit.ts +22 -0
  134. package/lib/host-control/client.ts +172 -0
  135. package/lib/host-control/command.ts +60 -0
  136. package/lib/host-control/path.ts +167 -0
  137. package/lib/host-control/secure-fs.ts +135 -0
  138. package/lib/host-control/server.ts +180 -0
  139. package/lib/host-control/service.ts +133 -0
  140. package/lib/init.ts +15 -2
  141. package/lib/internal/cli-route-inventory.ts +4 -2
  142. package/lib/internal/codex-lifecycle.ts +6 -6
  143. package/lib/internal/demo-promotion.ts +354 -0
  144. package/lib/internal/demo-transcript.ts +419 -0
  145. package/lib/internal/host-control.ts +28 -0
  146. package/lib/internal/manual-validation.ts +315 -0
  147. package/lib/internal/platform-pr.ts +15 -4
  148. package/lib/internal/release-workflow.ts +74 -82
  149. package/lib/internal/sandbox-control.ts +162 -1
  150. package/lib/internal/task-artifact.ts +14 -217
  151. package/lib/internal/task-create.ts +5 -5
  152. package/lib/internal/task-event.ts +20 -11
  153. package/lib/internal/task-lifecycle.ts +4 -3
  154. package/lib/internal/task-operation-registry.ts +111 -4
  155. package/lib/internal/task-review.ts +9 -54
  156. package/lib/internal/task-validate.ts +26 -10
  157. package/lib/owned-path.ts +26 -0
  158. package/lib/platform/check-status.ts +9 -0
  159. package/lib/platform/comment-safety.ts +5 -0
  160. package/lib/platform/completion-backfill.ts +1 -1
  161. package/lib/platform/github-data.ts +322 -0
  162. package/lib/platform/github-provider.ts +15 -20
  163. package/lib/platform/issue-comments.ts +21 -14
  164. package/lib/platform/issues.ts +5 -246
  165. package/lib/platform/pr-change-report.ts +7 -5
  166. package/lib/platform/pr-checks.ts +13 -77
  167. package/lib/platform/pr-summary.ts +123 -35
  168. package/lib/platform/pull-requests.ts +6 -173
  169. package/lib/platform/snapshots.ts +53 -0
  170. package/lib/platform/task-identities.ts +3 -14
  171. package/lib/platform/verification-sync.ts +150 -156
  172. package/lib/pr-review/evidence-grading.ts +4 -9
  173. package/lib/release/workflow.ts +3 -3
  174. package/lib/sandbox/commands/create.ts +7 -6
  175. package/lib/sandbox/commands/rm.ts +21 -1895
  176. package/lib/sandbox/control/audit.ts +253 -0
  177. package/lib/sandbox/control/client.ts +109 -66
  178. package/lib/sandbox/control/executor.ts +134 -74
  179. package/lib/sandbox/control/finalization-response.ts +29 -0
  180. package/lib/sandbox/control/identity-sentinel.ts +137 -0
  181. package/lib/sandbox/control/lifecycle.ts +45 -3
  182. package/lib/sandbox/control/native-file-lock.ts +6 -107
  183. package/lib/sandbox/control/protocol.ts +80 -6
  184. package/lib/sandbox/control/server.ts +567 -132
  185. package/lib/sandbox/control/state.ts +86 -0
  186. package/lib/sandbox/control/task-workflow.ts +95 -0
  187. package/lib/sandbox/control/workflow-executor.ts +92 -0
  188. package/lib/sandbox/index.ts +1 -2
  189. package/lib/sandbox/recovery.ts +28 -5
  190. package/lib/sandbox/removal.ts +1142 -0
  191. package/lib/sandbox/task-cleanup.ts +209 -0
  192. package/lib/sandbox/workspace-identity.ts +19 -3
  193. package/lib/sandbox/workspace-view.ts +17 -15
  194. package/lib/task/activity-intent.ts +2 -2
  195. package/lib/task/activity-log.ts +27 -19
  196. package/lib/task/artifact-command.ts +85 -0
  197. package/lib/task/artifact-lifecycle.ts +31 -26
  198. package/lib/task/artifact-name.ts +55 -0
  199. package/lib/task/artifact-operations.ts +34 -310
  200. package/lib/task/artifact-receipts.ts +3 -14
  201. package/lib/task/artifact-recovery.ts +519 -0
  202. package/lib/task/artifact-repair-intent.ts +162 -33
  203. package/lib/task/artifact-schema.ts +5 -34
  204. package/lib/task/capabilities.ts +13 -22
  205. package/lib/task/codex-orchestration.ts +85 -24
  206. package/lib/task/commit-identity.ts +31 -0
  207. package/lib/task/commit-operation.ts +37 -20
  208. package/lib/task/control-authority.ts +540 -10
  209. package/lib/task/control-recovery.ts +186 -0
  210. package/lib/task/create-service.ts +1 -10
  211. package/lib/task/create.ts +63 -8
  212. package/lib/task/decision-details.ts +3 -71
  213. package/lib/task/delegation-receipts.ts +73 -2
  214. package/lib/task/events.ts +309 -24
  215. package/lib/task/finalization-state.ts +11 -0
  216. package/lib/task/human-override.ts +8 -16
  217. package/lib/task/implementation-inputs.ts +3 -3
  218. package/lib/task/intermediate-cleanup.ts +493 -0
  219. package/lib/task/invalidation.ts +18 -62
  220. package/lib/task/ledger-intents.ts +7 -24
  221. package/lib/task/ledger.ts +1 -3
  222. package/lib/task/lifecycle-recovery.ts +691 -0
  223. package/lib/task/lifecycle.ts +30 -5
  224. package/lib/task/local-artifact-finalization.ts +244 -234
  225. package/lib/task/manual-validation-completion.ts +40 -0
  226. package/lib/task/manual-validation-evidence.ts +209 -0
  227. package/lib/task/manual-validation-receipt.ts +156 -0
  228. package/lib/task/manual-validation-shared.ts +50 -0
  229. package/lib/task/manual-validation-transaction.ts +304 -0
  230. package/lib/task/markdown.ts +70 -0
  231. package/lib/task/orchestration.ts +84 -19
  232. package/lib/task/pr-delivery-fact.ts +15 -62
  233. package/lib/task/qualification-audit.ts +22 -33
  234. package/lib/task/recovery-warning.ts +21 -0
  235. package/lib/task/review-artifacts.ts +1 -20
  236. package/lib/task/review-command.ts +24 -0
  237. package/lib/task/review-finalization.ts +183 -292
  238. package/lib/task/review-fingerprint.ts +2 -2
  239. package/lib/task/sections.ts +33 -54
  240. package/lib/task/short-id.ts +27 -5
  241. package/lib/task/task-execution-lock.ts +1 -1
  242. package/lib/task/verification-engine.ts +113 -383
  243. package/lib/task/verification-types.ts +15 -0
  244. package/lib/task/verification.ts +1 -1
  245. package/lib/task/workflow-command.ts +17 -0
  246. package/lib/task/workflow-warning-intents.ts +0 -13
  247. package/lib/task/workflow-warnings.ts +21 -2
  248. package/lib/update.ts +6 -0
  249. package/lib/version.ts +1 -15
  250. package/package.json +6 -6
  251. package/templates/.agents/hooks/lifecycle-delegation.js +6 -6
  252. package/templates/.agents/rules/create-issue.en.md +1 -1
  253. package/templates/.agents/rules/create-issue.zh-CN.md +1 -1
  254. package/templates/.agents/rules/issue-sync.en.md +4 -2
  255. package/templates/.agents/rules/issue-sync.zh-CN.md +4 -3
  256. package/templates/.agents/rules/local-artifact-repair.en.md +46 -39
  257. package/templates/.agents/rules/local-artifact-repair.zh-CN.md +43 -36
  258. package/templates/.agents/rules/testing-discipline.en.md +2 -0
  259. package/templates/.agents/rules/testing-discipline.zh-CN.md +2 -0
  260. package/templates/.agents/scripts/package.json +3 -0
  261. package/templates/.agents/skills/analyze-task/SKILL.en.md +6 -6
  262. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +6 -6
  263. package/templates/.agents/skills/analyze-task/config/verify.en.json +1 -1
  264. package/templates/.agents/skills/analyze-task/config/verify.zh-CN.json +1 -1
  265. package/templates/.agents/skills/block-task/SKILL.en.md +2 -2
  266. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +2 -2
  267. package/templates/.agents/skills/block-task/config/verify.json +1 -1
  268. package/templates/.agents/skills/cancel-task/SKILL.en.md +3 -3
  269. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +3 -3
  270. package/templates/.agents/skills/cancel-task/config/verify.json +1 -1
  271. package/templates/.agents/skills/code-task/SKILL.en.md +7 -7
  272. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +7 -7
  273. package/templates/.agents/skills/code-task/config/verify.en.json +1 -1
  274. package/templates/.agents/skills/code-task/config/verify.zh-CN.json +1 -1
  275. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  276. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  277. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +33 -21
  278. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +33 -21
  279. package/templates/.agents/skills/complete-manual-validation/config/verify.en.json +1 -1
  280. package/templates/.agents/skills/complete-manual-validation/config/verify.zh-CN.json +1 -1
  281. package/templates/.agents/skills/complete-manual-validation/reference/report-template.en.md +2 -0
  282. package/templates/.agents/skills/complete-manual-validation/reference/report-template.zh-CN.md +2 -0
  283. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +16 -7
  284. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +16 -7
  285. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  286. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  287. package/templates/.agents/skills/complete-task/config/verify.en.json +2 -2
  288. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +2 -2
  289. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +1 -1
  290. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +1 -1
  291. package/templates/.agents/skills/create-pr/SKILL.en.md +2 -2
  292. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +2 -2
  293. package/templates/.agents/skills/create-pr/config/verify.json +1 -1
  294. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +2 -2
  295. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +2 -2
  296. package/templates/.agents/skills/create-task/SKILL.en.md +5 -5
  297. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -5
  298. package/templates/.agents/skills/create-task/config/verify.json +1 -1
  299. package/templates/.agents/skills/import-issue/SKILL.en.md +8 -8
  300. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +8 -8
  301. package/templates/.agents/skills/import-issue/config/verify.json +2 -2
  302. package/templates/.agents/skills/plan-task/SKILL.en.md +4 -4
  303. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +4 -4
  304. package/templates/.agents/skills/plan-task/config/verify.en.json +1 -1
  305. package/templates/.agents/skills/plan-task/config/verify.zh-CN.json +1 -1
  306. package/templates/.agents/skills/release/SKILL.en.md +7 -3
  307. package/templates/.agents/skills/release/SKILL.zh-CN.md +7 -3
  308. package/templates/.agents/skills/restore-task/SKILL.en.md +2 -2
  309. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +2 -2
  310. package/templates/.agents/skills/restore-task/config/verify.json +1 -1
  311. package/templates/.agents/skills/review-analysis/SKILL.en.md +2 -2
  312. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +2 -2
  313. package/templates/.agents/skills/review-analysis/config/verify.en.json +1 -1
  314. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +1 -1
  315. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +7 -7
  316. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +6 -6
  317. package/templates/.agents/skills/review-code/SKILL.en.md +2 -2
  318. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +2 -2
  319. package/templates/.agents/skills/review-code/config/verify.en.json +1 -1
  320. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +1 -1
  321. package/templates/.agents/skills/review-code/reference/report-template.en.md +12 -12
  322. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +12 -12
  323. package/templates/.agents/skills/review-plan/SKILL.en.md +2 -2
  324. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +2 -2
  325. package/templates/.agents/skills/review-plan/config/verify.en.json +1 -1
  326. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +1 -1
  327. package/templates/.agents/skills/review-plan/reference/report-template.en.md +7 -7
  328. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +7 -7
  329. package/templates/.agents/skills/review-pr/config/verify.en.json +1 -1
  330. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +1 -1
  331. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +3 -3
  332. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +3 -3
  333. package/templates/.agents/skills/run-manual-validation/SKILL.en.md +20 -3
  334. package/templates/.agents/skills/run-manual-validation/SKILL.zh-CN.md +20 -3
  335. package/templates/.agents/skills/run-manual-validation/config/verify.en.json +1 -1
  336. package/templates/.agents/skills/run-manual-validation/config/verify.zh-CN.json +1 -1
  337. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.en.md +4 -1
  338. package/templates/.agents/skills/run-manual-validation/reference/discovery-and-execution.zh-CN.md +4 -1
  339. package/templates/.agents/skills/run-manual-validation/reference/report-template.en.md +2 -0
  340. package/templates/.agents/skills/run-manual-validation/reference/report-template.zh-CN.md +2 -0
  341. package/templates/.agents/skills/run-task/SKILL.en.md +1 -1
  342. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +1 -1
  343. package/templates/.agents/skills/test/SKILL.en.md +17 -6
  344. package/templates/.agents/skills/test/SKILL.zh-CN.md +17 -6
  345. package/templates/.agents/templates/task.en.md +1 -1
  346. package/templates/.agents/templates/task.zh-CN.md +1 -1
  347. package/templates/.claude/commands/import-issue.en.md +1 -1
  348. package/templates/.claude/commands/import-issue.zh-CN.md +1 -1
  349. package/templates/.claude/commands/restore-task.en.md +1 -1
  350. package/templates/.claude/commands/restore-task.zh-CN.md +1 -1
  351. package/templates/.claude/commands/run-manual-validation.en.md +1 -1
  352. package/templates/.claude/commands/run-manual-validation.zh-CN.md +1 -1
  353. package/dist/lib/platform/adapters.js +0 -56
  354. package/lib/platform/adapters.ts +0 -197
@@ -1,30 +1,56 @@
1
1
  import fs from 'node:fs';
2
- import { inspectDecisionDetailDuplicates, scanVisibleMarkdown } from './decision-details.js';
3
- import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
2
+ import { inspectDecisionDetailDuplicates } from './decision-details.js';
3
+ import { scanVisibleMarkdown } from './markdown.js';
4
+ import { parseArtifactName } from './artifact-name.js';
5
+ import { hasOpenArtifactRound, parseCodePlanInputReference, validateArtifactPublication, validateCompletedArtifact } from './artifact-lifecycle.js';
4
6
  import { resolveTaskRef } from './resolve-ref.js';
5
7
  import { expectedQualificationRelations, validateQualificationAudit } from './qualification-audit.js';
6
8
  import { canonicalSemanticDigest, inspectArtifactPatterns, inspectArtifactStructure, sha256Content } from './artifact-operations.js';
7
9
  import { getArtifactSchema } from './artifact-schema.js';
8
- import { readArtifactRepairIntent, writeArtifactRepairIntent } from './artifact-repair-intent.js';
10
+ import { readArtifactRecoveryIntent } from './artifact-repair-intent.js';
11
+ import { beginArtifactRecovery, commitArtifactRecovery, consumeArtifactRecovery, prepareArtifactRecoveryCommit, recordArtifactRecoveryPassed, recoveryContextFromIntent, stageArtifactCandidate } from './artifact-recovery.js';
12
+ import { consumeLifecycleRecoveryAttestation, lifecycleRecoveryAttestationDigest, validateLifecycleRecoveryAttestation } from './control-authority.js';
9
13
  const LOCAL_ARTIFACT_REQUIRED_SECTIONS = {
10
14
  analysis: getArtifactSchema('analysis').sections.map((section) => section.headings.zh),
11
15
  plan: getArtifactSchema('plan').sections.map((section) => section.headings.zh),
12
16
  code: getArtifactSchema('code').sections.map((section) => section.headings.zh)
13
17
  };
14
- function readLocalArtifactFinalizationIntent(repoRoot, taskId, family, artifact) {
15
- return readArtifactRepairIntent(repoRoot, taskId, family, artifact);
18
+ function authorityDigest(authority) {
19
+ return lifecycleRecoveryAttestationDigest(authority);
16
20
  }
17
- function writeLocalArtifactFinalizationIntent(repoRoot, value) {
18
- writeArtifactRepairIntent(repoRoot, value);
21
+ function validFinalizerAuthority(authority, request, taskId) {
22
+ if (!authority)
23
+ return false;
24
+ try {
25
+ validateLifecycleRecoveryAttestation(authority);
26
+ }
27
+ catch {
28
+ return false;
29
+ }
30
+ return authority.version === 1
31
+ && authority.phase === 'artifact.finalize-local'
32
+ && authority.taskId === taskId
33
+ && authority.family === request.family
34
+ && authority.artifact === request.artifact
35
+ && authority.round === (parseArtifactName(request.artifact)?.round ?? 0)
36
+ && authority.requestId.length > 0
37
+ && authority.operationId.length > 0;
19
38
  }
20
- function consumeLocalArtifactFinalizationIntent(repoRoot, intent) {
39
+ function recoveryInfo(context) {
40
+ return {
41
+ recoveryId: context.recoveryId,
42
+ candidatePath: context.stagingPath,
43
+ baselineSha256: context.baselineSha256,
44
+ baselineSemanticDigest: context.baselineSemanticDigest
45
+ };
46
+ }
47
+ function consumeLocalArtifactFinalizationIntent(repoRoot, intent, options = {}) {
21
48
  if (intent.state === 'consumed')
22
49
  return intent;
23
- if (intent.state !== 'passed')
24
- throw new Error('LOCAL_FINALIZATION_INTENT_INVALID: only passed provenance can be consumed');
25
- const consumed = { ...intent, state: 'consumed' };
26
- writeLocalArtifactFinalizationIntent(repoRoot, consumed);
27
- return consumed;
50
+ const resolved = resolveTaskRef(intent.taskId, { repoRoot });
51
+ if (!resolved.ok)
52
+ throw new Error(resolved.message);
53
+ return consumeArtifactRecovery(recoveryContextFromIntent(repoRoot, resolved.taskDir, intent), options);
28
54
  }
29
55
  function localDiagnosticCode(code) {
30
56
  const map = {
@@ -36,78 +62,56 @@ function localDiagnosticCode(code) {
36
62
  return map[code] ?? 'LOCAL_STRUCTURAL_INVALID';
37
63
  }
38
64
  function localDiagnostic(item) {
39
- const code = localDiagnosticCode(item.code);
40
- if (!code)
41
- return null;
42
- return {
43
- code,
44
- message: item.message,
45
- repairable: item.repairable,
46
- line: item.line,
47
- ...(item.operation?.kind === 'replace-line'
48
- ? { from: item.operation.from, to: item.operation.to, operation: 'replace-line' }
49
- : {})
50
- };
65
+ return { code: localDiagnosticCode(item.code), message: item.message, line: item.line };
51
66
  }
52
67
  function isStatusPattern(pattern) {
53
68
  return pattern === '^\\$ ';
54
69
  }
55
70
  function validateLocalArtifact(content, options) {
56
71
  const schema = getArtifactSchema(options.family);
57
- const patterns = schema.requiredPatterns;
58
72
  const diagnostics = [];
59
73
  const scanned = scanVisibleMarkdown(content);
60
74
  const structure = inspectArtifactStructure(content, schema);
61
- for (const item of structure.diagnostics) {
62
- const mapped = localDiagnostic(item);
63
- if (mapped)
64
- diagnostics.push(mapped);
65
- }
75
+ for (const item of structure.diagnostics)
76
+ diagnostics.push(localDiagnostic(item));
66
77
  const statusSection = schema.sections.find((section) => section.id === 'state-check');
67
78
  if (statusSection) {
68
79
  const statusHeading = scanned.headings.find((heading) => (heading.level === 2 && [statusSection.headings.zh, statusSection.headings.en].some((name) => (heading.text === name || heading.text === `${name}:` || heading.text === `${name}:`))));
69
80
  if (statusHeading) {
70
81
  const next = scanned.headings.find((candidate) => candidate.start > statusHeading.start && candidate.level <= 2);
71
82
  const body = content.slice(statusHeading.end, next?.start ?? content.length);
72
- for (const pattern of patterns.filter(isStatusPattern)) {
83
+ for (const pattern of schema.requiredPatterns.filter(isStatusPattern)) {
73
84
  if (!new RegExp(pattern, 'm').test(body)) {
74
- diagnostics.push({ code: 'LOCAL_STATUS_COMMAND_MISSING', message: `status section '${statusHeading.text}' is missing required command output`, repairable: false, line: content.slice(0, statusHeading.start).split('\n').length });
85
+ diagnostics.push({ code: 'LOCAL_STATUS_COMMAND_MISSING', message: `status section '${statusHeading.text}' is missing required command output`, line: content.slice(0, statusHeading.start).split('\n').length });
75
86
  }
76
87
  }
77
88
  }
78
89
  }
79
90
  const patternInspection = inspectArtifactPatterns(content, {
80
91
  ...schema,
81
- requiredPatterns: patterns.filter((item) => !isStatusPattern(item))
92
+ requiredPatterns: schema.requiredPatterns.filter((item) => !isStatusPattern(item))
82
93
  });
83
- for (const item of patternInspection.diagnostics) {
84
- diagnostics.push({ code: 'LOCAL_REQUIRED_PATTERN_MISSING', message: item.message, repairable: false, line: null });
85
- }
94
+ for (const item of patternInspection.diagnostics)
95
+ diagnostics.push({ code: 'LOCAL_REQUIRED_PATTERN_MISSING', message: item.message, line: null });
86
96
  const decisionDetails = inspectDecisionDetailDuplicates(content);
87
- if (!decisionDetails.ok) {
88
- diagnostics.push({ code: 'LOCAL_DECISION_DETAIL_DUPLICATE', message: decisionDetails.message, repairable: false, line: null });
89
- }
97
+ if (!decisionDetails.ok)
98
+ diagnostics.push({ code: 'LOCAL_DECISION_DETAIL_DUPLICATE', message: decisionDetails.message, line: null });
90
99
  if (options.taskContent !== undefined) {
91
100
  const expected = expectedQualificationRelations(options.taskContent, options.family);
92
- if (!expected.ok) {
93
- diagnostics.push({ code: 'LOCAL_QUALIFICATION_AUDIT_INVALID', message: `${expected.code}: ${expected.message}`, repairable: false, line: null });
94
- }
101
+ if (!expected.ok)
102
+ diagnostics.push({ code: 'LOCAL_QUALIFICATION_AUDIT_INVALID', message: `${expected.code}: ${expected.message}`, line: null });
95
103
  const qualification = validateQualificationAudit(options.taskContent, content, {
96
- family: options.family === 'analysis' ? 'analysis' : options.family === 'plan' ? 'plan' : 'code',
104
+ family: options.family,
97
105
  artifact: options.artifact,
98
106
  expectedUpstreamRelations: expected.ok ? expected.relations : undefined
99
107
  });
100
- if (!qualification.ok) {
101
- diagnostics.push({ code: 'LOCAL_QUALIFICATION_AUDIT_INVALID', message: `${qualification.code}: ${qualification.message}`, repairable: false, line: null });
102
- }
108
+ if (!qualification.ok)
109
+ diagnostics.push({ code: 'LOCAL_QUALIFICATION_AUDIT_INVALID', message: `${qualification.code}: ${qualification.message}`, line: null });
103
110
  }
104
- const repairable = structure.repair !== null && diagnostics.length === 1 && diagnostics[0]?.repairable === true;
105
- const semanticDigestValue = canonicalSemanticDigest(content, structure.repair);
106
111
  return {
107
112
  ok: diagnostics.length === 0,
108
113
  family: options.family,
109
- semanticDigest: semanticDigestValue,
110
- repairable,
114
+ semanticDigest: canonicalSemanticDigest(content),
111
115
  diagnostics
112
116
  };
113
117
  }
@@ -117,183 +121,179 @@ function failedFinalization(request, error, extra = {}) {
117
121
  taskId: null, taskDir: null,
118
122
  family: request.family, artifact: request.artifact,
119
123
  artifactSha256: null, semanticDigest: null,
120
- repairable: false, diagnostics: [], error, ...extra
124
+ diagnostics: [], error, ...extra
121
125
  };
122
126
  }
123
- function provenanceFailure(request, resolved, content, artifactSha256, semanticDigestValue, code, message) {
124
- return failedFinalization(request, { code, message }, {
125
- taskId: resolved.taskId,
126
- taskDir: resolved.taskDir,
127
- artifactSha256,
128
- semanticDigest: semanticDigestValue,
129
- diagnostics: [{ code, message, repairable: false, line: null }]
130
- });
127
+ function tupleFor(request, taskId, authority) {
128
+ const round = parseArtifactName(request.artifact)?.round ?? 0;
129
+ return {
130
+ taskId,
131
+ family: request.family,
132
+ artifact: request.artifact,
133
+ round,
134
+ requestId: authority?.lifecycleRequestId ?? `local-finalize:${taskId}:${request.family}:${round}`,
135
+ phase: authority?.phase ?? 'artifact.finalize-local',
136
+ authorityDigest: authority ? authorityDigest(authority) : null
137
+ };
131
138
  }
132
- function finalizeLocalArtifact(request) {
139
+ function prepareLocalArtifact(request, candidate, authority) {
140
+ const failed = (code, message, extra = {}) => ({
141
+ result: failedFinalization(request, { code, message }, extra), content: candidate ?? ''
142
+ });
133
143
  const resolved = resolveTaskRef(request.taskRef, { repoRoot: request.repoRoot });
134
144
  if (!resolved.ok)
135
- return failedFinalization(request, { code: resolved.code, message: resolved.message });
145
+ return failed(resolved.code, resolved.message);
136
146
  const parsed = parseArtifactName(request.artifact);
137
- if (!parsed || parsed.family !== request.family) {
138
- return failedFinalization(request, {
139
- code: 'ARTIFACT_IDENTITY_INVALID',
140
- message: `artifact '${request.artifact}' does not match ${request.family}`
141
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir });
142
- }
143
- const validated = validateCompletedArtifact(resolved.taskDir, request.family, request.artifact, parsed.round);
144
- if (!validated.ok) {
145
- return failedFinalization(request, validated.error, { taskId: resolved.taskId, taskDir: resolved.taskDir });
146
- }
147
- let content;
148
- try {
149
- content = fs.readFileSync(validated.artifact.path, 'utf8');
150
- }
151
- catch (error) {
152
- return failedFinalization(request, { code: 'ARTIFACT_NOT_READABLE', message: String(error) }, {
153
- taskId: resolved.taskId, taskDir: resolved.taskDir
154
- });
147
+ if (!parsed || parsed.family !== request.family)
148
+ return failed('ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${request.family}`);
149
+ if (authority && !validFinalizerAuthority(authority, request, resolved.taskId)) {
150
+ return failed('LOCAL_EXECUTION_AUTHORITY_INVALID', 'finalizer authority does not match the artifact tuple');
155
151
  }
156
152
  let taskContent;
153
+ let content;
154
+ let recovery;
157
155
  try {
158
156
  taskContent = fs.readFileSync(resolved.taskMdPath, 'utf8');
157
+ if (request.recoveryId) {
158
+ const intent = readArtifactRecoveryIntent(resolved.repoRoot, resolved.taskId, request.family, request.artifact);
159
+ if (!intent || intent.recoveryOperationId !== request.recoveryId)
160
+ return failed('LOCAL_RECOVERY_PROVENANCE_CONFLICT', 'recovery id does not match the artifact journal');
161
+ if (!['awaiting-recovery', 'finalize-ready', 'commit-started'].includes(intent.state))
162
+ return failed('LOCAL_RECOVERY_PROVENANCE_CONFLICT', `recovery journal is in '${intent.state}' state`);
163
+ recovery = recoveryContextFromIntent(resolved.repoRoot, resolved.taskDir, intent);
164
+ content = fs.existsSync(recovery.stagingPath)
165
+ ? fs.readFileSync(recovery.stagingPath, 'utf8')
166
+ : fs.readFileSync(recovery.formalPath, 'utf8');
167
+ }
168
+ else {
169
+ const validated = validateCompletedArtifact(resolved.taskDir, request.family, request.artifact, parsed.round);
170
+ if (!validated.ok)
171
+ return failed(validated.error.code, validated.error.message);
172
+ content = candidate ?? fs.readFileSync(validated.artifact.path, 'utf8');
173
+ }
159
174
  }
160
175
  catch (error) {
161
- return failedFinalization(request, { code: 'TASK_READ_FAILED', message: error instanceof Error ? error.message : String(error) }, {
162
- taskId: resolved.taskId, taskDir: resolved.taskDir
163
- });
176
+ return failed('ARTIFACT_NOT_READABLE', String(error));
164
177
  }
165
- const result = validateLocalArtifact(content, {
166
- family: request.family,
167
- requiredSections: request.requiredSections,
168
- taskContent,
169
- artifact: request.artifact
178
+ if (resolved.state !== 'active' || !hasOpenArtifactRound(taskContent, request.family, parsed.round)) {
179
+ return failed('ARTIFACT_IDENTITY_INVALID', 'candidate must match one open started round in an active task');
180
+ }
181
+ const validation = validateLocalArtifact(content, {
182
+ family: request.family, requiredSections: request.requiredSections, taskContent, artifact: request.artifact
170
183
  });
171
184
  const artifactSha256 = sha256Content(content);
172
- let intent;
173
- try {
174
- intent = readLocalArtifactFinalizationIntent(resolved.repoRoot, resolved.taskId, request.family, request.artifact);
175
- }
176
- catch (error) {
177
- return failedFinalization(request, {
178
- code: 'LOCAL_FINALIZATION_INTENT_INVALID',
179
- message: error instanceof Error ? error.message : String(error)
180
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
185
+ const result = failedFinalization(request, {
186
+ code: 'LOCAL_ARTIFACT_INVALID',
187
+ message: validation.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
188
+ }, {
189
+ taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256,
190
+ semanticDigest: validation.semanticDigest, diagnostics: validation.diagnostics
191
+ });
192
+ if (request.recoveryId) {
193
+ if (!validation.ok)
194
+ return { result, content, repoRoot: resolved.repoRoot, recovery, authority, lockAlreadyHeld: request.lockAlreadyHeld };
195
+ return {
196
+ result: { ...result, status: 'passed', error: null, recovery: recoveryInfo(recovery) },
197
+ content, repoRoot: resolved.repoRoot, recovery, authority, lockAlreadyHeld: request.lockAlreadyHeld
198
+ };
181
199
  }
182
- if (result.repairable) {
183
- if (intent && (intent.state !== 'awaiting-repair' || intent.baselineSemanticDigest !== result.semanticDigest)) {
184
- return provenanceFailure(request, resolved, content, artifactSha256, result.semanticDigest, 'LOCAL_REPAIR_PROVENANCE_CONFLICT', 'a different local repair baseline is already recorded for this artifact');
185
- }
186
- if (!intent) {
187
- try {
188
- writeLocalArtifactFinalizationIntent(resolved.repoRoot, {
189
- version: 1,
190
- taskId: resolved.taskId,
191
- family: request.family,
192
- artifact: request.artifact,
193
- state: 'awaiting-repair',
194
- baselineSemanticDigest: result.semanticDigest,
195
- artifactSha256,
196
- semanticDigest: result.semanticDigest
197
- });
198
- }
199
- catch (error) {
200
- return failedFinalization(request, {
201
- code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED',
202
- message: error instanceof Error ? error.message : String(error)
203
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
204
- }
200
+ const existing = readArtifactRecoveryIntent(resolved.repoRoot, resolved.taskId, request.family, request.artifact);
201
+ if (existing?.state === 'passed' || existing?.state === 'consumed') {
202
+ if (existing.finalArtifactSha256 !== artifactSha256 || existing.finalSemanticDigest !== validation.semanticDigest) {
203
+ return { ...failed('LOCAL_RECOVERY_PROVENANCE_CONFLICT', 'formal artifact does not match its completed recovery journal'), content, repoRoot: resolved.repoRoot, authority, lockAlreadyHeld: request.lockAlreadyHeld };
205
204
  }
205
+ const context = recoveryContextFromIntent(resolved.repoRoot, resolved.taskDir, existing);
206
206
  return {
207
- status: 'failed',
208
- changed: false,
209
- taskId: resolved.taskId,
210
- taskDir: resolved.taskDir,
211
- family: request.family,
212
- artifact: request.artifact,
213
- artifactSha256,
214
- semanticDigest: result.semanticDigest,
215
- repairable: true,
216
- diagnostics: result.diagnostics,
217
- error: {
218
- code: 'LOCAL_ARTIFACT_INVALID',
219
- message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
220
- }
207
+ result: { ...result, status: 'passed', error: null, recovery: recoveryInfo(context) },
208
+ content, repoRoot: resolved.repoRoot, recovery: context, authority, lockAlreadyHeld: request.lockAlreadyHeld
221
209
  };
222
210
  }
223
- if (!result.ok) {
224
- return {
225
- status: 'failed',
226
- changed: false,
227
- taskId: resolved.taskId,
211
+ try {
212
+ if (validation.ok) {
213
+ const context = recordArtifactRecoveryPassed(tupleFor(request, resolved.taskId, authority), {
214
+ repoRoot: resolved.repoRoot,
215
+ taskDir: resolved.taskDir,
216
+ expectedFinalSha256: artifactSha256,
217
+ expectedFinalSemanticDigest: validation.semanticDigest,
218
+ ...(authority ? { recoveryId: authority.operationId } : {}),
219
+ lockAlreadyHeld: request.lockAlreadyHeld
220
+ });
221
+ recovery = context;
222
+ return { result: { ...result, status: 'passed', error: null, recovery: recoveryInfo(context) }, content, repoRoot: resolved.repoRoot, recovery, authority, lockAlreadyHeld: request.lockAlreadyHeld };
223
+ }
224
+ const context = beginArtifactRecovery(tupleFor(request, resolved.taskId, authority), Buffer.from(content, 'utf8'), {
225
+ repoRoot: resolved.repoRoot,
228
226
  taskDir: resolved.taskDir,
229
- family: request.family,
230
- artifact: request.artifact,
231
- artifactSha256,
232
- semanticDigest: result.semanticDigest,
233
- repairable: false,
234
- diagnostics: result.diagnostics,
235
- error: {
236
- code: 'LOCAL_ARTIFACT_INVALID',
237
- message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
238
- }
227
+ ...(authority ? { recoveryId: authority.operationId } : {}),
228
+ lockAlreadyHeld: request.lockAlreadyHeld
229
+ });
230
+ recovery = context;
231
+ return {
232
+ result: { ...result, recovery: recoveryInfo(context) },
233
+ content, repoRoot: resolved.repoRoot, recovery, authority, lockAlreadyHeld: request.lockAlreadyHeld
239
234
  };
240
235
  }
241
- if (intent?.state === 'awaiting-repair' && intent.baselineSemanticDigest !== result.semanticDigest) {
242
- return provenanceFailure(request, resolved, content, artifactSha256, result.semanticDigest, 'LOCAL_REPAIR_BASELINE_MISMATCH', 'the repaired artifact semantic digest does not match the recorded repair baseline');
243
- }
244
- if ((intent?.state === 'passed' || intent?.state === 'consumed')
245
- && (intent.artifactSha256 !== artifactSha256 || intent.semanticDigest !== result.semanticDigest)) {
246
- return provenanceFailure(request, resolved, content, artifactSha256, result.semanticDigest, 'LOCAL_REPAIR_PROVENANCE_CONFLICT', 'the artifact changed after its finalization provenance was recorded');
236
+ catch (error) {
237
+ return { ...failed('LOCAL_RECOVERY_PROVENANCE_CONFLICT', String(error)), content, repoRoot: resolved.repoRoot, authority, lockAlreadyHeld: request.lockAlreadyHeld };
247
238
  }
248
- if (intent?.state === 'consumed') {
239
+ }
240
+ function commitLocalArtifactProvenance(prepared) {
241
+ if (!prepared.recovery || !prepared.repoRoot || prepared.result.status === 'failed' && !prepared.result.recovery)
242
+ return prepared.result;
243
+ if (prepared.result.status === 'failed')
244
+ return prepared.result;
245
+ try {
246
+ const intent = readArtifactRecoveryIntent(prepared.repoRoot, prepared.recovery.taskId, prepared.recovery.family, prepared.recovery.artifact);
247
+ if (!intent)
248
+ throw new Error('ARTIFACT_RECOVERY_INTENT_MISSING');
249
+ let committed;
250
+ if (intent.state === 'passed' || intent.state === 'consumed') {
251
+ return {
252
+ ...prepared.result,
253
+ artifactSha256: intent.finalArtifactSha256,
254
+ semanticDigest: intent.finalSemanticDigest,
255
+ error: null
256
+ };
257
+ }
258
+ else if (intent.state === 'finalize-ready' || intent.state === 'commit-started') {
259
+ committed = commitArtifactRecovery(prepared.recovery, { lockAlreadyHeld: prepared.lockAlreadyHeld });
260
+ }
261
+ else {
262
+ const staged = stageArtifactCandidate(prepared.recovery, Buffer.from(prepared.content, 'utf8'), { lockAlreadyHeld: prepared.lockAlreadyHeld });
263
+ prepareArtifactRecoveryCommit(prepared.recovery, staged.candidateSha256, staged.semanticDigest, { lockAlreadyHeld: prepared.lockAlreadyHeld });
264
+ committed = commitArtifactRecovery(prepared.recovery, { lockAlreadyHeld: prepared.lockAlreadyHeld });
265
+ }
266
+ if (committed.state !== 'passed')
267
+ throw new Error(`ARTIFACT_RECOVERY_STATE_INVALID: commit ended in '${committed.state}'`);
249
268
  return {
269
+ ...prepared.result,
250
270
  status: 'passed',
251
- changed: false,
252
- taskId: resolved.taskId,
253
- taskDir: resolved.taskDir,
254
- family: request.family,
255
- artifact: request.artifact,
256
- artifactSha256,
257
- semanticDigest: result.semanticDigest,
258
- repairable: false,
259
- diagnostics: result.diagnostics,
271
+ artifactSha256: committed.finalArtifactSha256,
272
+ semanticDigest: committed.finalSemanticDigest,
260
273
  error: null
261
274
  };
262
275
  }
263
- try {
264
- writeLocalArtifactFinalizationIntent(resolved.repoRoot, {
265
- version: 1,
266
- taskId: resolved.taskId,
267
- family: request.family,
268
- artifact: request.artifact,
269
- state: 'passed',
270
- baselineSemanticDigest: intent?.baselineSemanticDigest ?? null,
271
- artifactSha256,
272
- semanticDigest: result.semanticDigest
273
- });
274
- }
275
276
  catch (error) {
276
- return failedFinalization(request, {
277
- code: 'LOCAL_FINALIZATION_INTENT_WRITE_FAILED',
278
- message: error instanceof Error ? error.message : String(error)
279
- }, { taskId: resolved.taskId, taskDir: resolved.taskDir, artifactSha256, semanticDigest: result.semanticDigest });
277
+ return { ...prepared.result, status: 'failed', error: {
278
+ code: 'LOCAL_RECOVERY_COMMIT_FAILED', message: String(error)
279
+ } };
280
280
  }
281
- return {
282
- status: result.ok ? 'passed' : 'failed',
283
- changed: false,
284
- taskId: resolved.taskId,
285
- taskDir: resolved.taskDir,
286
- family: request.family,
287
- artifact: request.artifact,
288
- artifactSha256,
289
- semanticDigest: result.semanticDigest,
290
- repairable: result.repairable,
291
- diagnostics: result.diagnostics,
292
- error: result.ok ? null : {
293
- code: 'LOCAL_ARTIFACT_INVALID',
294
- message: result.diagnostics.map((item) => `${item.code}: ${item.message}`).join('; ')
281
+ }
282
+ function finalizeLocalArtifact(request, authority, options = {}) {
283
+ const prepared = prepareLocalArtifact(request, undefined, authority);
284
+ const result = commitLocalArtifactProvenance(prepared);
285
+ if (authority && !options.deferLifecycleRecoveryConsumption && result.status === 'passed') {
286
+ try {
287
+ consumeLifecycleRecoveryAttestation(authority);
295
288
  }
296
- };
289
+ catch (error) {
290
+ return { ...result, status: 'failed', error: {
291
+ code: 'LOCAL_EXECUTION_AUTHORITY_CONSUME_FAILED',
292
+ message: error instanceof Error ? error.message : String(error)
293
+ } };
294
+ }
295
+ }
296
+ return result;
297
297
  }
298
- export { LOCAL_ARTIFACT_REQUIRED_SECTIONS, consumeLocalArtifactFinalizationIntent, finalizeLocalArtifact, readLocalArtifactFinalizationIntent, canonicalSemanticDigest as semanticDigest, sha256Content, validateLocalArtifact };
298
+ export { LOCAL_ARTIFACT_REQUIRED_SECTIONS, consumeLocalArtifactFinalizationIntent, finalizeLocalArtifact, prepareLocalArtifact, commitLocalArtifactProvenance, readArtifactRecoveryIntent as readLocalArtifactFinalizationIntent, canonicalSemanticDigest as semanticDigest, sha256Content, validateLocalArtifact };
299
299
  //# sourceMappingURL=local-artifact-finalization.js.map
@@ -0,0 +1,26 @@
1
+ import { readManualValidationReceipt } from './manual-validation-receipt.js';
2
+ import { readManualValidationTransaction } from './manual-validation-transaction.js';
3
+ function readManualValidationCompletion(taskDir, expected = {}) {
4
+ const { receiptDigest: expectedReceiptDigest, ...receiptIdentity } = expected;
5
+ const receipt = readManualValidationReceipt(taskDir, receiptIdentity);
6
+ if (!receipt.ok)
7
+ return receipt;
8
+ if (expectedReceiptDigest !== undefined && receipt.value.receiptDigest !== expectedReceiptDigest) {
9
+ return { ok: false, error: { code: 'MANUAL_VALIDATION_RECEIPT_IDENTITY_MISMATCH', message: 'receipt digest does not match the expected completion' } };
10
+ }
11
+ const transaction = readManualValidationTransaction(taskDir, {
12
+ transactionId: receipt.value.transactionId,
13
+ taskId: receipt.value.taskId,
14
+ prNumber: receipt.value.prNumber,
15
+ prHeadSha: receipt.value.prHeadSha,
16
+ artifact: receipt.value.artifact
17
+ });
18
+ if (!transaction.ok)
19
+ return transaction;
20
+ if (transaction.value.committedReceipt !== receipt.value.receiptDigest) {
21
+ return { ok: false, error: { code: 'MANUAL_VALIDATION_TRANSACTION_PHASE_INVALID', message: 'completion transaction is not bound to the canonical receipt' } };
22
+ }
23
+ return { ok: true, value: { receipt: receipt.value, transaction: transaction.value } };
24
+ }
25
+ export { readManualValidationCompletion };
26
+ //# sourceMappingURL=manual-validation-completion.js.map
@@ -0,0 +1,130 @@
1
+ import fs from 'node:fs';
2
+ import { createHash } from 'node:crypto';
3
+ import { MANUAL_VALIDATION_SHA40 as SHA40, MANUAL_VALIDATION_TASK_ID as TASK_ID, exactKeys, isRecord, validTimestamp } from './manual-validation-shared.js';
4
+ const MANUAL_VALIDATION_EVIDENCE_SCHEMA = 'agent-infra/branch-only-validation-evidence';
5
+ const MANUAL_VALIDATION_EVIDENCE_VERSION = 1;
6
+ function invalid(message) {
7
+ return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_INVALID', message } };
8
+ }
9
+ function validateShape(value) {
10
+ if (!isRecord(value))
11
+ return invalid('evidence must be a JSON object');
12
+ const topError = exactKeys(value, ['schema', 'version', 'mode', 'taskId', 'branch', 'commit', 'recoverable', 'source', 'result'], 'evidence');
13
+ if (topError)
14
+ return invalid(topError);
15
+ if (value.schema !== MANUAL_VALIDATION_EVIDENCE_SCHEMA || value.version !== MANUAL_VALIDATION_EVIDENCE_VERSION) {
16
+ return invalid('evidence schema or version is unsupported');
17
+ }
18
+ if (value.mode !== 'task-bound' && value.mode !== 'branch-only')
19
+ return invalid('mode must be task-bound or branch-only');
20
+ if (value.taskId !== null && (typeof value.taskId !== 'string' || !TASK_ID.test(value.taskId)))
21
+ return invalid('taskId must be a TASK identifier or null');
22
+ if (typeof value.branch !== 'string' || !value.branch.trim() || /[\r\n]/u.test(value.branch))
23
+ return invalid('branch must be a non-empty single line');
24
+ if (typeof value.commit !== 'string' || !SHA40.test(value.commit))
25
+ return invalid('commit must be a 40-character lowercase hexadecimal SHA');
26
+ if (typeof value.recoverable !== 'boolean')
27
+ return invalid('recoverable must be boolean');
28
+ if (value.source !== 'run-manual-validation')
29
+ return invalid('source is unsupported');
30
+ if (value.mode === 'branch-only' && (value.taskId !== null || value.recoverable !== false))
31
+ return invalid('branch-only evidence must be non-recoverable and task-free');
32
+ if (value.mode === 'task-bound' && (value.taskId === null || value.recoverable !== true))
33
+ return invalid('task-bound evidence must identify a recoverable task');
34
+ if (!isRecord(value.result))
35
+ return invalid('result must be a JSON object');
36
+ const result = value.result;
37
+ const resultError = exactKeys(result, ['scope', 'command', 'startedAt', 'completedAt', 'exitCode', 'signal', 'cleanup'], 'result');
38
+ if (resultError)
39
+ return invalid(resultError);
40
+ if (result.scope !== 'snapshot' && result.scope !== 'inplace')
41
+ return invalid('result.scope is invalid');
42
+ if (typeof result.command !== 'string' || !result.command || /[\\/\r\n]/u.test(result.command))
43
+ return invalid('result.command must be a basename');
44
+ if (!validTimestamp(result.startedAt) || !validTimestamp(result.completedAt) || Date.parse(result.completedAt) < Date.parse(result.startedAt))
45
+ return invalid('result timestamps are invalid');
46
+ const exitCode = result.exitCode;
47
+ if (!Number.isSafeInteger(exitCode) || exitCode < 0)
48
+ return invalid('result.exitCode must be a non-negative integer');
49
+ if (result.signal !== null && (typeof result.signal !== 'string' || !result.signal || /[\r\n]/u.test(result.signal)))
50
+ return invalid('result.signal must be a string or null');
51
+ if (!['completed', 'pending', 'failed', 'not-created'].includes(result.cleanup))
52
+ return invalid('result.cleanup is invalid');
53
+ return { ok: true, value: value };
54
+ }
55
+ function createManualValidationEvidence(input) {
56
+ const value = {
57
+ schema: MANUAL_VALIDATION_EVIDENCE_SCHEMA,
58
+ version: MANUAL_VALIDATION_EVIDENCE_VERSION,
59
+ mode: input.mode,
60
+ taskId: input.taskId,
61
+ branch: input.branch,
62
+ commit: input.commit,
63
+ recoverable: input.recoverable,
64
+ source: 'run-manual-validation',
65
+ result: {
66
+ scope: input.scope,
67
+ command: input.command,
68
+ startedAt: input.startedAt,
69
+ completedAt: input.completedAt,
70
+ exitCode: input.exitCode,
71
+ signal: input.signal,
72
+ cleanup: input.cleanup
73
+ }
74
+ };
75
+ const checked = validateShape(value);
76
+ if (!checked.ok)
77
+ throw new Error(`${checked.error.code}: ${checked.error.message}`);
78
+ return checked.value;
79
+ }
80
+ function manualValidationEvidenceSummary(evidence) {
81
+ return {
82
+ version: 1,
83
+ taskId: evidence.taskId,
84
+ branch: evidence.branch,
85
+ scope: evidence.result.scope,
86
+ commit: evidence.commit,
87
+ command: evidence.result.command,
88
+ startedAt: evidence.result.startedAt,
89
+ completedAt: evidence.result.completedAt,
90
+ exitCode: evidence.result.exitCode,
91
+ signal: evidence.result.signal,
92
+ cleanup: evidence.result.cleanup
93
+ };
94
+ }
95
+ function validateManualValidationEvidence(value, expected) {
96
+ const shape = validateShape(value);
97
+ if (!shape.ok)
98
+ return shape;
99
+ const evidence = shape.value;
100
+ if (evidence.result.exitCode !== 0 || evidence.result.signal !== null || evidence.result.cleanup !== 'completed') {
101
+ return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_UNSUCCESSFUL', message: 'validation must exit 0 without a signal and complete cleanup' } };
102
+ }
103
+ if (expected) {
104
+ if (evidence.taskId !== expected.taskId || evidence.branch !== expected.branch) {
105
+ return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_IDENTITY_MISMATCH', message: 'evidence task or branch does not match the expected identity' } };
106
+ }
107
+ if (expected.commit !== undefined && evidence.commit !== expected.commit) {
108
+ return { ok: false, error: { code: 'MANUAL_VALIDATION_EVIDENCE_STALE', message: 'evidence commit does not match the current head' } };
109
+ }
110
+ }
111
+ return shape;
112
+ }
113
+ function readManualValidationEvidence(file, expected) {
114
+ let parsed;
115
+ try {
116
+ parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
117
+ }
118
+ catch (error) {
119
+ const code = error.code === 'ENOENT'
120
+ ? 'MANUAL_VALIDATION_EVIDENCE_MISSING'
121
+ : 'MANUAL_VALIDATION_EVIDENCE_INVALID';
122
+ return { ok: false, error: { code, message: error instanceof Error ? error.message : String(error) } };
123
+ }
124
+ return validateManualValidationEvidence(parsed, expected);
125
+ }
126
+ function manualValidationEvidenceDigest(evidence) {
127
+ return createHash('sha256').update(JSON.stringify(evidence), 'utf8').digest('hex');
128
+ }
129
+ export { MANUAL_VALIDATION_EVIDENCE_SCHEMA, MANUAL_VALIDATION_EVIDENCE_VERSION, createManualValidationEvidence, manualValidationEvidenceSummary, manualValidationEvidenceDigest, readManualValidationEvidence, validateManualValidationEvidence };
130
+ //# sourceMappingURL=manual-validation-evidence.js.map