@fitlab-ai/agent-infra 0.9.0 → 0.9.2

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 (327) hide show
  1. package/README.md +22 -5
  2. package/README.zh-CN.md +21 -5
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +20 -0
  6. package/dist/lib/agent-client.js +163 -0
  7. package/dist/lib/agent-clients/adapter.js +294 -0
  8. package/dist/lib/agent-clients/adapters/claude-code.js +62 -0
  9. package/dist/lib/agent-clients/adapters/codex-sandbox.js +210 -0
  10. package/dist/lib/agent-clients/adapters/codex.js +54 -0
  11. package/dist/lib/agent-clients/adapters/gemini-cli.js +64 -0
  12. package/dist/lib/agent-clients/adapters/index.js +20 -0
  13. package/dist/lib/agent-clients/adapters/opencode.js +64 -0
  14. package/dist/lib/agent-clients/config.js +177 -0
  15. package/dist/lib/agent-clients/custom-tuis.js +99 -0
  16. package/dist/lib/agent-clients/invocation.js +9 -0
  17. package/dist/lib/agent-clients/next-steps.js +38 -0
  18. package/dist/lib/agent-clients/project-assets.js +45 -0
  19. package/dist/lib/agent-clients/reconcile.js +235 -0
  20. package/dist/lib/agent-clients/registry.js +72 -0
  21. package/dist/lib/agent-clients/schema.js +57 -0
  22. package/dist/lib/agent-clients/types.js +29 -0
  23. package/dist/lib/builtin-tuis.js +9 -14
  24. package/dist/lib/defaults.json +85 -73
  25. package/dist/lib/git/review-snapshot.js +25 -10
  26. package/dist/lib/git/reviewed-commit-equivalence.js +110 -0
  27. package/dist/lib/init.js +47 -91
  28. package/dist/lib/internal/agent-client.js +117 -0
  29. package/dist/lib/internal/git-workflow.js +1 -1
  30. package/dist/lib/internal/platform-release-notes.js +53 -0
  31. package/dist/lib/internal/release-workflow.js +175 -17
  32. package/dist/lib/internal/task-orchestration.js +151 -0
  33. package/dist/lib/internal/task-review.js +65 -0
  34. package/dist/lib/merge.js +2 -1
  35. package/dist/lib/platform/adapters.js +38 -1
  36. package/dist/lib/platform/change-request-git-evidence.js +113 -0
  37. package/dist/lib/platform/github-release-notes.js +96 -0
  38. package/dist/lib/platform/issues.js +4 -2
  39. package/dist/lib/platform/merged-pr-equivalence.js +84 -0
  40. package/dist/lib/platform/pr-checks.js +43 -15
  41. package/dist/lib/platform/pull-requests.js +113 -7
  42. package/dist/lib/platform/release-notes.js +143 -0
  43. package/dist/lib/platform/releases.js +1 -1
  44. package/dist/lib/platform/verification-required.js +31 -9
  45. package/dist/lib/prompt.js +15 -3
  46. package/dist/lib/release/channels.js +4 -1
  47. package/dist/lib/release/workflow.js +4 -2
  48. package/dist/lib/remove-dir.js +25 -0
  49. package/dist/lib/run/tui.js +8 -2
  50. package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
  51. package/dist/lib/sandbox/build-proxy.js +63 -0
  52. package/dist/lib/sandbox/clipboard/linux.js +2 -1
  53. package/dist/lib/sandbox/commands/create.js +133 -189
  54. package/dist/lib/sandbox/commands/enter.js +17 -1
  55. package/dist/lib/sandbox/commands/prune.js +2 -2
  56. package/dist/lib/sandbox/commands/rebuild.js +24 -7
  57. package/dist/lib/sandbox/commands/rm.js +3 -2
  58. package/dist/lib/sandbox/config.js +21 -4
  59. package/dist/lib/sandbox/constants.js +3 -0
  60. package/dist/lib/sandbox/dockerfile.js +2 -1
  61. package/dist/lib/sandbox/image-build.js +2 -1
  62. package/dist/lib/sandbox/managed-fs.js +10 -5
  63. package/dist/lib/sandbox/recovery.js +52 -36
  64. package/dist/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  65. package/dist/lib/sandbox/runtimes/base.dockerfile +8 -1
  66. package/dist/lib/sandbox/runtimes/java17.dockerfile +8 -1
  67. package/dist/lib/sandbox/runtimes/java21.dockerfile +8 -1
  68. package/dist/lib/sandbox/runtimes/node20.dockerfile +8 -1
  69. package/dist/lib/sandbox/runtimes/node22.dockerfile +8 -1
  70. package/dist/lib/sandbox/runtimes/python3.dockerfile +8 -1
  71. package/dist/lib/sandbox/shell.js +3 -2
  72. package/dist/lib/sandbox/tool-types.js +8 -0
  73. package/dist/lib/sandbox/tools.js +2 -126
  74. package/dist/lib/task/artifact-lifecycle.js +1 -49
  75. package/dist/lib/task/commands/decisions.js +50 -20
  76. package/dist/lib/task/commands/issue-body.js +10 -5
  77. package/dist/lib/task/delegation-receipts.js +107 -0
  78. package/dist/lib/task/events.js +101 -2
  79. package/dist/lib/task/issue-form.js +2 -0
  80. package/dist/lib/task/orchestration.js +420 -0
  81. package/dist/lib/task/review-artifacts.js +143 -59
  82. package/dist/lib/task/review-finalization.js +166 -0
  83. package/dist/lib/task/review-fingerprint.js +13 -0
  84. package/dist/lib/task/verification-checks.js +2 -1
  85. package/dist/lib/task/verification-engine.js +168 -23
  86. package/dist/lib/task/verification-review.js +1 -1
  87. package/dist/lib/task/verification.js +4 -2
  88. package/dist/lib/task/workspace-snapshot.js +34 -0
  89. package/dist/lib/update.js +42 -161
  90. package/lib/agent-client.ts +214 -0
  91. package/lib/agent-clients/adapter.ts +461 -0
  92. package/lib/agent-clients/adapters/claude-code.ts +70 -0
  93. package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
  94. package/lib/agent-clients/adapters/codex.ts +58 -0
  95. package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
  96. package/lib/agent-clients/adapters/index.ts +27 -0
  97. package/lib/agent-clients/adapters/opencode.ts +66 -0
  98. package/lib/agent-clients/config.ts +278 -0
  99. package/lib/agent-clients/custom-tuis.ts +149 -0
  100. package/lib/agent-clients/invocation.ts +19 -0
  101. package/lib/agent-clients/next-steps.ts +72 -0
  102. package/lib/agent-clients/project-assets.ts +96 -0
  103. package/lib/agent-clients/reconcile.ts +324 -0
  104. package/lib/agent-clients/registry.ts +144 -0
  105. package/lib/agent-clients/schema.ts +62 -0
  106. package/lib/agent-clients/types.ts +78 -0
  107. package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
  108. package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
  109. package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
  110. package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
  111. package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
  112. package/lib/builtin-tuis.ts +16 -15
  113. package/lib/defaults.json +24 -12
  114. package/lib/git/review-snapshot.ts +39 -9
  115. package/lib/git/reviewed-commit-equivalence.ts +135 -0
  116. package/lib/init.ts +53 -121
  117. package/lib/internal/agent-client.ts +131 -0
  118. package/lib/internal/git-workflow.ts +1 -1
  119. package/lib/internal/platform-release-notes.ts +55 -0
  120. package/lib/internal/release-workflow.ts +172 -18
  121. package/lib/internal/task-orchestration.ts +132 -0
  122. package/lib/internal/task-review.ts +65 -0
  123. package/lib/merge.ts +2 -1
  124. package/lib/platform/adapters.ts +142 -3
  125. package/lib/platform/change-request-git-evidence.ts +159 -0
  126. package/lib/platform/github-release-notes.ts +132 -0
  127. package/lib/platform/issues.ts +6 -4
  128. package/lib/platform/merged-pr-equivalence.ts +107 -0
  129. package/lib/platform/pr-checks.ts +57 -28
  130. package/lib/platform/pull-requests.ts +140 -25
  131. package/lib/platform/release-notes.ts +167 -0
  132. package/lib/platform/releases.ts +1 -1
  133. package/lib/platform/verification-required.ts +37 -9
  134. package/lib/prompt.ts +16 -3
  135. package/lib/release/channels.ts +4 -1
  136. package/lib/release/workflow.ts +4 -3
  137. package/lib/remove-dir.ts +28 -0
  138. package/lib/run/tui.ts +9 -1
  139. package/lib/sandbox/agent-client-reconciler.ts +378 -0
  140. package/lib/sandbox/build-proxy.ts +94 -0
  141. package/lib/sandbox/clipboard/linux.ts +2 -1
  142. package/lib/sandbox/commands/create.ts +188 -203
  143. package/lib/sandbox/commands/enter.ts +23 -1
  144. package/lib/sandbox/commands/prune.ts +2 -2
  145. package/lib/sandbox/commands/rebuild.ts +29 -7
  146. package/lib/sandbox/commands/rm.ts +3 -2
  147. package/lib/sandbox/config.ts +31 -4
  148. package/lib/sandbox/constants.ts +6 -0
  149. package/lib/sandbox/dockerfile.ts +2 -1
  150. package/lib/sandbox/image-build.ts +4 -1
  151. package/lib/sandbox/managed-fs.ts +18 -5
  152. package/lib/sandbox/recovery.ts +98 -67
  153. package/lib/sandbox/runtimes/ai-tools.dockerfile +24 -3
  154. package/lib/sandbox/runtimes/base.dockerfile +8 -1
  155. package/lib/sandbox/runtimes/java17.dockerfile +8 -1
  156. package/lib/sandbox/runtimes/java21.dockerfile +8 -1
  157. package/lib/sandbox/runtimes/node20.dockerfile +8 -1
  158. package/lib/sandbox/runtimes/node22.dockerfile +8 -1
  159. package/lib/sandbox/runtimes/python3.dockerfile +8 -1
  160. package/lib/sandbox/shell.ts +4 -2
  161. package/lib/sandbox/tool-types.ts +143 -0
  162. package/lib/sandbox/tools.ts +5 -157
  163. package/lib/task/artifact-lifecycle.ts +1 -38
  164. package/lib/task/commands/decisions.ts +53 -20
  165. package/lib/task/commands/issue-body.ts +10 -5
  166. package/lib/task/delegation-receipts.ts +170 -0
  167. package/lib/task/events.ts +111 -3
  168. package/lib/task/issue-form.ts +4 -0
  169. package/lib/task/orchestration.ts +543 -0
  170. package/lib/task/review-artifacts.ts +201 -69
  171. package/lib/task/review-finalization.ts +275 -0
  172. package/lib/task/review-fingerprint.ts +15 -1
  173. package/lib/task/verification-checks.ts +2 -1
  174. package/lib/task/verification-engine.ts +190 -25
  175. package/lib/task/verification-review.ts +2 -0
  176. package/lib/task/verification.ts +6 -3
  177. package/lib/task/workspace-snapshot.ts +36 -0
  178. package/lib/update.ts +48 -184
  179. package/package.json +2 -2
  180. package/templates/.agents/README.en.md +21 -20
  181. package/templates/.agents/README.zh-CN.md +21 -20
  182. package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
  183. package/templates/.agents/rules/README.en.md +2 -0
  184. package/templates/.agents/rules/README.zh-CN.md +2 -0
  185. package/templates/.agents/rules/commit-and-pr.en.md +1 -0
  186. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
  187. package/templates/.agents/rules/human-decision-context.en.md +14 -12
  188. package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
  189. package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
  190. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
  191. package/templates/.agents/rules/next-step-output.en.md +16 -0
  192. package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
  193. package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
  194. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
  195. package/templates/.agents/rules/release-commands.en.md +2 -2
  196. package/templates/.agents/rules/release-commands.github.en.md +15 -39
  197. package/templates/.agents/rules/release-commands.github.zh-CN.md +14 -38
  198. package/templates/.agents/rules/release-commands.zh-CN.md +2 -2
  199. package/templates/.agents/rules/review-handshake.en.md +4 -3
  200. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -3
  201. package/templates/.agents/rules/review-method.en.md +113 -0
  202. package/templates/.agents/rules/review-method.zh-CN.md +98 -0
  203. package/templates/.agents/rules/testing-discipline.en.md +20 -2
  204. package/templates/.agents/rules/testing-discipline.zh-CN.md +20 -2
  205. package/templates/.agents/skills/analyze-task/SKILL.en.md +9 -6
  206. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +9 -6
  207. package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
  208. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
  209. package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
  210. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
  211. package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
  212. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
  213. package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
  214. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
  215. package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
  216. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
  217. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  218. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  219. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
  220. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
  221. package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
  222. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
  223. package/templates/.agents/skills/commit/SKILL.en.md +11 -1
  224. package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
  225. package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
  226. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
  227. package/templates/.agents/skills/complete-task/SKILL.en.md +3 -3
  228. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +3 -3
  229. package/templates/.agents/skills/complete-task/config/verify.en.json +0 -1
  230. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +0 -1
  231. package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
  232. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
  233. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
  234. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
  235. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -38
  236. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +16 -37
  237. package/templates/.agents/skills/create-task/SKILL.en.md +15 -11
  238. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +15 -11
  239. package/templates/.agents/skills/create-task/reference/context-capture.en.md +29 -0
  240. package/templates/.agents/skills/create-task/reference/context-capture.zh-CN.md +29 -0
  241. package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
  242. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
  243. package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
  244. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
  245. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
  246. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
  247. package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
  248. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
  249. package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
  250. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
  251. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
  252. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
  253. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  254. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  255. package/templates/.agents/skills/release/SKILL.en.md +1 -1
  256. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
  257. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
  258. package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
  259. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
  260. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
  261. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
  262. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
  263. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
  264. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
  265. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
  266. package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
  267. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
  268. package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
  269. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
  270. package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
  271. package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
  272. package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
  273. package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
  274. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
  275. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
  276. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
  277. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
  278. package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
  279. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
  280. package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
  281. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
  282. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
  283. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
  284. package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
  285. package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
  286. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
  287. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
  288. package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
  289. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
  290. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
  291. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
  292. package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
  293. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
  294. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
  295. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
  296. package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
  297. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
  298. package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
  299. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
  300. package/templates/.agents/skills/test/SKILL.en.md +4 -4
  301. package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
  302. package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
  303. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
  304. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
  305. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
  306. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
  307. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
  308. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
  309. package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
  310. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
  311. package/templates/.agents/templates/task.en.md +18 -0
  312. package/templates/.agents/templates/task.zh-CN.md +18 -0
  313. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
  314. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
  315. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
  316. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
  317. package/templates/.claude/commands/run-task.en.md +8 -0
  318. package/templates/.claude/commands/run-task.zh-CN.md +8 -0
  319. package/templates/.claude/settings.json +24 -0
  320. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
  321. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
  322. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
  323. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
  324. package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
  325. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
  326. package/templates/.opencode/commands/run-task.en.md +11 -0
  327. package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
