@fitlab-ai/agent-infra 0.9.2 → 0.9.3

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 (318) hide show
  1. package/README.md +10 -9
  2. package/README.zh-CN.md +10 -9
  3. package/dist/bin/internal-cli.js +15 -0
  4. package/dist/lib/agent-clients/adapter.js +45 -2
  5. package/dist/lib/agent-clients/adapters/antigravity-cli.js +64 -0
  6. package/dist/lib/agent-clients/adapters/claude-code.js +10 -1
  7. package/dist/lib/agent-clients/adapters/codex.js +9 -0
  8. package/dist/lib/agent-clients/adapters/index.js +2 -2
  9. package/dist/lib/agent-clients/adapters/opencode.js +9 -0
  10. package/dist/lib/agent-clients/config.js +42 -4
  11. package/dist/lib/agent-clients/next-steps.js +11 -2
  12. package/dist/lib/agent-clients/reconcile.js +2 -1
  13. package/dist/lib/agent-clients/registry.js +7 -1
  14. package/dist/lib/agent-clients/schema.js +18 -0
  15. package/dist/lib/agent-clients/tokens.js +49 -0
  16. package/dist/lib/agent-clients/types.js +1 -1
  17. package/dist/lib/defaults.json +1 -1
  18. package/dist/lib/git/workflow.js +54 -1
  19. package/dist/lib/internal/agent-client.js +61 -4
  20. package/dist/lib/internal/git-workflow.js +6 -1
  21. package/dist/lib/internal/platform-checks.js +3 -3
  22. package/dist/lib/internal/platform-comment.js +29 -2
  23. package/dist/lib/internal/platform-issue.js +7 -0
  24. package/dist/lib/internal/platform-pr-review.js +132 -0
  25. package/dist/lib/internal/platform-pr.js +20 -2
  26. package/dist/lib/internal/platform-release-notes.js +52 -16
  27. package/dist/lib/internal/pr-review-grade.js +140 -0
  28. package/dist/lib/internal/release-workflow.js +13 -6
  29. package/dist/lib/internal/task-activity.js +73 -0
  30. package/dist/lib/internal/task-event.js +17 -1
  31. package/dist/lib/internal/task-lifecycle.js +7 -0
  32. package/dist/lib/internal/task-orchestration.js +51 -6
  33. package/dist/lib/internal/task-review.js +8 -3
  34. package/dist/lib/platform/adapters.js +8 -1
  35. package/dist/lib/platform/completion-backfill.js +122 -0
  36. package/dist/lib/platform/issue-comments.js +3 -2
  37. package/dist/lib/platform/merged-pr-equivalence.js +115 -5
  38. package/dist/lib/platform/pr-checks.js +64 -41
  39. package/dist/lib/platform/pr-review.js +166 -0
  40. package/dist/lib/platform/pull-requests.js +324 -3
  41. package/dist/lib/platform/release-notes.js +85 -3
  42. package/dist/lib/pr-review/evidence-grading.js +229 -0
  43. package/dist/lib/run/tui.js +3 -5
  44. package/dist/lib/sandbox/commands/create.js +0 -20
  45. package/dist/lib/sandbox/commands/show.js +1 -1
  46. package/dist/lib/task/activity-intent.js +101 -0
  47. package/dist/lib/task/artifact-lifecycle.js +2 -1
  48. package/dist/lib/task/commands/log.js +15 -14
  49. package/dist/lib/task/delegation-receipts.js +23 -2
  50. package/dist/lib/task/events.js +67 -28
  51. package/dist/lib/task/finalization-artifacts.js +35 -0
  52. package/dist/lib/task/lifecycle-execution.js +46 -0
  53. package/dist/lib/task/orchestration.js +408 -44
  54. package/dist/lib/task/review-finalization.js +29 -9
  55. package/dist/lib/task/task-execution-lock.js +231 -0
  56. package/dist/lib/task/verification-checks.js +1 -1
  57. package/dist/lib/task/verification-engine.js +218 -2
  58. package/dist/lib/task/verification.js +4 -3
  59. package/dist/lib/task/workspace-snapshot.js +17 -5
  60. package/lib/agent-clients/adapter.ts +75 -2
  61. package/lib/agent-clients/adapters/antigravity-cli.ts +65 -0
  62. package/lib/agent-clients/adapters/claude-code.ts +10 -1
  63. package/lib/agent-clients/adapters/codex.ts +9 -0
  64. package/lib/agent-clients/adapters/index.ts +2 -2
  65. package/lib/agent-clients/adapters/opencode.ts +9 -0
  66. package/lib/agent-clients/config.ts +49 -4
  67. package/lib/agent-clients/next-steps.ts +15 -2
  68. package/lib/agent-clients/reconcile.ts +2 -1
  69. package/lib/agent-clients/registry.ts +10 -0
  70. package/lib/agent-clients/schema.ts +18 -0
  71. package/lib/agent-clients/tokens.ts +53 -0
  72. package/lib/agent-clients/types.ts +15 -1
  73. package/lib/defaults.json +1 -1
  74. package/lib/git/workflow.ts +66 -2
  75. package/lib/internal/agent-client.ts +59 -4
  76. package/lib/internal/git-workflow.ts +5 -1
  77. package/lib/internal/platform-checks.ts +4 -4
  78. package/lib/internal/platform-comment.ts +17 -2
  79. package/lib/internal/platform-issue.ts +4 -0
  80. package/lib/internal/platform-pr-review.ts +104 -0
  81. package/lib/internal/platform-pr.ts +14 -1
  82. package/lib/internal/platform-release-notes.ts +59 -16
  83. package/lib/internal/pr-review-grade.ts +130 -0
  84. package/lib/internal/release-workflow.ts +13 -6
  85. package/lib/internal/task-activity.ts +55 -0
  86. package/lib/internal/task-event.ts +9 -1
  87. package/lib/internal/task-lifecycle.ts +4 -0
  88. package/lib/internal/task-orchestration.ts +45 -6
  89. package/lib/internal/task-review.ts +8 -3
  90. package/lib/platform/adapters.ts +29 -2
  91. package/lib/platform/completion-backfill.ts +134 -0
  92. package/lib/platform/issue-comments.ts +3 -2
  93. package/lib/platform/merged-pr-equivalence.ts +127 -5
  94. package/lib/platform/pr-checks.ts +72 -45
  95. package/lib/platform/pr-review.ts +201 -0
  96. package/lib/platform/pull-requests.ts +395 -2
  97. package/lib/platform/release-notes.ts +100 -4
  98. package/lib/pr-review/evidence-grading.ts +318 -0
  99. package/lib/run/tui.ts +3 -4
  100. package/lib/sandbox/commands/create.ts +0 -20
  101. package/lib/sandbox/commands/show.ts +1 -1
  102. package/lib/server/server.schema.json +2 -2
  103. package/lib/task/activity-intent.ts +128 -0
  104. package/lib/task/artifact-lifecycle.ts +2 -1
  105. package/lib/task/commands/log.ts +15 -14
  106. package/lib/task/delegation-receipts.ts +32 -3
  107. package/lib/task/events.ts +75 -30
  108. package/lib/task/finalization-artifacts.ts +58 -0
  109. package/lib/task/lifecycle-execution.ts +106 -0
  110. package/lib/task/orchestration.ts +543 -64
  111. package/lib/task/review-finalization.ts +40 -9
  112. package/lib/task/task-execution-lock.ts +296 -0
  113. package/lib/task/verification-checks.ts +1 -1
  114. package/lib/task/verification-engine.ts +249 -2
  115. package/lib/task/verification.ts +5 -3
  116. package/lib/task/workspace-snapshot.ts +26 -5
  117. package/package.json +3 -3
  118. package/templates/.agents/QUICKSTART.en.md +25 -8
  119. package/templates/.agents/QUICKSTART.zh-CN.md +25 -8
  120. package/templates/.agents/README.en.md +10 -7
  121. package/templates/.agents/README.zh-CN.md +10 -7
  122. package/templates/.agents/hooks/lifecycle-delegation.js +15 -4
  123. package/templates/.agents/rules/create-issue.github.en.md +4 -2
  124. package/templates/.agents/rules/create-issue.github.zh-CN.md +4 -2
  125. package/templates/.agents/rules/issue-fields.github.en.md +3 -1
  126. package/templates/.agents/rules/issue-fields.github.zh-CN.md +3 -1
  127. package/templates/.agents/rules/issue-pr-commands.en.md +5 -3
  128. package/templates/.agents/rules/issue-pr-commands.github.en.md +5 -3
  129. package/templates/.agents/rules/issue-pr-commands.github.zh-CN.md +5 -3
  130. package/templates/.agents/rules/issue-pr-commands.zh-CN.md +5 -3
  131. package/templates/.agents/rules/issue-sync.github.en.md +7 -3
  132. package/templates/.agents/rules/issue-sync.github.zh-CN.md +8 -4
  133. package/templates/.agents/rules/lifecycle-orchestration.en.md +5 -2
  134. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +5 -2
  135. package/templates/.agents/rules/milestone-inference.github.en.md +4 -2
  136. package/templates/.agents/rules/milestone-inference.github.zh-CN.md +4 -2
  137. package/templates/.agents/rules/next-step-output.en.md +3 -1
  138. package/templates/.agents/rules/next-step-output.zh-CN.md +3 -1
  139. package/templates/.agents/rules/no-mid-flow-questions.en.md +17 -0
  140. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +17 -0
  141. package/templates/.agents/rules/pr-checks-commands.en.md +3 -3
  142. package/templates/.agents/rules/pr-checks-commands.github.en.md +2 -2
  143. package/templates/.agents/rules/pr-checks-commands.github.zh-CN.md +2 -2
  144. package/templates/.agents/rules/pr-checks-commands.zh-CN.md +3 -3
  145. package/templates/.agents/rules/pr-sync.en.md +3 -1
  146. package/templates/.agents/rules/pr-sync.github.en.md +11 -1
  147. package/templates/.agents/rules/pr-sync.github.zh-CN.md +11 -1
  148. package/templates/.agents/rules/pr-sync.zh-CN.md +3 -1
  149. package/templates/.agents/rules/release-commands.en.md +1 -1
  150. package/templates/.agents/rules/release-commands.github.en.md +12 -2
  151. package/templates/.agents/rules/release-commands.github.zh-CN.md +12 -2
  152. package/templates/.agents/rules/release-commands.zh-CN.md +1 -1
  153. package/templates/.agents/rules/task-management.en.md +11 -0
  154. package/templates/.agents/rules/task-management.zh-CN.md +11 -0
  155. package/templates/.agents/skills/analyze-task/SKILL.en.md +10 -7
  156. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +10 -7
  157. package/templates/.agents/skills/block-task/SKILL.en.md +7 -5
  158. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +7 -5
  159. package/templates/.agents/skills/cancel-task/SKILL.en.md +6 -4
  160. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +6 -4
  161. package/templates/.agents/skills/close-codescan/SKILL.en.md +3 -1
  162. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +3 -1
  163. package/templates/.agents/skills/close-dependabot/SKILL.en.md +3 -1
  164. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +3 -1
  165. package/templates/.agents/skills/code-task/SKILL.en.md +9 -6
  166. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +11 -8
  167. package/templates/.agents/skills/commit/SKILL.en.md +3 -1
  168. package/templates/.agents/skills/commit/SKILL.zh-CN.md +3 -1
  169. package/templates/.agents/skills/commit/reference/commit-message.en.md +1 -1
  170. package/templates/.agents/skills/commit/reference/commit-message.zh-CN.md +1 -1
  171. package/templates/.agents/skills/commit/reference/issue-metadata-sync.en.md +1 -1
  172. package/templates/.agents/skills/commit/reference/issue-metadata-sync.zh-CN.md +1 -1
  173. package/templates/.agents/skills/commit/reference/pr-summary-sync.en.md +1 -1
  174. package/templates/.agents/skills/commit/reference/pr-summary-sync.zh-CN.md +1 -1
  175. package/templates/.agents/skills/complete-manual-validation/SKILL.en.md +6 -4
  176. package/templates/.agents/skills/complete-manual-validation/SKILL.zh-CN.md +6 -4
  177. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.en.md +1 -1
  178. package/templates/.agents/skills/complete-manual-validation/reference/summary-update.zh-CN.md +1 -1
  179. package/templates/.agents/skills/complete-task/SKILL.en.md +21 -6
  180. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +21 -6
  181. package/templates/.agents/skills/complete-task/config/verify.en.json +1 -0
  182. package/templates/.agents/skills/complete-task/config/verify.zh-CN.json +1 -0
  183. package/templates/.agents/skills/complete-task/reference/external-delivery.en.md +17 -0
  184. package/templates/.agents/skills/complete-task/reference/external-delivery.zh-CN.md +17 -0
  185. package/templates/.agents/skills/create-pr/SKILL.en.md +3 -1
  186. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +3 -1
  187. package/templates/.agents/skills/create-pr/reference/comment-publish.en.md +1 -1
  188. package/templates/.agents/skills/create-pr/reference/comment-publish.zh-CN.md +1 -1
  189. package/templates/.agents/skills/create-release-note/SKILL.en.md +17 -16
  190. package/templates/.agents/skills/create-release-note/SKILL.zh-CN.md +17 -16
  191. package/templates/.agents/skills/create-task/SKILL.en.md +5 -3
  192. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +5 -3
  193. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -3
  194. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -3
  195. package/templates/.agents/skills/plan-task/SKILL.en.md +8 -5
  196. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +8 -5
  197. package/templates/.agents/skills/post-release/SKILL.en.md +2 -0
  198. package/templates/.agents/skills/post-release/SKILL.zh-CN.md +2 -0
  199. package/templates/.agents/skills/release/SKILL.en.md +16 -10
  200. package/templates/.agents/skills/release/SKILL.zh-CN.md +16 -10
  201. package/templates/.agents/skills/restore-task/SKILL.en.md +4 -1
  202. package/templates/.agents/skills/restore-task/SKILL.zh-CN.md +4 -1
  203. package/templates/.agents/skills/review-analysis/SKILL.en.md +7 -4
  204. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +7 -4
  205. package/templates/.agents/skills/review-code/SKILL.en.md +9 -6
  206. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +9 -6
  207. package/templates/.agents/skills/review-plan/SKILL.en.md +7 -4
  208. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +7 -4
  209. package/templates/.agents/skills/review-pr/SKILL.en.md +158 -0
  210. package/templates/.agents/skills/review-pr/SKILL.zh-CN.md +158 -0
  211. package/templates/.agents/skills/review-pr/config/verify.en.json +37 -0
  212. package/templates/.agents/skills/review-pr/config/verify.zh-CN.json +37 -0
  213. package/templates/.agents/skills/review-pr/reference/evidence-grading.en.md +65 -0
  214. package/templates/.agents/skills/review-pr/reference/evidence-grading.zh-CN.md +65 -0
  215. package/templates/.agents/skills/review-pr/reference/output-guidance.en.md +18 -0
  216. package/templates/.agents/skills/review-pr/reference/output-guidance.zh-CN.md +18 -0
  217. package/templates/.agents/skills/review-pr/reference/report-template.en.md +85 -0
  218. package/templates/.agents/skills/review-pr/reference/report-template.zh-CN.md +85 -0
  219. package/templates/.agents/skills/run-task/SKILL.en.md +8 -8
  220. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +8 -8
  221. package/templates/.agents/skills/run-task/config/verify.en.json +2 -1
  222. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +2 -1
  223. package/templates/.agents/skills/run-task/reference/host-validation.en.md +20 -0
  224. package/templates/.agents/skills/run-task/reference/host-validation.zh-CN.md +20 -0
  225. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +35 -61
  226. package/templates/.agents/skills/watch-pr/SKILL.en.md +13 -13
  227. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +13 -13
  228. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.en.md +27 -6
  229. package/templates/.agents/skills/watch-pr/reference/monitor-and-heal.zh-CN.md +26 -5
  230. package/templates/.agents/templates/task.en.md +1 -1
  231. package/templates/.agents/templates/task.zh-CN.md +1 -1
  232. package/templates/.agents/workflows/bug-fix.en.yaml +3 -3
  233. package/templates/.agents/workflows/bug-fix.zh-CN.yaml +3 -3
  234. package/templates/.agents/workflows/code-review.en.yaml +1 -1
  235. package/templates/.agents/workflows/code-review.zh-CN.yaml +1 -1
  236. package/templates/.agents/workflows/feature-development.en.yaml +4 -4
  237. package/templates/.agents/workflows/feature-development.zh-CN.yaml +4 -4
  238. package/templates/.agents/workflows/refactoring.en.yaml +3 -3
  239. package/templates/.agents/workflows/refactoring.zh-CN.yaml +3 -3
  240. package/templates/.claude/commands/post-release.en.md +1 -0
  241. package/templates/.claude/commands/post-release.zh-CN.md +1 -0
  242. package/templates/.claude/commands/review-pr.en.md +8 -0
  243. package/templates/.claude/commands/review-pr.zh-CN.md +8 -0
  244. package/templates/.gemini/commands/_project_/review-pr.en.toml +10 -0
  245. package/templates/.gemini/commands/_project_/review-pr.zh-CN.toml +10 -0
  246. package/templates/.opencode/commands/post-release.en.md +2 -0
  247. package/templates/.opencode/commands/post-release.zh-CN.md +2 -0
  248. package/templates/.opencode/commands/review-pr.en.md +11 -0
  249. package/templates/.opencode/commands/review-pr.zh-CN.md +11 -0
  250. package/dist/lib/agent-clients/adapters/gemini-cli.js +0 -64
  251. package/lib/agent-clients/adapters/gemini-cli.ts +0 -65
  252. package/templates/.gemini/commands/_project_/analyze-task.en.toml +0 -10
  253. package/templates/.gemini/commands/_project_/analyze-task.zh-CN.toml +0 -10
  254. package/templates/.gemini/commands/_project_/archive-tasks.en.toml +0 -10
  255. package/templates/.gemini/commands/_project_/archive-tasks.zh-CN.toml +0 -10
  256. package/templates/.gemini/commands/_project_/block-task.en.toml +0 -10
  257. package/templates/.gemini/commands/_project_/block-task.zh-CN.toml +0 -10
  258. package/templates/.gemini/commands/_project_/cancel-task.en.toml +0 -10
  259. package/templates/.gemini/commands/_project_/cancel-task.zh-CN.toml +0 -10
  260. package/templates/.gemini/commands/_project_/check-task.en.toml +0 -10
  261. package/templates/.gemini/commands/_project_/check-task.zh-CN.toml +0 -10
  262. package/templates/.gemini/commands/_project_/close-codescan.en.toml +0 -8
  263. package/templates/.gemini/commands/_project_/close-codescan.zh-CN.toml +0 -8
  264. package/templates/.gemini/commands/_project_/close-dependabot.en.toml +0 -8
  265. package/templates/.gemini/commands/_project_/close-dependabot.zh-CN.toml +0 -8
  266. package/templates/.gemini/commands/_project_/code-task.en.toml +0 -10
  267. package/templates/.gemini/commands/_project_/code-task.zh-CN.toml +0 -10
  268. package/templates/.gemini/commands/_project_/commit.en.toml +0 -10
  269. package/templates/.gemini/commands/_project_/commit.zh-CN.toml +0 -10
  270. package/templates/.gemini/commands/_project_/complete-manual-validation.en.toml +0 -10
  271. package/templates/.gemini/commands/_project_/complete-manual-validation.zh-CN.toml +0 -10
  272. package/templates/.gemini/commands/_project_/complete-task.en.toml +0 -10
  273. package/templates/.gemini/commands/_project_/complete-task.zh-CN.toml +0 -10
  274. package/templates/.gemini/commands/_project_/create-pr.en.toml +0 -10
  275. package/templates/.gemini/commands/_project_/create-pr.zh-CN.toml +0 -10
  276. package/templates/.gemini/commands/_project_/create-release-note.en.toml +0 -8
  277. package/templates/.gemini/commands/_project_/create-release-note.zh-CN.toml +0 -8
  278. package/templates/.gemini/commands/_project_/create-task.en.toml +0 -8
  279. package/templates/.gemini/commands/_project_/create-task.zh-CN.toml +0 -8
  280. package/templates/.gemini/commands/_project_/import-codescan.en.toml +0 -8
  281. package/templates/.gemini/commands/_project_/import-codescan.zh-CN.toml +0 -8
  282. package/templates/.gemini/commands/_project_/import-dependabot.en.toml +0 -8
  283. package/templates/.gemini/commands/_project_/import-dependabot.zh-CN.toml +0 -8
  284. package/templates/.gemini/commands/_project_/import-issue.en.toml +0 -8
  285. package/templates/.gemini/commands/_project_/import-issue.zh-CN.toml +0 -8
  286. package/templates/.gemini/commands/_project_/init-labels.en.toml +0 -8
  287. package/templates/.gemini/commands/_project_/init-labels.zh-CN.toml +0 -8
  288. package/templates/.gemini/commands/_project_/init-milestones.en.toml +0 -10
  289. package/templates/.gemini/commands/_project_/init-milestones.zh-CN.toml +0 -10
  290. package/templates/.gemini/commands/_project_/plan-task.en.toml +0 -10
  291. package/templates/.gemini/commands/_project_/plan-task.zh-CN.toml +0 -10
  292. package/templates/.gemini/commands/_project_/post-release.en.toml +0 -6
  293. package/templates/.gemini/commands/_project_/post-release.zh-CN.toml +0 -6
  294. package/templates/.gemini/commands/_project_/refine-title.en.toml +0 -8
  295. package/templates/.gemini/commands/_project_/refine-title.zh-CN.toml +0 -8
  296. package/templates/.gemini/commands/_project_/release.en.toml +0 -8
  297. package/templates/.gemini/commands/_project_/release.zh-CN.toml +0 -8
  298. package/templates/.gemini/commands/_project_/restore-task.en.toml +0 -8
  299. package/templates/.gemini/commands/_project_/restore-task.zh-CN.toml +0 -8
  300. package/templates/.gemini/commands/_project_/review-analysis.en.toml +0 -10
  301. package/templates/.gemini/commands/_project_/review-analysis.zh-CN.toml +0 -10
  302. package/templates/.gemini/commands/_project_/review-code.en.toml +0 -10
  303. package/templates/.gemini/commands/_project_/review-code.zh-CN.toml +0 -10
  304. package/templates/.gemini/commands/_project_/review-plan.en.toml +0 -10
  305. package/templates/.gemini/commands/_project_/review-plan.zh-CN.toml +0 -10
  306. package/templates/.gemini/commands/_project_/run-task.en.toml +0 -8
  307. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +0 -8
  308. package/templates/.gemini/commands/_project_/test-integration.en.toml +0 -6
  309. package/templates/.gemini/commands/_project_/test-integration.zh-CN.toml +0 -6
  310. package/templates/.gemini/commands/_project_/test.en.toml +0 -6
  311. package/templates/.gemini/commands/_project_/test.zh-CN.toml +0 -6
  312. package/templates/.gemini/commands/_project_/update-agent-infra.en.toml +0 -6
  313. package/templates/.gemini/commands/_project_/update-agent-infra.zh-CN.toml +0 -6
  314. package/templates/.gemini/commands/_project_/upgrade-dependency.en.toml +0 -8
  315. package/templates/.gemini/commands/_project_/upgrade-dependency.zh-CN.toml +0 -8
  316. package/templates/.gemini/commands/_project_/watch-pr.en.toml +0 -10
  317. package/templates/.gemini/commands/_project_/watch-pr.zh-CN.toml +0 -10
  318. package/templates/.gemini/settings.json +0 -3
