@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
@@ -12,12 +12,16 @@ import { resolveMaterializedReviewedHeadRelation } from "../platform/change-requ
12
12
  import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.js";
13
13
  import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.js";
14
14
  import { parseTypedTaskFrontmatter } from "./frontmatter.js";
15
- import { LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
15
+ import { LEDGER_TERMINAL, LEDGER_SECTION_MISSING_CODE, LEDGER_SECTION_MISSING_MESSAGE, parseLedgerDocument, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
16
16
  import { isValidAgentInfraVersion } from "../version.js";
17
17
  import { equalCounts, parseReviewSummary } from "./review-artifacts.js";
18
18
  import { inspectDecisionDetailDuplicates } from "./decision-details.js";
19
+ import { parseImplementationInputs } from "./implementation-inputs.js";
20
+ import { scanVisibleMarkdown } from "./markdown.js";
19
21
  import { loadVerificationConfig } from "./verification-config.js";
20
22
  import { snapshotReview } from "../git/review-snapshot.js";
23
+ import { inspectActivityLog } from "./activity-log.js";
24
+ import { parseWorkflowWarnings } from "./workflow-warnings.js";
21
25
  import { OrchestrationStateError, readRun } from "./orchestration.js";
22
26
  import { resolveDeliveryTarget } from "./delivery-target.js";
23
27
  import { readPrDeliveryFact } from "./pr-delivery-fact.js";
@@ -25,6 +29,11 @@ import { validateLocalArtifact } from "./local-artifact-finalization.js";
25
29
  import { validateQualificationAudit } from "./qualification-audit.js";
26
30
  import { getArtifactSchema } from "./artifact-schema.js";
27
31
  import { inspectArtifactContract } from "./artifact-operations.js";
32
+ import { manualValidationFinalSummaryProjectionMatches } from "./manual-validation-receipt.js";
33
+ import { readManualValidationCompletion } from "./manual-validation-completion.js";
34
+ import { sha256File } from "./artifact-receipts.js";
35
+ import { summaryCommentState } from "../platform/pr-summary.js";
36
+ import { taskIssueIdentity } from "../platform/task-identities.js";
28
37
  const TASK_ENUMS = {
29
38
  type: ["feature", "bugfix", "refactor", "docs", "chore"],
30
39
  workflow: ["feature-development", "bug-fix", "refactoring"],
@@ -42,7 +51,6 @@ const DEFAULT_REQUIRED_FIELDS = [
42
51
  "assigned_to"
43
52
  ];
44
53
  const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?$/;
45
- const ACTIVITY_LOG_PATTERN = /^- (\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[+-]\d{2}:\d{2})?) — \*\*(.+?)\*\* by (.+?) — (.+)$/;
46
54
  // Start markers (action suffixed with ` [started]`) are excluded from the
47
55
  // "latest action" / freshness computation so a step's in-flight marker never
48
56
  // satisfies a skill's expected_action_pattern; the matching done entry does.
@@ -50,27 +58,11 @@ const ACTIVITY_LOG_STARTED_RE = /\s*\[started\]\s*$/;
50
58
  const BRANCH_SLUG_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
51
59
  // Review disagreement ledger (see .agents/rules/review-handshake.md).
52
60
  const LEDGER_SECTION_NAMES = ["审查分歧账本", "Review Disagreement Ledger"];
53
- const LEDGER_STATUSES = new Set([
54
- "open",
55
- "accepted",
56
- "adjusted",
57
- "refuted",
58
- "cannot-judge",
59
- "confirmed",
60
- "needs-human-decision",
61
- "closed",
62
- "human-decided"
63
- ]);
64
- const LEDGER_TERMINAL_OK = new Set(["confirmed", "closed", "human-decided"]);
65
61
  const DEFAULT_MAX_HANDSHAKE_ROUNDS = 3;
66
62
  const POST_REVIEW_COMMIT_STAGE = "post-review-commit";
67
63
  const SHA_PATTERN = /^[0-9a-f]{7,40}$/i;
68
- const WORKFLOW_WARNING_SECTION_NAMES = ["工作流告警", "Workflow Warnings"];
69
- const WORKFLOW_WARNING_STATUSES = new Set(["open", "resolved", "ignored"]);
70
- const WORKFLOW_WARNING_SEVERITIES = new Set(["IMPORTANT", "ACTION_REQUIRED"]);
71
- const WORKFLOW_WARNING_ID_PATTERN = /^WW-\d+$/;
72
64
  const scriptPath = fileURLToPath(import.meta.url);
73
- let repoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
65
+ const defaultRepoRoot = path.resolve(path.dirname(scriptPath), "..", "..");
74
66
  const PLATFORM_ADAPTERS = {
75
67
  "platform-sync": checkPlatformSync,
76
68
  "platform-sync-preflight": async (context, shared) => ({ ...await checkPlatformSync(context, shared), type: "platform-sync-preflight" }),
@@ -87,8 +79,6 @@ const sharedUtils = {
87
79
  failResult,
88
80
  blockedResult,
89
81
  safeStat,
90
- parseIssueNumber,
91
- parsePrNumber
92
82
  };
93
83
  async function runCheck(type, context, shared) {
94
84
  switch (type) {
@@ -175,14 +165,12 @@ function exactText(value) {
175
165
  function validateCleanCompletionEvidence(run) {
176
166
  const evidence = run.completionEvidence;
177
167
  const shaPattern = /^[0-9a-f]{40}$/i;
178
- if (evidence?.kind !== 'reviewed-head-clean'
179
- || !exactText(evidence.observedAt)
168
+ if (!evidence
180
169
  || Number.isNaN(Date.parse(evidence.observedAt))
181
170
  || !shaPattern.test(evidence.head)
182
171
  || !shaPattern.test(evidence.headTree)
183
172
  || !shaPattern.test(evidence.worktreeTree)
184
173
  || !shaPattern.test(evidence.lastReviewedCommit)
185
- || !(evidence.prNumber === null || (Number.isInteger(evidence.prNumber) && evidence.prNumber > 0))
186
174
  || !(evidence.prHead === null || shaPattern.test(evidence.prHead))) {
187
175
  return 'Clean completion evidence has an invalid structure';
188
176
  }
@@ -195,7 +183,6 @@ function validateCleanCompletionEvidence(run) {
195
183
  || run.pendingDelegation !== null
196
184
  || run.commitAuthorization?.issuedAt !== null
197
185
  || run.commitAuthorization?.consumedAt !== null
198
- || !Array.isArray(run.receipts)
199
186
  || run.receipts.some((receipt) => receipt.stage === 'commit')) {
200
187
  return 'Clean completion evidence conflicts with commit delegation state';
201
188
  }
@@ -214,43 +201,10 @@ function checkOrchestrationEvidence({ taskDir }) {
214
201
  const message = error instanceof OrchestrationStateError ? error.message : String(error);
215
202
  return failResult('orchestration-evidence', `Invalid orchestration.json: ${message}`);
216
203
  }
204
+ if (!run)
205
+ return failResult('orchestration-evidence', 'orchestration.json is missing');
206
+ // readRun validates the persisted schema, receipt identities and client provenance.
217
207
  const policy = run.modelPolicy;
218
- if (!policy
219
- || !exactText(policy.executor?.model)
220
- || !exactText(policy.executor?.reasoningEffort)
221
- || !exactText(policy.reviewer?.model)
222
- || !exactText(policy.reviewer?.reasoningEffort)) {
223
- return failResult('orchestration-evidence', 'Run model policy requires exact executor and reviewer model and effort');
224
- }
225
- if (!run.modelPolicySource
226
- || !['explicit', 'project-config'].includes(run.modelPolicySource.kind)
227
- || !exactText(run.modelPolicySource.client)
228
- || !exactText(run.modelPolicySource.resolvedAt)
229
- || !Array.isArray(run.recoveryHistory)) {
230
- return failResult('orchestration-evidence', 'Run model policy source or recovery history is invalid');
231
- }
232
- for (const recovery of run.recoveryHistory) {
233
- const guards = recovery.guards;
234
- const validClaudeCodeRecovery = recovery.code === 'CLIENT_CAPABILITY_ENABLED'
235
- && recovery.previousStatus === 'paused'
236
- && recovery.previousPause?.code === 'ORCHESTRATION_CLIENT_UNSUPPORTED'
237
- && recovery.client === 'claude-code'
238
- && recovery.resultingStatus === 'running'
239
- && exactText(recovery.recoveredAt)
240
- && guards?.stepCount === 0
241
- && guards?.nextStage === null
242
- && guards?.baselineEmpty === true
243
- && guards?.receiptCount === 0
244
- && guards?.pendingDelegation === false
245
- && guards?.commitAuthorizationUnused === true
246
- && guards?.completionEvidenceAbsent === true;
247
- if (!validClaudeCodeRecovery) {
248
- return failResult('orchestration-evidence', 'Run recovery history contains invalid provenance');
249
- }
250
- }
251
- if (!Array.isArray(run.receipts)) {
252
- return failResult('orchestration-evidence', 'Run receipts must be an array');
253
- }
254
208
  if (run.completionEvidence != null) {
255
209
  const evidenceError = validateCleanCompletionEvidence(run);
256
210
  if (evidenceError)
@@ -282,10 +236,6 @@ function checkOrchestrationEvidence({ taskDir }) {
282
236
  return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has no host-observed actual reasoning effort`);
283
237
  }
284
238
  }
285
- // parentId/childId 校验对所有 client 保持统一(不新增分支);spawnMode 检查按 client 判断
286
- if (!exactText(receipt.parentId) || !exactText(receipt.childId) || receipt.parentId === receipt.childId) {
287
- return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid delegation identity`);
288
- }
289
239
  if (!isClaudeCode && receipt.spawnMode !== 'fresh') {
290
240
  return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid fresh delegation identity`);
291
241
  }
@@ -307,41 +257,6 @@ function checkOrchestrationEvidence({ taskDir }) {
307
257
  && receipt.reasoningEffortFallbackReason !== null) {
308
258
  return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has an unrelated reasoning-effort fallback reason`);
309
259
  }
310
- if (receipt.client === 'codex') {
311
- const activatedCodex = ['activated', 'stage-completed', 'sealed', 'consumed'].includes(receipt.status);
312
- const host = receipt.hostEvidence;
313
- const provenance = receipt.lifecycleProvenance;
314
- if (!provenance
315
- || (activatedCodex && (host?.kind !== 'codex-lifecycle-v2'
316
- || host.protocolVersion !== provenance.protocolVersion
317
- || host.hookDefinitionHash !== provenance.hookDefinitionHash
318
- || host.hookSource !== provenance.hookSource
319
- || host.hookSourcePathDigest !== provenance.hookSourcePathDigest
320
- || host.hookSourceHash !== provenance.hookSourceHash
321
- || host.capabilitySessionId !== provenance.capabilitySessionId
322
- || receipt.parentId !== provenance.capabilitySessionId
323
- || host.capabilityTurnId !== provenance.capabilityTurnId
324
- || host.controllerInstanceDigest !== provenance.controllerInstanceDigest
325
- || host.controlGeneration !== provenance.controlGeneration
326
- || host.spawnToolUseId === provenance.capabilityToolUseId
327
- || !exactText(host.spawnToolUseId)
328
- || !Number.isFinite(Date.parse(host.spawnObservedAt ?? ''))
329
- || !Number.isFinite(Date.parse(receipt.spawnDispatchedAt ?? ''))
330
- || !Number.isFinite(Date.parse(receipt.activationDeadlineAt ?? ''))
331
- || Date.parse(host.spawnObservedAt ?? '') < Date.parse(receipt.spawnDispatchedAt ?? '')
332
- || Date.parse(host.spawnObservedAt ?? '') > Date.parse(receipt.activationDeadlineAt ?? '')
333
- || !exactText(host.hookDefinitionHash)
334
- || !Number.isSafeInteger(host.startRevision)
335
- || host.startRevision < 1))) {
336
- return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid Codex start evidence`);
337
- }
338
- if (['sealed', 'consumed'].includes(receipt.status) && (!Number.isSafeInteger(host.stopRevision)
339
- || host.stopRevision <= host.startRevision
340
- || host.consumer !== receipt.id
341
- || !exactText(host.consumedAt))) {
342
- return failResult('orchestration-evidence', `Receipt '${receipt.id ?? '(unknown)'}' has invalid Codex consumed stop evidence`);
343
- }
344
- }
345
260
  }
346
261
  }
347
262
  if (run.receipts.some((receipt) => receipt.status !== 'consumed')) {
@@ -350,7 +265,7 @@ function checkOrchestrationEvidence({ taskDir }) {
350
265
  return passResult('orchestration-evidence', 'Persisted orchestration model and delegation evidence is internally consistent');
351
266
  }
352
267
  // === Check Functions ===
353
- function checkTaskMeta({ taskDir, config }) {
268
+ function checkTaskMeta({ taskDir, config, repositoryRoot }) {
354
269
  const task = loadTask(taskDir);
355
270
  if (!task.ok) {
356
271
  return failResult("task-meta", task.message);
@@ -380,13 +295,15 @@ function checkTaskMeta({ taskDir, config }) {
380
295
  return failResult("task-meta", `Invalid ${field}: ${metadata[field]}`);
381
296
  }
382
297
  }
383
- const branchValidationError = validateTaskBranch(metadata);
298
+ const branchValidationError = validateTaskBranch(metadata, repositoryRoot);
384
299
  if (branchValidationError) {
385
300
  return failResult("task-meta", branchValidationError);
386
301
  }
387
- const warningValidationErrors = validateWorkflowWarnings(task.content);
388
- if (warningValidationErrors.length > 0) {
389
- return failResult("task-meta", `Invalid Workflow Warnings: ${warningValidationErrors.join("; ")}`);
302
+ try {
303
+ parseWorkflowWarnings(task.content);
304
+ }
305
+ catch (error) {
306
+ return failResult("task-meta", `Invalid Workflow Warnings: ${error instanceof Error ? error.message : String(error)}`);
390
307
  }
391
308
  const expectedStep = config.expected_step;
392
309
  if (expectedStep && metadata.current_step !== expectedStep) {
@@ -396,8 +313,8 @@ function checkTaskMeta({ taskDir, config }) {
396
313
  if (expectedStatus && metadata.status !== expectedStatus) {
397
314
  return failResult("task-meta", `Expected status '${expectedStatus}', got '${metadata.status || "(empty)"}'`);
398
315
  }
399
- if (config.require_issue_number && !parseIssueNumber(metadata.issue_number)) {
400
- return failResult("task-meta", "Expected a valid issue_number in task metadata");
316
+ if (config.require_platform_issue_identity && !taskIssueIdentity(metadata)) {
317
+ return failResult("task-meta", "Expected a valid platform_issue_identity in task metadata");
401
318
  }
402
319
  if (config.require_completed_at && isBlank(metadata.completed_at)) {
403
320
  return failResult("task-meta", "Expected completed_at to be present");
@@ -481,11 +398,11 @@ async function checkRequiredPrDelivery({ taskDir, repositoryRoot, mode }) {
481
398
  }
482
399
  return passResult('required-pr-delivery', `Pull request delivery policy satisfied (${status})`);
483
400
  }
484
- function validateTaskBranch(metadata) {
401
+ function validateTaskBranch(metadata, repoRoot) {
485
402
  if (isBlank(metadata.branch)) {
486
403
  return null;
487
404
  }
488
- const projectName = loadProjectName();
405
+ const projectName = loadProjectName(repoRoot);
489
406
  const expectedPrefix = projectName ? `${projectName}-${metadata.type}-` : "";
490
407
  if (expectedPrefix && !String(metadata.branch).startsWith(expectedPrefix)) {
491
408
  return `Invalid branch: expected prefix '${expectedPrefix}', got '${metadata.branch}'`;
@@ -496,7 +413,7 @@ function validateTaskBranch(metadata) {
496
413
  }
497
414
  return null;
498
415
  }
499
- function loadProjectName() {
416
+ function loadProjectName(repoRoot) {
500
417
  const configPath = path.join(repoRoot, ".agents", ".airc.json");
501
418
  if (!fs.existsSync(configPath)) {
502
419
  return "";
@@ -647,30 +564,17 @@ function checkImplementationInput({ taskDir, artifactFile }) {
647
564
  const artifactPath = path.join(taskDir, artifactFile);
648
565
  if (!safeStat(artifactPath)?.isFile())
649
566
  return failResult("implementation-input", `Artifact not found: ${artifactFile}`);
650
- const inputSection = getSectionContent(task.content, ["实现输入", "Implementation Inputs"]);
651
- const rows = [];
652
- if (inputSection) {
653
- const table = inputSection.split(/\r?\n/).filter((line) => line.trim().startsWith("|"));
654
- const cells = (line) => line.split("|").slice(1, -1).map((cell) => cell.trim());
655
- const expected = ["id", "ledger_id", "decision_evidence", "stage", "needs_implementation", "decided_at", "status", "consumed_by"];
656
- if (table.length < 2 || JSON.stringify(cells(table[0])) !== JSON.stringify(expected)) {
657
- return failResult("implementation-input", "Implementation Inputs table schema is invalid");
658
- }
659
- const seen = new Set();
660
- for (const line of table.slice(2)) {
661
- const row = cells(line);
662
- if (row.length !== 8 || !/^II-[1-9]\d*$/.test(row[0]) || seen.has(row[0])) {
663
- return failResult("implementation-input", "Implementation Inputs table contains an invalid or duplicate id");
664
- }
665
- seen.add(row[0]);
666
- rows.push({ id: row[0], ledgerId: row[1], evidence: row[2], stage: row[3], needs: row[4], status: row[6], consumedBy: row[7] });
667
- }
567
+ let rows;
568
+ try {
569
+ rows = parseImplementationInputs(task.content).rows;
668
570
  }
669
- const logSection = getSectionContent(task.content, ["活动日志", "Activity Log"]);
670
- const doneActions = logSection.split(/\r?\n/).flatMap((line) => {
671
- const match = line.trim().match(ACTIVITY_LOG_PATTERN);
672
- return match && !ACTIVITY_LOG_STARTED_RE.test(match[2]) ? [match[2]] : [];
673
- });
571
+ catch (error) {
572
+ return failResult("implementation-input", `Invalid Implementation Inputs: ${error instanceof Error ? error.message : String(error)}`);
573
+ }
574
+ const doneActions = (inspectActivityLog(task.content).section?.entries ?? [])
575
+ .filter((entry) => !ACTIVITY_LOG_STARTED_RE.test(entry.step))
576
+ .map((entry) => entry.step)
577
+ .filter((step) => /^(?:Code Task|Code) \(Round \d+/.test(step));
674
578
  const latestAction = doneActions.at(-1) || "";
675
579
  const actionDecision = /(?:Code Task|Code) \(Round \d+, decision (II-[1-9]\d*)\)/.exec(latestAction)?.[1] || null;
676
580
  const report = fs.readFileSync(artifactPath, "utf8");
@@ -698,10 +602,10 @@ function checkImplementationInput({ taskDir, artifactFile }) {
698
602
  if (matches.length !== 1)
699
603
  return failResult("implementation-input", `${actionDecision} is missing or duplicated in task table`);
700
604
  const row = matches[0];
701
- if (row.stage !== "code" || row.needs !== "true" || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.evidence) {
605
+ if (row.stage !== "code" || !row.needsImplementation || row.status !== "consumed" || row.consumedBy !== artifactFile || !row.decisionEvidence) {
702
606
  return failResult("implementation-input", `${actionDecision} is not a consumed input for ${artifactFile}`);
703
607
  }
704
- if (reportLedger !== row.ledgerId || reportEvidence !== row.evidence) {
608
+ if (reportLedger !== row.ledgerId || reportEvidence !== row.decisionEvidence) {
705
609
  return failResult("implementation-input", `${actionDecision} report identity does not match task table evidence`);
706
610
  }
707
611
  return passResult("implementation-input", `${actionDecision} matches Activity Log, report, and task table`);
@@ -711,27 +615,22 @@ function checkActivityLog({ taskDir, config }) {
711
615
  if (!task.ok) {
712
616
  return failResult("activity-log", task.message);
713
617
  }
714
- const logSection = getSectionContent(task.content, ["活动日志", "Activity Log"]);
715
- if (!logSection) {
716
- return failResult("activity-log", "Activity Log section not found");
717
- }
718
- const entries = logSection
719
- .split(/\r?\n/)
720
- .map((line) => line.trim())
721
- .filter((line) => line.startsWith("- "));
722
- if (entries.length === 0) {
618
+ const { section, invalidEntries } = inspectActivityLog(task.content);
619
+ if (!section)
620
+ return failResult("activity-log", "Activity Log section not found or ambiguous");
621
+ if (invalidEntries.length)
622
+ return failResult("activity-log", `Invalid Activity Log entry format: ${invalidEntries[0]}`);
623
+ const entries = section.entries;
624
+ if (entries.length === 0)
723
625
  return failResult("activity-log", "Activity Log has no entries");
724
- }
725
626
  let previousTimestamp = "";
726
627
  let latestAction = "";
727
628
  let latestTimestamp = "";
728
629
  const doneActions = [];
729
630
  for (const entry of entries) {
730
- const match = entry.match(ACTIVITY_LOG_PATTERN);
731
- if (!match) {
732
- return failResult("activity-log", `Invalid Activity Log entry format: ${entry}`);
733
- }
734
- const [, timestamp, action] = match;
631
+ if (!entry.note.trim())
632
+ return failResult("activity-log", "Activity Log entry note is required");
633
+ const { time: timestamp, step: action } = entry;
735
634
  if (previousTimestamp && timestamp < previousTimestamp) {
736
635
  return failResult("activity-log", "Activity Log timestamps are not in ascending order");
737
636
  }
@@ -786,111 +685,7 @@ function checkCompletionChecklist({ taskDir, config }) {
786
685
  }
787
686
  return passResult("completion-checklist", `Completion Checklist valid (${items.length} items checked)`);
788
687
  }
789
- function splitMarkdownTableRow(line) {
790
- let value = String(line || "").trim();
791
- if (!value.startsWith("|")) {
792
- return [];
793
- }
794
- value = value.replace(/^\|/, "").replace(/\|$/, "");
795
- const cells = [];
796
- let cell = "";
797
- for (let index = 0; index < value.length; index += 1) {
798
- const char = value[index];
799
- if (char === "|" && !isEscapedAt(value, index)) {
800
- cells.push(unescapeMarkdownTableCell(cell.trim()));
801
- cell = "";
802
- continue;
803
- }
804
- cell += char;
805
- }
806
- cells.push(unescapeMarkdownTableCell(cell.trim()));
807
- return cells;
808
- }
809
- function unescapeMarkdownTableCell(value) {
810
- let output = "";
811
- for (let index = 0; index < value.length; index += 1) {
812
- const char = value[index];
813
- const next = value[index + 1];
814
- if (char === "\\" && (next === "\\" || next === "|")) {
815
- output += next;
816
- index += 1;
817
- continue;
818
- }
819
- output += char;
820
- }
821
- return output;
822
- }
823
- function isEscapedAt(value, index) {
824
- let backslashes = 0;
825
- for (let cursor = index - 1; cursor >= 0 && value[cursor] === "\\"; cursor -= 1) {
826
- backslashes += 1;
827
- }
828
- return backslashes % 2 === 1;
829
- }
830
- function parseWorkflowWarningRows(section) {
831
- const rows = [];
832
- for (const rawLine of String(section || "").split(/\r?\n/)) {
833
- const cells = splitMarkdownTableRow(rawLine);
834
- if (cells.length === 0) {
835
- continue;
836
- }
837
- if ((cells[0] || "").toLowerCase() === "id") {
838
- continue;
839
- }
840
- if (cells.every((cell) => /^:?-{3,}:?$/.test(cell))) {
841
- continue;
842
- }
843
- rows.push(cells);
844
- }
845
- return rows;
846
- }
847
- function validateWorkflowWarnings(content) {
848
- const section = getSectionContent(content, WORKFLOW_WARNING_SECTION_NAMES);
849
- if (!section.trim()) {
850
- return [];
851
- }
852
- const rows = parseWorkflowWarningRows(section);
853
- const errors = [];
854
- for (const cells of rows) {
855
- if (cells.length < 11) {
856
- errors.push(`malformed row (expected 11 columns): ${cells.join(" | ")}`);
857
- continue;
858
- }
859
- const [id, time, step, severity, code, status, target, message, action, resolvedAt, resolution] = cells;
860
- if (!WORKFLOW_WARNING_ID_PATTERN.test(id)) {
861
- errors.push(`${id || "(empty id)"}: invalid id`);
862
- }
863
- if (!DATE_TIME_PATTERN.test(time)) {
864
- errors.push(`${id}: invalid time '${time}'`);
865
- }
866
- if (isBlank(step)) {
867
- errors.push(`${id}: step is required`);
868
- }
869
- if (!WORKFLOW_WARNING_SEVERITIES.has(severity)) {
870
- errors.push(`${id}: illegal severity '${severity}'`);
871
- }
872
- if (isBlank(code)) {
873
- errors.push(`${id}: code is required`);
874
- }
875
- if (!WORKFLOW_WARNING_STATUSES.has(status)) {
876
- errors.push(`${id}: illegal status '${status}'`);
877
- }
878
- if (isBlank(target)) {
879
- errors.push(`${id}: target is required`);
880
- }
881
- if (isBlank(message)) {
882
- errors.push(`${id}: message is required`);
883
- }
884
- if (status === "open" && isBlank(action)) {
885
- errors.push(`${id}: open warning requires action`);
886
- }
887
- if ((status === "resolved" || status === "ignored") && (isBlank(resolvedAt) || isBlank(resolution))) {
888
- errors.push(`${id}: ${status} warning requires resolved_at and resolution`);
889
- }
890
- }
891
- return errors;
892
- }
893
- function resolveReviewSetting(config, key, fallback) {
688
+ function resolveReviewSetting(config, key, fallback, repoRoot) {
894
689
  if (config && config[key] !== undefined && config[key] !== null) {
895
690
  return config[key];
896
691
  }
@@ -900,7 +695,7 @@ function resolveReviewSetting(config, key, fallback) {
900
695
  }
901
696
  return fallback;
902
697
  }
903
- function checkReviewLedger({ taskDir, config }) {
698
+ function checkReviewLedger({ taskDir, config, repositoryRoot }) {
904
699
  const task = loadTask(taskDir);
905
700
  if (!task.ok) {
906
701
  return failResult("review-ledger", task.message);
@@ -910,9 +705,7 @@ function checkReviewLedger({ taskDir, config }) {
910
705
  const ledger = parseLedgerDocument(task.content);
911
706
  if (!ledger.present)
912
707
  return failResult("review-ledger", `${LEDGER_SECTION_MISSING_CODE}: ${LEDGER_SECTION_MISSING_MESSAGE}`);
913
- rows = ledger.rows.map((row) => [
914
- row.id, row.stage, row.round, row.severity, row.status, row.evidence
915
- ]);
708
+ rows = ledger.rows;
916
709
  }
917
710
  catch (error) {
918
711
  return failResult("review-ledger", `Invalid disagreement ledger: ${error instanceof Error ? error.message : String(error)}`);
@@ -921,15 +714,11 @@ function checkReviewLedger({ taskDir, config }) {
921
714
  return passResult("review-ledger", "Disagreement ledger has no entries");
922
715
  }
923
716
  const stageScope = Array.isArray(config.stage_scope) ? config.stage_scope : null;
924
- const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS));
717
+ const maxRounds = Number(resolveReviewSetting(config, "maxHandshakeRounds", DEFAULT_MAX_HANDSHAKE_ROUNDS, repositoryRoot));
925
718
  const problems = [];
926
719
  let inScopeCount = 0;
927
- for (const cells of rows) {
928
- if (cells.length < 6) {
929
- problems.push(`malformed row (expected 6 columns): ${cells.join(" | ")}`);
930
- continue;
931
- }
932
- const [id, stage, roundRaw, , status, evidence] = cells;
720
+ for (const row of rows) {
721
+ const { id, stage, round: roundRaw, status, evidence } = row;
933
722
  const stageScoped = stageScope ? stageScope.includes(stage) : true;
934
723
  // post-review-commit exemption rows are consumed by the post-review-commit
935
724
  // check, not enforced here.
@@ -940,8 +729,9 @@ function checkReviewLedger({ taskDir, config }) {
940
729
  continue;
941
730
  }
942
731
  inScopeCount += 1;
943
- if (!LEDGER_STATUSES.has(status)) {
944
- problems.push(`${id}: illegal status '${status}'`);
732
+ const invalid = validateLedgerRows([row]);
733
+ if (invalid) {
734
+ problems.push(`${invalid.code}: ${invalid.message}`);
945
735
  continue;
946
736
  }
947
737
  if (status !== "open" && evidence === "") {
@@ -950,11 +740,11 @@ function checkReviewLedger({ taskDir, config }) {
950
740
  const round = Number.parseInt(roundRaw, 10);
951
741
  if (Number.isFinite(round) &&
952
742
  round >= maxRounds &&
953
- !LEDGER_TERMINAL_OK.has(status) &&
743
+ !LEDGER_TERMINAL.has(status) &&
954
744
  status !== "needs-human-decision") {
955
745
  problems.push(`${id}: round ${round} reached limit ${maxRounds} without convergence; escalate to needs-human-decision`);
956
746
  }
957
- if (!LEDGER_TERMINAL_OK.has(status)) {
747
+ if (!LEDGER_TERMINAL.has(status)) {
958
748
  problems.push(`${id}: unresolved (status '${status}')`);
959
749
  }
960
750
  }
@@ -964,7 +754,7 @@ function checkReviewLedger({ taskDir, config }) {
964
754
  const scopeLabel = stageScope ? ` for stages [${stageScope.join(", ")}]` : "";
965
755
  return passResult("review-ledger", `Disagreement ledger clean (${inScopeCount} in-scope entries terminal${scopeLabel})`);
966
756
  }
967
- function checkManualValidation({ taskDir }) {
757
+ async function checkManualValidation({ taskDir, repositoryRoot }) {
968
758
  // 1. Latest review-code artifact; none -> pass (no review, check not applicable).
969
759
  const review = findAuthoritativeReviewCodeArtifact(taskDir);
970
760
  if (!review.ok) {
@@ -995,10 +785,23 @@ function checkManualValidation({ taskDir }) {
995
785
  const task = loadTask(taskDir);
996
786
  if (!task.ok)
997
787
  return failResult("manual-validation", task.message);
998
- const log = getSectionContent(task.content, ["活动日志", "Activity Log"]);
999
- const completed = new RegExp(`\\*\\*Complete Manual Validation\\*\\*[\\s\\S]*?Manual validation passed → ${escapeRegExp(artifactName)};`);
1000
- if (!completed.test(log)) {
1001
- return failResult("manual-validation", `Manual validation artifact exists but completion is not recorded for ${artifactName}: re-run /complete-manual-validation`);
788
+ const completion = readManualValidationCompletion(taskDir, {
789
+ taskId: task.metadata.id,
790
+ artifact: artifactName
791
+ });
792
+ if (!completion.ok) {
793
+ const source = completion.error.code.startsWith('MANUAL_VALIDATION_RECEIPT_') ? 'receipt' : 'transaction';
794
+ return failResult("manual-validation", `Manual validation ${source} is unavailable: ${completion.error.message}`);
795
+ }
796
+ const { receipt, transaction } = completion.value;
797
+ if (transaction.phase !== "committed" || !transaction.eventAppended || !transaction.postWriteVerified) {
798
+ return failResult("manual-validation", "Manual validation transaction has not reached the committed post-write-verified state");
799
+ }
800
+ if (transaction.pendingSummaryDigest !== receipt.pendingSummaryDigest || transaction.finalSummaryDigest !== receipt.finalSummaryDigest) {
801
+ return failResult("manual-validation", "Manual validation summary digests do not match the committed receipt");
802
+ }
803
+ if (sha256File(resolved.path) !== receipt.artifactSha256) {
804
+ return failResult("manual-validation", `Manual validation artifact digest does not match the receipt for ${artifactName}`);
1002
805
  }
1003
806
  // 6. Timing correlation (PL-3 fix, PL-4 corrected): the completion entry must
1004
807
  // sit AFTER the latest review-code round's completion entry in the
@@ -1007,21 +810,39 @@ function checkManualValidation({ taskDir }) {
1007
810
  // which indexOf never matches). Not reusing completed.exec().index: exec
1008
811
  // anchors to the first '**Complete Manual Validation**' heading, which can
1009
812
  // belong to an earlier round's entry and misorder the standard path.
1010
- const reviewDoneIndex = log.indexOf(`**Review Code (Round ${review.round})** by `);
1011
- const completedIndex = log.indexOf(`Manual validation passed → ${artifactName};`);
1012
- if (reviewDoneIndex === -1) {
1013
- // The latest review-code round's completion entry is missing entirely (abnormal
1014
- // state, e.g. a restored/historical task without a review-code.completed record).
1015
- // Re-running complete-manual-validation cannot restore it, so the remediation
1016
- // targets the review record itself. Fail closed either way.
1017
- return failResult("manual-validation", `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`);
1018
- }
1019
- if (completedIndex < reviewDoneIndex) {
1020
- return failResult("manual-validation", `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`);
1021
- }
1022
- return passResult("manual-validation", `Manual validation completed → ${artifactName}`);
813
+ const inspectedLog = inspectActivityLog(task.content);
814
+ if (!inspectedLog.section)
815
+ return failResult("manual-validation", "Activity Log is missing or invalid");
816
+ const reviewDoneIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === `Review Code (Round ${review.round})`);
817
+ const completedIndex = inspectedLog.section.entries.findIndex((entry) => entry.step === "Complete Manual Validation"
818
+ && entry.note.includes(`Manual validation passed → ${artifactName};`)
819
+ && entry.note.includes(`transaction=${receipt.transactionId};`)
820
+ && entry.note.includes(`receipt=${receipt.receiptDigest};`)
821
+ && entry.note.includes(`head=${receipt.prHeadSha}`));
822
+ if (reviewDoneIndex === -1)
823
+ return failResult("manual-validation", `Latest review-code (round ${review.round}) completion entry is missing from the Activity Log`);
824
+ if (completedIndex === -1)
825
+ return failResult("manual-validation", `Committed manual validation completion is not recorded for ${artifactName}`);
826
+ if (completedIndex < reviewDoneIndex)
827
+ return failResult("manual-validation", `Latest review-code (round ${review.round}) came after the manual validation completion recorded for ${artifactName}`);
828
+ const fact = readPrDeliveryFact(task.metadata);
829
+ if (fact.status === "invalid")
830
+ return failResult("manual-validation", fact.error.message);
831
+ if (fact.status === "valid" && fact.fact.state === "bound") {
832
+ const inspected = await inspectPlatformPullRequest(task.metadata.id, { cwd: repositoryRoot });
833
+ if (!inspected.pullRequest)
834
+ return failResult("manual-validation", inspected.error?.message ?? "canonical pull-request head is unavailable");
835
+ if (inspected.pullRequest.head.sha !== receipt.prHeadSha)
836
+ return failResult("manual-validation", "manual validation receipt is stale for the current pull-request head");
837
+ const summary = await summaryCommentState(task.metadata.id, { cwd: repositoryRoot });
838
+ if (!summary.comment)
839
+ return failResult("manual-validation", "canonical pull-request summary comment is unavailable");
840
+ if (!manualValidationFinalSummaryProjectionMatches(summary.comment.body, receipt))
841
+ return failResult("manual-validation", "canonical pull-request summary does not match the committed manual validation projection");
842
+ }
843
+ return passResult("manual-validation", `Manual validation completed → ${artifactName} (committed receipt and post-write verification)`);
1023
844
  }
1024
- async function checkPostReviewCommit({ taskDir, config }) {
845
+ async function checkPostReviewCommit({ taskDir, config, repositoryRoot }) {
1025
846
  const reviewArtifact = findAuthoritativeReviewCodeArtifact(taskDir);
1026
847
  if (!reviewArtifact.ok) {
1027
848
  if (reviewArtifact.error)
@@ -1043,7 +864,7 @@ async function checkPostReviewCommit({ taskDir, config }) {
1043
864
  return failResult("post-review-commit", factRead.error.message);
1044
865
  const fact = factRead.status === 'valid' ? factRead.fact : null;
1045
866
  const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
1046
- const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repoRoot));
867
+ const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repositoryRoot));
1047
868
  const hasPullRequest = fact?.state === 'bound';
1048
869
  let inspected = null;
1049
870
  if (hasPullRequest) {
@@ -1189,7 +1010,7 @@ function resolvePostReviewExemption(content) {
1189
1010
  };
1190
1011
  }
1191
1012
  }
1192
- function checkReviewFact({ taskDir, artifactFile }) {
1013
+ function checkReviewFact({ taskDir, artifactFile, repositoryRoot }) {
1193
1014
  const resolvedArtifact = resolveArtifactPath(taskDir, "review-code.md|review-code-r{N}.md", artifactFile);
1194
1015
  if (!resolvedArtifact.ok) {
1195
1016
  return failResult("review-fact", resolvedArtifact.message);
@@ -1255,7 +1076,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
1255
1076
  mode: "worktree",
1256
1077
  baseline,
1257
1078
  diffBase,
1258
- globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repoRoot))
1079
+ globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repositoryRoot))
1259
1080
  });
1260
1081
  }
1261
1082
  catch {
@@ -1342,40 +1163,12 @@ function resolveArtifactPath(taskDir, filePattern, artifactFile) {
1342
1163
  return { ok: true, path: path.join(taskDir, matches[0].fileName) };
1343
1164
  }
1344
1165
  function getSectionContent(content, names) {
1345
- const lines = content.split(/\r?\n/);
1346
- function visibleHeadings() {
1347
- const headings = [];
1348
- let fence = null;
1349
- for (let index = 0; index < lines.length; index += 1) {
1350
- const line = lines[index];
1351
- if (fence) {
1352
- const closer = line.match(/^ {0,3}(`+|~+)\s*$/);
1353
- if (closer && closer[1][0] === fence.character && closer[1].length >= fence.length) {
1354
- fence = null;
1355
- }
1356
- continue;
1357
- }
1358
- const opener = line.match(/^ {0,3}(`{3,}|~{3,})(?:[^`~].*)?$/);
1359
- if (opener) {
1360
- fence = { character: opener[1][0], length: opener[1].length };
1361
- continue;
1362
- }
1363
- if (line.startsWith("## ")) {
1364
- headings.push({ index, text: line.trim() });
1365
- }
1366
- }
1367
- return headings;
1368
- }
1369
- const headings = visibleHeadings();
1166
+ const headings = scanVisibleMarkdown(content).headings.filter((heading) => heading.level === 2);
1370
1167
  for (const name of names) {
1371
- const heading = `## ${name}`;
1372
- const position = headings.findIndex((item) => item.text === heading);
1373
- if (position === -1) {
1168
+ const position = headings.findIndex((heading) => heading.text === name);
1169
+ if (position === -1)
1374
1170
  continue;
1375
- }
1376
- const startIndex = headings[position].index;
1377
- const endIndex = headings[position + 1]?.index ?? lines.length;
1378
- return lines.slice(startIndex + 1, endIndex).join("\n").trim();
1171
+ return content.slice(headings[position].end + 1, headings[position + 1]?.start ?? content.length).replace(/\r\n/g, "\n").trim();
1379
1172
  }
1380
1173
  return "";
1381
1174
  }
@@ -1391,16 +1184,6 @@ function getCheckedRequirements(content) {
1391
1184
  .filter(Boolean)
1392
1185
  .map((match) => match[1].trim());
1393
1186
  }
1394
- function parseIssueNumber(value) {
1395
- if (isBlank(value) || value === "N/A") {
1396
- return null;
1397
- }
1398
- const match = String(value).match(/\d+/);
1399
- return match ? Number(match[0]) : null;
1400
- }
1401
- function parsePrNumber(value) {
1402
- return parseIssueNumber(value);
1403
- }
1404
1187
  // === Utilities ===
1405
1188
  function normalizeContent(text) {
1406
1189
  return String(text || "")
@@ -1479,9 +1262,8 @@ function isBlank(value) {
1479
1262
  return value === undefined || value === null || String(value).trim() === "";
1480
1263
  }
1481
1264
  async function verifyInProcess({ mode, skillName, taskDir, artifactFile, checks: requestedChecks, repositoryRoot }) {
1482
- if (repositoryRoot)
1483
- repoRoot = path.resolve(repositoryRoot);
1484
- else {
1265
+ let repoRoot = repositoryRoot ? path.resolve(repositoryRoot) : defaultRepoRoot;
1266
+ if (!repositoryRoot) {
1485
1267
  let cursor = path.resolve(taskDir);
1486
1268
  while (path.dirname(cursor) !== cursor && !fs.existsSync(path.join(cursor, ".agents")))
1487
1269
  cursor = path.dirname(cursor);