@@ -0,0 +1,166 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { locateActivityLog, pairEntries } from './activity-log.js';
5
+ import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecycle.js';
6
+ import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
7
+ import { finalizeReviewSummaryContent } from './review-artifacts.js';
8
+ import { resolveTaskRef } from './resolve-ref.js';
9
+ import { validateOrchestrationStage } from './orchestration.js';
10
+ const STAGES = {
11
+ analysis: { family: 'review-analysis', action: 'Review Analysis' },
12
+ plan: { family: 'review-plan', action: 'Review Plan' },
13
+ code: { family: 'review-code', action: 'Review Code' }
14
+ };
15
+ const DEFAULT_FILE_SYSTEM = {
16
+ readFileSync: (file) => fs.readFileSync(file, 'utf8'),
17
+ statModeSync: (file) => fs.statSync(file).mode,
18
+ writeFileSync: (file, content, mode) => fs.writeFileSync(file, content, { encoding: 'utf8', flag: 'wx', mode }),
19
+ renameSync: (from, to) => fs.renameSync(from, to),
20
+ unlinkSync: (file) => fs.unlinkSync(file)
21
+ };
22
+ function failed(request, code, message, taskId = null, stageStatus = null) {
23
+ return {
24
+ status: 'failed',
25
+ changed: false,
26
+ intent: 'finalize-summary',
27
+ requestRef: request.taskRef,
28
+ taskId,
29
+ stage: request.stage,
30
+ artifact: request.artifact,
31
+ stageStatus,
32
+ operations: [],
33
+ error: { code, message }
34
+ };
35
+ }
36
+ function openReviewRound(content, action, round) {
37
+ const section = locateActivityLog(content);
38
+ if (!section)
39
+ return false;
40
+ const expected = `${action} (Round ${round})`;
41
+ return pairEntries(section.entries).filter((row) => (row.step === expected && Boolean(row.started) && !row.done)).length === 1;
42
+ }
43
+ function cleanupTemp(fileSystem, tempPath) {
44
+ try {
45
+ fileSystem.unlinkSync(tempPath);
46
+ }
47
+ catch {
48
+ // Best-effort cleanup preserves the primary failure.
49
+ }
50
+ }
51
+ function finalizeReviewSummary(request, options = {}) {
52
+ const stage = request.stage;
53
+ const spec = STAGES[stage];
54
+ if (!spec)
55
+ return failed(request, 'REVIEW_STAGE_INVALID', `unsupported review stage '${request.stage}'`);
56
+ if (!request.taskRef || !request.artifact) {
57
+ return failed(request, 'REVIEW_PAYLOAD_INVALID', 'taskRef, stage, and artifact are required');
58
+ }
59
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
60
+ if (!resolved.ok)
61
+ return failed(request, resolved.code, resolved.message, resolved.taskId);
62
+ if (resolved.state !== 'active') {
63
+ return failed(request, 'TASK_STATE_MISMATCH', `task ${resolved.taskId} is ${resolved.state}, expected active`, resolved.taskId);
64
+ }
65
+ const parsedArtifact = parseArtifactName(request.artifact);
66
+ if (!parsedArtifact || parsedArtifact.family !== spec.family) {
67
+ return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `artifact '${request.artifact}' does not match ${spec.family}`, resolved.taskId);
68
+ }
69
+ const validated = validateCompletedArtifact(resolved.taskDir, spec.family, request.artifact, parsedArtifact.round);
70
+ if (!validated.ok) {
71
+ const code = validated.error.code === 'ARTIFACT_NOT_REGULAR'
72
+ ? 'REVIEW_ARTIFACT_NOT_REGULAR'
73
+ : 'REVIEW_ARTIFACT_IDENTITY_INVALID';
74
+ return failed(request, code, validated.error.message, resolved.taskId);
75
+ }
76
+ const fileSystem = { ...DEFAULT_FILE_SYSTEM, ...options.fileSystem };
77
+ let taskContent;
78
+ let artifactContent;
79
+ try {
80
+ taskContent = fileSystem.readFileSync(resolved.taskMdPath);
81
+ artifactContent = fileSystem.readFileSync(validated.artifact.path);
82
+ }
83
+ catch (error) {
84
+ return failed(request, 'REVIEW_ARTIFACT_NOT_REGULAR', String(error), resolved.taskId);
85
+ }
86
+ if (!openReviewRound(taskContent, spec.action, parsedArtifact.round)) {
87
+ return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`, resolved.taskId);
88
+ }
89
+ const provenance = validateOrchestrationStage(request.taskRef, {
90
+ stage: spec.family,
91
+ round: parsedArtifact.round,
92
+ artifact: request.artifact,
93
+ role: 'reviewer'
94
+ }, { repoRoot: options.repoRoot });
95
+ if (provenance.status === 'failed' || provenance.status === 'paused') {
96
+ return failed(request, 'REVIEW_PROVENANCE_INVALID', provenance.error?.message ?? provenance.run?.pause?.message ?? 'orchestration provenance validation failed', resolved.taskId);
97
+ }
98
+ let rows;
99
+ try {
100
+ rows = parseLedger(taskContent);
101
+ }
102
+ catch (error) {
103
+ return failed(request, 'REVIEW_LEDGER_INVALID', String(error), resolved.taskId);
104
+ }
105
+ const ledgerError = validateLedgerRows(rows);
106
+ if (ledgerError) {
107
+ return failed(request, 'REVIEW_LEDGER_INVALID', `${ledgerError.code}: ${ledgerError.message}`, resolved.taskId);
108
+ }
109
+ const stageStatus = summarizeLedgerStage(rows, stage);
110
+ const transformed = finalizeReviewSummaryContent(artifactContent, stageStatus.unresolvedFindingCounts);
111
+ if (!transformed.ok) {
112
+ return failed(request, transformed.code, transformed.message, resolved.taskId, stageStatus);
113
+ }
114
+ if (!transformed.changed) {
115
+ return {
116
+ ...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
117
+ status: 'no-op',
118
+ error: null
119
+ };
120
+ }
121
+ const operations = [{ kind: 'artifact', artifact: request.artifact, operation: 'update' }];
122
+ if (request.dryRun) {
123
+ return {
124
+ ...failed(request, 'REVIEW_ARTIFACT_CONFLICT', '', resolved.taskId, stageStatus),
125
+ status: 'planned',
126
+ changed: true,
127
+ operations,
128
+ error: null
129
+ };
130
+ }
131
+ const tempPath = path.join(resolved.taskDir, `.${request.artifact}.tmp-${process.pid}-${(options.randomSuffix ?? randomUUID)()}`);
132
+ let mode;
133
+ try {
134
+ mode = fileSystem.statModeSync(validated.artifact.path);
135
+ fileSystem.writeFileSync(tempPath, transformed.content, mode);
136
+ }
137
+ catch (error) {
138
+ cleanupTemp(fileSystem, tempPath);
139
+ return failed(request, 'REVIEW_TEMP_WRITE_FAILED', String(error), resolved.taskId, stageStatus);
140
+ }
141
+ try {
142
+ if (fileSystem.readFileSync(validated.artifact.path) !== artifactContent) {
143
+ cleanupTemp(fileSystem, tempPath);
144
+ return failed(request, 'REVIEW_ARTIFACT_CONFLICT', `${request.artifact} changed during finalization`, resolved.taskId, stageStatus);
145
+ }
146
+ fileSystem.renameSync(tempPath, validated.artifact.path);
147
+ }
148
+ catch (error) {
149
+ cleanupTemp(fileSystem, tempPath);
150
+ return failed(request, 'REVIEW_RENAME_FAILED', String(error), resolved.taskId, stageStatus);
151
+ }
152
+ return {
153
+ status: 'applied',
154
+ changed: true,
155
+ intent: 'finalize-summary',
156
+ requestRef: request.taskRef,
157
+ taskId: resolved.taskId,
158
+ stage,
159
+ artifact: request.artifact,
160
+ stageStatus,
161
+ operations,
162
+ error: null
163
+ };
164
+ }
165
+ export { finalizeReviewSummary };
166
+ //# sourceMappingURL=review-finalization.js.map
@@ -5,6 +5,15 @@ import { artifactName, maxRound } from "./review-artifacts.js";
5
5
  // covers ALL tracked changes by default. This default denylist is EMPTY —
6
6
  // projects opt into exclusions explicitly via review.post_review_exclude_globs.
7
7
  export const DEFAULT_POST_REVIEW_EXCLUDES = [];
8
+ export function loadPostReviewConfig(repoRoot) {
9
+ try {
10
+ const config = JSON.parse(fs.readFileSync(path.join(repoRoot, ".agents", ".airc.json"), "utf8"));
11
+ return config.review && typeof config.review === "object" ? config.review : {};
12
+ }
13
+ catch {
14
+ return {};
15
+ }
16
+ }
8
17
  export function resolvePostReviewGlobs(config = {}, reviewConfig = {}) {
9
18
  const projectExcludes = [
10
19
  ...(Array.isArray(reviewConfig.post_review_exclude_globs) ? reviewConfig.post_review_exclude_globs : []),
@@ -31,6 +40,10 @@ export function extractReviewBaseline(content) {
31
40
  const match = String(content).match(/^[-*]?\s*\*\*(?:审查基线提交|Review Baseline Commit)\*\*[::]\s*(.*?)\s*$/m);
32
41
  return match ? match[1].trim().replace(/`/g, "") : "";
