@fitlab-ai/agent-infra 0.9.1 → 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 (283) hide show
  1. package/README.md +16 -4
  2. package/README.zh-CN.md +16 -4
  3. package/bin/cli.ts +12 -0
  4. package/dist/bin/cli.js +14 -0
  5. package/dist/bin/internal-cli.js +15 -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/release-workflow.js +71 -16
  31. package/dist/lib/internal/task-orchestration.js +151 -0
  32. package/dist/lib/internal/task-review.js +65 -0
  33. package/dist/lib/merge.js +2 -1
  34. package/dist/lib/platform/adapters.js +38 -1
  35. package/dist/lib/platform/change-request-git-evidence.js +113 -0
  36. package/dist/lib/platform/merged-pr-equivalence.js +41 -11
  37. package/dist/lib/platform/pr-checks.js +38 -10
  38. package/dist/lib/platform/pull-requests.js +110 -6
  39. package/dist/lib/platform/releases.js +1 -1
  40. package/dist/lib/platform/verification-required.js +8 -10
  41. package/dist/lib/prompt.js +15 -3
  42. package/dist/lib/release/channels.js +4 -1
  43. package/dist/lib/release/workflow.js +4 -2
  44. package/dist/lib/remove-dir.js +25 -0
  45. package/dist/lib/run/tui.js +8 -2
  46. package/dist/lib/sandbox/agent-client-reconciler.js +234 -0
  47. package/dist/lib/sandbox/clipboard/linux.js +2 -1
  48. package/dist/lib/sandbox/commands/create.js +76 -180
  49. package/dist/lib/sandbox/commands/enter.js +17 -1
  50. package/dist/lib/sandbox/commands/prune.js +2 -2
  51. package/dist/lib/sandbox/commands/rm.js +3 -2
  52. package/dist/lib/sandbox/config.js +21 -4
  53. package/dist/lib/sandbox/constants.js +3 -0
  54. package/dist/lib/sandbox/dockerfile.js +2 -1
  55. package/dist/lib/sandbox/managed-fs.js +10 -5
  56. package/dist/lib/sandbox/recovery.js +52 -36
  57. package/dist/lib/sandbox/shell.js +1 -1
  58. package/dist/lib/sandbox/tool-types.js +8 -0
  59. package/dist/lib/sandbox/tools.js +2 -126
  60. package/dist/lib/task/artifact-lifecycle.js +1 -49
  61. package/dist/lib/task/commands/decisions.js +50 -20
  62. package/dist/lib/task/delegation-receipts.js +107 -0
  63. package/dist/lib/task/events.js +100 -1
  64. package/dist/lib/task/orchestration.js +420 -0
  65. package/dist/lib/task/review-artifacts.js +143 -59
  66. package/dist/lib/task/review-finalization.js +166 -0
  67. package/dist/lib/task/review-fingerprint.js +4 -0
  68. package/dist/lib/task/verification-checks.js +2 -1
  69. package/dist/lib/task/verification-engine.js +156 -28
  70. package/dist/lib/task/verification-review.js +1 -1
  71. package/dist/lib/task/verification.js +3 -1
  72. package/dist/lib/task/workspace-snapshot.js +34 -0
  73. package/dist/lib/update.js +42 -161
  74. package/lib/agent-client.ts +214 -0
  75. package/lib/agent-clients/adapter.ts +461 -0
  76. package/lib/agent-clients/adapters/claude-code.ts +70 -0
  77. package/lib/agent-clients/adapters/codex-sandbox.ts +245 -0
  78. package/lib/agent-clients/adapters/codex.ts +58 -0
  79. package/lib/agent-clients/adapters/gemini-cli.ts +65 -0
  80. package/lib/agent-clients/adapters/index.ts +27 -0
  81. package/lib/agent-clients/adapters/opencode.ts +66 -0
  82. package/lib/agent-clients/config.ts +278 -0
  83. package/lib/agent-clients/custom-tuis.ts +149 -0
  84. package/lib/agent-clients/invocation.ts +19 -0
  85. package/lib/agent-clients/next-steps.ts +72 -0
  86. package/lib/agent-clients/project-assets.ts +96 -0
  87. package/lib/agent-clients/reconcile.ts +324 -0
  88. package/lib/agent-clients/registry.ts +144 -0
  89. package/lib/agent-clients/schema.ts +62 -0
  90. package/lib/agent-clients/types.ts +78 -0
  91. package/lib/benchmark/schemas/v1.0.0/case-manifest.schema.json +120 -0
  92. package/lib/benchmark/schemas/v1.0.0/common.schema.json +109 -0
  93. package/lib/benchmark/schemas/v1.0.0/grader-result.schema.json +160 -0
  94. package/lib/benchmark/schemas/v1.0.0/run-manifest.schema.json +122 -0
  95. package/lib/benchmark/schemas/v1.0.0/subject.schema.json +227 -0
  96. package/lib/builtin-tuis.ts +16 -15
  97. package/lib/defaults.json +24 -12
  98. package/lib/git/review-snapshot.ts +39 -9
  99. package/lib/git/reviewed-commit-equivalence.ts +135 -0
  100. package/lib/init.ts +53 -121
  101. package/lib/internal/agent-client.ts +131 -0
  102. package/lib/internal/git-workflow.ts +1 -1
  103. package/lib/internal/release-workflow.ts +68 -16
  104. package/lib/internal/task-orchestration.ts +132 -0
  105. package/lib/internal/task-review.ts +65 -0
  106. package/lib/merge.ts +2 -1
  107. package/lib/platform/adapters.ts +142 -3
  108. package/lib/platform/change-request-git-evidence.ts +159 -0
  109. package/lib/platform/merged-pr-equivalence.ts +51 -14
  110. package/lib/platform/pr-checks.ts +50 -22
  111. package/lib/platform/pull-requests.ts +134 -25
  112. package/lib/platform/releases.ts +1 -1
  113. package/lib/platform/verification-required.ts +12 -10
  114. package/lib/prompt.ts +16 -3
  115. package/lib/release/channels.ts +4 -1
  116. package/lib/release/workflow.ts +4 -3
  117. package/lib/remove-dir.ts +28 -0
  118. package/lib/run/tui.ts +9 -1
  119. package/lib/sandbox/agent-client-reconciler.ts +378 -0
  120. package/lib/sandbox/clipboard/linux.ts +2 -1
  121. package/lib/sandbox/commands/create.ts +111 -192
  122. package/lib/sandbox/commands/enter.ts +23 -1
  123. package/lib/sandbox/commands/prune.ts +2 -2
  124. package/lib/sandbox/commands/rm.ts +3 -2
  125. package/lib/sandbox/config.ts +31 -4
  126. package/lib/sandbox/constants.ts +6 -0
  127. package/lib/sandbox/dockerfile.ts +2 -1
  128. package/lib/sandbox/managed-fs.ts +18 -5
  129. package/lib/sandbox/recovery.ts +98 -67
  130. package/lib/sandbox/shell.ts +1 -1
  131. package/lib/sandbox/tool-types.ts +143 -0
  132. package/lib/sandbox/tools.ts +5 -157
  133. package/lib/task/artifact-lifecycle.ts +1 -38
  134. package/lib/task/commands/decisions.ts +53 -20
  135. package/lib/task/delegation-receipts.ts +170 -0
  136. package/lib/task/events.ts +110 -2
  137. package/lib/task/orchestration.ts +543 -0
  138. package/lib/task/review-artifacts.ts +201 -69
  139. package/lib/task/review-finalization.ts +275 -0
  140. package/lib/task/review-fingerprint.ts +5 -0
  141. package/lib/task/verification-checks.ts +2 -1
  142. package/lib/task/verification-engine.ts +177 -28
  143. package/lib/task/verification-review.ts +1 -0
  144. package/lib/task/verification.ts +5 -2
  145. package/lib/task/workspace-snapshot.ts +36 -0
  146. package/lib/update.ts +48 -184
  147. package/package.json +2 -2
  148. package/templates/.agents/README.en.md +21 -20
  149. package/templates/.agents/README.zh-CN.md +21 -20
  150. package/templates/.agents/hooks/lifecycle-delegation.js +64 -0
  151. package/templates/.agents/rules/README.en.md +2 -0
  152. package/templates/.agents/rules/README.zh-CN.md +2 -0
  153. package/templates/.agents/rules/commit-and-pr.en.md +1 -0
  154. package/templates/.agents/rules/commit-and-pr.zh-CN.md +1 -0
  155. package/templates/.agents/rules/human-decision-context.en.md +14 -12
  156. package/templates/.agents/rules/human-decision-context.zh-CN.md +14 -12
  157. package/templates/.agents/rules/lifecycle-orchestration.en.md +21 -0
  158. package/templates/.agents/rules/lifecycle-orchestration.zh-CN.md +21 -0
  159. package/templates/.agents/rules/next-step-output.en.md +16 -0
  160. package/templates/.agents/rules/next-step-output.zh-CN.md +16 -0
  161. package/templates/.agents/rules/no-mid-flow-questions.en.md +2 -0
  162. package/templates/.agents/rules/no-mid-flow-questions.zh-CN.md +2 -0
  163. package/templates/.agents/rules/release-commands.github.en.md +11 -5
  164. package/templates/.agents/rules/release-commands.github.zh-CN.md +11 -5
  165. package/templates/.agents/rules/review-handshake.en.md +4 -4
  166. package/templates/.agents/rules/review-handshake.zh-CN.md +4 -4
  167. package/templates/.agents/rules/review-method.en.md +113 -0
  168. package/templates/.agents/rules/review-method.zh-CN.md +98 -0
  169. package/templates/.agents/skills/analyze-task/SKILL.en.md +5 -5
  170. package/templates/.agents/skills/analyze-task/SKILL.zh-CN.md +5 -5
  171. package/templates/.agents/skills/block-task/SKILL.en.md +4 -4
  172. package/templates/.agents/skills/block-task/SKILL.zh-CN.md +4 -4
  173. package/templates/.agents/skills/cancel-task/SKILL.en.md +4 -4
  174. package/templates/.agents/skills/cancel-task/SKILL.zh-CN.md +5 -5
  175. package/templates/.agents/skills/check-task/SKILL.en.md +16 -16
  176. package/templates/.agents/skills/check-task/SKILL.zh-CN.md +16 -16
  177. package/templates/.agents/skills/close-codescan/SKILL.en.md +4 -4
  178. package/templates/.agents/skills/close-codescan/SKILL.zh-CN.md +4 -4
  179. package/templates/.agents/skills/close-dependabot/SKILL.en.md +4 -4
  180. package/templates/.agents/skills/close-dependabot/SKILL.zh-CN.md +4 -4
  181. package/templates/.agents/skills/code-task/SKILL.en.md +1 -1
  182. package/templates/.agents/skills/code-task/SKILL.zh-CN.md +2 -2
  183. package/templates/.agents/skills/code-task/reference/fix-mode.en.md +14 -16
  184. package/templates/.agents/skills/code-task/reference/fix-mode.zh-CN.md +14 -16
  185. package/templates/.agents/skills/code-task/reference/output-template.en.md +3 -3
  186. package/templates/.agents/skills/code-task/reference/output-template.zh-CN.md +3 -3
  187. package/templates/.agents/skills/commit/SKILL.en.md +11 -1
  188. package/templates/.agents/skills/commit/SKILL.zh-CN.md +11 -1
  189. package/templates/.agents/skills/commit/reference/task-status-update.en.md +24 -28
  190. package/templates/.agents/skills/commit/reference/task-status-update.zh-CN.md +24 -28
  191. package/templates/.agents/skills/complete-task/SKILL.en.md +2 -2
  192. package/templates/.agents/skills/complete-task/SKILL.zh-CN.md +2 -2
  193. package/templates/.agents/skills/create-pr/SKILL.en.md +10 -10
  194. package/templates/.agents/skills/create-pr/SKILL.zh-CN.md +10 -10
  195. package/templates/.agents/skills/create-pr/reference/pr-body-template.en.md +3 -3
  196. package/templates/.agents/skills/create-pr/reference/pr-body-template.zh-CN.md +3 -3
  197. package/templates/.agents/skills/create-task/SKILL.en.md +11 -11
  198. package/templates/.agents/skills/create-task/SKILL.zh-CN.md +11 -11
  199. package/templates/.agents/skills/import-codescan/SKILL.en.md +5 -5
  200. package/templates/.agents/skills/import-codescan/SKILL.zh-CN.md +5 -5
  201. package/templates/.agents/skills/import-dependabot/SKILL.en.md +5 -5
  202. package/templates/.agents/skills/import-dependabot/SKILL.zh-CN.md +5 -5
  203. package/templates/.agents/skills/import-issue/SKILL.en.md +5 -5
  204. package/templates/.agents/skills/import-issue/SKILL.zh-CN.md +5 -5
  205. package/templates/.agents/skills/init-labels/SKILL.en.md +4 -4
  206. package/templates/.agents/skills/init-labels/SKILL.zh-CN.md +4 -4
  207. package/templates/.agents/skills/init-milestones/SKILL.en.md +4 -4
  208. package/templates/.agents/skills/init-milestones/SKILL.zh-CN.md +4 -4
  209. package/templates/.agents/skills/plan-task/SKILL.en.md +5 -5
  210. package/templates/.agents/skills/plan-task/SKILL.zh-CN.md +5 -5
  211. package/templates/.agents/skills/refine-title/SKILL.en.md +1 -1
  212. package/templates/.agents/skills/refine-title/SKILL.zh-CN.md +1 -1
  213. package/templates/.agents/skills/release/SKILL.en.md +1 -1
  214. package/templates/.agents/skills/review-analysis/SKILL.en.md +13 -2
  215. package/templates/.agents/skills/review-analysis/SKILL.zh-CN.md +14 -3
  216. package/templates/.agents/skills/review-analysis/config/verify.en.json +6 -0
  217. package/templates/.agents/skills/review-analysis/config/verify.zh-CN.json +6 -0
  218. package/templates/.agents/skills/review-analysis/reference/output-templates.en.md +13 -15
  219. package/templates/.agents/skills/review-analysis/reference/output-templates.zh-CN.md +13 -15
  220. package/templates/.agents/skills/review-analysis/reference/report-template.en.md +51 -5
  221. package/templates/.agents/skills/review-analysis/reference/report-template.zh-CN.md +52 -6
  222. package/templates/.agents/skills/review-analysis/reference/review-criteria.en.md +25 -22
  223. package/templates/.agents/skills/review-analysis/reference/review-criteria.zh-CN.md +25 -22
  224. package/templates/.agents/skills/review-code/SKILL.en.md +28 -8
  225. package/templates/.agents/skills/review-code/SKILL.zh-CN.md +28 -8
  226. package/templates/.agents/skills/review-code/config/verify.en.json +7 -0
  227. package/templates/.agents/skills/review-code/config/verify.zh-CN.json +7 -0
  228. package/templates/.agents/skills/review-code/reference/concurrency-risks.en.md +25 -0
  229. package/templates/.agents/skills/review-code/reference/concurrency-risks.zh-CN.md +25 -0
  230. package/templates/.agents/skills/review-code/reference/cross-platform-risks.en.md +27 -0
  231. package/templates/.agents/skills/review-code/reference/cross-platform-risks.zh-CN.md +27 -0
  232. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.en.md +13 -0
  233. package/templates/.agents/skills/review-code/reference/documentation-antipatterns.zh-CN.md +13 -0
  234. package/templates/.agents/skills/review-code/reference/migration-risks.en.md +25 -0
  235. package/templates/.agents/skills/review-code/reference/migration-risks.zh-CN.md +25 -0
  236. package/templates/.agents/skills/review-code/reference/output-templates.en.md +22 -24
  237. package/templates/.agents/skills/review-code/reference/output-templates.zh-CN.md +22 -24
  238. package/templates/.agents/skills/review-code/reference/report-template.en.md +54 -7
  239. package/templates/.agents/skills/review-code/reference/report-template.zh-CN.md +54 -7
  240. package/templates/.agents/skills/review-code/reference/review-criteria.en.md +29 -24
  241. package/templates/.agents/skills/review-code/reference/review-criteria.zh-CN.md +29 -24
  242. package/templates/.agents/skills/review-code/reference/security-risks.en.md +25 -0
  243. package/templates/.agents/skills/review-code/reference/security-risks.zh-CN.md +25 -0
  244. package/templates/.agents/skills/review-plan/SKILL.en.md +13 -2
  245. package/templates/.agents/skills/review-plan/SKILL.zh-CN.md +14 -3
  246. package/templates/.agents/skills/review-plan/config/verify.en.json +6 -0
  247. package/templates/.agents/skills/review-plan/config/verify.zh-CN.json +6 -0
  248. package/templates/.agents/skills/review-plan/reference/output-templates.en.md +13 -15
  249. package/templates/.agents/skills/review-plan/reference/output-templates.zh-CN.md +13 -15
  250. package/templates/.agents/skills/review-plan/reference/report-template.en.md +61 -5
  251. package/templates/.agents/skills/review-plan/reference/report-template.zh-CN.md +61 -5
  252. package/templates/.agents/skills/review-plan/reference/review-criteria.en.md +21 -24
  253. package/templates/.agents/skills/review-plan/reference/review-criteria.zh-CN.md +21 -24
  254. package/templates/.agents/skills/run-task/SKILL.en.md +22 -0
  255. package/templates/.agents/skills/run-task/SKILL.zh-CN.md +22 -0
  256. package/templates/.agents/skills/run-task/config/verify.en.json +9 -0
  257. package/templates/.agents/skills/run-task/config/verify.zh-CN.json +9 -0
  258. package/templates/.agents/skills/test/SKILL.en.md +4 -4
  259. package/templates/.agents/skills/test/SKILL.zh-CN.md +4 -4
  260. package/templates/.agents/skills/test-integration/SKILL.en.md +4 -4
  261. package/templates/.agents/skills/test-integration/SKILL.zh-CN.md +4 -4
  262. package/templates/.agents/skills/update-agent-infra/SKILL.en.md +5 -5
  263. package/templates/.agents/skills/update-agent-infra/SKILL.zh-CN.md +5 -5
  264. package/templates/.agents/skills/update-agent-infra/scripts/sync-templates.js +647 -203
  265. package/templates/.agents/skills/upgrade-dependency/SKILL.en.md +4 -4
  266. package/templates/.agents/skills/upgrade-dependency/SKILL.zh-CN.md +4 -4
  267. package/templates/.agents/skills/watch-pr/SKILL.en.md +8 -8
  268. package/templates/.agents/skills/watch-pr/SKILL.zh-CN.md +8 -8
  269. package/templates/.claude/agents/agent-infra-lifecycle-executor.en.md +6 -0
  270. package/templates/.claude/agents/agent-infra-lifecycle-executor.zh-CN.md +6 -0
  271. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.en.md +6 -0
  272. package/templates/.claude/agents/agent-infra-lifecycle-reviewer.zh-CN.md +6 -0
  273. package/templates/.claude/commands/run-task.en.md +8 -0
  274. package/templates/.claude/commands/run-task.zh-CN.md +8 -0
  275. package/templates/.claude/settings.json +24 -0
  276. package/templates/.codex/agents/agent-infra-lifecycle-executor.en.toml +3 -0
  277. package/templates/.codex/agents/agent-infra-lifecycle-executor.zh-CN.toml +3 -0
  278. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.en.toml +3 -0
  279. package/templates/.codex/agents/agent-infra-lifecycle-reviewer.zh-CN.toml +3 -0
  280. package/templates/.gemini/commands/_project_/run-task.en.toml +8 -0
  281. package/templates/.gemini/commands/_project_/run-task.zh-CN.toml +8 -0
  282. package/templates/.opencode/commands/run-task.en.md +11 -0
  283. package/templates/.opencode/commands/run-task.zh-CN.md +11 -0
