@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
@@ -24,20 +24,31 @@ import { resolveMaterializedReviewedHeadRelation } from "../platform/change-requ
24
24
  import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.ts";
25
25
  import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.ts";
26
26
  import { parseTypedTaskFrontmatter } from "./frontmatter.ts";
27
- import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.ts";
27
+ import { LEDGER_TERMINAL, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.ts";
28
28
  import type { LedgerRow } from "./ledger.ts";
29
29
  import { isValidAgentInfraVersion } from "../version.ts";
30
30
  import { equalCounts, parseReviewSummary } from "./review-artifacts.ts";
31
31
  import { inspectDecisionDetailDuplicates } from "./decision-details.ts";
32
+ import { parseImplementationInputs, type ImplementationInput } from "./implementation-inputs.ts";
33
+ import { scanVisibleMarkdown } from "./markdown.ts";
32
34
  import { loadVerificationConfig } from "./verification-config.ts";
33
35
  import { snapshotReview } from "../git/review-snapshot.ts";
36
+ import { inspectActivityLog } from "./activity-log.ts";
37
+ import { parseWorkflowWarnings } from "./workflow-warnings.ts";
34
38
  import { OrchestrationStateError, readRun } from "./orchestration.ts";
39
+ import type { OrchestrationRun } from "./orchestration.ts";
35
40
  import { resolveDeliveryTarget } from "./delivery-target.ts";
36
41
  import { readPrDeliveryFact } from "./pr-delivery-fact.ts";
37
42
  import { validateLocalArtifact } from "./local-artifact-finalization.ts";
38
43
  import { validateQualificationAudit } from "./qualification-audit.ts";
39
44
  import { getArtifactSchema } from "./artifact-schema.ts";
40
45
  import { inspectArtifactContract } from "./artifact-operations.ts";
46
+ import type { VerificationShared } from "./verification-types.ts";
47
+ import { manualValidationFinalSummaryProjectionMatches } from "./manual-validation-receipt.ts";
48
+ import { readManualValidationCompletion } from "./manual-validation-completion.ts";
49
+ import { sha256File } from "./artifact-receipts.ts";
50
+ import { summaryCommentState } from "../platform/pr-summary.ts";
51
+ import { taskIssueIdentity } from "../platform/task-identities.ts";
41
52
 
42
53
  const TASK_ENUMS = {
43
54
  type: ["feature", "bugfix", "refactor", "docs", "chore"],
@@ -58,7 +69,6 @@ const DEFAULT_REQUIRED_FIELDS = [
58
69
  ];
59
70
 
60
71
  const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
61
- const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
62
72
  // Start markers (action suffixed with ` [started]`) are excluded from the
63
73
  // "latest action" / freshness computation so a step's in-flight marker never
64
74
  // satisfies a skill's expected_action_pattern; the matching done entry does.
@@ -67,28 +77,12 @@ const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
67
77
 
68
78
  // Review disagreement ledger (see .agents/rules/review-handshake.md).
69
79
  const LEDGER_SECTION_NAMES = ["审查分歧账本", "Review Disagreement Ledger"];
70
- const LEDGER_STATUSES = new Set([
71
- "open",
72
- "accepted",
73
- "adjusted",
74
- "refuted",
75
- "cannot-judge",
76
- "confirmed",
77
- "needs-human-decision",
78
- "closed",
79
- "human-decided"
80
- ]);
81
- const LEDGER_TERMINAL_OK = new Set(["confirmed", "closed", "human-decided"]);
82
80
  const DEFAULT_MAX_HANDSHAKE_ROUNDS = 3;
83
81
  const POST_REVIEW_COMMIT_STAGE = "post-review-commit";
84
82
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
85
- const WORKFLOW_WARNING_SECTION_NAMES = ["工作流告警", "Workflow Warnings"];
86
- const WORKFLOW_WARNING_STATUSES = new Set(["open", "resolved", "ignored"]);
87
- const WORKFLOW_WARNING_SEVERITIES = new Set(["IMPORTANT", "ACTION_REQUIRED"]);
88
- const WORKFLOW_WARNING_ID_PATTERN = /^WW-\d+$/;
89
83
 
90
84
  const scriptPath = fileURLToPath(import.meta.url);
91
- let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
85
+ const defaultRepoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
92
86
 
93
87
  const PLATFORM_ADAPTERS: Record<string, (context: any, shared: any) => any> = {
94
88
  "platform-sync": checkPlatformSync,
@@ -107,8 +101,6 @@ const sharedUtils = {
107
101
  failResult,
108
102
  blockedResult,
109
103
  safeStat,
110
- parseIssueNumber,
111
- parsePrNumber
112
104
  };
113
105
 
114
106
  async function runCheck(type: any, context: any, shared: any): Promise<any> {
@@ -160,7 +152,7 @@ function checkOrchestrationState({ taskDir }: any): any {
160
152
  const file = path.join(taskDir, 'orchestration.json');
161
153
  const stat = safeStat(file);
162
154
  if (!stat?.isFile()) return failResult('orchestration-state', 'orchestration.json is missing');
163
- let run: any;
155
+ let run: OrchestrationRun | null;
164
156
  try {
165
157
  run = readRun(taskDir);
166
158
  } catch (error) {
@@ -192,18 +184,16 @@ function exactText(value: unknown): value is string {
192
184
  return typeof value === 'string' && value.length > 0 && value.trim() === value;
193
185
  }
194
186
 
195
- function validateCleanCompletionEvidence(run: any): string | null {
187
+ function validateCleanCompletionEvidence(run: OrchestrationRun): string | null {
196
188
  const evidence = run.completionEvidence;
197
189
  const shaPattern = /^[0-9a-f]{40}$/i;
198
190
  if (
199
- evidence?.kind !== 'reviewed-head-clean'
200
- || !exactText(evidence.observedAt)
191
+ !evidence
201
192
  || Number.isNaN(Date.parse(evidence.observedAt))
202
193
  || !shaPattern.test(evidence.head)
203
194
  || !shaPattern.test(evidence.headTree)
204
195
  || !shaPattern.test(evidence.worktreeTree)
205
196
  || !shaPattern.test(evidence.lastReviewedCommit)
206
- || !(evidence.prNumber === null || (Number.isInteger(evidence.prNumber) && evidence.prNumber > 0))
207
197
  || !(evidence.prHead === null || shaPattern.test(evidence.prHead))
208
198
  ) {
209
199
  return 'Clean completion evidence has an invalid structure';
@@ -220,8 +210,7 @@ function validateCleanCompletionEvidence(run: any): string | null {
220
210
  || run.pendingDelegation !== null
221
211
  || run.commitAuthorization?.issuedAt !== null
222
212
  || run.commitAuthorization?.consumedAt !== null
223
- || !Array.isArray(run.receipts)
224
- || run.receipts.some((receipt: any) => receipt.stage === 'commit')
213
+ || run.receipts.some((receipt) => receipt.stage === 'commit')
225
214
  ) {
226
215
  return 'Clean completion evidence conflicts with commit delegation state';
227
216
  }
@@ -232,54 +221,16 @@ function checkOrchestrationEvidence({ taskDir }: any): any {
232
221
  const file = path.join(taskDir, 'orchestration.json');
233
222
  const stat = safeStat(file);
234
223
  if (!stat?.isFile()) return failResult('orchestration-evidence', 'orchestration.json is missing');
235
- let run: any;
224
+ let run: OrchestrationRun | null;
236
225
  try {
237
226
  run = readRun(taskDir);
238
227
  } catch (error) {
239
228
  const message = error instanceof OrchestrationStateError ? error.message : String(error);
240
229
  return failResult('orchestration-evidence', `Invalid orchestration.json: ${message}`);
241
230
  }
231
+ if (!run) return failResult('orchestration-evidence', 'orchestration.json is missing');
232
+ // readRun validates the persisted schema, receipt identities and client provenance.
242
233
  const policy = run.modelPolicy;
243
- if (
244
- !policy
245
- || !exactText(policy.executor?.model)
246
- || !exactText(policy.executor?.reasoningEffort)
247
- || !exactText(policy.reviewer?.model)
248
- || !exactText(policy.reviewer?.reasoningEffort)
249
- ) {
250
- return failResult('orchestration-evidence', 'Run model policy requires exact executor and reviewer model and effort');
251
- }
252
- if (
253
- !run.modelPolicySource
254
- || !['explicit', 'project-config'].includes(run.modelPolicySource.kind)
255
- || !exactText(run.modelPolicySource.client)
256
- || !exactText(run.modelPolicySource.resolvedAt)
257
- || !Array.isArray(run.recoveryHistory)
258
- ) {
259
- return failResult('orchestration-evidence', 'Run model policy source or recovery history is invalid');
260
- }
261
- for (const recovery of run.recoveryHistory) {
262
- const guards = recovery.guards;
263
- const validClaudeCodeRecovery = recovery.code === 'CLIENT_CAPABILITY_ENABLED'
264
- && recovery.previousStatus === 'paused'
265
- && recovery.previousPause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
266
- && recovery.client === 'claude-code'
267
- && recovery.resultingStatus === 'running'
268
- && exactText(recovery.recoveredAt)
269
- && guards?.stepCount === 0
270
- && guards?.nextStage === null
271
- && guards?.baselineEmpty === true
272
- && guards?.receiptCount === 0
273
- && guards?.pendingDelegation === false
274
- && guards?.commitAuthorizationUnused === true
275
- && guards?.completionEvidenceAbsent === true;
276
- if (!validClaudeCodeRecovery) {
277
- return failResult('orchestration-evidence', 'Run recovery history contains invalid provenance');
278
- }
279
- }
280
- if (!Array.isArray(run.receipts)) {
281
- return failResult('orchestration-evidence', 'Run receipts must be an array');
282
- }
283
234
  if (run.completionEvidence != null) {
284
235
  const evidenceError = validateCleanCompletionEvidence(run);
285
236
  if (evidenceError) return failResult('orchestration-evidence', evidenceError);
@@ -309,10 +260,6 @@ function checkOrchestrationEvidence({ taskDir }: any): any {
309
260
  return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual reasoning effort`);
310
261
  }
311
262
  }
312
- // parentId/childId 校验对所有 client 保持统一(不新增分支);spawnMode 检查按 client 判断
313
- if (!exactText(receipt.parentId) || !exactText(receipt.childId) || receipt.parentId === receipt.childId) {
314
- return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid delegation identity`);
315
- }
316
263
  if (!isClaudeCode && receipt.spawnMode !== 'fresh') {
317
264
  return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid fresh delegation identity`);
318
265
  }
@@ -338,50 +285,9 @@ function checkOrchestrationEvidence({ taskDir }: any): any {
338
285
  ) {
339
286
  return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated reasoning-effort fallback reason`);
340
287
  }
341
- if (receipt.client === 'codex') {
342
- const activatedCodex = ['activated', 'stage-completed', 'sealed', 'consumed'].includes(receipt.status);
343
- const host = receipt.hostEvidence;
344
- const provenance = receipt.lifecycleProvenance;
345
- if (
346
- !provenance
347
- || (activatedCodex && (
348
- host?.kind !== 'codex-lifecycle-v2'
349
- || host.protocolVersion !== provenance.protocolVersion
350
- || host.hookDefinitionHash !== provenance.hookDefinitionHash
351
- || host.hookSource !== provenance.hookSource
352
- || host.hookSourcePathDigest !== provenance.hookSourcePathDigest
353
- || host.hookSourceHash !== provenance.hookSourceHash
354
- || host.capabilitySessionId !== provenance.capabilitySessionId
355
- || receipt.parentId !== provenance.capabilitySessionId
356
- || host.capabilityTurnId !== provenance.capabilityTurnId
357
- || host.controllerInstanceDigest !== provenance.controllerInstanceDigest
358
- || host.controlGeneration !== provenance.controlGeneration
359
- || host.spawnToolUseId === provenance.capabilityToolUseId
360
- || !exactText(host.spawnToolUseId)
361
- || !Number.isFinite(Date.parse(host.spawnObservedAt ?? ''))
362
- || !Number.isFinite(Date.parse(receipt.spawnDispatchedAt ?? ''))
363
- || !Number.isFinite(Date.parse(receipt.activationDeadlineAt ?? ''))
364
- || Date.parse(host.spawnObservedAt ?? '') < Date.parse(receipt.spawnDispatchedAt ?? '')
365
- || Date.parse(host.spawnObservedAt ?? '') > Date.parse(receipt.activationDeadlineAt ?? '')
366
- || !exactText(host.hookDefinitionHash)
367
- || !Number.isSafeInteger(host.startRevision)
368
- || host.startRevision < 1
369
- ))
370
- ) {
371
- return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid Codex start evidence`);
372
- }
373
- if (['sealed', 'consumed'].includes(receipt.status) && (
374
- !Number.isSafeInteger(host.stopRevision)
375
- || host.stopRevision <= host.startRevision
376
- || host.consumer !== receipt.id
377
- || !exactText(host.consumedAt)
378
- )) {
379
- return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid Codex consumed stop evidence`);
380
- }
381
- }
382
288
  }
383
289
  }
384
- if (run.receipts.some((receipt: any) => receipt.status !== 'consumed')) {
290
+ if (run.receipts.some((receipt) => receipt.status !== 'consumed')) {
385
291
  return failResult('orchestration-evidence', 'Historical receipts must be consumed');
386
292
  }
387
293
  return passResult('orchestration-evidence', 'Persisted orchestration model and delegation evidence is internally consistent');
@@ -389,7 +295,7 @@ function checkOrchestrationEvidence({ taskDir }: any): any {
389
295
 
390
296
  // === Check Functions ===
391
297
 
392
- function checkTaskMeta({ taskDir, config }: any): any {
298
+ function checkTaskMeta({ taskDir, config, repositoryRoot }: any): any {
393
299
  const task = loadTask(taskDir);
394
300
  if (!task.ok) {
395
301
  return failResult("task-meta", task.message);
@@ -427,14 +333,15 @@ function checkTaskMeta({ taskDir, config }: any): any {
427
333
  }
428
334
  }
429
335
 
430
- const branchValidationError = validateTaskBranch(metadata);
336
+ const branchValidationError = validateTaskBranch(metadata, repositoryRoot);
431
337
  if (branchValidationError) {
432
338
  return failResult("task-meta", branchValidationError);
433
339
  }
434
340
 
435
- const warningValidationErrors = validateWorkflowWarnings(task.content);
436
- if (warningValidationErrors.length > 0) {
437
- return failResult("task-meta", `Invalid Workflow Warnings: ${warningValidationErrors.join("; ")}`);
341
+ try {
342
+ parseWorkflowWarnings(task.content);
343
+ } catch (error) {
344
+ return failResult("task-meta", `Invalid Workflow Warnings: ${error instanceof Error ? error.message : String(error)}`);
438
345
  }
439
346
 
440
347
  const expectedStep = config.expected_step;
@@ -453,8 +360,8 @@ function checkTaskMeta({ taskDir, config }: any): any {
453
360
  );
454
361
  }
455
362
 
456
- if (config.require_issue_number && !parseIssueNumber(metadata.issue_number)) {
457
- return failResult("task-meta", "Expected a valid issue_number in task metadata");
363
+ if (config.require_platform_issue_identity && !taskIssueIdentity(metadata)) {
364
+ return failResult("task-meta", "Expected a valid platform_issue_identity in task metadata");
458
365
  }
459
366
 
460
367
  if (config.require_completed_at && isBlank(metadata.completed_at)) {
@@ -552,12 +459,12 @@ async function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }: any):
552
459
  return passResult('required-pr-delivery', `Pull request delivery policy satisfied (${status})`);
553
460
  }
554
461
 
555
- function validateTaskBranch(metadata: any): any {
462
+ function validateTaskBranch(metadata: any, repoRoot: string): any {
556
463
  if (isBlank(metadata.branch)) {
557
464
  return null;
558
465
  }
559
466
 
560
- const projectName = loadProjectName();
467
+ const projectName = loadProjectName(repoRoot);
561
468
  const expectedPrefix = projectName ? `${projectName}-${metadata.type}-` : "";
562
469
 
563
470
  if (expectedPrefix && !String(metadata.branch).startsWith(expectedPrefix)) {
@@ -572,7 +479,7 @@ function validateTaskBranch(metadata: any): any {
572
479
  return null;
573
480
  }
574
481
 
575
- function loadProjectName(): any {
482
+ function loadProjectName(repoRoot: string): any {
576
483
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
577
484
  if (!fs.existsSync(configPath)) {
578
485
  return "";
@@ -743,31 +650,17 @@ function checkImplementationInput({ taskDir, artifactFile }: any): any {
743
650
  const artifactPath = path.join(taskDir, artifactFile);
744
651
  if (!safeStat(artifactPath)?.isFile()) return failResult("implementation-input", `Artifact not found: ${artifactFile}`);
745
652
 
746
- const inputSection = getSectionContent(task.content, ["实现输入", "Implementation Inputs"]);
747
- const rows = [];
748
- if (inputSection) {
749
- const table = inputSection.split(/\r?\n/).filter((line: any) => line.trim().startsWith("|"));
750
- const cells = (line: any) => line.split("|").slice(1, -1).map((cell: any) => cell.trim());
751
- const expected = ["id", "ledger_id", "decision_evidence", "stage", "needs_implementation", "decided_at", "status", "consumed_by"];
752
- if (table.length < 2 || JSON.stringify(cells(table[0])) !== JSON.stringify(expected)) {
753
- return failResult("implementation-input", "Implementation Inputs table schema is invalid");
754
- }
755
- const seen = new Set();
756
- for (const line of table.slice(2)) {
757
- const row = cells(line);
758
- if (row.length !== 8 || !/^II-[1-9]\d*$/.test(row[0]) || seen.has(row[0])) {
759
- return failResult("implementation-input", "Implementation Inputs table contains an invalid or duplicate id");
760
- }
761
- seen.add(row[0]);
762
- rows.push({ id: row[0], ledgerId: row[1], evidence: row[2], stage: row[3], needs: row[4], status: row[6], consumedBy: row[7] });
763
- }
653
+ let rows: ImplementationInput[];
654
+ try {
655
+ rows = parseImplementationInputs(task.content).rows;
656
+ } catch (error) {
657
+ return failResult("implementation-input", `Invalid Implementation Inputs: ${error instanceof Error ? error.message : String(error)}`);
764
658
  }
765
659
 
766
- const logSection = getSectionContent(task.content, ["活动日志", "Activity Log"]);
767
- const doneActions = logSection.split(/\r?\n/).flatMap((line: any) => {
768
- const match = line.trim().match(ACTIVITY_LOG_PATTERN);
769
- return match && !ACTIVITY_LOG_STARTED_RE.test(match[2]) ? [match[2]] : [];
770
- });
660
+ const doneActions = (inspectActivityLog(task.content).section?.entries ?? [])
661
+ .filter((entry) => !ACTIVITY_LOG_STARTED_RE.test(entry.step))
662
+ .map((entry) => entry.step)
663
+ .filter((step) => /^(?:Code Task|Code) \(Round \d+/.test(step));
771
664
  const latestAction = doneActions.at(-1) || "";
772
665
  const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
773
666
  const report = fs.readFileSync(artifactPath, "utf8");
@@ -794,10 +687,10 @@ function checkImplementationInput({ taskDir, artifactFile }: any): any {
794
687
  const matches = rows.filter((row) => row.id === actionDecision);
795
688
  if (matches.length !== 1) return failResult("implementation-input", `${actionDecision} is missing or duplicated in task table`);
796
689
  const row = matches[0]!;
797
- if (row.stage !== "code" || row.needs !== "true" || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.evidence) {
690
+ if (row.stage !== "code" || !row.needsImplementation || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.decisionEvidence) {
798
691
  return failResult("implementation-input", `${actionDecision} is not a consumed input for ${artifactFile}`);
799
692
  }
800
- if (reportLedger !== row.ledgerId || reportEvidence !== row.evidence) {
693
+ if (reportLedger !== row.ledgerId || reportEvidence !== row.decisionEvidence) {
801
694
  return failResult("implementation-input", `${actionDecision} report identity does not match task table evidence`);
802
695
  }
803
696
  return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
@@ -809,19 +702,11 @@ function checkActivityLog({ taskDir, config }: any): any {
809
702
  return failResult("activity-log", task.message);
810
703
  }
811
704
 
812
- const logSection = getSectionContent(task.content, ["活动日志", "Activity Log"]);
813
- if (!logSection) {
814
- return failResult("activity-log", "Activity Log section not found");
815
- }
816
-
817
- const entries = logSection
818
- .split(/\r?\n/)
819
- .map((line: any) => line.trim())
820
- .filter((line: any) => line.startsWith("- "));
821
-
822
- if (entries.length === 0) {
823
- return failResult("activity-log", "Activity Log has no entries");
824
- }
705
+ const { section, invalidEntries } = inspectActivityLog(task.content);
706
+ if (!section) return failResult("activity-log", "Activity Log section not found or ambiguous");
707
+ if (invalidEntries.length) return failResult("activity-log", `Invalid Activity Log entry format: ${invalidEntries[0]}`);
708
+ const entries = section.entries;
709
+ if (entries.length === 0) return failResult("activity-log", "Activity Log has no entries");
825
710
 
826
711
  let previousTimestamp = "";
827
712
  let latestAction = "";
@@ -829,12 +714,8 @@ function checkActivityLog({ taskDir, config }: any): any {
829
714
  const doneActions: string[] = [];
830
715
 
831
716
  for (const entry of entries) {
832
- const match = entry.match(ACTIVITY_LOG_PATTERN);
833
- if (!match) {
834
- return failResult("activity-log", `Invalid Activity Log entry format: ${entry}`);
835
- }
836
-
837
- const [, timestamp, action] = match;
717
+ if (!entry.note.trim()) return failResult("activity-log", "Activity Log entry note is required");
718
+ const { time: timestamp, step: action } = entry;
838
719
  if (previousTimestamp && timestamp < previousTimestamp) {
839
720
  return failResult("activity-log", "Activity Log timestamps are not in ascending order");
840
721
  }
@@ -906,118 +787,7 @@ function checkCompletionChecklist({ taskDir, config }: any): any {
906
787
  return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
907
788
  }
908
789
 
909
- function splitMarkdownTableRow(line: any): any {
910
- let value = String(line || "").trim();
911
- if (!value.startsWith("|")) {
912
- return [];
913
- }
914
- value = value.replace(/^\|/, "").replace(/\|$/, "");
915
-
916
- const cells = [];
917
- let cell = "";
918
- for (let index = 0; index < value.length; index += 1) {
919
- const char = value[index];
920
- if (char === "|" && !isEscapedAt(value, index)) {
921
- cells.push(unescapeMarkdownTableCell(cell.trim()));
922
- cell = "";
923
- continue;
924
- }
925
- cell += char;
926
- }
927
- cells.push(unescapeMarkdownTableCell(cell.trim()));
928
- return cells;
929
- }
930
-
931
- function unescapeMarkdownTableCell(value: any): any {
932
- let output = "";
933
- for (let index = 0; index < value.length; index += 1) {
934
- const char = value[index];
935
- const next = value[index + 1];
936
- if (char === "\\" && (next === "\\" || next === "|")) {
937
- output += next;
938
- index += 1;
939
- continue;
940
- }
941
- output += char;
942
- }
943
- return output;
944
- }
945
-
946
- function isEscapedAt(value: any, index: any): any {
947
- let backslashes = 0;
948
- for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
949
- backslashes += 1;
950
- }
951
- return backslashes % 2 === 1;
952
- }
953
-
954
- function parseWorkflowWarningRows(section: any): any {
955
- const rows = [];
956
- for (const rawLine of String(section || "").split(/\r?\n/)) {
957
- const cells = splitMarkdownTableRow(rawLine);
958
- if (cells.length === 0) {
959
- continue;
960
- }
961
- if ((cells[0] || "").toLowerCase() === "id") {
962
- continue;
963
- }
964
- if (cells.every((cell: any) => /^:?-{3,}:?$/.test(cell))) {
965
- continue;
966
- }
967
- rows.push(cells);
968
- }
969
- return rows;
970
- }
971
-
972
- function validateWorkflowWarnings(content: any): any {
973
- const section = getSectionContent(content, WORKFLOW_WARNING_SECTION_NAMES);
974
- if (!section.trim()) {
975
- return [];
976
- }
977
-
978
- const rows = parseWorkflowWarningRows(section);
979
- const errors = [];
980
- for (const cells of rows) {
981
- if (cells.length < 11) {
982
- errors.push(`malformed row (expected 11 columns): ${cells.join(" | ")}`);
983
- continue;
984
- }
985
- const [id, time, step, severity, code, status, target, message, action, resolvedAt, resolution] = cells;
986
- if (!WORKFLOW_WARNING_ID_PATTERN.test(id)) {
987
- errors.push(`${id || "(empty id)"}: invalid id`);
988
- }
989
- if (!DATE_TIME_PATTERN.test(time)) {
990
- errors.push(`${id}: invalid time '${time}'`);
991
- }
992
- if (isBlank(step)) {
993
- errors.push(`${id}: step is required`);
994
- }
995
- if (!WORKFLOW_WARNING_SEVERITIES.has(severity)) {
996
- errors.push(`${id}: illegal severity '${severity}'`);
997
- }
998
- if (isBlank(code)) {
999
- errors.push(`${id}: code is required`);
1000
- }
1001
- if (!WORKFLOW_WARNING_STATUSES.has(status)) {
1002
- errors.push(`${id}: illegal status '${status}'`);
1003
- }
1004
- if (isBlank(target)) {
1005
- errors.push(`${id}: target is required`);
1006
- }
1007
- if (isBlank(message)) {
1008
- errors.push(`${id}: message is required`);
1009
- }
1010
- if (status === "open" && isBlank(action)) {
1011
- errors.push(`${id}: open warning requires action`);
1012
- }
1013
- if ((status === "resolved" || status === "ignored") && (isBlank(resolvedAt) || isBlank(resolution))) {
1014
- errors.push(`${id}: ${status} warning requires resolved_at and resolution`);
1015
- }
1016
- }
1017
- return errors;
1018
- }
1019
-
1020
- function resolveReviewSetting(config: any, key: any, fallback: any): any {
790
+ function resolveReviewSetting(config: any, key: any, fallback: any, repoRoot: string): any {
1021
791
  if (config && config[key] !== undefined && config[key] !== null) {
1022
792
  return config[key];
1023
793
  }
@@ -1028,7 +798,7 @@ function resolveReviewSetting(config: any, key: any, fallback: any): any {
1028
798
  return fallback;
1029
799
  }
1030
800
 
1031
- function checkReviewLedger({ taskDir, config }: any): any {
801
+ function checkReviewLedger({ taskDir, config, repositoryRoot }: any): any {
1032
802
  const task = loadTask(taskDir);
1033
803
  if (!task.ok) {
1034
804
  return failResult("review-ledger", task.message);
@@ -1038,9 +808,7 @@ function checkReviewLedger({ taskDir, config }: any): any {
1038
808
  try {
1039
809
  const ledger = parseLedgerDocument(task.content);
1040
810
  if (!ledger.present) return failResult("review-ledger", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
1041
- rows = ledger.rows.map((row) => [
1042
- row.id, row.stage, row.round, row.severity, row.status, row.evidence
1043
- ]);
811
+ rows = ledger.rows;
1044
812
  } catch (error) {
1045
813
  return failResult("review-ledger", `Invalid disagreement ledger: ${error instanceof Error ? error.message : String(error)}`);
1046
814
  }
@@ -1049,17 +817,12 @@ function checkReviewLedger({ taskDir, config }: any): any {
1049
817
  }
1050
818
 
1051
819
  const stageScope = Array.isArray(config.stage_scope) ? config.stage_scope : null;
1052
- const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS));
820
+ const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS, repositoryRoot));
1053
821
  const problems = [];
1054
822
  let inScopeCount = 0;
1055
823
 
1056
- for (const cells of rows) {
1057
- if (cells.length < 6) {
1058
- problems.push(`malformed row (expected 6 columns): ${cells.join(" | ")}`);
1059
- continue;
1060
- }
1061
-
1062
- const [id, stage, roundRaw, , status, evidence] = cells;
824
+ for (const row of rows) {
825
+ const { id, stage, round: roundRaw, status, evidence } = row;
1063
826
  const stageScoped = stageScope ? stageScope.includes(stage) : true;
1064
827
  // post-review-commit exemption rows are consumed by the post-review-commit
1065
828
  // check, not enforced here.
@@ -1071,8 +834,9 @@ function checkReviewLedger({ taskDir, config }: any): any {
1071
834
  }
1072
835
  inScopeCount += 1;
1073
836
 
1074
- if (!LEDGER_STATUSES.has(status!)) {
1075
- problems.push(`${id}: illegal status '${status}'`);
837
+ const invalid = validateLedgerRows([row]);
838
+ if (invalid) {
839
+ problems.push(`${invalid.code}: ${invalid.message}`);
1076
840
  continue;
1077
841
  }
1078
842
  if (status !== "open" && evidence === "") {
@@ -1082,12 +846,12 @@ function checkReviewLedger({ taskDir, config }: any): any {
1082
846
  if (
1083
847
  Number.isFinite(round) &&
1084
848
  round >= maxRounds &&
1085
- !LEDGER_TERMINAL_OK.has(status!) &&
849
+ !LEDGER_TERMINAL.has(status!) &&
1086
850
  status !== "needs-human-decision"
1087
851
  ) {
1088
852
  problems.push(`${id}: round ${round} reached limit ${maxRounds} without convergence; escalate to needs-human-decision`);
1089
853
  }
1090
- if (!LEDGER_TERMINAL_OK.has(status!)) {
854
+ if (!LEDGER_TERMINAL.has(status!)) {
1091
855
  problems.push(`${id}: unresolved (status '${status}')`);
1092
856
  }
1093
857
  }
@@ -1100,7 +864,7 @@ function checkReviewLedger({ taskDir, config }: any): any {
1100
864
  return passResult("review-ledger", `Disagreement ledger clean (${inScopeCount} in-scope entries terminal${scopeLabel})`);
1101
865
  }
1102
866
 
1103
- function checkManualValidation({ taskDir }: any): any {
867
+ async function checkManualValidation({ taskDir, repositoryRoot }: any): Promise<any> {
1104
868
  // 1. Latest review-code artifact; none -> pass (no review, check not applicable).
1105
869
  const review = findAuthoritativeReviewCodeArtifact(taskDir);
1106
870
  if (!review.ok) {
@@ -1132,15 +896,23 @@ function checkManualValidation({ taskDir }: any): any {
1132
896
  const artifactName = path.basename(resolved.path);
1133
897
  const task = loadTask(taskDir);
1134
898
  if (!task.ok) return failResult("manual-validation", task.message);
1135
- const log = getSectionContent(task.content, ["活动日志", "Activity Log"]);
1136
- const completed = new RegExp(
1137
- `\\*\\*Complete Manual Validation\\*\\*[\\s\\S]*?Manual validation passed → ${escapeRegExp(artifactName)};`
1138
- );
1139
- if (!completed.test(log)) {
1140
- return failResult(
1141
- "manual-validation",
1142
- `Manual validation artifact exists but completion is not recorded for ${artifactName}: re-run /complete-manual-validation`
1143
- );
899
+ const completion = readManualValidationCompletion(taskDir, {
900
+ taskId: task.metadata.id,
901
+ artifact: artifactName
902
+ });
903
+ if (!completion.ok) {
904
+ const source = completion.error.code.startsWith('MANUAL_VALIDATION_RECEIPT_') ? 'receipt' : 'transaction';
905
+ return failResult("manual-validation", `Manual validation ${source} is unavailable: ${completion.error.message}`);
906
+ }
907
+ const { receipt, transaction } = completion.value;
908
+ if (transaction.phase !== "committed" || !transaction.eventAppended || !transaction.postWriteVerified) {
909
+ return failResult("manual-validation", "Manual validation transaction has not reached the committed post-write-verified state");
910
+ }
911
+ if (transaction.pendingSummaryDigest !== receipt.pendingSummaryDigest || transaction.finalSummaryDigest !== receipt.finalSummaryDigest) {
912
+ return failResult("manual-validation", "Manual validation summary digests do not match the committed receipt");
913
+ }
914
+ if (sha256File(resolved.path) !== receipt.artifactSha256) {
915
+ return failResult("manual-validation", `Manual validation artifact digest does not match the receipt for ${artifactName}`);
1144
916
  }
1145
917
  // 6. Timing correlation (PL-3 fix, PL-4 corrected): the completion entry must
1146
918
  // sit AFTER the latest review-code round's completion entry in the
@@ -1149,28 +921,32 @@ function checkManualValidation({ taskDir }: any): any {
1149
921
  // which indexOf never matches). Not reusing completed.exec().index: exec
1150
922
  // anchors to the first '**Complete Manual Validation**' heading, which can
1151
923
  // belong to an earlier round's entry and misorder the standard path.
1152
- const reviewDoneIndex = log.indexOf(`**Review Code (Round ${review.round})** by `);
1153
- const completedIndex = log.indexOf(`Manual validation passed → ${artifactName};`);
1154
- if (reviewDoneIndex === -1) {
1155
- // The latest review-code round's completion entry is missing entirely (abnormal
1156
- // state, e.g. a restored/historical task without a review-code.completed record).
1157
- // Re-running complete-manual-validation cannot restore it, so the remediation
1158
- // targets the review record itself. Fail closed either way.
1159
- return failResult(
1160
- "manual-validation",
1161
- `Latest review-code (round ${review.round}) completion entry is missing from the Activity Log (abnormal state): re-run review-code or restore the completion record`
1162
- );
1163
- }
1164
- if (completedIndex < reviewDoneIndex) {
1165
- return failResult(
1166
- "manual-validation",
1167
- `Latest review-code (round ${review.round}) came after the manual validation completion recorded for ${artifactName}: re-run /complete-manual-validation to cover new pending items`
1168
- );
924
+ const inspectedLog = inspectActivityLog(task.content);
925
+ if (!inspectedLog.section) return failResult("manual-validation", "Activity Log is missing or invalid");
926
+ const reviewDoneIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === `Review Code (Round ${review.round})`);
927
+ const completedIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === "Complete Manual Validation"
928
+ && entry.note.includes(`Manual validation passed → ${artifactName};`)
929
+ && entry.note.includes(`transaction=${receipt.transactionId};`)
930
+ && entry.note.includes(`receipt=${receipt.receiptDigest};`)
931
+ && entry.note.includes(`head=${receipt.prHeadSha}`));
932
+ if (reviewDoneIndex === -1) return failResult("manual-validation", `Latest review-code (round ${review.round}) completion entry is missing from the Activity Log`);
933
+ if (completedIndex === -1) return failResult("manual-validation", `Committed manual validation completion is not recorded for ${artifactName}`);
934
+ if (completedIndex < reviewDoneIndex) return failResult("manual-validation", `Latest review-code (round ${review.round}) came after the manual validation completion recorded for ${artifactName}`);
935
+
936
+ const fact = readPrDeliveryFact(task.metadata);
937
+ if (fact.status === "invalid") return failResult("manual-validation", fact.error.message);
938
+ if (fact.status === "valid" && fact.fact.state === "bound") {
939
+ const inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
940
+ if (!inspected.pullRequest) return failResult("manual-validation", inspected.error?.message ?? "canonical pull-request head is unavailable");
941
+ if (inspected.pullRequest.head.sha !== receipt.prHeadSha) return failResult("manual-validation", "manual validation receipt is stale for the current pull-request head");
942
+ const summary = await summaryCommentState(task.metadata.id, { cwd: repositoryRoot });
943
+ if (!summary.comment) return failResult("manual-validation", "canonical pull-request summary comment is unavailable");
944
+ if (!manualValidationFinalSummaryProjectionMatches(summary.comment.body, receipt)) return failResult("manual-validation", "canonical pull-request summary does not match the committed manual validation projection");
1169
945
  }
1170
- return passResult("manual-validation", `Manual validation completed → ${artifactName}`);
946
+ return passResult("manual-validation", `Manual validation completed → ${artifactName} (committed receipt and post-write verification)`);
1171
947
  }
1172
948
 
1173
- async function checkPostReviewCommit({ taskDir, config }: any): Promise<any> {
949
+ async function checkPostReviewCommit({ taskDir, config, repositoryRoot }: any): Promise<any> {
1174
950
  const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
1175
951
  if (!reviewArtifact.ok) {
1176
952
  if (reviewArtifact.error) return failResult("post-review-commit", `Review-code artifact is unavailable: ${reviewArtifact.error}`);
@@ -1190,7 +966,7 @@ async function checkPostReviewCommit({ taskDir, config }: any): Promise<any> {
1190
966
  if (factRead.status === 'invalid') return failResult("post-review-commit", factRead.error.message);
1191
967
  const fact = factRead.status === 'valid' ? factRead.fact : null;
1192
968
  const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
1193
- const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repoRoot));
969
+ const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repositoryRoot));
1194
970
  const hasPullRequest = fact?.state === 'bound';
1195
971
  let inspected: Awaited<ReturnType<typeof inspectPlatformPullRequest>> | null = null;
1196
972
  if (hasPullRequest) {
@@ -1364,7 +1140,7 @@ function resolvePostReviewExemption(content: string):
1364
1140
  }
1365
1141
  }
1366
1142
 
1367
- function checkReviewFact({ taskDir, artifactFile }: any): any {
1143
+ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }: any): any {
1368
1144
  const resolvedArtifact = resolveArtifactPath(
1369
1145
  taskDir,
1370
1146
  "review-code.md|review-code-r{N}.md",
@@ -1448,7 +1224,7 @@ function checkReviewFact({ taskDir, artifactFile }: any): any {
1448
1224
  mode: "worktree",
1449
1225
  baseline,
1450
1226
  diffBase,
1451
- globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repoRoot))
1227
+ globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repositoryRoot))
1452
1228
  });
1453
1229
  } catch {
1454
1230
  return blockedResult(
@@ -1575,46 +1351,13 @@ function resolveArtifactPath(taskDir: any, filePattern: any, artifactFile: any):
1575
1351
  return { ok: true, path: path.join(taskDir, matches[0]!.fileName) };
1576
1352
  }
1577
1353
 
1578
- function getSectionContent(content: any, names: any): any {
1579
- const lines = content.split(/\r?\n/);
1580
-
1581
- function visibleHeadings(): any {
1582
- const headings = [];
1583
- let fence = null;
1584
- for (let index = 0; index < lines.length; index += 1) {
1585
- const line = lines[index];
1586
- if (fence) {
1587
- const closer = line.match(/^ {0,3}(`+|~+)\s*$/);
1588
- if (closer && closer[1][0] === fence.character && closer[1].length >= fence.length) {
1589
- fence = null;
1590
- }
1591
- continue;
1592
- }
1593
- const opener = line.match(/^ {0,3}(`{3,}|~{3,})(?:[^`~].*)?$/);
1594
- if (opener) {
1595
- fence = { character: opener[1][0], length: opener[1].length };
1596
- continue;
1597
- }
1598
- if (line.startsWith("## ")) {
1599
- headings.push({ index, text: line.trim() });
1600
- }
1601
- }
1602
- return headings;
1603
- }
1604
-
1605
- const headings = visibleHeadings();
1606
-
1354
+ function getSectionContent(content: string, names: readonly string[]): string {
1355
+ const headings = scanVisibleMarkdown(content).headings.filter((heading) => heading.level === 2);
1607
1356
  for (const name of names) {
1608
- const heading = `## ${name}`;
1609
- const position = headings.findIndex((item: any) => item.text === heading);
1610
- if (position === -1) {
1611
- continue;
1612
- }
1613
- const startIndex = headings[position]!.index;
1614
- const endIndex = headings[position + 1]?.index ?? lines.length;
1615
- return lines.slice(startIndex + 1, endIndex).join("\n").trim();
1357
+ const position = headings.findIndex((heading) => heading.text === name);
1358
+ if (position === -1) continue;
1359
+ return content.slice(headings[position]!.end + 1, headings[position + 1]?.start ?? content.length).replace(/\r\n/g, "\n").trim();
1616
1360
  }
1617
-
1618
1361
  return "";
1619
1362
  }
1620
1363
 
@@ -1632,19 +1375,6 @@ function getCheckedRequirements(content: any): any {
1632
1375
  .map((match: any) => match[1].trim());
1633
1376
  }
1634
1377
 
1635
- function parseIssueNumber(value: any): any {
1636
- if (isBlank(value) || value === "N/A") {
1637
- return null;
1638
- }
1639
-
1640
- const match = String(value).match(/\d+/);
1641
- return match ? Number(match[0]) : null;
1642
- }
1643
-
1644
- function parsePrNumber(value: any): any {
1645
- return parseIssueNumber(value);
1646
- }
1647
-
1648
1378
  // === Utilities ===
1649
1379
 
1650
1380
  function normalizeContent(text: any): any {
@@ -1742,14 +1472,14 @@ function isBlank(value: any): any {
1742
1472
  }
1743
1473
 
1744
1474
  async function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }: any): Promise<any> {
1745
- if (repositoryRoot) repoRoot = path.resolve(repositoryRoot);
1746
- else {
1475
+ let repoRoot = repositoryRoot ? path.resolve(repositoryRoot) : defaultRepoRoot;
1476
+ if (!repositoryRoot) {
1747
1477
  let cursor = path.resolve(taskDir);
1748
1478
  while (path.dirname(cursor) !== cursor && !fs.existsSync(path.join(cursor, ".agents"))) cursor = path.dirname(cursor);
1749
1479
  if (fs.existsSync(path.join(cursor, ".agents"))) repoRoot = cursor;
1750
1480
  }
1751
1481
  const verifyConfig = loadVerificationConfig(repoRoot, skillName);
1752
- const shared = { ...sharedUtils, repoRoot };
1482
+ const shared: VerificationShared = { ...sharedUtils, repoRoot };
1753
1483
  if (mode === "gate") {
1754
1484
  const checks = [];
1755
1485
  for (const [type, checkConfig] of Object.entries(verifyConfig.checks || {})) {