@@ -7,8 +7,18 @@ import { inspectArtifactDirectory } from './artifact-lifecycle.js';
7
7
  import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
8
8
  import { resolveTaskRef } from './resolve-ref.js';
9
9
  import { activateDelegation, completeDelegationStage, consumeDelegation, managedDelegationRole, prepareDelegation, sealDelegation } from './delegation-receipts.js';
10
- import { getAgentClientCapability } from '../agent-clients/registry.js';
11
- import { captureWorkspaceSnapshot, diffWorkspaceSnapshots } from './workspace-snapshot.js';
10
+ import { normalizeAgentClients } from '../agent-clients/config.js';
11
+ import { inspectPlatformPullRequest } from '../platform/pull-requests.js';
12
+ import { getAgentClientCapability, getAgentClientDelegationEvidence, getAgentClientModelSelection } from '../agent-clients/registry.js';
13
+ import { isAgentClientId } from '../agent-clients/types.js';
14
+ import { captureRepositorySnapshot, captureWorkspaceSnapshot, diffWorkspaceSnapshots } from './workspace-snapshot.js';
15
+ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
16
+ function supportsLifecycleDelegation(client) {
17
+ return getAgentClientCapability(client, 'subagents').level !== 'unsupported'
18
+ && getAgentClientCapability(client, 'orchestration').level !== 'unsupported'
19
+ && getAgentClientDelegationEvidence(client).actualModel !== 'unavailable'
20
+ && getAgentClientDelegationEvidence(client).actualReasoningEffort !== 'unavailable';
21
+ }
12
22
  function orchestrationPath(taskDir) {
13
23
  return path.join(taskDir, 'orchestration.json');
14
24
  }