@@ -3,8 +3,11 @@ import { appendActivityEntry, locateActivityLog, pairEntries } from './activity-
3
3
  import { buildArtifactLinkSection, artifactName, parseArtifactName, resolveArtifactContext, validateCompletedArtifact } from './artifact-lifecycle.js';
4
4
  import { parseTypedTaskFrontmatter } from './frontmatter.js';
5
5
  import { consumeImplementationInput, IMPLEMENTATION_INPUT_ALIASES, parseImplementationInputs, renderImplementationInputs } from './implementation-inputs.js';
6
+ import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
7
+ import { parseReviewSummary } from './review-artifacts.js';
6
8
  import { resolveTaskRef } from './resolve-ref.js';
7
9
  import { findSectionHeading } from './sections.js';
10
+ import { completeOrchestrationStage, validateOrchestrationStage } from './orchestration.js';
8
11
  import { captureTaskWriteMetadata, writeTask } from './write.js';
9
12
  const eventCatalog = [
10
13
  'analyze.started', 'analyze.awaiting-input', 'analyze.completed',
@@ -75,12 +78,75 @@ function validateTaskEventRequest(request) {
75
78
  const FAMILY = {
76
79
  analyze: { artifact: 'analysis', started: ['requirement-analysis', 'requirement-analysis-review', 'code'], completed: ['requirement-analysis', 'requirement-analysis-review', 'code'], target: 'requirement-analysis', label: 'Analyze Task' },
77
80
  'review-analysis': { artifact: 'review-analysis', started: ['requirement-analysis', 'requirement-analysis-review'], completed: ['requirement-analysis', 'requirement-analysis-review'], target: 'requirement-analysis-review', label: 'Review Analysis' },
78
- plan: { artifact: 'plan', started: ['requirement-analysis-review', 'technical-design-review'], completed: ['requirement-analysis-review', 'technical-design-review'], target: 'technical-design', label: 'Plan Task' },
81
+ plan: { artifact: 'plan', started: ['requirement-analysis-review', 'technical-design-review', 'commit'], completed: ['requirement-analysis-review', 'technical-design-review', 'commit'], target: 'technical-design', label: 'Plan Task' },
79
82
  'review-plan': { artifact: 'review-plan', started: ['technical-design', 'technical-design-review'], completed: ['technical-design', 'technical-design-review'], target: 'technical-design-review', label: 'Review Plan' },
80
83
  code: { artifact: 'code', started: ['technical-design-review', 'code-review'], completed: ['technical-design-review', 'code-review'], target: 'code', label: 'Code Task' },
81
84
  'review-code': { artifact: 'review-code', started: ['code', 'code-review', 'commit'], completed: ['code', 'code-review', 'commit'], target: 'code-review', label: 'Review Code' },
82
85
  'manual-validation': { artifact: 'manual-validation', started: ['code-review', 'commit'], completed: ['code-review', 'commit'], target: null, label: 'Complete Manual Validation' }
83
86
  };
87
+ const REVIEW_LEDGER_STAGES = {
88
+ 'review-analysis': 'analysis',
89
+ 'review-plan': 'plan',
90
+ 'review-code': 'code'
91
+ };
92
+ function validateReviewFindingCounts(request, content, family, artifactPath) {
93
+ const stage = REVIEW_LEDGER_STAGES[family];
94
+ if (!stage || !artifactPath)
95
+ return null;
96
+ const rows = parseLedger(content);
97
+ const invalid = validateLedgerRows(rows);
98
+ if (invalid)
99
+ return { code: 'TASK_DOCUMENT_INVALID', message: `${invalid.code}: ${invalid.message}` };
100
+ const expected = summarizeLedgerStage(rows, stage).unresolvedFindingCounts;
101
+ const payload = {
102
+ blocker: request.blockers,
103
+ major: request.major,
104
+ minor: request.minor
105
+ };
106
+ let reportContent;
107
+ try {
108
+ reportContent = fs.readFileSync(artifactPath, 'utf8');
109
+ }
110
+ catch (error) {
111
+ return { code: 'EVENT_FINDING_COUNT_MISMATCH', message: String(error) };
112
+ }
113
+ const parsed = parseReviewSummary(reportContent);
114
+ if (!parsed.ok || !parsed.summary.counts) {
115
+ return {
116
+ code: 'EVENT_FINDING_COUNT_MISMATCH',
117
+ message: parsed.ok ? 'review summary finding counts are not finalized' : parsed.message
118
+ };
119
+ }
120
+ const report = parsed.summary.counts;
121
+ const reportVerdict = parsed.summary.verdict === 'Approved'
122
+ ? 'approved'
123
+ : parsed.summary.verdict === 'Changes Requested' ? 'changes-requested' : 'rejected';
124
+ const fields = [
125
+ ['blocker', 'blockers'],
126
+ ['major', 'major'],
127
+ ['minor', 'minor']
128
+ ];
129
+ const differences = fields.flatMap(([severity, cliField]) => {
130
+ const values = [
131
+ expected[severity] === payload[severity]
132
+ ? null
133
+ : `${cliField} ledger ${expected[severity]}, payload ${payload[severity]}`,
134
+ expected[severity] === report[severity]
135
+ ? null
136
+ : `${cliField} ledger ${expected[severity]}, report ${report[severity]}`
137
+ ];
138
+ return values.filter((value) => value !== null);
139
+ });
140
+ if (request.verdict !== reportVerdict) {
141
+ differences.push(`verdict report ${reportVerdict}, payload ${request.verdict}`);
142
+ }
143
+ if (differences.length === 0)
144
+ return null;
145
+ return {
146
+ code: 'EVENT_FINDING_COUNT_MISMATCH',
147
+ message: `review summary, payload, and ${stage} ledger do not match: ${differences.join('; ')}`
148
+ };
149
+ }
84
150
  function eventParts(event) {
85
151
  const [family, suffix] = event.split('.');
86
152
  return { family, phase: suffix === 'started' ? 'started' : suffix === 'awaiting-input' ? 'waiting' : 'completed' };
@@ -257,6 +323,24 @@ function applyTaskEvent(request, options = {}) {
257
323
  const allowed = FAMILY[eventIdentity.family][eventIdentity.phase === 'started' ? 'started' : 'completed'];
258
324
  if (!allowed.includes(currentStep))
259
325
  return failed(normalized, { code: 'EVENT_TRANSITION_INVALID', message: `${normalized.event} is not allowed from '${currentStep}'` }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
326
+ const findingCountError = validateReviewFindingCounts(normalized, content, eventIdentity.family, completedArtifact?.path ?? null);
327
+ if (findingCountError)
328
+ return failed(normalized, findingCountError, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase });
329
+ if (eventIdentity.phase === 'completed' && !normalized.dryRun && eventIdentity.family !== 'manual-validation') {
330
+ const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
331
+ const provenance = validateOrchestrationStage(normalized.taskRef, {
332
+ stage: orchestrationStage,
333
+ round: normalized.round,
334
+ artifact: normalized.artifact,
335
+ role: eventIdentity.family.startsWith('review-') ? 'reviewer' : 'executor'
336
+ }, { repoRoot: options.repoRoot });
337
+ if (provenance.status === 'failed' || provenance.status === 'paused') {
338
+ return failed(normalized, {
339
+ code: 'EVENT_TRANSITION_INVALID',
340
+ message: provenance.error?.message ?? provenance.run?.pause?.message ?? 'orchestration provenance validation failed'
341
+ }, { taskId: resolved.taskId, taskMdPath: resolved.taskMdPath, fromStep: currentStep, toStep: currentStep, action: eventIdentity.action, phase: eventIdentity.phase, artifactContext });
342
+ }
343
+ }
260
344
  let metadata;
261
345
  try {
262
346
  metadata = (options.metadataProvider ?? captureTaskWriteMetadata)();
@@ -295,6 +379,21 @@ function applyTaskEvent(request, options = {}) {
295
379
  const result = writeTask({ taskRef: normalized.taskRef, expectedState: 'active', dryRun: normalized.dryRun, mutations }, { ...options, metadataProvider: () => metadata });
296
380
  if (result.status === 'failed')
297
381
  return failed(normalized, result.error, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
382
+ if (eventIdentity.phase === 'completed' && !normalized.dryRun && eventIdentity.family !== 'manual-validation') {
383
+ const orchestrationStage = eventIdentity.family === 'analyze' ? 'analysis' : eventIdentity.family;
384
+ const orchestration = completeOrchestrationStage(normalized.taskRef, {
385
+ stage: orchestrationStage,
386
+ round: normalized.round,
387
+ artifact: normalized.artifact,
388
+ agent: normalized.agent
389
+ }, { repoRoot: options.repoRoot });
390
+ if (orchestration.status === 'failed' || orchestration.status === 'paused') {
391
+ return failed(normalized, {
392
+ code: 'EVENT_TRANSITION_INVALID',
393
+ message: orchestration.error?.message ?? orchestration.run?.pause?.message ?? 'orchestration provenance validation failed'
394
+ }, { taskId: result.taskId, taskMdPath: result.taskMdPath, fromStep: currentStep, toStep: step, action: eventIdentity.action, phase: eventIdentity.phase, timestamp: result.timestamp, agentInfraVersion: result.agentInfraVersion, operations: result.operations, artifactContext });
395
+ }
396
+ }
298
397
  return {
299
398
  status: result.status, changed: result.changed, event: normalized.event,
300
399
  requestRef: normalized.taskRef, taskId: result.taskId, taskMdPath: result.taskMdPath,
@@ -0,0 +1,420 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { randomUUID } from 'node:crypto';
4
+ import { parseTypedTaskFrontmatter } from './frontmatter.js';
5
+ import { parseReviewSummary } from './review-artifacts.js';
6
+ import { inspectArtifactDirectory } from './artifact-lifecycle.js';
7
+ import { parseLedger, summarizeLedgerStage, validateLedgerRows } from './ledger.js';
8
+ import { resolveTaskRef } from './resolve-ref.js';
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';
12
+ function orchestrationPath(taskDir) {
13
+ return path.join(taskDir, 'orchestration.json');
14
+ }
15
+ function readRun(taskDir) {
16
+ const file = orchestrationPath(taskDir);
17
+ if (!fs.existsSync(file))
18
+ return null;
19
+ return JSON.parse(fs.readFileSync(file, 'utf8'));
20
+ }
21
+ function atomicWrite(file, value) {
22
+ const temp = `${file}.${process.pid}.${randomUUID()}.tmp`;
23
+ fs.writeFileSync(temp, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', flag: 'wx' });
24
+ fs.renameSync(temp, file);
25
+ }
26
+ function saveRun(taskDir, run) {
27
+ atomicWrite(orchestrationPath(taskDir), run);
28
+ }
29
+ function withUpdatedRun(run, updates) {
30
+ return Object.freeze({ ...run, ...updates, updatedAt: new Date().toISOString() });
31
+ }
32
+ function failed(code, message, taskId = null) {
33
+ return { status: 'failed', changed: false, taskId, run: null, next: null, error: { code, message } };
34
+ }
35
+ function beginOrResumeOrchestration(taskRef, options = {}) {
36
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
37
+ if (!resolved.ok)
38
+ return failed(resolved.code, resolved.message, resolved.taskId);
39
+ const existing = readRun(resolved.taskDir);
40
+ 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 };
45
+ }
46
+ return { status: existing.status, changed: false, taskId: resolved.taskId, run: existing, next: null, error: null };
47
+ }
48
+ const now = (options.now ?? (() => new Date().toISOString()))();
49
+ const run = {
50
+ schemaVersion: 1,
51
+ taskId: resolved.taskId,
52
+ runId: (options.id ?? randomUUID)(),
53
+ status: 'running',
54
+ nextStage: null,
55
+ stepCount: 0,
56
+ maxSteps: options.maxSteps ?? 24,
57
+ baseline: '',
58
+ pendingDelegation: null,
59
+ receipts: [],
60
+ pause: null,
61
+ commitAuthorization: { issuedAt: null, consumedAt: null },
62
+ createdAt: now,
63
+ updatedAt: now
64
+ };
65
+ atomicWrite(orchestrationPath(resolved.taskDir), run);
66
+ return { status: 'running', changed: true, taskId: resolved.taskId, run, next: null, error: null };
67
+ }
68
+ function highestRound(taskDir, family) {
69
+ const pattern = new RegExp(`^${family}(?:-r(\\d+))?\\.md$`);
70
+ return fs.readdirSync(taskDir).reduce((max, name) => {
71
+ const match = pattern.exec(name);
72
+ return match ? Math.max(max, match[1] ? Number(match[1]) : 1) : max;
73
+ }, 0);
74
+ }
75
+ function artifactName(family, round) {
76
+ return round === 1 ? `${family}.md` : `${family}-r${round}.md`;
77
+ }
78
+ function hasReviewAfterArtifact(taskDir, family, reviewFamily) {
79
+ const artifact = inspectArtifactDirectory(taskDir, family);
80
+ const review = inspectArtifactDirectory(taskDir, reviewFamily);
81
+ return artifact.status === 'ready'
82
+ && review.status === 'ready'
83
+ && artifact.latest !== null
84
+ && review.reviewedInput?.name === artifact.latest.name;
85
+ }
86
+ function latestReviewApproved(taskDir, family) {
87
+ const round = highestRound(taskDir, family);
88
+ if (round === 0)
89
+ return false;
90
+ const parsed = parseReviewSummary(fs.readFileSync(path.join(taskDir, artifactName(family, round)), 'utf8'));
91
+ return parsed.ok && parsed.summary.verdict === 'Approved' && parsed.summary.counts !== null;
92
+ }
93
+ function routeFromFacts(taskDir) {
94
+ const analysisRound = highestRound(taskDir, 'analysis');
95
+ const analysisReviewRound = highestRound(taskDir, 'review-analysis');
96
+ const planRound = highestRound(taskDir, 'plan');
97
+ const planReviewRound = highestRound(taskDir, 'review-plan');
98
+ const codeRound = highestRound(taskDir, 'code');
99
+ const codeReviewRound = highestRound(taskDir, 'review-code');
100
+ if (analysisRound === 0) {
101
+ const round = analysisRound + 1;
102
+ return { action: 'analyze-task', role: 'executor', stage: 'analysis', round, artifact: artifactName('analysis', round) };
103
+ }
104
+ if (!hasReviewAfterArtifact(taskDir, 'analysis', 'review-analysis')) {
105
+ const round = analysisReviewRound + 1;
106
+ return { action: 'review-analysis', role: 'reviewer', stage: 'review-analysis', round, artifact: artifactName('review-analysis', round) };
107
+ }
108
+ if (!latestReviewApproved(taskDir, 'review-analysis')) {
109
+ const round = analysisRound + 1;
110
+ return { action: 'analyze-task', role: 'executor', stage: 'analysis', round, artifact: artifactName('analysis', round) };
111
+ }
112
+ if (planRound === 0) {
113
+ const round = planRound + 1;
114
+ return { action: 'plan-task', role: 'executor', stage: 'plan', round, artifact: artifactName('plan', round) };
115
+ }
116
+ if (!hasReviewAfterArtifact(taskDir, 'plan', 'review-plan')) {
117
+ const round = planReviewRound + 1;
118
+ return { action: 'review-plan', role: 'reviewer', stage: 'review-plan', round, artifact: artifactName('review-plan', round) };
119
+ }
120
+ if (!latestReviewApproved(taskDir, 'review-plan')) {
121
+ const round = planRound + 1;
122
+ return { action: 'plan-task', role: 'executor', stage: 'plan', round, artifact: artifactName('plan', round) };
123
+ }
124
+ if (codeRound === 0) {
125
+ const round = codeRound + 1;
126
+ return { action: 'code-task', role: 'executor', stage: 'code', round, artifact: artifactName('code', round) };
127
+ }
128
+ if (!hasReviewAfterArtifact(taskDir, 'code', 'review-code')) {
129
+ const round = codeReviewRound + 1;
130
+ return { action: 'review-code', role: 'reviewer', stage: 'review-code', round, artifact: artifactName('review-code', round) };
131
+ }
132
+ if (!latestReviewApproved(taskDir, 'review-code')) {
133
+ const round = codeRound + 1;
134
+ return { action: 'code-task', role: 'executor', stage: 'code', round, artifact: artifactName('code', round) };
135
+ }
136
+ return { action: 'commit', role: 'executor', stage: 'commit', round: 1, artifact: 'commit' };
137
+ }
138
+ function routeOrchestration(taskRef, options = {}) {
139
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
140
+ if (!resolved.ok)
141
+ return failed(resolved.code, resolved.message, resolved.taskId);
142
+ let content;
143
+ try {
144
+ content = fs.readFileSync(resolved.taskMdPath, 'utf8');
145
+ }
146
+ catch (error) {
147
+ return failed('ORCHESTRATION_TASK_READ_FAILED', String(error), resolved.taskId);
148
+ }
149
+ try {
150
+ parseTypedTaskFrontmatter(content);
151
+ }
152
+ catch (error) {
153
+ return failed('ORCHESTRATION_TASK_INVALID', error instanceof Error ? error.message : String(error), resolved.taskId);
154
+ }
155
+ const next = routeFromFacts(resolved.taskDir);
156
+ if (!next)
157
+ return failed('ORCHESTRATION_ROUTE_UNKNOWN', 'cannot determine a unique lifecycle action', resolved.taskId);
158
+ if (next.stage === 'commit') {
159
+ const reviewRound = highestRound(resolved.taskDir, 'review-code');
160
+ const review = parseReviewSummary(fs.readFileSync(path.join(resolved.taskDir, artifactName('review-code', reviewRound)), 'utf8'));
161
+ if (!review.ok || review.summary.manualValidation === null) {
162
+ return failed('ORCHESTRATION_REVIEW_INVALID', 'latest code review has no numeric manual-validation count', resolved.taskId);
163
+ }
164
+ if (review.summary.manualValidation > 0) {
165
+ return failed('ORCHESTRATION_MANUAL_VALIDATION_PENDING', 'manual validation must be completed before commit', resolved.taskId);
166
+ }
167
+ const rows = parseLedger(content);
168
+ const ledgerError = validateLedgerRows(rows);
169
+ if (ledgerError)
170
+ return failed('ORCHESTRATION_LEDGER_INVALID', ledgerError.message, resolved.taskId);
171
+ if (!summarizeLedgerStage(rows, 'code').canAdvance) {
172
+ return failed('ORCHESTRATION_LEDGER_BLOCKED', 'code review ledger has unresolved findings or human decisions', resolved.taskId);
173
+ }
174
+ }
175
+ return { status: 'running', changed: false, taskId: resolved.taskId, run: readRun(resolved.taskDir), next, error: null };
176
+ }
177
+ function statusOrchestration(taskRef, options = {}) {
178
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
179
+ if (!resolved.ok)
180
+ return failed(resolved.code, resolved.message, resolved.taskId);
181
+ const run = readRun(resolved.taskDir);
182
+ if (!run)
183
+ return failed('ORCHESTRATION_RUN_MISSING', 'no orchestration run exists', resolved.taskId);
184
+ return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
185
+ }
186
+ function prepareOrchestrationDelegation(taskRef, input, options = {}) {
187
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
188
+ if (!resolved.ok)
189
+ return failed(resolved.code, resolved.message, resolved.taskId);
190
+ if (getAgentClientCapability(input.client, 'subagents').level === 'unsupported'
191
+ || getAgentClientCapability(input.client, 'orchestration').level === 'unsupported') {
192
+ return failed('ORCHESTRATION_CLIENT_UNSUPPORTED', `client '${input.client}' does not support lifecycle orchestration`, resolved.taskId);
193
+ }
194
+ const run = readRun(resolved.taskDir);
195
+ if (!run || run.status !== 'running')
196
+ return failed('ORCHESTRATION_RUN_NOT_RUNNING', 'a running orchestration is required', resolved.taskId);
197
+ if (run.pendingDelegation)
198
+ return failed('ORCHESTRATION_DELEGATION_BUSY', 'the run already has a pending delegation', resolved.taskId);
199
+ const repositoryPending = ['claude-code', 'codex']
200
+ .flatMap((client) => matchingDelegations(client, () => true, options));
201
+ if (repositoryPending.length > 0) {
202
+ return failed('ORCHESTRATION_DELEGATION_BUSY', 'the repository already has a pending lifecycle delegation', resolved.taskId);
203
+ }
204
+ if (run.stepCount >= run.maxSteps)
205
+ return pauseOrchestration(taskRef, 'ORCHESTRATION_MAX_STEPS', 'maximum orchestration steps reached', true, options);
206
+ const routed = routeOrchestration(taskRef, options);
207
+ if (!routed.next)
208
+ return routed;
209
+ const next = routed.next;
210
+ let beforeFingerprint;
211
+ try {
212
+ beforeFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(resolved.repoRoot);
213
+ }
214
+ catch (error) {
215
+ return failed('ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), resolved.taskId);
216
+ }
217
+ const receipt = prepareDelegation({
218
+ taskId: resolved.taskId,
219
+ runId: run.runId,
220
+ role: next.role,
221
+ stage: next.stage,
222
+ round: next.round,
223
+ artifact: next.artifact,
224
+ client: input.client,
225
+ requestedModel: input.requestedModel ?? null,
226
+ beforeFingerprint
227
+ }, { id: options.id, now: options.now });
228
+ const updated = withUpdatedRun(run, {
229
+ nextStage: next.stage,
230
+ pendingDelegation: receipt,
231
+ commitAuthorization: next.stage === 'commit' && run.commitAuthorization.issuedAt === null
232
+ ? { issuedAt: (options.now ?? (() => new Date().toISOString()))(), consumedAt: null }
233
+ : run.commitAuthorization
234
+ });
235
+ saveRun(resolved.taskDir, updated);
236
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next, error: null };
237
+ }
238
+ function matchingDelegations(client, predicate, options) {
239
+ const repoRoot = options.repoRoot ?? process.cwd();
240
+ const activeRoot = path.join(repoRoot, '.agents', 'workspace', 'active');
241
+ if (!fs.existsSync(activeRoot))
242
+ return [];
243
+ return fs.readdirSync(activeRoot, { withFileTypes: true })
244
+ .filter((entry) => entry.isDirectory())
245
+ .flatMap((entry) => {
246
+ const run = readRun(path.join(activeRoot, entry.name));
247
+ if (!run?.pendingDelegation)
248
+ return [];
249
+ const receipt = run.pendingDelegation;
250
+ return receipt.client === client && predicate(receipt)
251
+ ? [{ taskId: entry.name, run }]
252
+ : [];
253
+ });
254
+ }
255
+ function uniqueMatchingDelegation(client, predicate, options) {
256
+ const matches = matchingDelegations(client, predicate, options);
257
+ if (matches.length === 0)
258
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no matching lifecycle delegation exists');
259
+ if (matches.length > 1)
260
+ return failed('ORCHESTRATION_DELEGATION_AMBIGUOUS', 'multiple lifecycle delegations match the native hook event');
261
+ return matches[0];
262
+ }
263
+ function activateMatchingOrchestrationDelegation(client, event, options = {}) {
264
+ const role = managedDelegationRole(event.nativeAgent);
265
+ if (!role)
266
+ return failed('DELEGATION_IGNORED', `subagent '${event.nativeAgent}' is not lifecycle-managed`);
267
+ const matched = uniqueMatchingDelegation(client, (receipt) => receipt.status === 'prepared', options);
268
+ if ('status' in matched)
269
+ return matched;
270
+ if (matched.run.receipts.some((receipt) => receipt.childId === event.childId)) {
271
+ return pauseOrchestration(matched.taskId, 'DELEGATION_IDENTITY_REUSED', 'native child identity was already used by this run', true, options);
272
+ }
273
+ return activateOrchestrationDelegation(matched.taskId, event, options);
274
+ }
275
+ function sealMatchingOrchestrationDelegation(client, event, options = {}) {
276
+ const role = managedDelegationRole(event.nativeAgent);
277
+ if (!role)
278
+ return failed('DELEGATION_IGNORED', `subagent '${event.nativeAgent}' is not lifecycle-managed`);
279
+ const matched = uniqueMatchingDelegation(client, (receipt) => receipt.status !== 'prepared', options);
280
+ if ('status' in matched)
281
+ return matched;
282
+ const receipt = matched.run.pendingDelegation;
283
+ if (receipt.role !== role) {
284
+ return pauseOrchestration(matched.taskId, 'DELEGATION_ROLE_MISMATCH', `managed role ${role} does not match ${receipt.role}`, true, options);
285
+ }
286
+ const repoRoot = options.repoRoot ?? process.cwd();
287
+ try {
288
+ const afterFingerprint = (options.captureWorkspace ?? captureWorkspaceSnapshot)(repoRoot);
289
+ const changedPaths = (options.diffWorkspace ?? diffWorkspaceSnapshots)(repoRoot, receipt.beforeFingerprint, afterFingerprint);
290
+ return sealOrchestrationDelegation(matched.taskId, {
291
+ childId: event.childId,
292
+ exitCode: 0,
293
+ afterFingerprint,
294
+ changedPaths
295
+ }, options);
296
+ }
297
+ catch (error) {
298
+ return pauseOrchestration(matched.taskId, 'ORCHESTRATION_SNAPSHOT_FAILED', error instanceof Error ? error.message : String(error), true, options);
299
+ }
300
+ }
301
+ function activateOrchestrationDelegation(taskRef, event, options = {}) {
302
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
303
+ if (!resolved.ok)
304
+ return failed(resolved.code, resolved.message, resolved.taskId);
305
+ const run = readRun(resolved.taskDir);
306
+ if (!run?.pendingDelegation)
307
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
308
+ const result = activateDelegation(run.pendingDelegation, event, { now: options.now });
309
+ if (!result.ok) {
310
+ if (result.code === 'DELEGATION_IGNORED')
311
+ return { status: run.status, changed: false, taskId: resolved.taskId, run, next: null, error: null };
312
+ return pauseOrchestration(taskRef, result.code, result.message, true, options);
313
+ }
314
+ const updated = withUpdatedRun(run, { pendingDelegation: result.receipt });
315
+ saveRun(resolved.taskDir, updated);
316
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
317
+ }
318
+ function completeOrchestrationStage(taskRef, event, options = {}) {
319
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
320
+ if (!resolved.ok)
321
+ return failed(resolved.code, resolved.message, resolved.taskId);
322
+ const run = readRun(resolved.taskDir);
323
+ if (!run)
324
+ return { status: 'running', changed: false, taskId: resolved.taskId, run: null, next: null, error: null };
325
+ if (!run.pendingDelegation)
326
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'active run has no pending delegation', resolved.taskId);
327
+ const result = completeDelegationStage(run.pendingDelegation, event);
328
+ if (!result.ok)
329
+ return pauseOrchestration(taskRef, result.code, result.message, true, options);
330
+ const updated = withUpdatedRun(run, { pendingDelegation: result.receipt });
331
+ saveRun(resolved.taskDir, updated);
332
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
333
+ }
334
+ function completeCommitOrchestrationStage(taskRef, agent, options = {}) {
335
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
336
+ if (!resolved.ok)
337
+ return failed(resolved.code, resolved.message, resolved.taskId);
338
+ const run = readRun(resolved.taskDir);
339
+ if (!run)
340
+ return { status: 'running', changed: false, taskId: resolved.taskId, run: null, next: null, error: null };
341
+ const receipt = run.pendingDelegation;
342
+ if (!receipt || receipt.stage !== 'commit') {
343
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'active run has no pending commit delegation', resolved.taskId);
344
+ }
345
+ return completeOrchestrationStage(taskRef, {
346
+ stage: receipt.stage,
347
+ round: receipt.round,
348
+ artifact: receipt.artifact,
349
+ agent
350
+ }, options);
351
+ }
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
+ function sealOrchestrationDelegation(taskRef, event, options = {}) {
371
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
372
+ if (!resolved.ok)
373
+ return failed(resolved.code, resolved.message, resolved.taskId);
374
+ const run = readRun(resolved.taskDir);
375
+ if (!run?.pendingDelegation)
376
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
377
+ const result = sealDelegation(run.pendingDelegation, event, { now: options.now });
378
+ if (!result.ok)
379
+ return pauseOrchestration(taskRef, result.code, result.message, true, options);
380
+ const updated = withUpdatedRun(run, { pendingDelegation: result.receipt });
381
+ saveRun(resolved.taskDir, updated);
382
+ return { status: 'running', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
383
+ }
384
+ function advanceOrchestration(taskRef, options = {}) {
385
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
386
+ if (!resolved.ok)
387
+ return failed(resolved.code, resolved.message, resolved.taskId);
388
+ const run = readRun(resolved.taskDir);
389
+ if (!run?.pendingDelegation)
390
+ return failed('ORCHESTRATION_DELEGATION_MISSING', 'no pending delegation exists', resolved.taskId);
391
+ const result = consumeDelegation(run.pendingDelegation, { now: options.now });
392
+ if (!result.ok)
393
+ return pauseOrchestration(taskRef, result.code, result.message, true, options);
394
+ const completed = result.receipt.stage === 'commit';
395
+ const updated = withUpdatedRun(run, {
396
+ status: completed ? 'completed' : 'running',
397
+ nextStage: null,
398
+ stepCount: run.stepCount + 1,
399
+ pendingDelegation: null,
400
+ receipts: Object.freeze([...run.receipts, result.receipt]),
401
+ commitAuthorization: completed
402
+ ? { ...run.commitAuthorization, consumedAt: (options.now ?? (() => new Date().toISOString()))() }
403
+ : run.commitAuthorization
404
+ });
405
+ saveRun(resolved.taskDir, updated);
406
+ return { status: updated.status, changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
407
+ }
408
+ function pauseOrchestration(taskRef, code, message, recoverable, options = {}) {
409
+ const resolved = resolveTaskRef(taskRef, { repoRoot: options.repoRoot });
410
+ if (!resolved.ok)
411
+ return failed(resolved.code, resolved.message, resolved.taskId);
412
+ const run = readRun(resolved.taskDir);
413
+ if (!run)
414
+ return failed('ORCHESTRATION_RUN_MISSING', 'no orchestration run exists', resolved.taskId);
415
+ const updated = withUpdatedRun(run, { status: 'paused', pause: { code, message, recoverable } });
416
+ saveRun(resolved.taskDir, updated);
417
+ return { status: 'paused', changed: true, taskId: resolved.taskId, run: updated, next: null, error: null };
418
+ }
419
+ export { activateMatchingOrchestrationDelegation, activateOrchestrationDelegation, advanceOrchestration, beginOrResumeOrchestration, completeCommitOrchestrationStage, completeOrchestrationStage, orchestrationPath, pauseOrchestration, prepareOrchestrationDelegation, readRun, routeOrchestration, sealMatchingOrchestrationDelegation, sealOrchestrationDelegation, statusOrchestration, validateOrchestrationStage };
420
+ //# sourceMappingURL=orchestration.js.map