33
42
  }
43
+ export function extractReviewDiffBase(content) {
44
+ const match = String(content).match(/^[-*]?\s*\*\*(?:审查差异基线|Reviewed Diff Base)\*\*[::]\s*(.*?)\s*$/m);
45
+ return match ? match[1].trim().replace(/`/g, "") : "";
46
+ }
34
47
  export function extractReviewDiffFingerprint(content) {
35
48
  const match = String(content).match(/^[-*]?\s*\*\*(?:审查差异指纹|Reviewed Diff Fingerprint)\*\*[::]\s*(.*?)\s*$/m);
36
49
  return match ? match[1].trim().replace(/`/g, "") : "";
@@ -1,5 +1,6 @@
1
1
  const LOCAL_VERIFICATION_CHECKS = [
2
- 'task-meta', 'artifact', 'implementation-input', 'activity-log', 'completion-checklist'
2
+ 'task-meta', 'artifact', 'implementation-input', 'activity-log', 'completion-checklist',
3
+ 'orchestration-state'
3
4
  ];
4
5
  function isLocalVerificationCheck(value) {
5
6
  return LOCAL_VERIFICATION_CHECKS.includes(value);
@@ -4,11 +4,16 @@ import path from "node:path";
4
4
  import process from "node:process";
5
5
  import { execFileSync } from "node:child_process";
6
6
  import { fileURLToPath } from "node:url";
7
- import { extractReviewBaseline, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, parseReviewVerdict, resolvePostReviewGlobs } from "./verification-review.js";
7
+ import { extractReviewBaseline, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from "./verification-review.js";
8
8
  import { check as checkPlatformSync } from "../platform/verification-sync.js";
9
9
  import { check as checkRequiredChecks } from "../platform/verification-required.js";
10
+ import { inspectPlatformPullRequest } from "../platform/pull-requests.js";
11
+ import { resolveMaterializedReviewedHeadRelation } from "../platform/change-request-git-evidence.js";
12
+ import { resolveReviewedHeadRelation } from "../platform/merged-pr-equivalence.js";
13
+ import { resolveLocalReviewedCommitRelation } from "../git/reviewed-commit-equivalence.js";
10
14
  import { parseTypedTaskFrontmatter } from "./frontmatter.js";
11
- import { parseLedger } from "./ledger.js";
15
+ import { parseLedger, summarizeLedgerStage, validateLedgerRows } from "./ledger.js";
16
+ import { equalCounts, parseReviewSummary } from "./review-artifacts.js";
12
17
  import { loadVerificationConfig } from "./verification-config.js";
13
18
  import { snapshotReview } from "../git/review-snapshot.js";
14
19
  const TASK_ENUMS = {
@@ -91,10 +96,14 @@ function runCheck(type, context, shared) {
91
96
  return checkCompletionChecklist(context);
92
97
  case "review-ledger":
93
98
  return checkReviewLedger(context);
99
+ case "review-summary":
100
+ return checkReviewSummary(context);
94
101
  case "review-fact":
95
102
  return checkReviewFact(context);
96
103
  case "post-review-commit":
97
104
  return checkPostReviewCommit(context);
105
+ case "orchestration-state":
106
+ return checkOrchestrationState(context);
98
107
  default: {
99
108
  const adapter = PLATFORM_ADAPTERS[type];
100
109
  if (!adapter) {
@@ -107,6 +116,34 @@ function runCheck(type, context, shared) {
107
116
  }
108
117
  }
109
118
  }
119
+ function checkOrchestrationState({ taskDir }) {
120
+ const file = path.join(taskDir, 'orchestration.json');
121
+ const stat = safeStat(file);
122
+ if (!stat?.isFile())
123
+ return failResult('orchestration-state', 'orchestration.json is missing');
124
+ let run;
125
+ try {
126
+ run = JSON.parse(fs.readFileSync(file, 'utf8'));
127
+ }
128
+ catch (error) {
129
+ return failResult('orchestration-state', `Invalid orchestration.json: ${String(error)}`);
130
+ }
131
+ if (run.schemaVersion !== 1 || !['paused', 'completed'].includes(run.status)) {
132
+ return failResult('orchestration-state', `Expected paused or completed run, received '${run.status}'`);
133
+ }
134
+ if (run.status === 'paused' && (!run.pause?.code || !run.pause?.message)) {
135
+ return failResult('orchestration-state', 'Paused run requires a stable pause code and message');
136
+ }
137
+ if (run.status === 'completed') {
138
+ if (run.pendingDelegation !== null || !run.commitAuthorization?.consumedAt) {
139
+ return failResult('orchestration-state', 'Completed run must consume commit authorization and clear pending delegation');
140
+ }
141
+ }
142
+ else if (run.pendingDelegation?.status === 'sealed') {
143
+ return failResult('orchestration-state', 'Paused run has a sealed delegation that could still advance');
144
+ }
145
+ return passResult('orchestration-state', `Orchestration run is safely ${run.status}`);
146
+ }
110
147
  // === Check Functions ===
111
148
  function checkTaskMeta({ taskDir, config }) {
112
149
  const task = loadTask(taskDir);
@@ -210,19 +247,6 @@ function loadProjectName() {
210
247
  return "";
211
248
  }
212
249
  }
213
- function loadReviewConfig() {
214
- const configPath = path.join(repoRoot, ".agents", ".airc.json");
215
- if (!fs.existsSync(configPath)) {
216
- return {};
217
- }
218
- try {
219
- const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
220
- return config.review && typeof config.review === "object" ? config.review : {};
221
- }
222
- catch {
223
- return {};
224
- }
225
- }
226
250
  function checkArtifact({ taskDir, config, artifactFile }) {
227
251
  const resolvedArtifact = resolveArtifactPath(taskDir, config.file_pattern, artifactFile);
228
252
  if (!resolvedArtifact.ok) {
@@ -250,6 +274,40 @@ function checkArtifact({ taskDir, config, artifactFile }) {
250
274
  }
251
275
  return passResult("artifact", `${path.basename(artifactPath)} passed (${requiredSections.length} sections)`);
252
276
  }
277
+ function checkReviewSummary({ taskDir, config, artifactFile }) {
278
+ const stage = String(config.stage || "");
279
+ if (!["analysis", "plan", "code"].includes(stage)) {
280
+ return failResult("review-summary", `Invalid review stage '${stage}'`);
281
+ }
282
+ const resolvedArtifact = resolveArtifactPath(taskDir, "", artifactFile);
283
+ if (!resolvedArtifact.ok || !safeStat(resolvedArtifact.path)?.isFile()) {
284
+ return failResult("review-summary", resolvedArtifact.message || "Review artifact is missing");
285
+ }
286
+ const parsed = parseReviewSummary(fs.readFileSync(resolvedArtifact.path, "utf8"));
287
+ if (!parsed.ok)
288
+ return failResult("review-summary", `${parsed.code}: ${parsed.message}`);
289
+ if (!parsed.summary.counts) {
290
+ return failResult("review-summary", "Review summary finding counts are not finalized");
291
+ }
292
+ const task = loadTask(taskDir);
293
+ if (!task.ok)
294
+ return failResult("review-summary", task.message);
295
+ let rows;
296
+ try {
297
+ rows = parseLedger(task.content);
298
+ }
299
+ catch (error) {
300
+ return failResult("review-summary", `Invalid disagreement ledger: ${String(error)}`);
301
+ }
302
+ const invalid = validateLedgerRows(rows);
303
+ if (invalid)
304
+ return failResult("review-summary", `${invalid.code}: ${invalid.message}`);
305
+ const expected = summarizeLedgerStage(rows, stage).unresolvedFindingCounts;
306
+ if (!equalCounts(parsed.summary.counts, expected)) {
307
+ return failResult("review-summary", `Review summary counts ${JSON.stringify(parsed.summary.counts)} do not match ledger ${JSON.stringify(expected)}`);
308
+ }
309
+ return passResult("review-summary", `${path.basename(resolvedArtifact.path)} finding counts match the ${stage} ledger`);
310
+ }
253
311
  function checkImplementationInput({ taskDir, artifactFile }) {
254
312
  const task = loadTask(taskDir);
255
313
  if (!task.ok)
@@ -495,7 +553,7 @@ function resolveReviewSetting(config, key, fallback) {
495
553
  if (config && config[key] !== undefined && config[key] !== null) {
496
554
  return config[key];
497
555
  }
498
- const reviewConfig = loadReviewConfig();
556
+ const reviewConfig = loadPostReviewConfig(repoRoot);
499
557
  if (reviewConfig[key] !== undefined && reviewConfig[key] !== null) {
500
558
  return reviewConfig[key];
501
559
  }
@@ -579,8 +637,42 @@ function checkPostReviewCommit({ taskDir, config }) {
579
637
  return blockedResult("post-review-commit", "git unavailable or task directory is not inside a git repository");
580
638
  }
581
639
  const task = loadTask(taskDir);
582
- const content = fs.readFileSync(reviewArtifact.path, "utf8");
640
+ if (!task.ok)
641
+ return failResult("post-review-commit", task.message);
583
642
  const lastReviewedCommit = task.ok ? (task.metadata.last_reviewed_commit || "").trim() : "";
643
+ const globs = resolvePostReviewGlobs(config, loadPostReviewConfig(repoRoot));
644
+ const hasPullRequest = Number(task.metadata.pr_number) > 0;
645
+ let inspected = null;
646
+ if (hasPullRequest) {
647
+ inspected = inspectPlatformPullRequest(task.metadata.id, { cwd: gitRoot });
648
+ if (!inspected.pullRequest) {
649
+ const message = inspected.error?.message || "PR merge snapshot is unavailable";
650
+ const code = inspected.error?.code || "PR_INSPECTION_INVALID";
651
+ return inspected.status === "blocked"
652
+ ? blockedResult("post-review-commit", message, code)
653
+ : failResult("post-review-commit", message, code);
654
+ }
655
+ if (inspected.pullRequest.state === "closed" &&
656
+ inspected.pullRequest.mergedAt &&
657
+ inspected.pullRequest.mergeCommitSha) {
658
+ const relation = resolveMaterializedReviewedHeadRelation({
659
+ cwd: gitRoot,
660
+ platformType: inspected.platform.type,
661
+ lastReviewedCommit,
662
+ pullRequest: inspected.pullRequest
663
+ });
664
+ if (relation.status === "merged-equivalent") {
665
+ return passResult("post-review-commit", `Reviewed PR head is content-equivalent to squash merge ${relation.mergeCommit.slice(0, 8)} on target ${relation.comparisonHead.slice(0, 8)}`);
666
+ }
667
+ if (relation.status === "blocked") {
668
+ return blockedResult("post-review-commit", relation.message, relation.code);
669
+ }
670
+ if (relation.status === "strict") {
671
+ return failResult("post-review-commit", "Merged PR evidence did not establish squash merge equivalence", "PR_MERGE_IDENTITY_INVALID");
672
+ }
673
+ return failResult("post-review-commit", relation.message, relation.code);
674
+ }
675
+ }
584
676
  const baselineSource = resolvePostReviewBaseline({
585
677
  gitRoot,
586
678
  lastReviewedCommit,
@@ -590,7 +682,6 @@ function checkPostReviewCommit({ taskDir, config }) {
590
682
  return baselineSource.result;
591
683
  }
592
684
  const sha = baselineSource.sha;
593
- const globs = resolvePostReviewGlobs(config, loadReviewConfig());
594
685
  let commits;
595
686
  try {
596
687
  const out = execFileSync("git", ["-C", gitRoot, "rev-list", `${sha}..HEAD`, "--", ...globs], { encoding: "utf8" });
@@ -602,18 +693,63 @@ function checkPostReviewCommit({ taskDir, config }) {
602
693
  if (commits.length === 0) {
603
694
  return passResult("post-review-commit", `No post-review commits to code/rule paths since ${sha.slice(0, 8)}`);
604
695
  }
605
- let exempt = false;
696
+ let localHead = "";
606
697
  try {
607
- exempt = task.ok && parseLedger(task.content).some((row) => row.stage === POST_REVIEW_COMMIT_STAGE && row.status === "human-decided");
698
+ localHead = execFileSync("git", ["-C", gitRoot, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
608
699
  }
609
700
  catch {
610
- return failResult("post-review-commit", "Invalid disagreement ledger");
701
+ return blockedResult("post-review-commit", "Unable to resolve the local HEAD");
702
+ }
703
+ if (hasPullRequest) {
704
+ if (inspected?.pullRequest) {
705
+ const relation = resolveReviewedHeadRelation({
706
+ gitRoot,
707
+ comparisonHead: localHead,
708
+ lastReviewedCommit: sha,
709
+ pullRequest: inspected.pullRequest
710
+ });
711
+ if (relation.status === "merged-equivalent") {
712
+ return passResult("post-review-commit", `Reviewed PR head is content-equivalent to squash merge ${relation.mergeCommit.slice(0, 8)}`);
713
+ }
714
+ if (relation.status === "blocked") {
715
+ return blockedResult("post-review-commit", relation.message, relation.code);
716
+ }
717
+ }
718
+ }
719
+ else if (commits.length === 1) {
720
+ const relation = resolveLocalReviewedCommitRelation({
721
+ gitRoot,
722
+ localHead,
723
+ lastReviewedCommit: sha,
724
+ rewrittenCommit: commits[0],
725
+ pathspecs: globs
726
+ });
727
+ if (relation.status === "local-equivalent") {
728
+ return passResult("post-review-commit", `Reviewed commit is content-equivalent to local rewrite ${relation.rewrittenCommit.slice(0, 8)}`);
729
+ }
730
+ if (relation.status === "blocked") {
731
+ return blockedResult("post-review-commit", relation.message);
732
+ }
611
733
  }
612
- if (exempt) {
734
+ const exemption = resolvePostReviewExemption(task.content);
735
+ if (!exemption.ok)
736
+ return failResult("post-review-commit", exemption.message);
737
+ if (exemption.exempt) {
613
738
  return passResult("post-review-commit", `${commits.length} post-review commit(s) covered by a human-decided exemption`);
614
739
  }
615
740
  return failResult("post-review-commit", `${commits.length} commit(s) to code/rule paths after reviewed commit ${sha.slice(0, 8)}; re-run review-code or record a human-decided exemption`);
616
741
  }
742
+ function resolvePostReviewExemption(content) {
743
+ try {
744
+ return {
745
+ ok: true,
746
+ exempt: parseLedger(content).some((row) => row.stage === POST_REVIEW_COMMIT_STAGE && row.status === "human-decided")
747
+ };
748
+ }
749
+ catch {
750
+ return { ok: false, message: "Invalid disagreement ledger" };
751
+ }
752
+ }
617
753
  function checkReviewFact({ taskDir, artifactFile }) {
618
754
  const resolvedArtifact = resolveArtifactPath(taskDir, "review-code.md|review-code-r{N}.md", artifactFile);
619
755
  if (!resolvedArtifact.ok) {
@@ -626,6 +762,7 @@ function checkReviewFact({ taskDir, artifactFile }) {
626
762
  const content = fs.readFileSync(resolvedArtifact.path, "utf8");
627
763
  const verdict = parseReviewVerdict(content);
628
764
  const reviewBaseline = extractReviewBaseline(content);
765
+ const reviewDiffBase = extractReviewDiffBase(content);
629
766
  const reviewedFingerprint = extractReviewDiffFingerprint(content);
630
767
  const reviewedTree = extractReviewedSnapshotTree(content);
631
768
  if (!["通过", "需要修改", "拒绝", "Approved", "Changes Requested", "Rejected"].includes(verdict)) {
@@ -634,10 +771,12 @@ function checkReviewFact({ taskDir, artifactFile }) {
634
771
  let gitRoot;
635
772
  let head;
636
773
  let baseline;
774
+ let diffBase;
637
775
  try {
638
776
  gitRoot = execFileSync("git", ["-C", taskDir, "rev-parse", "--show-toplevel"], { encoding: "utf8" }).trim();
639
777
  head = execFileSync("git", ["-C", gitRoot, "rev-parse", "HEAD"], { encoding: "utf8" }).trim();
640
778
  baseline = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewBaseline}^{commit}`], { encoding: "utf8" }).trim();
779
+ diffBase = execFileSync("git", ["-C", gitRoot, "rev-parse", `${reviewDiffBase || reviewBaseline}^{commit}`], { encoding: "utf8" }).trim();
641
780
  }
642
781
  catch {
643
782
  return blockedResult("review-fact", `Unable to resolve review baseline '${reviewBaseline}' in the task repository; re-run review-code`);
@@ -647,7 +786,13 @@ function checkReviewFact({ taskDir, artifactFile }) {
647
786
  }
648
787
  let actualSnapshot;
649
788
  try {
650
- actualSnapshot = snapshotReview({ cwd: gitRoot, mode: "worktree", baseline, globs: resolvePostReviewGlobs({}, loadReviewConfig()) });
789
+ actualSnapshot = snapshotReview({
790
+ cwd: gitRoot,
791
+ mode: "worktree",
792
+ baseline,
793
+ diffBase,
794
+ globs: resolvePostReviewGlobs({}, loadPostReviewConfig(repoRoot))
795
+ });
651
796
  }
652
797
  catch {
653
798
  return blockedResult("review-fact", `Unable to recompute reviewed diff fingerprint from baseline ${baseline.slice(0, 8)}; re-run review-code`);
@@ -1,3 +1,3 @@
1
- export { extractReviewBaseline, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, parseReviewVerdict, resolvePostReviewGlobs } from './review-fingerprint.js';
1
+ export { extractReviewBaseline, extractReviewDiffBase, extractReviewDiffFingerprint, extractReviewedSnapshotTree, findAuthoritativeReviewCodeArtifact, loadPostReviewConfig, parseReviewVerdict, resolvePostReviewGlobs } from './review-fingerprint.js';
2
2
  export { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
3
3
  //# sourceMappingURL=verification-review.js.map
@@ -19,14 +19,16 @@ const VERIFICATION_CATALOG = {
19
19
  'block-task.completed': gate('block-task', 'blocked'),
20
20
  'cancel-task.completed': gate('cancel-task', 'completed'),
21
21
  'commit.completed': gate('commit', 'active'),
22
- 'complete-task.preflight': { skill: 'complete-task', expectedState: 'active', mode: 'checks', checks: ['review-ledger', 'post-review-commit', 'required-checks', 'platform-sync-preflight'] },
22
+ 'complete-task.preflight': { skill: 'complete-task', expectedState: 'active', mode: 'checks', checks: ['review-ledger', 'post-review-commit', 'platform-sync-preflight'] },
23
23
  'complete-task.completed': gate('complete-task', 'completed'),
24
24
  'create-pr.completed': gate('create-pr', 'active'),
25
25
  'create-task.completed': gate('create-task', 'active'),
26
26
  'import-codescan.completed': gate('import-codescan', 'active'),
27
27
  'import-dependabot.completed': gate('import-dependabot', 'active'),
28
28
  'import-issue.completed': gate('import-issue', 'active'),
29
- 'watch-pr.completed': gate('watch-pr', 'active')
29
+ 'watch-pr.completed': gate('watch-pr', 'active'),
30
+ 'run-task.paused': { skill: 'run-task', expectedState: 'active', mode: 'checks', checks: ['orchestration-state'] },
31
+ 'run-task.completed': { skill: 'run-task', expectedState: 'active', mode: 'checks', checks: ['orchestration-state'] }
30
32
  };
31
33
  function failure(request, code, message, extra = {}) {
32
34
  return {
@@ -0,0 +1,34 @@
1
+ import fs from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import { spawnSync } from 'node:child_process';
5
+ function git(repoRoot, indexFile, args) {
6
+ const env = indexFile ? { ...process.env, GIT_INDEX_FILE: indexFile } : process.env;
7
+ const result = spawnSync('git', args, { cwd: repoRoot, env, encoding: 'utf8' });
8
+ if (result.status !== 0) {
9
+ throw new Error(String(result.stderr || result.stdout || `git ${args[0]} failed`).trim());
10
+ }
11
+ return result.stdout;
12
+ }
13
+ function captureWorkspaceSnapshot(repoRoot) {
14
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-infra-orchestration-index-'));
15
+ const indexFile = path.join(tempDir, 'index');
16
+ try {
17
+ git(repoRoot, indexFile, ['read-tree', 'HEAD']);
18
+ git(repoRoot, indexFile, ['add', '-A', '--', ':/']);
19
+ const workspace = path.join(repoRoot, '.agents', 'workspace', 'active');
20
+ if (fs.existsSync(workspace)) {
21
+ git(repoRoot, indexFile, ['add', '-f', '--', '.agents/workspace/active']);
22
+ }
23
+ return git(repoRoot, indexFile, ['write-tree']).trim();
24
+ }
25
+ finally {
26
+ fs.rmSync(tempDir, { recursive: true, force: true });
27
+ }
28
+ }
29
+ function diffWorkspaceSnapshots(repoRoot, before, after) {
30
+ const output = git(repoRoot, null, ['diff', '--name-only', '-z', before, after]);
31
+ return output.split('\0').filter(Boolean);
32
+ }
33
+ export { captureWorkspaceSnapshot, diffWorkspaceSnapshots };
34
+ //# sourceMappingURL=workspace-snapshot.js.map