@@ -16,7 +26,22 @@ function readRun(taskDir) {
16
26
  const file = orchestrationPath(taskDir);
17
27
  if (!fs.existsSync(file))
18
28
  return null;
19
- return JSON.parse(fs.readFileSync(file, 'utf8'));
29
+ const run = JSON.parse(fs.readFileSync(file, 'utf8'));
30
+ if (run.schemaVersion !== 2 || !isV2Policy(run.modelPolicy))
31
+ return run;
32
+ return {
33
+ ...run,
34
+ modelPolicy: {
35
+ executor: {
36
+ model: run.modelPolicy.executor.model,
37
+ reasoningEffort: run.modelPolicy.executor.reasoningEffort
38
+ },
39
+ reviewer: {
40
+ model: run.modelPolicy.reviewer.model,
41
+ reasoningEffort: run.modelPolicy.reviewer.reasoningEffort
42
+ }
43
+ }
44
+ };
20
45
  }
21
46
  function atomicWrite(file, value) {
22
47
  const temp = `${file}.${process.pid}.${randomUUID()}.tmp`;
@@ -29,36 +54,209 @@ function saveRun(taskDir, run) {
29
54
  function withUpdatedRun(run, updates) {
30
55
  return Object.freeze({ ...run, ...updates, updatedAt: new Date().toISOString() });
31
56
  }
32
- function failed(code, message, taskId = null) {
33
- return { status: 'failed', changed: false, taskId, run: null, next: null, error: { code, message } };
57
+ function failed(code, message, taskId = null, details = {}) {
58
+ return { status: 'failed', changed: false, taskId, run: null, next: null, error: { code, message, ...details } };
59
+ }
60
+ function validModel(value) {
61
+ return typeof value === 'string' && value.length > 0 && value.trim() === value;
62
+ }
63
+ function validateModelPolicy(policy) {
64
+ if (!policy
65
+ || !validModel(policy.executor?.model)
66
+ || !validModel(policy.executor?.reasoningEffort)
67
+ || !validModel(policy.reviewer?.model)
68
+ || !validModel(policy.reviewer?.reasoningEffort)) {
69
+ return { code: 'ORCHESTRATION_MODEL_POLICY_REQUIRED', message: 'executor and reviewer model and reasoning effort are required' };
70
+ }
71
+ return null;
72
+ }
73
+ function sameModelPolicy(left, right) {
74
+ return left.executor.model === right.executor.model
75
+ && left.executor.reasoningEffort === right.executor.reasoningEffort
76
+ && left.reviewer.model === right.reviewer.model
77
+ && left.reviewer.reasoningEffort === right.reviewer.reasoningEffort;
78
+ }
79
+ function isV2Policy(policy) {
80
+ return typeof policy?.executor === 'object' && typeof policy?.reviewer === 'object';
81
+ }
82
+ function rolePolicy(run, role) {
83
+ return isV2Policy(run.modelPolicy) ? run.modelPolicy[role] : null;
84
+ }
85
+ function resolveProjectPolicy(repoRoot, client) {
86
+ const configPath = path.join(repoRoot, '.agents', '.airc.json');
87
+ if (!fs.existsSync(configPath))
88
+ return undefined;
89
+ const raw = JSON.parse(fs.readFileSync(configPath, 'utf8'));
90
+ return normalizeAgentClients(raw).state[client].orchestration;
34
91
  }
35
92
  function beginOrResumeOrchestration(taskRef, options = {}) {
36
93
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
37
94
  if (!resolved.ok)
38
95
  return failed(resolved.code, resolved.message, resolved.taskId);
39
- const existing = readRun(resolved.taskDir);
96
+ if (!isAgentClientId(options.client)) {
97
+ return failed('ORCHESTRATION_PAYLOAD_INVALID', 'begin-or-resume requires a known client', resolved.taskId);
98
+ }
99
+ let existing;
100
+ try {
101
+ existing = readRun(resolved.taskDir);
102
+ }
103
+ catch (error) {
104
+ return failed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
105
+ }
40
106
  if (existing) {
41
- if (existing.status === 'paused' && existing.pause?.recoverable && existing.pendingDelegation === null) {
42
- const resumed = withUpdatedRun(existing, { status: 'running', pause: null });
43
- saveRun(resolved.taskDir, resumed);
44
- return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
107
+ if (![1, 2].includes(existing.schemaVersion)
108
+ || !Array.isArray(existing.receipts)
109
+ || !Object.prototype.hasOwnProperty.call(existing, 'pendingDelegation')) {
110
+ return failed('ORCHESTRATION_STATE_INVALID', 'orchestration state has an invalid schema', resolved.taskId);
111
+ }
112
+ if (existing.status === 'completed' && existing.schemaVersion === 1) {
113
+ return { status: 'completed', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
114
+ }
115
+ if (existing.schemaVersion === 2) {
116
+ const policyError = validateModelPolicy(isV2Policy(existing.modelPolicy) ? existing.modelPolicy : undefined);
117
+ if (policyError
118
+ || !existing.modelPolicySource
119
+ || !isAgentClientId(existing.modelPolicySource.client)
120
+ || !Array.isArray(existing.recoveryHistory)) {
121
+ return failed('ORCHESTRATION_STATE_INVALID', 'schemaVersion 2 orchestration state is incomplete', resolved.taskId);
122
+ }
123
+ if (existing.status === 'completed') {
124
+ return { status: 'completed', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
125
+ }
126
+ if (existing.modelPolicySource.client !== options.client) {
127
+ return failed('ORCHESTRATION_CLIENT_MISMATCH', 'provided client does not match the persisted run policy source', resolved.taskId);
128
+ }
129
+ if (options.modelPolicy) {
130
+ const suppliedError = validateModelPolicy(options.modelPolicy);
131
+ if (suppliedError)
132
+ return failed(suppliedError.code, suppliedError.message, resolved.taskId);
133
+ if (!sameModelPolicy(existing.modelPolicy, options.modelPolicy)) {
134
+ return failed('ORCHESTRATION_MODEL_POLICY_MISMATCH', 'provided model policy does not match the persisted run policy', resolved.taskId);
135
+ }
136
+ }
137
+ if (existing.status === 'paused' && existing.pause?.recoverable && existing.pendingDelegation === null) {
138
+ const resumed = withUpdatedRun(existing, { status: 'running', pause: null });
139
+ saveRun(resolved.taskDir, resumed);
140
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: resumed, next: null, error: null };
141
+ }
142
+ return { status: existing.status, changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
143
+ }
144
+ let policy = options.modelPolicy;
145
+ let sourceKind = 'explicit';
146
+ if (!policy) {
147
+ try {
148
+ policy = resolveProjectPolicy(resolved.repoRoot, options.client);
149
+ sourceKind = 'project-config';
150
+ }
151
+ catch (error) {
152
+ return failed('ORCHESTRATION_CONFIG_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
153
+ }
154
+ }
155
+ const policyError = validateModelPolicy(policy);
156
+ if (policyError) {
157
+ return failed(policyError.code, policyError.message, resolved.taskId, {
158
+ client: options.client,
159
+ missingFields: ['executor.model', 'executor.reasoningEffort', 'reviewer.model', 'reviewer.reasoningEffort'],
160
+ modelSelectionContext: getAgentClientModelSelection(options.client)
161
+ });
162
+ }
163
+ if (existing.pendingDelegation !== null) {
164
+ const alreadyPaused = existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_DELEGATION_BUSY';
165
+ if (alreadyPaused)
166
+ return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
167
+ const paused = withUpdatedRun(existing, {
168
+ status: 'paused',
169
+ pause: { code: 'ORCHESTRATION_DELEGATION_BUSY', message: 'legacy run has a pending delegation', recoverable: false }
170
+ });
171
+ saveRun(resolved.taskDir, paused);
172
+ return { status: 'paused', changed: true, taskId: resolved.taskId, run: paused, next: null, error: null };
173
+ }
174
+ if (existing.receipts.length > 0) {
175
+ const alreadyPaused = existing.status === 'paused' && existing.pause?.code === 'ORCHESTRATION_HISTORICAL_EFFORT_UNVERIFIED';
176
+ if (alreadyPaused)
177
+ return { status: 'paused', changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
178
+ const paused = withUpdatedRun(existing, {
179
+ status: 'paused',
180
+ pause: {
181
+ code: 'ORCHESTRATION_HISTORICAL_EFFORT_UNVERIFIED',
182
+ message: 'legacy receipts do not contain actual reasoning-effort evidence',
183
+ recoverable: false
184
+ }
185
+ });
186
+ saveRun(resolved.taskDir, paused);
187
+ return { status: 'paused', changed: true, taskId: resolved.taskId, run: paused, next: null, error: null };
188
+ }
189
+ if (existing.modelPolicy
190
+ && typeof existing.modelPolicy.executor === 'string'
191
+ && (existing.modelPolicy.executor !== policy.executor.model
192
+ || existing.modelPolicy.reviewer !== policy.reviewer.model)) {
193
+ return failed('ORCHESTRATION_MODEL_POLICY_MISMATCH', 'provided model policy does not match the persisted run policy', resolved.taskId);
194
+ }
195
+ const now = (options.now ?? (() => new Date().toISOString()))();
196
+ const source = { kind: sourceKind, client: options.client, resolvedAt: now };
197
+ const clearsModelPause = existing.pause?.code === 'ORCHESTRATION_MODEL_EVIDENCE_MISSING';
198
+ const resultingStatus = clearsModelPause ? 'running' : existing.status;
199
+ const recovery = {
200
+ code: 'MODEL_POLICY_SUPPLEMENTED',
201
+ recoveredAt: now,
202
+ previousSchemaVersion: 1,
203
+ previousStatus: existing.status,
204
+ previousPause: existing.pause,
205
+ policySource: source,
206
+ receiptCount: 0,
207
+ pendingDelegation: false,
208
+ resultingStatus
209
+ };
210
+ const recovered = Object.freeze({
211
+ ...existing,
212
+ schemaVersion: 2,
213
+ status: resultingStatus,
214
+ modelPolicy: policy,
215
+ modelPolicySource: source,
216
+ recoveryHistory: Object.freeze([recovery]),
217
+ pause: clearsModelPause ? null : existing.pause,
218
+ updatedAt: now
219
+ });
220
+ saveRun(resolved.taskDir, recovered);
221
+ return { status: resultingStatus, changed: true, taskId: resolved.taskId, run: recovered, next: null, error: null };
222
+ }
223
+ let policy = options.modelPolicy;
224
+ let sourceKind = 'explicit';
225
+ if (!policy) {
226
+ try {
227
+ policy = resolveProjectPolicy(resolved.repoRoot, options.client);
228
+ sourceKind = 'project-config';
229
+ }
230
+ catch (error) {
231
+ return failed('ORCHESTRATION_CONFIG_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
45
232
  }
46
- return { status: existing.status, changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
47
233
  }
234
+ const policyError = validateModelPolicy(policy);
235
+ if (policyError)
236
+ return failed(policyError.code, policyError.message, resolved.taskId, {
237
+ client: options.client,
238
+ missingFields: ['executor.model', 'executor.reasoningEffort', 'reviewer.model', 'reviewer.reasoningEffort'],
239
+ modelSelectionContext: getAgentClientModelSelection(options.client)
240
+ });
48
241
  const now = (options.now ?? (() => new Date().toISOString()))();
242
+ const source = { kind: sourceKind, client: options.client, resolvedAt: now };
49
243
  const run = {
50
- schemaVersion: 1,
244
+ schemaVersion: 2,
51
245
  taskId: resolved.taskId,
52
246
  runId: (options.id ?? randomUUID)(),
53
247
  status: 'running',
54
248
  nextStage: null,
55
249
  stepCount: 0,
56
250
  maxSteps: options.maxSteps ?? 24,
251
+ modelPolicy: policy,
252
+ modelPolicySource: source,
253
+ recoveryHistory: [],
57
254
  baseline: '',
58
255
  pendingDelegation: null,
59
256
  receipts: [],
60
257
  pause: null,
61
258
  commitAuthorization: { issuedAt: null, consumedAt: null },
259
+ completionEvidence: null,
62
260
  createdAt: now,
63
261
  updatedAt: now
64
262
  };
@@ -146,24 +344,29 @@ function routeOrchestration(taskRef, options = {}) {
146
344
  catch (error) {
147
345
  return failed('ORCHESTRATION_TASK_READ_FAILED', String(error), resolved.taskId);
148
346
  }
347
+ let metadata;
149
348
  try {
150
- parseTypedTaskFrontmatter(content);
349
+ metadata = parseTypedTaskFrontmatter(content);
151
350
  }
152
351
  catch (error) {
153
352
  return failed('ORCHESTRATION_TASK_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
154
353
  }
155
- const next = routeFromFacts(resolved.taskDir);
156
- if (!next)
354
+ const routed = routeFromFacts(resolved.taskDir);
355
+ if (!routed)
157
356
  return failed('ORCHESTRATION_ROUTE_UNKNOWN', 'cannot determine a unique lifecycle action', resolved.taskId);
357
+ const run = readRun(resolved.taskDir);
358
+ const policy = run ? rolePolicy(run, routed.role) : null;
359
+ const next = {
360
+ ...routed,
361
+ requestedModel: policy?.model ?? null,
362
+ requestedReasoningEffort: policy?.reasoningEffort ?? null
363
+ };
158
364
  if (next.stage === 'commit') {
159
365
  const reviewRound = highestRound(resolved.taskDir, 'review-code');
160
366
  const review = parseReviewSummary(fs.readFileSync(path.join(resolved.taskDir, artifactName('review-code', reviewRound)), 'utf8'));
161
367
  if (!review.ok || review.summary.manualValidation === null) {
162
368
  return failed('ORCHESTRATION_REVIEW_INVALID', 'latest code review has no numeric manual-validation count', resolved.taskId);
163
369
  }
164
- if (review.summary.manualValidation > 0) {
165
- return failed('ORCHESTRATION_MANUAL_VALIDATION_PENDING', 'manual validation must be completed before commit', resolved.taskId);
166
- }
167
370
  const rows = parseLedger(content);
168
371
  const ledgerError = validateLedgerRows(rows);
169
372
  if (ledgerError)
@@ -171,8 +374,107 @@ function routeOrchestration(taskRef, options = {}) {
171
374
  if (!summarizeLedgerStage(rows, 'code').canAdvance) {
172
375
  return failed('ORCHESTRATION_LEDGER_BLOCKED', 'code review ledger has unresolved findings or human decisions', resolved.taskId);
173
376
  }
377
+ if (run?.status === 'completed') {
378
+ return { status: 'completed', changed: false, taskId: resolved.taskId, run, next: null, error: null };
379
+ }
380
+ let config;
381
+ try {
382
+ config = JSON.parse(fs.readFileSync(path.join(resolved.repoRoot, '.agents', '.airc.json'), 'utf8'));
383
+ }
384
+ catch (error) {
385
+ return failed('ORCHESTRATION_CONFIG_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
386
+ }
387
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
388
+ return failed('ORCHESTRATION_CONFIG_INVALID', 'project configuration must be an object', resolved.taskId);
389
+ }
390
+ const projectConfig = config;
391
+ if (!Object.hasOwn(projectConfig, 'prFlow') || projectConfig.prFlow === 'disabled') {
392
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
393
+ }
394
+ if (projectConfig.prFlow !== 'required') {
395
+ return failed('ORCHESTRATION_CONFIG_INVALID', "project configuration 'prFlow' must be 'required' or 'disabled'", resolved.taskId);
396
+ }
397
+ const prNumber = Number(metadata.pr_number);
398
+ if (!Number.isInteger(prNumber) || prNumber <= 0) {
399
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
400
+ }
401
+ if (!run) {
402
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
403
+ }
404
+ if (run.status !== 'running' || run.pendingDelegation !== null) {
405
+ return failed('ORCHESTRATION_RUN_NOT_RUNNING', 'clean completion requires an idle running orchestration', resolved.taskId);
406
+ }
407
+ const capture = options.captureRepository ?? captureRepositorySnapshot;
408
+ let before;
409
+ try {
410
+ before = capture(resolved.repoRoot);
411
+ }
412
+ catch (error) {
413
+ return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
414
+ }
415
+ if (before.headTree !== before.worktreeTree) {
416
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
417
+ }
418
+ const lastReviewedCommit = String(metadata.last_reviewed_commit ?? '');
419
+ if (before.head !== lastReviewedCommit) {
420
+ return failed('ORCHESTRATION_REVIEWED_HEAD_MISMATCH', 'local HEAD does not match last_reviewed_commit', resolved.taskId);
421
+ }
422
+ const inspect = options.inspectPullRequest ?? inspectPlatformPullRequest;
423
+ let inspection;
424
+ try {
425
+ inspection = inspect(resolved.taskId, { cwd: resolved.repoRoot });
426
+ }
427
+ catch (error) {
428
+ return failed('ORCHESTRATION_PR_INSPECTION_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
429
+ }
430
+ if (inspection.status === 'blocked') {
431
+ return failed('ORCHESTRATION_PR_INSPECTION_BLOCKED', inspection.error?.message ?? 'pull request inspection is blocked', resolved.taskId);
432
+ }
433
+ if (inspection.status === 'failed') {
434
+ return failed('ORCHESTRATION_PR_INSPECTION_FAILED', inspection.error?.message ?? 'pull request inspection failed', resolved.taskId);
435
+ }
436
+ const inspectedPrNumber = inspection.task?.prNumber ?? inspection.prNumber;
437
+ const prHead = inspection.pullRequest?.head?.sha;
438
+ if (typeof prHead !== 'string') {
439
+ return failed('ORCHESTRATION_PR_INSPECTION_INVALID', 'pull request inspection returned incomplete identity evidence', resolved.taskId);
440
+ }
441
+ if (inspectedPrNumber !== prNumber || prHead !== before.head) {
442
+ return failed('ORCHESTRATION_PR_HEAD_MISMATCH', 'pull request identity does not match the reviewed local HEAD', resolved.taskId);
443
+ }
444
+ let after;
445
+ try {
446
+ after = capture(resolved.repoRoot);
447
+ }
448
+ catch (error) {
449
+ return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
450
+ }
451
+ if (after.headTree !== after.worktreeTree) {
452
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
453
+ }
454
+ if (after.head !== before.head || after.headTree !== before.headTree) {
455
+ return failed('ORCHESTRATION_REPOSITORY_CHANGED', 'repository changed while clean completion evidence was collected', resolved.taskId);
456
+ }
457
+ const observedAt = (options.now ?? (() => new Date().toISOString()))();
458
+ const completionEvidence = {
459
+ kind: 'reviewed-head-clean',
460
+ observedAt,
461
+ head: after.head,
462
+ headTree: after.headTree,
463
+ worktreeTree: after.worktreeTree,
464
+ lastReviewedCommit,
465
+ prNumber,
466
+ prHead
467
+ };
468
+ const completed = withUpdatedRun(run, {
469
+ status: 'completed',
470
+ nextStage: null,
471
+ pause: null,
472
+ completionEvidence
473
+ });
474
+ saveRun(resolved.taskDir, completed);
475
+ return { status: 'completed', changed: true, taskId: resolved.taskId, run: completed, next: null, error: null };
174
476
  }
175
- return { status: 'running', changed: false, taskId: resolved.taskId, run: readRun(resolved.taskDir), next, error: null };
477
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next, error: null };
176
478
  }
177
479
  function statusOrchestration(taskRef, options = {}) {
178
480
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
@@ -183,17 +485,18 @@ function statusOrchestration(taskRef, options = {}) {
183
485
  return failed('ORCHESTRATION_RUN_MISSING', 'no orchestration run exists', resolved.taskId);
184
486
  return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
185
487
  }
186
- function prepareOrchestrationDelegation(taskRef, input, options = {}) {
488
+ function prepareOrchestrationDelegationUnlocked(taskRef, input, options = {}) {
187
489
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
188
490
  if (!resolved.ok)
189
491
  return failed(resolved.code, resolved.message, resolved.taskId);
190
- if (getAgentClientCapability(input.client, 'subagents').level === 'unsupported'
191
- || getAgentClientCapability(input.client, 'orchestration').level === 'unsupported') {
492
+ if (!(options.supportsLifecycleDelegation ?? supportsLifecycleDelegation)(input.client)) {
192
493
  return failed('ORCHESTRATION_CLIENT_UNSUPPORTED', `client '${input.client}' does not support lifecycle orchestration`, resolved.taskId);
193
494
  }
194
495
  const run = readRun(resolved.taskDir);
195
496
  if (!run || run.status !== 'running')
196
497
  return failed('ORCHESTRATION_RUN_NOT_RUNNING', 'a running orchestration is required', resolved.taskId);
498
+ if (!isV2Policy(run.modelPolicy))
499
+ return failed('ORCHESTRATION_MODEL_EVIDENCE_MISSING', 'running orchestration has no persisted model policy', resolved.taskId);
197
500
  if (run.pendingDelegation)
198
501
  return failed('ORCHESTRATION_DELEGATION_BUSY', 'the run already has a pending delegation', resolved.taskId);
199
502
  const repositoryPending = ['claude-code', 'codex']
@@ -207,9 +510,22 @@ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
207
510
  if (!routed.next)
208
511
  return routed;
209
512
  const next = routed.next;
513
+ if (!validModel(input.requestedModel)) {
514
+ return failed('ORCHESTRATION_REQUESTED_MODEL_REQUIRED', 'prepare requires the exact requested model identity', resolved.taskId);
515
+ }
516
+ if (!validModel(input.requestedReasoningEffort)) {
517
+ return failed('ORCHESTRATION_REQUESTED_REASONING_EFFORT_REQUIRED', 'prepare requires the exact requested reasoning effort', resolved.taskId);
518
+ }
519
+ const expectedPolicy = run.modelPolicy[next.role];
520
+ if (input.requestedModel !== expectedPolicy.model) {
521
+ return failed('ORCHESTRATION_REQUESTED_MODEL_MISMATCH', `requested model does not match the persisted ${next.role} model`, resolved.taskId);
522
+ }
523
+ if (input.requestedReasoningEffort !== expectedPolicy.reasoningEffort) {
524
+ return failed('ORCHESTRATION_REQUESTED_REASONING_EFFORT_MISMATCH', `requested reasoning effort does not match the persisted ${next.role} policy`, resolved.taskId);
525
+ }
210
526
  let beforeFingerprint;
211
527
  try {
212
- beforeFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(resolved.repoRoot);
528
+ beforeFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(resolved.repoRoot, resolved.taskId);
213
529
  }
214
530
  catch (error) {
215
531
  return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
@@ -222,7 +538,9 @@ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
222
538
  round: next.round,
223
539
  artifact: next.artifact,
224
540
  client: input.client,
225
- requestedModel: input.requestedModel ?? null,
541
+ requestedModel: input.requestedModel,
542
+ requestedReasoningEffort: input.requestedReasoningEffort,
543
+ workspaceSnapshotScope: 'task',
226
544
  beforeFingerprint
227
545
  }, { id: options.id, now: options.now });
228
546
  const updated = withUpdatedRun(run, {
@@ -235,6 +553,19 @@ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
235
553
  saveRun(resolved.taskDir, updated);
236
554
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next, error: null };
237
555
  }
556
+ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
557
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
558
+ if (!resolved.ok)
559
+ return failed(resolved.code, resolved.message, resolved.taskId);
560
+ try {
561
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-orchestration.prepare', () => prepareOrchestrationDelegationUnlocked(taskRef, input, options));
562
+ }
563
+ catch (error) {
564
+ if (error instanceof TaskExecutionLockError)
565
+ return failed(error.code, error.message, resolved.taskId);
566
+ throw error;
567
+ }
568
+ }
238
569
  function matchingDelegations(client, predicate, options) {
239
570
  const repoRoot = options.repoRoot ?? process.cwd();
240
571
  const activeRoot = path.join(repoRoot, '.agents', 'workspace', 'active');
@@ -285,7 +616,8 @@ function sealMatchingOrchestrationDelegation(client, event, options = {}) {
285
616
  }
286
617
  const repoRoot = options.repoRoot ?? process.cwd();
287
618
  try {
288
- const afterFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(repoRoot);
619
+ const snapshotTaskId = receipt.workspaceSnapshotScope === 'task' ? receipt.taskId : null;
620
+ const afterFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(repoRoot, snapshotTaskId);
289
621
  const changedPaths = (options.diffWorkspace ?? diffWorkspaceSnapshots)(repoRoot, receipt.beforeFingerprint, afterFingerprint);
290
622
  return sealOrchestrationDelegation(matched.taskId, {
291
623
  childId: event.childId,
@@ -331,6 +663,56 @@ function completeOrchestrationStage(taskRef, event, options = {}) {
331
663
  saveRun(resolved.taskDir, updated);
332
664
  return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
333
665
  }
666
+ function inspectOrchestrationStage(taskRef, event, options = {}) {
667
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
668
+ if (!resolved.ok)
669
+ return failed(resolved.code, resolved.message, resolved.taskId);
670
+ let run;
671
+ try {
672
+ run = readRun(resolved.taskDir);
673
+ }
674
+ catch (error) {
675
+ return failed('ORCHESTRATION_STATE_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
676
+ }
677
+ if (!run)
678
+ return failed('ORCHESTRATION_RUN_MISSING', 'no orchestration run exists', resolved.taskId);
679
+ const receipt = run.pendingDelegation;
680
+ if (!receipt
681
+ || receipt.status !== 'activated'
682
+ || receipt.stage !== event.stage
683
+ || receipt.round !== event.round
684
+ || receipt.artifact !== event.artifact
685
+ || receipt.role !== event.role) {
686
+ return failed('ORCHESTRATION_PROVENANCE_MISMATCH', 'active run does not have one matching activated delegation', resolved.taskId);
687
+ }
688
+ return { status: 'running', changed: false, taskId: resolved.taskId, run, next: null, error: null };
689
+ }
690
+ function planOrchestrationStageCompletion(taskRef, event, options = {}) {
691
+ const inspected = inspectOrchestrationStage(taskRef, event, options);
692
+ if (inspected.status === 'failed' || !inspected.run?.pendingDelegation) {
693
+ return { result: inspected, plan: null };
694
+ }
695
+ const receipt = inspected.run.pendingDelegation;
696
+ const completed = completeDelegationStage(receipt, event);
697
+ if (!completed.ok) {
698
+ return { result: failed(completed.code, completed.message, inspected.taskId), plan: null };
699
+ }
700
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
701
+ if (!resolved.ok)
702
+ return { result: failed(resolved.code, resolved.message, resolved.taskId), plan: null };
703
+ const updatedRun = withUpdatedRun(inspected.run, { pendingDelegation: completed.receipt });
704
+ return {
705
+ result: { status: 'running', changed: true, taskId: resolved.taskId, run: updatedRun, next: null, error: null },
706
+ plan: {
707
+ taskId: resolved.taskId,
708
+ taskDir: resolved.taskDir,
709
+ updatedRun
710
+ }
711
+ };
712
+ }
713
+ function commitOrchestrationStageCompletion(plan) {
714
+ saveRun(plan.taskDir, plan.updatedRun);
715
+ }
334
716
  function completeCommitOrchestrationStage(taskRef, agent, options = {}) {
335
717
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
336
718
  if (!resolved.ok)
@@ -349,24 +731,6 @@ function completeCommitOrchestrationStage(taskRef, agent, options = {}) {
349
731
  agent
350
732
  }, options);
351
733
  }
352
- function validateOrchestrationStage(taskRef, event, options = {}) {
353
- const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
354
- if (!resolved.ok)
355
- return failed(resolved.code, resolved.message, resolved.taskId);
356
- const run = readRun(resolved.taskDir);
357
- if (!run)
358
- return { status: 'running', changed: false, taskId: resolved.taskId, run: null, next: null, error: null };
359
- const receipt = run.pendingDelegation;
360
- if (!receipt
361
- || receipt.status !== 'activated'
362
- || receipt.stage !== event.stage
363
- || receipt.round !== event.round
364
- || receipt.artifact !== event.artifact
365
- || receipt.role !== event.role) {
366
- return pauseOrchestration(taskRef, 'ORCHESTRATION_PROVENANCE_MISMATCH', 'active run does not have one matching activated delegation', true, options);
367
- }
368
- return { status: 'running', changed: false, taskId: resolved.taskId, run, next: null, error: null };
369
- }
370
734
  function sealOrchestrationDelegation(taskRef, event, options = {}) {
371
735
  const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
372
736
  if (!resolved.ok)
@@ -416,5 +780,5 @@ function pauseOrchestration(taskRef, code, message, recoverable, options = {}) {
416
780
  saveRun(resolved.taskDir, updated);
417
781
  return { status: 'paused', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
418
782
  }
419
- export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, beginOrResumeOrchestration, completeCommitOrchestrationStage, completeOrchestrationStage, orchestrationPath, pauseOrchestration, prepareOrchestrationDelegation, readRun, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration, validateOrchestrationStage };
783
+ export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, beginOrResumeOrchestration, commitOrchestrationStageCompletion, completeCommitOrchestrationStage, completeOrchestrationStage, inspectOrchestrationStage, orchestrationPath, pauseOrchestration, planOrchestrationStageCompletion, prepareOrchestrationDelegation, readRun, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration };
420
784
  //# sourceMappingURL=orchestration.js.map
@@ -6,7 +6,8 @@ import { parseArtifactName, validateCompletedArtifact } from './artifact-lifecyc
6
6
  import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
7
7
  import { finalizeReviewSummaryContent } from './review-artifacts.js';
8
8
  import { resolveTaskRef } from './resolve-ref.js';
9
- import { validateOrchestrationStage } from './orchestration.js';
9
+ import { validateLifecycleExecution } from './lifecycle-execution.js';
10
+ import { TaskExecutionLockError, withTaskExecutionLock } from './task-execution-lock.js';
10
11
  const STAGES = {
11
12
  analysis: { family: 'review-analysis', action: 'Review Analysis' },
12
13
  plan: { family: 'review-plan', action: 'Review Plan' },
@@ -48,7 +49,7 @@ function cleanupTemp(fileSystem, tempPath) {
48
49
  // Best-effort cleanup preserves the primary failure.
49
50
  }
50
51
  }
51
- function finalizeReviewSummary(request, options = {}) {
52
+ function finalizeReviewSummaryUnlocked(request, options = {}) {
52
53
  const stage = request.stage;
53
54
  const spec = STAGES[stage];
54
55
  if (!spec)
@@ -86,14 +87,18 @@ function finalizeReviewSummary(request, options = {}) {
86
87
  if (!openReviewRound(taskContent, spec.action, parsedArtifact.round)) {
87
88
  return failed(request, 'REVIEW_ARTIFACT_IDENTITY_INVALID', `${request.artifact} does not have one matching open started review event`, resolved.taskId);
88
89
  }
89
- const provenance = validateOrchestrationStage(request.taskRef, {
90
- stage: spec.family,
91
- round: parsedArtifact.round,
92
- artifact: request.artifact,
93
- role: 'reviewer'
90
+ const execution = validateLifecycleExecution(request.taskRef, {
91
+ mode: request.orchestrated ? 'orchestrated' : 'standalone',
92
+ identity: {
93
+ stage: spec.family,
94
+ round: parsedArtifact.round,
95
+ artifact: request.artifact,
96
+ role: 'reviewer'
97
+ },
98
+ dryRun: request.dryRun
94
99
  }, { 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);
100
+ if (!execution.ok) {
101
+ return failed(request, 'REVIEW_PROVENANCE_INVALID', `${execution.error?.code ?? 'ORCHESTRATION_PROVENANCE_MISMATCH'}: ${execution.error?.message ?? 'orchestration provenance validation failed'}`, resolved.taskId);
97
102
  }
98
103
  let rows;
99
104
  try {
@@ -162,5 +167,20 @@ function finalizeReviewSummary(request, options = {}) {
162
167
  error: null
163
168
  };
164
169
  }
170
+ function finalizeReviewSummary(request, options = {}) {
171
+ if (request.dryRun)
172
+ return finalizeReviewSummaryUnlocked(request, options);
173
+ const resolved = resolveTaskRef(request.taskRef, { repoRoot: options.repoRoot });
174
+ if (!resolved.ok)
175
+ return finalizeReviewSummaryUnlocked(request, options);
176
+ try {
177
+ return withTaskExecutionLock(resolved.repoRoot, resolved.taskId, 'task-review.finalize-summary', () => finalizeReviewSummaryUnlocked(request, options));
178
+ }
179
+ catch (error) {
180
+ if (!(error instanceof TaskExecutionLockError))
181
+ throw error;
182
+ return failed(request, 'REVIEW_PROVENANCE_INVALID', `${error.code}: ${error.message}`, resolved.taskId);
183
+ }
184
+ }
165
185
  export { finalizeReviewSummary };
166
186
  //# sourceMappingURL=review-finalization.js.map