@sema-agent/server 1.322.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (539) hide show
  1. package/dist/approval-hmac.d.ts +40 -0
  2. package/dist/approval-hmac.js +67 -0
  3. package/dist/approval.d.ts +31 -0
  4. package/dist/approval.js +72 -4
  5. package/dist/audit.d.ts +26 -0
  6. package/dist/audit.js +40 -1
  7. package/dist/auth-bridge.d.ts +10 -0
  8. package/dist/auth-bridge.js +47 -4
  9. package/dist/auth-keys.d.ts +19 -0
  10. package/dist/auth-keys.js +13 -0
  11. package/dist/bake-runner/main.d.ts +5 -0
  12. package/dist/bake-runner/main.js +43 -4
  13. package/dist/bake-runner/protocol.d.ts +57 -0
  14. package/dist/bake-runner/protocol.js +58 -3
  15. package/dist/bake-runner/runner.d.ts +54 -0
  16. package/dist/bake-runner/runner.js +87 -5
  17. package/dist/bench/l8/artifact.d.ts +63 -0
  18. package/dist/bench/l8/artifact.js +61 -2
  19. package/dist/bench/l8/escape.d.ts +36 -0
  20. package/dist/bench/l8/escape.js +25 -0
  21. package/dist/bench/l8/index.d.ts +14 -0
  22. package/dist/bench/l8/index.js +14 -0
  23. package/dist/bench/l8/probes.d.ts +74 -0
  24. package/dist/bench/l8/probes.js +60 -0
  25. package/dist/bench/l8/run-probes.d.ts +43 -0
  26. package/dist/bench/l8/run-probes.js +45 -2
  27. package/dist/bench/s1/arms.d.ts +126 -0
  28. package/dist/bench/s1/arms.js +188 -13
  29. package/dist/bench/s1/live-deps.d.ts +66 -0
  30. package/dist/bench/s1/live-deps.js +249 -11
  31. package/dist/bench/s1/oracle.d.ts +49 -0
  32. package/dist/bench/s1/oracle.js +36 -1
  33. package/dist/bench/s1/repair-oracle-adapter.d.ts +33 -0
  34. package/dist/bench/s1/repair-oracle-adapter.js +30 -0
  35. package/dist/bench/s1/reviewer.d.ts +38 -0
  36. package/dist/bench/s1/reviewer.js +34 -0
  37. package/dist/bench/s1/row.d.ts +77 -0
  38. package/dist/bench/s1/row.js +62 -0
  39. package/dist/bench/s1/run-firm.d.ts +47 -0
  40. package/dist/bench/s1/run-firm.js +70 -4
  41. package/dist/bench/s1/runner-ctx.d.ts +71 -0
  42. package/dist/bench/s1/runner-ctx.js +36 -0
  43. package/dist/bench/s1/tasks.d.ts +108 -0
  44. package/dist/bench/s1/tasks.js +115 -0
  45. package/dist/boot-reclaim.d.ts +19 -0
  46. package/dist/boot-reclaim.js +20 -0
  47. package/dist/brain.d.ts +25 -0
  48. package/dist/brain.js +61 -1
  49. package/dist/budget.d.ts +66 -0
  50. package/dist/budget.js +128 -4
  51. package/dist/capabilities/builtin-tools.d.ts +3 -0
  52. package/dist/capabilities/builtin-tools.js +3 -0
  53. package/dist/capabilities/center-plugins.d.ts +17 -1
  54. package/dist/capabilities/center-plugins.js +45 -4
  55. package/dist/capabilities/center-prompts.d.ts +46 -0
  56. package/dist/capabilities/center-prompts.js +57 -3
  57. package/dist/capabilities/code-review-council.d.ts +28 -0
  58. package/dist/capabilities/code-review-council.js +40 -7
  59. package/dist/capabilities/collab-wire.d.ts +2 -0
  60. package/dist/capabilities/collab-workflows.d.ts +7 -0
  61. package/dist/capabilities/collab-workflows.js +44 -1
  62. package/dist/capabilities/oa-tools.d.ts +6 -0
  63. package/dist/capabilities/oa-tools.js +10 -0
  64. package/dist/capabilities/prompt.d.ts +14 -0
  65. package/dist/capabilities/prompt.js +14 -0
  66. package/dist/capabilities/prompts/code-review.d.ts +14 -0
  67. package/dist/capabilities/prompts/code-review.js +14 -0
  68. package/dist/capabilities/prompts/identity.d.ts +6 -0
  69. package/dist/capabilities/prompts/identity.js +6 -0
  70. package/dist/capabilities/prompts/team.d.ts +4 -0
  71. package/dist/capabilities/prompts/team.js +4 -0
  72. package/dist/capabilities/repo-tools.d.ts +11 -0
  73. package/dist/capabilities/repo-tools.js +8 -0
  74. package/dist/capabilities/sandbox-file-send.d.ts +95 -0
  75. package/dist/capabilities/sandbox-file-send.js +91 -3
  76. package/dist/capabilities/scenarios.d.ts +130 -0
  77. package/dist/capabilities/scenarios.js +180 -7
  78. package/dist/capabilities/select-environment-tool.d.ts +7 -0
  79. package/dist/capabilities/select-environment-tool.js +30 -0
  80. package/dist/capabilities/send-user-file-tool.d.ts +33 -0
  81. package/dist/capabilities/send-user-file-tool.js +65 -1
  82. package/dist/capabilities/skills.d.ts +29 -0
  83. package/dist/capabilities/skills.js +13 -2
  84. package/dist/capabilities/team.d.ts +22 -0
  85. package/dist/capabilities/team.js +22 -2
  86. package/dist/capabilities/tool-defer.d.ts +26 -0
  87. package/dist/capabilities/tool-defer.js +3 -0
  88. package/dist/config-center/apply-effective.d.ts +65 -0
  89. package/dist/config-center/apply-effective.js +204 -12
  90. package/dist/config-center/http-client.d.ts +34 -0
  91. package/dist/config-center/http-client.js +68 -0
  92. package/dist/config-center/restart-signal.d.ts +22 -0
  93. package/dist/config-center/restart-signal.js +39 -0
  94. package/dist/config-center/skills-mcp.d.ts +20 -1
  95. package/dist/config-center/skills-mcp.js +42 -7
  96. package/dist/config-center/types.d.ts +92 -1
  97. package/dist/config-lkg.d.ts +12 -0
  98. package/dist/config-lkg.js +41 -0
  99. package/dist/config-provider.d.ts +78 -0
  100. package/dist/config-provider.js +165 -2
  101. package/dist/config-types.d.ts +546 -0
  102. package/dist/config.d.ts +64 -0
  103. package/dist/config.js +455 -60
  104. package/dist/degenerate-instrument.d.ts +38 -0
  105. package/dist/degenerate-instrument.js +55 -3
  106. package/dist/elicitation.d.ts +39 -0
  107. package/dist/elicitation.js +87 -3
  108. package/dist/env-facts.d.ts +61 -0
  109. package/dist/env-facts.js +73 -7
  110. package/dist/fleet/fleet-bus.d.ts +185 -0
  111. package/dist/fleet/fleet-bus.js +333 -27
  112. package/dist/fleet/subagent-tail-bus.d.ts +11 -0
  113. package/dist/fleet/subagent-tail-bus.js +33 -2
  114. package/dist/fleet-client.d.ts +38 -0
  115. package/dist/fleet-client.js +44 -9
  116. package/dist/fleet-lease.d.ts +46 -0
  117. package/dist/fleet-lease.js +73 -5
  118. package/dist/hooks/branch-transcript.d.ts +8 -0
  119. package/dist/hooks/branch-transcript.js +33 -0
  120. package/dist/hooks/cc-stop-prompt.d.ts +42 -0
  121. package/dist/hooks/cc-stop-prompt.js +43 -1
  122. package/dist/hooks/hook-llm.d.ts +15 -0
  123. package/dist/hooks/hook-llm.js +47 -0
  124. package/dist/hooks/hook-runner.d.ts +89 -0
  125. package/dist/hooks/hook-runner.js +327 -18
  126. package/dist/http/idempotency.d.ts +31 -0
  127. package/dist/http/idempotency.js +34 -0
  128. package/dist/http/principal-gate.d.ts +17 -0
  129. package/dist/http/principal-gate.js +35 -3
  130. package/dist/http/route-ctx.d.ts +36 -0
  131. package/dist/http/routes/approvals-assistant.d.ts +25 -0
  132. package/dist/http/routes/approvals-assistant.js +253 -23
  133. package/dist/http/routes/attachments.js +22 -4
  134. package/dist/http/routes/capabilities.d.ts +7 -0
  135. package/dist/http/routes/capabilities.js +202 -1
  136. package/dist/http/routes/fleet.d.ts +6 -0
  137. package/dist/http/routes/fleet.js +94 -5
  138. package/dist/http/routes/images.d.ts +17 -0
  139. package/dist/http/routes/images.js +222 -14
  140. package/dist/http/routes/leader.d.ts +7 -0
  141. package/dist/http/routes/leader.js +10 -0
  142. package/dist/http/routes/memory-policy.d.ts +6 -0
  143. package/dist/http/routes/memory-policy.js +38 -6
  144. package/dist/http/routes/notify-wake.d.ts +10 -0
  145. package/dist/http/routes/notify-wake.js +19 -3
  146. package/dist/http/routes/observability.d.ts +6 -0
  147. package/dist/http/routes/observability.js +19 -2
  148. package/dist/http/routes/runs.d.ts +15 -0
  149. package/dist/http/routes/runs.js +464 -41
  150. package/dist/http/routes/session-sync.d.ts +15 -0
  151. package/dist/http/routes/session-sync.js +229 -19
  152. package/dist/http/routes/sessions-list.d.ts +6 -0
  153. package/dist/http/routes/sessions-list.js +35 -4
  154. package/dist/http/routes/sessions.d.ts +14 -0
  155. package/dist/http/routes/sessions.js +176 -31
  156. package/dist/http/routes/side-query.d.ts +8 -0
  157. package/dist/http/routes/side-query.js +26 -1
  158. package/dist/http/routes/tasks.d.ts +18 -0
  159. package/dist/http/routes/tasks.js +501 -38
  160. package/dist/http/routes/trace-usage.d.ts +10 -0
  161. package/dist/http/routes/trace-usage.js +66 -14
  162. package/dist/http/routes/workflows.d.ts +12 -0
  163. package/dist/http/routes/workflows.js +180 -19
  164. package/dist/http/run-meta.d.ts +11 -0
  165. package/dist/http/run-meta.js +6 -0
  166. package/dist/http/send.d.ts +19 -0
  167. package/dist/http/send.js +11 -0
  168. package/dist/http/server.d.ts +255 -0
  169. package/dist/http/server.js +921 -75
  170. package/dist/http/sse-log.d.ts +15 -0
  171. package/dist/http/sse-log.js +16 -0
  172. package/dist/http/tar.d.ts +9 -0
  173. package/dist/http/tar.js +21 -5
  174. package/dist/http/wire-gate.d.ts +9 -0
  175. package/dist/http/wire-gate.js +9 -0
  176. package/dist/http/wire-types.d.ts +187 -0
  177. package/dist/http/workspace-content.d.ts +8 -0
  178. package/dist/http/workspace-content.js +10 -0
  179. package/dist/images/bake-validate.d.ts +63 -0
  180. package/dist/images/bake-validate.js +71 -1
  181. package/dist/images/manifest.d.ts +19 -0
  182. package/dist/images/manifest.js +6 -1
  183. package/dist/index.d.ts +1 -5
  184. package/dist/index.js +10 -5
  185. package/dist/key-resolver.d.ts +23 -0
  186. package/dist/key-resolver.js +27 -2
  187. package/dist/leader/diffout.d.ts +23 -0
  188. package/dist/leader/diffout.js +8 -1
  189. package/dist/leader/diffup.d.ts +32 -0
  190. package/dist/leader/diffup.js +43 -0
  191. package/dist/leader/endpoint.d.ts +20 -0
  192. package/dist/leader/endpoint.js +25 -2
  193. package/dist/leader/fanout.d.ts +60 -0
  194. package/dist/leader/fanout.js +29 -3
  195. package/dist/leader/grader-env-factory.d.ts +74 -0
  196. package/dist/leader/grader-env-factory.js +62 -3
  197. package/dist/leader/leader.d.ts +97 -0
  198. package/dist/leader/leader.js +151 -4
  199. package/dist/leader/merge.d.ts +94 -0
  200. package/dist/leader/merge.js +112 -9
  201. package/dist/leader/planner.d.ts +52 -0
  202. package/dist/leader/planner.js +47 -3
  203. package/dist/leader/repair-oracle.d.ts +61 -0
  204. package/dist/leader/repair-oracle.js +59 -1
  205. package/dist/leader/repair-wire.d.ts +78 -0
  206. package/dist/leader/repair-wire.js +79 -2
  207. package/dist/leader/wire.d.ts +79 -0
  208. package/dist/leader/wire.js +255 -8
  209. package/dist/lsp/e2b-bridge.d.ts +16 -0
  210. package/dist/lsp/e2b-bridge.js +32 -4
  211. package/dist/lsp/e2b-manager.d.ts +10 -0
  212. package/dist/lsp/e2b-manager.js +18 -2
  213. package/dist/lsp/lsp-frames.d.ts +12 -0
  214. package/dist/lsp/lsp-frames.js +12 -0
  215. package/dist/lsp/manager.d.ts +12 -0
  216. package/dist/lsp/manager.js +35 -2
  217. package/dist/lsp/types.d.ts +10 -0
  218. package/dist/lsp/ws-transport.d.ts +12 -0
  219. package/dist/lsp/ws-transport.js +53 -5
  220. package/dist/lsp-evict.d.ts +14 -0
  221. package/dist/lsp-evict.js +15 -1
  222. package/dist/main.js +2132 -96
  223. package/dist/memory-export.d.ts +1 -0
  224. package/dist/memory-export.js +4 -0
  225. package/dist/memory-scope.d.ts +49 -0
  226. package/dist/memory-scope.js +87 -4
  227. package/dist/memory-sync-client.d.ts +24 -0
  228. package/dist/memory-sync-client.js +41 -2
  229. package/dist/memory-sync.d.ts +23 -0
  230. package/dist/memory-sync.js +70 -1
  231. package/dist/model-select.d.ts +39 -0
  232. package/dist/model-select.js +42 -1
  233. package/dist/observability/cost-quota.d.ts +20 -0
  234. package/dist/observability/cost-quota.js +4 -0
  235. package/dist/observability/cost-taxonomy.d.ts +45 -0
  236. package/dist/observability/cost-taxonomy.js +34 -0
  237. package/dist/observability/logger.d.ts +1 -0
  238. package/dist/observability/logger.js +6 -0
  239. package/dist/observability/metrics.d.ts +13 -0
  240. package/dist/observability/metrics.js +63 -0
  241. package/dist/observability/otel-exporter.d.ts +9 -0
  242. package/dist/observability/otel-exporter.js +11 -3
  243. package/dist/observability/principal-context.d.ts +9 -0
  244. package/dist/observability/principal-context.js +9 -0
  245. package/dist/observability/prompt-manifest.d.ts +37 -0
  246. package/dist/observability/prompt-manifest.js +35 -1
  247. package/dist/observability/rate-limit.d.ts +10 -0
  248. package/dist/observability/rate-limit.js +1 -0
  249. package/dist/observability/tool-trace.d.ts +24 -0
  250. package/dist/observability/tool-trace.js +41 -1
  251. package/dist/orchestration/hardened-vm-runner.d.ts +107 -0
  252. package/dist/orchestration/hardened-vm-runner.js +119 -4
  253. package/dist/orchestration/hardened-vm-worker-runner.d.ts +14 -0
  254. package/dist/orchestration/hardened-vm-worker-runner.js +26 -1
  255. package/dist/orchestration/hardened-vm-worker.js +27 -0
  256. package/dist/orchestration/subagent-steer.d.ts +44 -0
  257. package/dist/orchestration/subagent-steer.js +45 -1
  258. package/dist/orchestration/workflow-agent-steer.d.ts +54 -0
  259. package/dist/orchestration/workflow-agent-steer.js +80 -1
  260. package/dist/orchestration/workflow-completion-inbox.d.ts +189 -2
  261. package/dist/orchestration/workflow-completion-inbox.js +283 -32
  262. package/dist/orchestration/workflow-notify-journal.d.ts +132 -1
  263. package/dist/orchestration/workflow-notify-journal.js +187 -13
  264. package/dist/parked-decide.d.ts +61 -0
  265. package/dist/parked-decide.js +58 -1
  266. package/dist/per-task-image.d.ts +54 -0
  267. package/dist/per-task-image.js +41 -0
  268. package/dist/plan-cache-probe.d.ts +35 -0
  269. package/dist/plan-cache-probe.js +18 -3
  270. package/dist/plugins/approval-exemption-store.d.ts +7 -0
  271. package/dist/plugins/approval-exemption-store.js +28 -2
  272. package/dist/plugins/approval-store-sql.d.ts +64 -0
  273. package/dist/plugins/approval-store-sql.js +32 -0
  274. package/dist/plugins/background-agent-store-sql.d.ts +55 -0
  275. package/dist/plugins/background-agent-store-sql.js +91 -4
  276. package/dist/plugins/background-shell-support.d.ts +98 -0
  277. package/dist/plugins/background-shell-support.js +117 -13
  278. package/dist/plugins/blob-backend.d.ts +104 -0
  279. package/dist/plugins/blob-backend.js +163 -6
  280. package/dist/plugins/breaker-state-sql.d.ts +65 -1
  281. package/dist/plugins/breaker-state-sql.js +46 -8
  282. package/dist/plugins/caching-session-store.d.ts +42 -0
  283. package/dist/plugins/caching-session-store.js +63 -3
  284. package/dist/plugins/checkpoint-store-sql.d.ts +179 -0
  285. package/dist/plugins/checkpoint-store-sql.js +239 -11
  286. package/dist/plugins/file-outcome-sink.d.ts +4 -0
  287. package/dist/plugins/file-outcome-sink.js +9 -0
  288. package/dist/plugins/file-resume-anchor-store.d.ts +20 -0
  289. package/dist/plugins/file-resume-anchor-store.js +43 -4
  290. package/dist/plugins/file-run-store.d.ts +90 -0
  291. package/dist/plugins/file-run-store.js +145 -13
  292. package/dist/plugins/file-snapshot-store-sql.d.ts +133 -1
  293. package/dist/plugins/file-snapshot-store-sql.js +178 -10
  294. package/dist/plugins/file-workflow-journal-store.d.ts +10 -0
  295. package/dist/plugins/file-workflow-journal-store.js +10 -0
  296. package/dist/plugins/fork-routing-session-store.d.ts +47 -0
  297. package/dist/plugins/fork-routing-session-store.js +51 -3
  298. package/dist/plugins/host-platform.d.ts +69 -0
  299. package/dist/plugins/host-platform.js +81 -2
  300. package/dist/plugins/image-bake-store-sql.d.ts +136 -1
  301. package/dist/plugins/image-bake-store-sql.js +241 -7
  302. package/dist/plugins/image-index-sql.d.ts +46 -0
  303. package/dist/plugins/image-index-sql.js +113 -4
  304. package/dist/plugins/k8s-bg-scripts.d.ts +34 -0
  305. package/dist/plugins/k8s-bg-scripts.js +88 -4
  306. package/dist/plugins/k8s-exec-protocol.d.ts +33 -0
  307. package/dist/plugins/k8s-exec-protocol.js +41 -0
  308. package/dist/plugins/local-checkpoint-store.d.ts +40 -0
  309. package/dist/plugins/local-checkpoint-store.js +86 -7
  310. package/dist/plugins/local-session-store.d.ts +157 -0
  311. package/dist/plugins/local-session-store.js +289 -34
  312. package/dist/plugins/local-task-attachment-store.js +14 -2
  313. package/dist/plugins/mailbox-store-sql.d.ts +38 -0
  314. package/dist/plugins/mailbox-store-sql.js +39 -6
  315. package/dist/plugins/memory-engine-pg.d.ts +30 -0
  316. package/dist/plugins/memory-engine-pg.js +122 -4
  317. package/dist/plugins/memory-engine-tidb.d.ts +26 -0
  318. package/dist/plugins/memory-engine-tidb.js +115 -5
  319. package/dist/plugins/memory-engine-vector-util.d.ts +5 -0
  320. package/dist/plugins/memory-engine-vector-util.js +5 -0
  321. package/dist/plugins/memory-resume-anchor-store.d.ts +8 -0
  322. package/dist/plugins/memory-resume-anchor-store.js +17 -0
  323. package/dist/plugins/memory-run-store.d.ts +63 -0
  324. package/dist/plugins/memory-run-store.js +73 -8
  325. package/dist/plugins/memory-session-policy-store.d.ts +17 -0
  326. package/dist/plugins/memory-session-policy-store.js +17 -0
  327. package/dist/plugins/memory-sync-store-pg.d.ts +42 -0
  328. package/dist/plugins/memory-sync-store-pg.js +45 -2
  329. package/dist/plugins/memory-sync-store-tidb.d.ts +9 -0
  330. package/dist/plugins/memory-sync-store-tidb.js +31 -1
  331. package/dist/plugins/outcome-ledger-sql.d.ts +63 -0
  332. package/dist/plugins/outcome-ledger-sql.js +97 -3
  333. package/dist/plugins/pg-approval-store.d.ts +7 -0
  334. package/dist/plugins/pg-approval-store.js +7 -0
  335. package/dist/plugins/pg-breaker-state.d.ts +6 -0
  336. package/dist/plugins/pg-breaker-state.js +6 -0
  337. package/dist/plugins/pg-checkpoint-store.d.ts +8 -0
  338. package/dist/plugins/pg-checkpoint-store.js +8 -0
  339. package/dist/plugins/pg-cost-quota.d.ts +17 -0
  340. package/dist/plugins/pg-cost-quota.js +6 -0
  341. package/dist/plugins/pg-file-snapshot-store.d.ts +6 -0
  342. package/dist/plugins/pg-file-snapshot-store.js +6 -0
  343. package/dist/plugins/pg-image-bake.d.ts +9 -0
  344. package/dist/plugins/pg-image-bake.js +9 -0
  345. package/dist/plugins/pg-image-index.d.ts +9 -0
  346. package/dist/plugins/pg-image-index.js +9 -0
  347. package/dist/plugins/pg-outcome-ledger.d.ts +9 -0
  348. package/dist/plugins/pg-outcome-ledger.js +9 -0
  349. package/dist/plugins/pg-pool.d.ts +50 -0
  350. package/dist/plugins/pg-pool.js +78 -0
  351. package/dist/plugins/pg-query.d.ts +11 -0
  352. package/dist/plugins/pg-rate-limiter.d.ts +23 -0
  353. package/dist/plugins/pg-rate-limiter.js +12 -2
  354. package/dist/plugins/pg-resume-anchor-store.d.ts +5 -0
  355. package/dist/plugins/pg-resume-anchor-store.js +5 -0
  356. package/dist/plugins/pg-run-store.d.ts +7 -0
  357. package/dist/plugins/pg-run-store.js +7 -0
  358. package/dist/plugins/pg-safe-json.d.ts +13 -0
  359. package/dist/plugins/pg-safe-json.js +40 -4
  360. package/dist/plugins/pg-session-policy-store.d.ts +5 -0
  361. package/dist/plugins/pg-session-policy-store.js +5 -0
  362. package/dist/plugins/pg-session-storage.d.ts +72 -0
  363. package/dist/plugins/pg-session-storage.js +152 -20
  364. package/dist/plugins/pg-session-store.d.ts +10 -0
  365. package/dist/plugins/pg-session-store.js +10 -0
  366. package/dist/plugins/pg-tool-result-store.d.ts +7 -0
  367. package/dist/plugins/pg-tool-result-store.js +7 -0
  368. package/dist/plugins/pg-workflow-journal-store.d.ts +7 -0
  369. package/dist/plugins/pg-workflow-journal-store.js +7 -0
  370. package/dist/plugins/pg-workflow-run-store.d.ts +7 -0
  371. package/dist/plugins/pg-workflow-run-store.js +7 -0
  372. package/dist/plugins/posix-shell-fs.d.ts +3 -0
  373. package/dist/plugins/posix-shell-fs.js +31 -1
  374. package/dist/plugins/remote-env-adb.d.ts +25 -0
  375. package/dist/plugins/remote-env-adb.js +95 -12
  376. package/dist/plugins/remote-env-e2b.d.ts +146 -0
  377. package/dist/plugins/remote-env-e2b.js +371 -40
  378. package/dist/plugins/remote-env-file-error.d.ts +34 -0
  379. package/dist/plugins/remote-env-file-error.js +37 -0
  380. package/dist/plugins/remote-env-host.d.ts +151 -0
  381. package/dist/plugins/remote-env-host.js +468 -70
  382. package/dist/plugins/remote-env-k8s.d.ts +135 -0
  383. package/dist/plugins/remote-env-k8s.js +318 -32
  384. package/dist/plugins/remote-env-local-docker.d.ts +65 -0
  385. package/dist/plugins/remote-env-local-docker.js +149 -24
  386. package/dist/plugins/remote-env-ssh.d.ts +35 -0
  387. package/dist/plugins/remote-env-ssh.js +117 -20
  388. package/dist/plugins/remote-scratchpad.d.ts +38 -0
  389. package/dist/plugins/remote-scratchpad.js +32 -2
  390. package/dist/plugins/remote-shell.d.ts +22 -0
  391. package/dist/plugins/remote-shell.js +27 -1
  392. package/dist/plugins/resume-anchor-store-sql.d.ts +28 -0
  393. package/dist/plugins/resume-anchor-store-sql.js +11 -0
  394. package/dist/plugins/roster-store-sql.d.ts +27 -0
  395. package/dist/plugins/roster-store-sql.js +54 -0
  396. package/dist/plugins/run-store-sql.d.ts +194 -0
  397. package/dist/plugins/run-store-sql.js +210 -9
  398. package/dist/plugins/s3-presign.d.ts +20 -0
  399. package/dist/plugins/s3-presign.js +49 -2
  400. package/dist/plugins/scheduler-support.d.ts +12 -0
  401. package/dist/plugins/scheduler-support.js +75 -3
  402. package/dist/plugins/send-file-ledger.d.ts +15 -0
  403. package/dist/plugins/send-file-ledger.js +53 -4
  404. package/dist/plugins/send-user-file.d.ts +77 -0
  405. package/dist/plugins/send-user-file.js +92 -4
  406. package/dist/plugins/session-policy-store-sql.d.ts +15 -0
  407. package/dist/plugins/session-policy-store-sql.js +75 -3
  408. package/dist/plugins/session-store.d.ts +45 -0
  409. package/dist/plugins/session-store.js +51 -0
  410. package/dist/plugins/sql-driver.d.ts +77 -0
  411. package/dist/plugins/sql-driver.js +4 -0
  412. package/dist/plugins/sql-escape.d.ts +8 -0
  413. package/dist/plugins/sql-escape.js +8 -0
  414. package/dist/plugins/sql-row-helpers.d.ts +25 -0
  415. package/dist/plugins/sql-row-helpers.js +25 -0
  416. package/dist/plugins/store-backend.d.ts +103 -0
  417. package/dist/plugins/store-backend.js +120 -27
  418. package/dist/plugins/store-contracts.d.ts +62 -0
  419. package/dist/plugins/store-contracts.js +3 -0
  420. package/dist/plugins/task-attachment-store.d.ts +60 -0
  421. package/dist/plugins/task-attachment-store.js +49 -3
  422. package/dist/plugins/task-list-store-sql.d.ts +25 -0
  423. package/dist/plugins/task-list-store-sql.js +21 -0
  424. package/dist/plugins/tidb-approval-store.d.ts +6 -0
  425. package/dist/plugins/tidb-approval-store.js +6 -0
  426. package/dist/plugins/tidb-breaker-state.d.ts +5 -0
  427. package/dist/plugins/tidb-breaker-state.js +5 -0
  428. package/dist/plugins/tidb-checkpoint-store.d.ts +7 -0
  429. package/dist/plugins/tidb-checkpoint-store.js +7 -0
  430. package/dist/plugins/tidb-cost-quota.d.ts +6 -0
  431. package/dist/plugins/tidb-cost-quota.js +1 -0
  432. package/dist/plugins/tidb-file-snapshot-store.d.ts +6 -0
  433. package/dist/plugins/tidb-file-snapshot-store.js +6 -0
  434. package/dist/plugins/tidb-image-bake.d.ts +8 -0
  435. package/dist/plugins/tidb-image-bake.js +8 -0
  436. package/dist/plugins/tidb-image-index.d.ts +8 -0
  437. package/dist/plugins/tidb-image-index.js +8 -0
  438. package/dist/plugins/tidb-outcome-ledger.d.ts +10 -0
  439. package/dist/plugins/tidb-outcome-ledger.js +10 -0
  440. package/dist/plugins/tidb-pool.d.ts +56 -0
  441. package/dist/plugins/tidb-pool.js +181 -1
  442. package/dist/plugins/tidb-rate-limiter.d.ts +11 -0
  443. package/dist/plugins/tidb-rate-limiter.js +5 -2
  444. package/dist/plugins/tidb-resume-anchor-store.d.ts +5 -0
  445. package/dist/plugins/tidb-resume-anchor-store.js +5 -0
  446. package/dist/plugins/tidb-run-store.d.ts +7 -0
  447. package/dist/plugins/tidb-run-store.js +7 -0
  448. package/dist/plugins/tidb-session-policy-store.d.ts +5 -0
  449. package/dist/plugins/tidb-session-policy-store.js +5 -0
  450. package/dist/plugins/tidb-session-storage.d.ts +43 -0
  451. package/dist/plugins/tidb-session-storage.js +62 -3
  452. package/dist/plugins/tidb-session-store.d.ts +142 -0
  453. package/dist/plugins/tidb-session-store.js +264 -16
  454. package/dist/plugins/tidb-tool-result-store.d.ts +5 -0
  455. package/dist/plugins/tidb-tool-result-store.js +7 -0
  456. package/dist/plugins/tidb-workflow-journal-store.d.ts +7 -0
  457. package/dist/plugins/tidb-workflow-journal-store.js +7 -0
  458. package/dist/plugins/tidb-workflow-run-store.d.ts +8 -0
  459. package/dist/plugins/tidb-workflow-run-store.js +8 -0
  460. package/dist/plugins/tool-result-store-sql.d.ts +58 -0
  461. package/dist/plugins/tool-result-store-sql.js +38 -2
  462. package/dist/plugins/web-search.d.ts +35 -0
  463. package/dist/plugins/web-search.js +45 -9
  464. package/dist/plugins/workflow-journal-limits.d.ts +10 -0
  465. package/dist/plugins/workflow-journal-limits.js +10 -0
  466. package/dist/plugins/workflow-journal-store-sql.d.ts +78 -0
  467. package/dist/plugins/workflow-journal-store-sql.js +59 -3
  468. package/dist/plugins/workflow-run-store-sql.d.ts +84 -0
  469. package/dist/plugins/workflow-run-store-sql.js +84 -6
  470. package/dist/plugins/worktree-isolation.d.ts +45 -0
  471. package/dist/plugins/worktree-isolation.js +105 -6
  472. package/dist/plugins/write-behind-counter.d.ts +56 -1
  473. package/dist/plugins/write-behind-counter.js +53 -14
  474. package/dist/principal-jwt.d.ts +24 -0
  475. package/dist/principal-jwt.js +60 -5
  476. package/dist/project-memory.d.ts +22 -0
  477. package/dist/project-memory.js +144 -15
  478. package/dist/prompts-domain-validate.d.ts +28 -0
  479. package/dist/prompts-domain-validate.js +42 -1
  480. package/dist/question.d.ts +33 -0
  481. package/dist/question.js +69 -2
  482. package/dist/resource-suspend.d.ts +21 -0
  483. package/dist/resource-suspend.js +16 -0
  484. package/dist/router/route-orchestration.d.ts +78 -0
  485. package/dist/router/route-orchestration.js +77 -0
  486. package/dist/run-local.d.ts +32 -0
  487. package/dist/run-local.js +172 -8
  488. package/dist/runs.d.ts +189 -4
  489. package/dist/runs.js +465 -24
  490. package/dist/runtime-caps-resolver.d.ts +106 -0
  491. package/dist/runtime-caps-resolver.js +89 -4
  492. package/dist/runtime-governance.d.ts +84 -0
  493. package/dist/runtime-governance.js +127 -1
  494. package/dist/sandbox-pkg-source.d.ts +23 -0
  495. package/dist/sandbox-pkg-source.js +37 -0
  496. package/dist/sealed-key.d.ts +54 -0
  497. package/dist/sealed-key.js +68 -3
  498. package/dist/security.d.ts +108 -0
  499. package/dist/security.js +145 -6
  500. package/dist/sema-registry.d.ts +21 -0
  501. package/dist/sema-registry.js +21 -0
  502. package/dist/session-leaf-bus.d.ts +31 -0
  503. package/dist/session-leaf-bus.js +32 -0
  504. package/dist/session-sync-content.d.ts +46 -0
  505. package/dist/session-sync-content.js +47 -1
  506. package/dist/session-sync-kernel.d.ts +89 -0
  507. package/dist/session-sync-kernel.js +48 -3
  508. package/dist/session-sync.d.ts +125 -0
  509. package/dist/session-sync.js +181 -8
  510. package/dist/session-titler.d.ts +26 -0
  511. package/dist/session-titler.js +41 -7
  512. package/dist/session-watch.d.ts +53 -1
  513. package/dist/session-watch.js +73 -9
  514. package/dist/sighup-idle.d.ts +30 -0
  515. package/dist/sighup-idle.js +12 -1
  516. package/dist/spec-fields.d.ts +91 -3
  517. package/dist/spec-fields.js +116 -4
  518. package/dist/task-cwd.d.ts +50 -0
  519. package/dist/task-cwd.js +68 -1
  520. package/dist/task-mcp.d.ts +47 -0
  521. package/dist/task-mcp.js +29 -0
  522. package/dist/task-settings.d.ts +175 -0
  523. package/dist/task-settings.js +226 -11
  524. package/dist/task-workflow.d.ts +67 -0
  525. package/dist/task-workflow.js +75 -8
  526. package/dist/tool-approval.d.ts +91 -0
  527. package/dist/tool-approval.js +215 -0
  528. package/dist/trace/artifacts.d.ts +9 -0
  529. package/dist/trace/artifacts.js +30 -5
  530. package/dist/trace/core-keyset-guard.d.ts +18 -0
  531. package/dist/trace/ledger-sink.d.ts +43 -0
  532. package/dist/trace/ledger-sink.js +64 -5
  533. package/dist/trace/project.d.ts +133 -0
  534. package/dist/trace/project.js +189 -2
  535. package/dist/trace/redact.d.ts +19 -0
  536. package/dist/trace/redact.js +66 -9
  537. package/dist/usage-analytics.d.ts +26 -0
  538. package/dist/usage-analytics.js +26 -3
  539. package/package.json +1 -1
@@ -1,7 +1,27 @@
1
+ /**
2
+ * v2 MVP M4 — the leader orchestrator (design/50 §3, V2-MVP-PLAN.md). Composes the proven pieces into one
3
+ * callable API: Planner → fanOut (M1) → diff-out (M2) → merge(b) (M3) → Coordinator push.
4
+ *
5
+ * Worker-env model (design/68 §8 F2(a)): preferred = FACTORY env (runner-owned lifecycle; durable suspend only
6
+ * yields a complete ownedEnv on this path) + diff-out via the worker's mandatory SELF-UPLOAD last step
7
+ * (`fetchDiff`, diffup.ts). Compat = the original static env the leader owns: provision up-front, pull each
8
+ * branch's diff OUT of the still-alive env (pullDiff), destroy every env in a `finally`.
9
+ * fanOut's runner just routes a sessionId to that worker's env-bound runner. This is the leaderless-leader
10
+ * pattern (service[19]): authority = owning the integration+verification point + disjoint file-ownership.
11
+ *
12
+ * Deps injected → mock-tested; the real-infra wiring (E2B envs + deepseek runners + git push) lives in the
13
+ * joint dogfood, which this generalizes.
14
+ */
1
15
  import { type RunnerLike, type WorkerReport } from "./fanout.js";
2
16
  import { type ExecStreamLike } from "./diffout.js";
3
17
  import { type MergeDeps, type MergeResult } from "./merge.js";
4
18
  import { type TaskSpec, type VerifyConfig, type CheckpointToken, type ToolSpec, type RepairTerminal, type OracleTier, type RepairResult } from "@sema-agent/core";
19
+ /** design/74 Slice 6: drive a worker's resource-suspend auto-resume to a terminal (or bound) state. Exported
20
+ * for unit tests. Loops `resume(token, slice)` WHILE the result carries a `resource_limit` checkpoint gate —
21
+ * NOT by status (the verify wrapper may surface a suspend as failed-with-token). Exits on: a terminal result
22
+ * (completed/failed → no gate), an exhausted budget (core fails the resume fast → no token/gate), a
23
+ * human-approval gate (kind ≠ "resource_limit" — never auto-resumed), `signal.aborted`, or `maxSlices` (a
24
+ * belt; core's ledger fail-fast + per-task suspend-loop cap are the primary bounds). Returns the final result. */
5
25
  export declare function autoResumeOnResource<T extends {
6
26
  checkpointToken?: CheckpointToken;
7
27
  checkpointGate?: {
@@ -10,35 +30,61 @@ export declare function autoResumeOnResource<T extends {
10
30
  }>(initial: T, signal: {
11
31
  readonly aborted: boolean;
12
32
  }, resume: (token: CheckpointToken, slice: number) => Promise<T>, maxSlices?: number): Promise<T>;
33
+ /** A planned sub-task: a worker id, its branch, disjoint file-ownership, and the agent objective. */
13
34
  export interface SubtaskSpec {
14
35
  workerId: string;
15
36
  branch: string;
16
37
  files: string[];
17
38
  spec: Omit<TaskSpec, "sessionId" | "signal">;
18
39
  }
40
+ /** A leader-OWNED worker: its env-bound runner + the env handle to pull its diff out + lifecycle. */
19
41
  export interface ProvisionedWorker {
20
42
  workerId: string;
21
43
  sessionId: string;
22
44
  branch: string;
45
+ /** base commit of THIS worker's env (drives `git format-patch <baseSha>..<branch>` diff-out). */
23
46
  baseSha: string;
47
+ /** runs the worker agent on this worker's env (static `executionEnv` or a factory — design/68 F2(a)). */
24
48
  runner: RunnerLike;
49
+ /** Static-env mode (M2 compat): pull the worker's branch diff OUT of its (post-task, still-alive) env. */
25
50
  diffEnv?: ExecStreamLike;
51
+ /** Factory-env mode (design/68 F2(a), preferred when set): fetch the diff the worker SELF-UPLOADED as its
52
+ * mandatory last task step (presigned MinIO object) — the env is runner-owned and already gone. */
26
53
  fetchDiff?: () => Promise<import("./diffout.js").PullDiffResult>;
54
+ /** Static-env mode only: the leader owns + destroys the env. Factory envs omit this — the runner's factory
55
+ * lifecycle destroys them, and a SUSPENDED worker's paused env is thereby exempt from the leader's reap
56
+ * (design/68 row4/C4: destroying a suspended worker's env = expiring its resume token). */
27
57
  destroy?: () => Promise<void>;
28
58
  spec: Omit<TaskSpec, "sessionId" | "signal">;
59
+ /** Optional read-effect PROBE tools for the L3 verifier (verifyWorker path). The default verifierTools = the
60
+ * impl's tools filtered to effect:"read", which DROPS the env's write-effect `bash` → the verifier can't run
61
+ * python3/tests → PARTIAL. Provision a read-effect exec/probe tool here so the verifier can actually verify. */
29
62
  verifierTools?: ToolSpec[];
30
63
  }
31
64
  export interface LeaderDeps {
65
+ /** Plan a task into N disjoint-file sub-tasks (MVP: simple/hand-authored; adaptive replan = scale). */
32
66
  plan: (task: string) => Promise<SubtaskSpec[]>;
67
+ /** Provision a leader-owned worker (its env seeded with base at `branch` + an env-bound runner). */
33
68
  provisionWorker: (sub: SubtaskSpec) => Promise<ProvisionedWorker>;
69
+ /** Ephemeral no-creds integration sandbox + the credentialed Coordinator push (merge(b) deps). */
34
70
  provisionIntegrationSandbox: MergeDeps["provisionIntegrationSandbox"];
35
71
  push: MergeDeps["push"];
72
+ /** Integration test command (the merge gate) + repo dir inside the sandbox. */
36
73
  testCmd: string;
74
+ /** Optional truecorrect MEASURE (design/59): a thorough hidden-oracle command run IN the integration sandbox
75
+ * after the gate passes (NOT a gate) — offloads the measure from the control plane. Result in result.merge.measure. */
37
76
  measureCmd?: string;
38
77
  repoDir?: string;
78
+ /** Diff-out repo dir inside each WORKER env (default = repoDir). */
39
79
  workerRepoDir?: string;
80
+ /** fan-out deadline + concurrency cap. */
40
81
  timeoutMs: number;
41
82
  maxConcurrency: number;
83
+ /** design/52 L3a — optional per-module sub-gate + bounded repair, run AFTER fan-out, BEFORE merge. For each
84
+ * completed worker: judge its module (diff) vs its sub-objective; on fail, re-run that ONE worker with the
85
+ * judge's feedback (bounded by maxRepairs, default 1) on its own still-alive env, then re-judge. A module that
86
+ * still fails is marked `failed` (merge quarantines it). Catches per-module escapes the end-integration test
87
+ * misses + restores cheap-team correctness by local repair (search [38] / N=6 all-or-nothing). Omit = off. */
42
88
  moduleGate?: {
43
89
  judge: (sub: SubtaskSpec, diff: string) => Promise<{
44
90
  ok: boolean;
@@ -47,11 +93,34 @@ export interface LeaderDeps {
47
93
  repairObjective: (sub: SubtaskSpec, reason: string) => string;
48
94
  maxRepairs?: number;
49
95
  };
96
+ /** core 1.72 native L3a (design/54 §4): when set, each worker runs via `runWithVerification` (run the module +
97
+ * an ADVERSARIAL DECORRELATED verifier tries to break it reading the diff/workspace + a bounded fix-loop)
98
+ * instead of plain fan-out. The worker runner's `models` catalog MUST carry the heterogeneous `verifierModel`
99
+ * (decorrelation = deployment contract). Mutually exclusive with `moduleGate` (this IS the native version). */
50
100
  verifyWorker?: VerifyConfig;
101
+ /** Replan-lite (design/68 §6): bounded, DETERMINISTIC reactions — no runtime DAG surgery. When set:
102
+ * worker failed → redispatch ×1 on a FRESH env (clean base; a crashed worker's half-written workspace is
103
+ * never reused) → still failed = collapse-remainder-to-single; verify FAIL (repair already bounded inside
104
+ * the verify loop) → collapse; structural merge conflict → collapse + record; budgetUsd exceeded → stop
105
+ * fan-out, single continues. Multi-trigger arbitration priority (C6): suspended > budget > merge-conflict >
106
+ * verify-fail > worker-failed — only the highest-priority reaction runs. (The suspended reaction itself —
107
+ * cancel the others, exempt the suspended worker, surface its token — is unconditional, not gated here.) */
51
108
  replan?: {
109
+ /** Fan-out budget (USD, sum of worker costs). Exceeded → stop fan-out, collapse to single (C5). */
52
110
  budgetUsd?: number;
53
111
  };
112
+ /** LEADER-REPAIRLOOP-INTEGRATION §3/§10 — the OPT-IN single-agent self-repair loop (`runRepairLoop`). When
113
+ * set (LEADER_REPAIR_LOOP on; the wire attaches it via `attachRepairLoopDeps`), the single-agent paths
114
+ * (`collapseToSingle` `:409` and the N=1 `route==="single"` path) route their solo worker through this
115
+ * instead of the plain fan-out map: GENERATE == one `runner.runTask`, GRADED by an ISOLATED grader (the
116
+ * reused integration sandbox), capped at `candidate_only` (SAFE-tier never auto-accepts). Stage-2 wires the
117
+ * call-sites; this is the additive dep slot. `run` returns the worker's `WorkerReport` (carrying
118
+ * `repairTerminal` — §10.6) so the merge push chokepoint can hold an unconfirmed candidate. Unset ⇒ the
119
+ * default path is byte-identical to today. */
54
120
  repairLoop?: {
121
+ /** Run the bounded repair loop over a single provisioned worker; the returned report carries `repairTerminal`
122
+ * (and the candidate patch is surfaced on LeaderResult). The grader env / oracle steps / model ids are
123
+ * captured by the wire (`runRepairLoopForLeader`). */
55
124
  run: (solo: ProvisionedWorker, sub: SubtaskSpec) => Promise<{
56
125
  report: WorkerReport;
57
126
  result: RepairResult;
@@ -63,6 +132,10 @@ export interface LeaderDeps {
63
132
  };
64
133
  }>;
65
134
  };
135
+ /** LEADER-REPAIRLOOP-INTEGRATION §10.3/§10.4 — the merge-path push-gate extras (the wire sets them from
136
+ * `LEADER_MEASURE_GATES`, default OFF). Threaded straight into `MergeDeps` (`measureGates` / `strongOracleSeeded`
137
+ * / `measureDrivesRepair`). Unset ⇒ the merge push path is byte-identical to today (the §10.6 repairTerminal
138
+ * chokepoint still fires independently — it does NOT need these). */
66
139
  mergeGates?: Pick<MergeDeps, "measureGates" | "strongOracleSeeded" | "measureDrivesRepair">;
67
140
  logger?: {
68
141
  warn?: (m: string, x?: Record<string, unknown>) => void;
@@ -74,23 +147,43 @@ export interface LeaderResult {
74
147
  reports: WorkerReport[];
75
148
  merge?: MergeResult;
76
149
  cancelled: boolean;
150
+ /** Which route the difficulty router picked (search [43]): "single" = a 1-subtask plan, "fanout" = N. */
77
151
  route?: "single" | "fanout";
152
+ /** Set when planning/provisioning failed before fan-out. */
78
153
  error?: string;
154
+ /** Replan-lite (design/68 §6): which trigger won arbitration + what was done. */
79
155
  replan?: {
80
156
  trigger: "suspended" | "budget" | "merge-conflict" | "verify-fail" | "worker-failed";
81
157
  redispatched?: string[];
82
158
  collapsed?: string;
83
159
  };
160
+ /** C4: suspended workers' resume tokens, surfaced to the caller (their checkpoints + paused envs are intact —
161
+ * the single-agent resume path owns them from here; orphan protection = the existing deadline reap). */
84
162
  suspended?: Array<{
85
163
  workerId: string;
86
164
  sessionId: string;
87
165
  }>;
166
+ /** design/74 Slice 6 / task#16: the diff (uncommitted work auto-committed by the belt, then diff-out) of
167
+ * workers that did NOT merge (failed / still-suspended). Their progress is otherwise lost — the merge only
168
+ * integrates COMPLETED workers — so surface it here for review/cherry-pick instead of silently dropping it
169
+ * (the migration-run loss: a network-failed worker's 4 commits vanished). Best-effort + non-empty only. */
88
170
  salvaged?: Array<{
89
171
  workerId: string;
90
172
  sessionId: string;
91
173
  patch: string;
92
174
  }>;
175
+ /** LEADER-REPAIRLOOP-INTEGRATION §5 — the single-agent repair loop's terminal (when `LeaderDeps.repairLoop`
176
+ * ran on a single-agent path). Surfaced so the HTTP status map (`endpoint.ts:75`) can distinguish "abstained,
177
+ * awaiting a human" (`candidate_only`/`needs_human_oracle`/`conflict` → `needs_human`) from "broke"
178
+ * (`oracle.unprotected`/`gave_up` → `failed`). Undefined ⇒ the repair loop did not run. */
93
179
  repairTerminal?: RepairTerminal;
180
+ /** LEADER-REPAIRLOOP-INTEGRATION §5/§10.7 — the held candidate when the repair loop resolved to a
181
+ * non-auto-accepting terminal (`candidate_only` etc.). `patch` is the worker-authored diff, DELIMITED as
182
+ * untrusted at the wire surface (`delimitUntrusted("CANDIDATE PATCH (untrusted worker code)", …)` — §10.7) so
183
+ * it can safely reach the HTTP body + a durable-approval row a human reads; `reason` is sourced ONLY from the
184
+ * core-sanitized `RepairResult.verification.findings[0]`, never the raw oracle trace. The push is HELD — a
185
+ * human `/decide` accept fires it, reject discards (an unattended `candidate_only` is never a silent push and
186
+ * never a silent drop — §5 invariant). */
94
187
  candidatePatch?: {
95
188
  patch: string;
96
189
  tier: OracleTier;
@@ -98,5 +191,9 @@ export interface LeaderResult {
98
191
  gradedHash?: string;
99
192
  };
100
193
  }
194
+ /**
195
+ * Run a task to an integrated, pushed result. Never throws — failures (plan, provision, fan-out, merge) are
196
+ * captured in LeaderResult. ALWAYS destroys every provisioned worker env (leader owns the lifecycle).
197
+ */
101
198
  export declare function runLeaderTask(task: string, durableBaseSha: string, deps: LeaderDeps): Promise<LeaderResult>;
102
199
  //# sourceMappingURL=leader.d.ts.map
@@ -1,8 +1,34 @@
1
+ /**
2
+ * v2 MVP M4 — the leader orchestrator (design/50 §3, V2-MVP-PLAN.md). Composes the proven pieces into one
3
+ * callable API: Planner → fanOut (M1) → diff-out (M2) → merge(b) (M3) → Coordinator push.
4
+ *
5
+ * Worker-env model (design/68 §8 F2(a)): preferred = FACTORY env (runner-owned lifecycle; durable suspend only
6
+ * yields a complete ownedEnv on this path) + diff-out via the worker's mandatory SELF-UPLOAD last step
7
+ * (`fetchDiff`, diffup.ts). Compat = the original static env the leader owns: provision up-front, pull each
8
+ * branch's diff OUT of the still-alive env (pullDiff), destroy every env in a `finally`.
9
+ * fanOut's runner just routes a sessionId to that worker's env-bound runner. This is the leaderless-leader
10
+ * pattern (service[19]): authority = owning the integration+verification point + disjoint file-ownership.
11
+ *
12
+ * Deps injected → mock-tested; the real-infra wiring (E2B envs + deepseek runners + git push) lives in the
13
+ * joint dogfood, which this generalizes.
14
+ */
1
15
  import { fanOut } from "./fanout.js";
2
16
  import { pullDiff } from "./diffout.js";
3
17
  import { mergeBranches } from "./merge.js";
4
18
  import { Runner, runWithVerification, resumeWithVerification, delimitUntrusted } from "@sema-agent/core";
19
+ /** design/74 Slice 6: a belt-and-suspenders bound on the leader's resource auto-resume loop. The PRIMARY bound
20
+ * is the resource ledger (core fails an exhausted resume fast) + core's per-task suspend-loop cap; this only
21
+ * guards against an unforeseen non-progressing loop. Generous so a legitimate many-slice budget never hits it. */
5
22
  const MAX_RESUME_SLICES = 200;
23
+ /** design/74 Slice 6: drive a worker's resource-suspend auto-resume to a terminal (or bound) state. Exported
24
+ * for unit tests. Loops `resume(token, slice)` WHILE the result carries a `resource_limit` checkpoint gate —
25
+ * NOT by status (the verify wrapper may surface a suspend as failed-with-token). Exits on: a terminal result
26
+ * (completed/failed → no gate), an exhausted budget (core fails the resume fast → no token/gate), a
27
+ * human-approval gate (kind ≠ "resource_limit" — never auto-resumed), `signal.aborted`, or `maxSlices` (a
28
+ * belt; core's ledger fail-fast + per-task suspend-loop cap are the primary bounds). Returns the final result. */
29
+ // Generic over the result type so BOTH leader worker paths reuse it: the verify path (VerificationResult via
30
+ // runWithVerification/resumeWithVerification) AND the non-verify path (plain TaskResult via runTaskStream/
31
+ // runner.resume). The loop only reads `checkpointToken` / `checkpointGate`, both on TaskResult.
6
32
  export async function autoResumeOnResource(initial, signal, resume, maxSlices = MAX_RESUME_SLICES) {
7
33
  let vr = initial;
8
34
  for (let slice = 0; vr.checkpointToken !== undefined && vr.checkpointGate?.kind === "resource_limit" && !signal.aborted && slice < maxSlices; slice++) {
@@ -10,6 +36,10 @@ export async function autoResumeOnResource(initial, signal, resume, maxSlices =
10
36
  }
11
37
  return vr;
12
38
  }
39
+ /**
40
+ * Run a task to an integrated, pushed result. Never throws — failures (plan, provision, fan-out, merge) are
41
+ * captured in LeaderResult. ALWAYS destroys every provisioned worker env (leader owns the lifecycle).
42
+ */
13
43
  export async function runLeaderTask(task, durableBaseSha, deps) {
14
44
  let subs;
15
45
  try {
@@ -20,10 +50,12 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
20
50
  }
21
51
  if (subs.length === 0)
22
52
  return { ok: false, reports: [], cancelled: false, error: "planner produced no sub-tasks" };
53
+ // difficulty router (search [43]): a 1-subtask plan IS the single route — run through the same N=1 pipeline.
23
54
  const route = subs.length === 1 ? "single" : "fanout";
24
55
  const workers = [];
25
- let finalReports = [];
56
+ let finalReports = []; // visible to `finally` — drives the suspended-worker destroy exemption
26
57
  try {
58
+ // Provision every worker env up-front (leader-owned; each outlives its task for diff-out).
27
59
  for (const sub of subs) {
28
60
  try {
29
61
  workers.push(await deps.provisionWorker(sub));
@@ -34,15 +66,22 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
34
66
  }
35
67
  const byId = new Map(workers.map((w) => [w.workerId, w]));
36
68
  const bySession = new Map(workers.map((w) => [w.sessionId, w]));
69
+ // fan-out: route each sessionId to its own env-bound runner (M1).
37
70
  const runner = {
38
71
  runTaskStream: (spec) => bySession.get(spec.sessionId).runner.runTaskStream(spec),
39
72
  };
40
73
  const toSubtask = (w) => ({
41
74
  workerId: w.workerId, sessionId: w.sessionId, branch: w.branch, baseSha: w.baseSha, spec: w.spec,
42
75
  });
76
+ // cancelOnSuspend = the unconditional C4 reaction: a suspended settle preempts the remaining fan-out.
43
77
  const foBase = { runner, timeoutMs: deps.timeoutMs, maxConcurrency: deps.maxConcurrency, cancelOnSuspend: true, ...(deps.logger ? { logger: deps.logger } : {}) };
44
78
  const runWave = async (sts) => {
45
79
  if (!deps.verifyWorker) {
80
+ // design/74 Slice 6 (live-test bug): the NON-verify path ALSO needs the resource-suspend auto-resume.
81
+ // The auto-resume previously lived only in the verify path's runWorker, so a leader with NO verifier
82
+ // (e.g. the drill) ran via fanOut's plain runTaskStream — a resource-suspended worker was never resumed,
83
+ // just surfaced "suspended". Give this path its own runWorker: run, then auto-resume across slices
84
+ // (plain runner.resume, no verify), then map + WARN-log any non-completed worker (no silent failures).
46
85
  return fanOut(sts, {
47
86
  ...foBase,
48
87
  runWorker: async (st, signal) => {
@@ -58,12 +97,17 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
58
97
  deps.logger?.warn?.("worker_failed", {
59
98
  workerId: w.workerId, status: r.status, turns: r.stats?.turns ?? 0,
60
99
  ...(r.errorCode ? { errorCode: r.errorCode } : {}),
100
+ // A `blocked` worker carries its reason in `blockedReason`, NOT `errorMessage` — surface it too,
101
+ // else a report_blocked is a silent "worker blocked" with no WHY (clay no-silent-failures).
61
102
  ...(r.errorMessage ? { error: r.errorMessage.slice(0, 200) } : {}),
62
103
  ...(r.blockedReason ? { blockedReason: r.blockedReason.slice(0, 200) } : {}),
63
104
  });
64
105
  }
65
106
  return {
66
107
  ...base,
108
+ // Map the TaskResult status directly (like fanOut's own mapStatus) — a `suspended` result that the
109
+ // auto-resume left unresumed (a non-resource gate, e.g. human-approval) stays `suspended` so the
110
+ // leader's C4 surface/cancel reaction still fires; only completed/timeout pass through, else failed.
67
111
  status: r.status === "completed" ? "completed" : r.status === "suspended" ? "suspended" : r.status === "timeout" ? "timeout" : "failed",
68
112
  stats: r.stats,
69
113
  ...(r.status === "completed" ? {} : { error: r.errorMessage ?? r.blockedReason ?? `worker ${r.status}` }),
@@ -73,6 +117,13 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
73
117
  },
74
118
  });
75
119
  }
120
+ // design/54 §4 L3a (core 1.72 NATIVE): each worker = runWithVerification — run the module, then an
121
+ // ADVERSARIAL DECORRELATED verifier (a different model) tries to BREAK it (reads diff/workspace, runs
122
+ // probes), with a bounded fix-loop = native per-module sub-gate + repair. Replaces the hand-rolled
123
+ // moduleGate. verdict FAIL after maxRounds → status:"failed" (merge quarantines). Run cost incl verify+fix.
124
+ // Routed THROUGH fanOut (not an unbounded Promise.all — council): reuses the semaphore (maxConcurrency), the
125
+ // overall timeout→cancelAll, and the shared abort signal — passed into the spec so a hung/cancelled verify
126
+ // actually aborts (so the overall-timeout's `await work` can unblock).
76
127
  const verify = deps.verifyWorker;
77
128
  return fanOut(sts, {
78
129
  ...foBase,
@@ -81,14 +132,27 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
81
132
  const base = { workerId: w.workerId, sessionId: w.sessionId, branch: w.branch, baseSha: w.baseSha };
82
133
  const cfg = w.verifierTools ? { ...verify, verifierTools: w.verifierTools } : verify;
83
134
  let vr = await runWithVerification(w.runner, { ...w.spec, sessionId: w.sessionId, signal }, cfg);
135
+ // design/74 Slice 6: auto-resume a RESOURCE-suspended worker (a per-slice budget/turn/walltime overrun)
136
+ // until terminal — the leader spends the worker's TOTAL budget across slices instead of failing at the
137
+ // first slice. Loop + exit conditions live in `autoResumeOnResource` (unit-tested).
84
138
  vr = await autoResumeOnResource(vr, signal, async (token, slice) => {
85
139
  deps.logger?.info?.("worker_resource_resume", { workerId: w.workerId, slice });
86
140
  return resumeWithVerification(w.runner, token, { gate: "resource_limit", decision: "continue" }, { ...w.spec, sessionId: w.sessionId, signal }, w.spec.objective ?? "", cfg);
87
141
  });
88
142
  deps.logger?.info?.("verify_outcome", { workerId: w.workerId, status: vr.status, verdict: vr.verification.verdict, rounds: vr.verification.rounds, finding: (vr.verification.findings[0] ?? "").slice(0, 220) });
89
143
  const pass = vr.status === "completed" && vr.verification.verdict === "PASS";
144
+ // round-3 review BLOCKER: a DURABLE suspend — resource OR human-approval — comes back from
145
+ // runWithVerification as failed-WITH-token (core mapNestedSuspend), so gating `stillSuspended` on
146
+ // `resource_limit` ONLY mis-routed a human-approval suspend to `failed` → the C4 surface/cancel
147
+ // reaction never fired and its paused env could be reaped. Any worker still carrying a checkpoint
148
+ // token is suspended (resumable); a genuine failure has no token. The resource auto-resume already
149
+ // ran above, so a still-tokened resource worker is one the leader couldn't fully resume (deadline).
90
150
  const stillSuspended = vr.checkpointToken !== undefined;
91
151
  const reportStatus = pass ? "completed" : stillSuspended ? "suspended" : "failed";
152
+ // No-silent-failures (clay 2026-06-15): WARN on any non-completed REPORT status — incl. a verify-FAIL
153
+ // on an impl that COMPLETED (vr.status "completed" but reportStatus "failed"), which the old
154
+ // `vr.status !== completed` guard missed. Carry the impl's reason: errorCode, errorMessage, AND
155
+ // blockedReason (a report_blocked worker's reason lives there, not in errorMessage), plus the verdict.
92
156
  if (reportStatus !== "completed") {
93
157
  deps.logger?.warn?.("worker_failed", {
94
158
  workerId: w.workerId, status: reportStatus, turns: vr.stats?.turns ?? 0, verdict: vr.verification.verdict,
@@ -100,6 +164,8 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
100
164
  return {
101
165
  ...base, status: reportStatus, stats: vr.stats,
102
166
  moduleJudge: vr.verification.verdict === "PASS" ? "pass" : "fail", repairs: Math.max(0, vr.verification.rounds - 1),
167
+ // A verify FAIL/PARTIAL (the impl completed but the verifier rejected it) reports the verdict;
168
+ // an `unverified` (the impl didn't complete — suspend/block/error) reports the impl's own reason.
103
169
  ...(pass
104
170
  ? {}
105
171
  : {
@@ -113,8 +179,18 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
113
179
  },
114
180
  });
115
181
  };
182
+ // LEADER-REPAIRLOOP-INTEGRATION §10.6 — the single-agent repair loop's terminal + held candidate, lifted onto
183
+ // every terminal LeaderResult. Set ONLY when `deps.repairLoop` ran on a single-agent path (LEADER_REPAIR_LOOP
184
+ // on); undefined otherwise → the result is byte-identical to today. The `repairTerminal` ALSO rides on the
185
+ // solo worker's report (so the merge push chokepoint, merge.ts, holds an unconfirmed candidate by construction).
116
186
  let repairTerminal;
117
187
  let candidatePatch;
188
+ // Route a SINGLE provisioned worker through the opt-in `runRepairLoop` (when `deps.repairLoop` is set) instead
189
+ // of the plain fan-out map: GENERATE == one runner.runTask, GRADED by the isolated grader, capped at
190
+ // `candidate_only`. Attaches `repairTerminal` to the report (the chokepoint reads it) + lifts the held
191
+ // candidate. Falls back to `runWave([toSubtask(solo)])` (today's path) when the repair loop is not attached
192
+ // OR the per-worker resolve throws (never break the leader). Returns the same shape as `runWave` so the
193
+ // call-sites are a drop-in. §10.6: this covers BOTH single-agent paths (collapse + N=1) through one helper.
118
194
  const runSolo = async (solo, sub) => {
119
195
  if (!deps.repairLoop)
120
196
  return runWave([toSubtask(solo)]);
@@ -127,10 +203,14 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
127
203
  return { reports: [rr.report], cancelled: false };
128
204
  }
129
205
  catch (e) {
206
+ // The repair wire already maps a thrown engine error to a failed report; a throw HERE is a wire/resolve
207
+ // failure — degrade to the plain wave so the solo still runs (no silent break; warn the WHY).
130
208
  deps.logger?.warn?.("repair_loop_dispatch_failed", { workerId: solo.workerId, err: e instanceof Error ? e.message : String(e) });
131
209
  return runWave([toSubtask(solo)]);
132
210
  }
133
211
  };
212
+ // N=1 (route==="single"): the lone worker IS the single-agent path → route it through `runSolo`. With
213
+ // `deps.repairLoop` unset, `runSolo` delegates straight to `runWave` → byte-identical to today's `runWave(...)`.
134
214
  const fo1 = route === "single" && workers.length === 1
135
215
  ? await runSolo(workers[0], subs[0])
136
216
  : await runWave(workers.map(toSubtask));
@@ -138,11 +218,17 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
138
218
  let cancelled = fo1.cancelled;
139
219
  finalReports = reports;
140
220
  const workerRepoDir = deps.workerRepoDir ?? deps.repoDir;
221
+ // One diff source per worker: self-uploaded (factory env, F2(a)) preferred; else pull from the static env.
141
222
  const workerDiff = (w) => w.fetchDiff
142
223
  ? w.fetchDiff()
143
224
  : w.diffEnv
144
225
  ? pullDiff(w.diffEnv, w.baseSha, { ref: w.branch, ...(workerRepoDir ? { cwd: workerRepoDir } : {}) })
145
226
  : Promise.resolve({ ok: false, error: `worker ${w.workerId} has neither fetchDiff nor diffEnv` });
227
+ // design/74 Slice 6 (task#16, round-3 review BLOCKER): salvage the diff (belt auto-commit + diff-out) of
228
+ // workers that did NOT merge (failed / still-suspended) so their progress isn't silently dropped. Must run
229
+ // on EVERY terminal LeaderResult path — the main merge AND the early returns (surfaceSuspended, collapse) —
230
+ // not just the merge, else a suspended-preempted or collapsed run loses the non-completed workers' work.
231
+ // Best-effort: a fetch failure or an empty/paused-env diff is skipped; it NEVER blocks the result.
146
232
  const salvageNonCompleted = async (rs) => {
147
233
  const out = [];
148
234
  await Promise.all(rs
@@ -157,10 +243,19 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
157
243
  out.push({ workerId: r.workerId, sessionId: r.sessionId, patch: d.patch });
158
244
  }
159
245
  catch {
246
+ /* best-effort — a salvage fetch must not break the leader result */
160
247
  }
161
248
  }));
162
249
  return out;
163
250
  };
251
+ // design/52 L3a — per-module sub-gate + bounded repair (between fan-out and merge). Judge each completed
252
+ // worker's module diff vs its sub-objective; on fail, re-run that ONE worker with feedback (bounded), then
253
+ // re-judge. Still-failing modules → status:"failed" so merge quarantines them. Reaps per-module escapes the
254
+ // end-integration test can't see + restores cheap-team correctness via localized repair (search [38]).
255
+ // design/158 A13: lifted from an inline `if (deps.moduleGate) { await Promise.all(...) }` block into a named
256
+ // stage function (same closure scope/capture/call-site as before — behavior identical), alongside the other
257
+ // already-named internal stages of this function (runWave/runSolo/salvageNonCompleted/surfaceSuspended/
258
+ // collapseToSingle below).
164
259
  const runModuleGate = async () => {
165
260
  if (!deps.moduleGate)
166
261
  return;
@@ -172,7 +267,7 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
172
267
  for (let attempt = 0; attempt <= maxR; attempt++) {
173
268
  const d = await workerDiff(w);
174
269
  if (!d.ok)
175
- return;
270
+ return; // diff-out problem → leave it for merge to quarantine
176
271
  const verdict = await deps.moduleGate.judge(sub, d.patch);
177
272
  r.moduleJudge = verdict.ok ? "pass" : "fail";
178
273
  r.repairs = attempt;
@@ -187,7 +282,7 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
187
282
  try {
188
283
  const rr = await w.runner.runTaskStream({ ...sub.spec, objective: deps.moduleGate.repairObjective(sub, verdict.reason ?? ""), sessionId: `${w.sessionId}-r${attempt + 1}` }).result();
189
284
  if (r.stats && rr?.stats)
190
- r.stats = { ...r.stats, tokens: (r.stats.tokens ?? 0) + (rr.stats.tokens ?? 0), costMicroUsd: (r.stats.costMicroUsd ?? 0) + (rr.stats.costMicroUsd ?? 0) };
285
+ r.stats = { ...r.stats, tokens: (r.stats.tokens ?? 0) + (rr.stats.tokens ?? 0), costMicroUsd: (r.stats.costMicroUsd ?? 0) + (rr.stats.costMicroUsd ?? 0) }; // fold repair cost into the worker's report
191
286
  }
192
287
  catch (e) {
193
288
  r.status = "failed";
@@ -198,6 +293,7 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
198
293
  }));
199
294
  };
200
295
  await runModuleGate();
296
+ // merge(b) deps: diff-out per worker (self-upload or static pull), integrate, Coordinator push.
201
297
  const mergeDeps = {
202
298
  pullWorkerDiff: async (r) => workerDiff(byId.get(r.workerId)),
203
299
  provisionIntegrationSandbox: deps.provisionIntegrationSandbox,
@@ -205,12 +301,23 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
205
301
  testCmd: deps.testCmd,
206
302
  ...(deps.measureCmd ? { measureCmd: deps.measureCmd } : {}),
207
303
  ...(deps.repoDir ? { repoDir: deps.repoDir } : {}),
304
+ // §10.3/§10.4 — the push-gate extras (OFF by default; set by the wire from LEADER_MEASURE_GATES).
208
305
  ...(deps.mergeGates?.measureGates ? { measureGates: true } : {}),
209
306
  ...(deps.mergeGates?.strongOracleSeeded ? { strongOracleSeeded: true } : {}),
210
307
  ...(deps.mergeGates?.measureDrivesRepair ? { measureDrivesRepair: deps.mergeGates.measureDrivesRepair } : {}),
211
308
  ...(deps.logger ? { logger: deps.logger } : {}),
212
309
  };
310
+ // ── replan-lite (design/68 §6): deterministic reaction table, arbitrated in C6 priority order ──
311
+ // Spec priority: suspended > budget > merge-conflict > verify-fail > worker-failed; only the highest-
312
+ // priority reaction runs, and the check order below IS the arbitration (each returns; later checks never
313
+ // see its trigger). DETECTION order differs for merge-conflict: it is only observable AFTER mergeBranches
314
+ // runs, i.e. after the verify/failed reactions — which is spec-equivalent, because all three reactions are
315
+ // the same collapse-to-single (the ordering only affects the recorded `trigger` label, and a verify/failed
316
+ // collapse removes the conflicting diff before a merge could ever surface its conflict).
213
317
  let redispatched;
318
+ // C4 (unconditional): a suspended worker preempted the wave (fan-out cancelOnSuspend already cancelled the
319
+ // rest). NO merge, NO redispatch — surface failed + the resume token; its checkpoint + paused env are intact
320
+ // (the finally below exempts it from the static-env destroy; factory envs are exempt by construction).
214
321
  const surfaceSuspended = async (rs, wave) => {
215
322
  const sus = wave.filter((r) => r.status === "suspended");
216
323
  if (sus.length === 0)
@@ -225,9 +332,16 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
225
332
  ...(salvaged.length > 0 ? { salvaged } : {}),
226
333
  };
227
334
  };
335
+ // Collapse-to-single (at most once): one fresh worker redoes the whole task on a clean branch. The discarded
336
+ // workers' envs die via the normal lifecycle (factory finish / the static finally) — E1. The full env-layer
337
+ // "adopt N half-done workspaces" seam (design/68 §8) stays future; INSTEAD (search 2026-06-16) we REUSE the
338
+ // fan-out work the lightweight, zero-new-seam way — hand the collapse-solo the diffs the parallel workers
339
+ // already produced as reference so it adapts their correct output (copy the non-overlapping modules, resolve
340
+ // only the overlap) rather than re-deriving the whole task blind.
228
341
  const collapseToSingle = async (trigger, reason, priorMerge) => {
229
342
  deps.logger?.warn?.("replan_collapse_to_single", { trigger, reason: reason.slice(0, 300) });
230
343
  const replan = { trigger, collapsed: reason.slice(0, 300), ...(redispatched ? { redispatched } : {}) };
344
+ // Best-effort gather of the fan-out workers' diffs (same source as salvage); an empty/failed diff is omitted.
231
345
  const priorDiffs = [];
232
346
  await Promise.all(reports.map(async (r) => {
233
347
  const w = byId.get(r.workerId);
@@ -239,6 +353,7 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
239
353
  priorDiffs.push({ workerId: r.workerId, status: r.status, patch: d.patch });
240
354
  }
241
355
  catch {
356
+ /* best-effort — a salvage fetch must not break the collapse path */
242
357
  }
243
358
  }));
244
359
  if (priorDiffs.length > 0)
@@ -250,8 +365,11 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
250
365
  ``,
251
366
  `--- PRIOR PARALLEL WORK — REUSE IT, do not re-derive from scratch ---`,
252
367
  `${priorDiffs.length} worker(s) attempted this task in parallel; their changes could NOT be integrated cleanly (${reason.slice(0, 150)}). Each worker's diff over the base is below. COPY the correct, non-overlapping parts verbatim and produce ONE coherent change for the WHOLE task, resolving only the overlaps. Treat these as a strong starting point — fix anything wrong, but do not throw the work away.`,
368
+ // BL-30/BL-32 — each prior worker's diff is untrusted worker-authored code; delimit it so an injected
369
+ // instruction in a diff comment can't steer the collapse-solo agent (design/53 trifecta).
253
370
  ...priorDiffs.map((d) => delimitUntrusted(`PRIOR WORKER '${d.workerId}' (${d.status}) DIFF (untrusted)`, d.patch.slice(0, 8000))),
254
371
  ].join("\n");
372
+ // The synthetic collapse-solo sub-task (kept as a value so the §10.6 repair-loop dispatch can pass it).
255
373
  const soloSub = { workerId: "collapse-solo", branch: "worker/collapse-solo", files: ["."], spec: { objective: soloObjective } };
256
374
  let solo;
257
375
  try {
@@ -264,12 +382,18 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
264
382
  workers.push(solo);
265
383
  byId.set(solo.workerId, solo);
266
384
  bySession.set(solo.sessionId, solo);
385
+ // §10.6: collapse-to-single IS a single-agent path → route through `runSolo` (the opt-in repair loop when
386
+ // `deps.repairLoop` is set; the plain wave otherwise). `runSolo` sets the outer `repairTerminal`/
387
+ // `candidatePatch`, which are lifted onto this return so the chokepoint-held candidate reaches the caller.
267
388
  const fo = await runSolo(solo, soloSub);
268
389
  finalReports = [...reports, ...fo.reports];
269
390
  const sus = await surfaceSuspended(finalReports, fo.reports);
270
391
  if (sus)
271
392
  return { ...sus, replan: { ...replan, trigger: "suspended" }, ...(repairTerminal ? { repairTerminal } : {}), ...(candidatePatch ? { candidatePatch } : {}) };
272
393
  const mRaw = await mergeBranches(fo.reports, durableBaseSha, mergeDeps);
394
+ // wq64gmm5e: carry the FAILED prior merge's resolver spend across the collapse so captureTeamC1 sees the
395
+ // tokens it already burned (a --3way conflict that triggered collapse may have run a conflictResolver). Fold
396
+ // it into the collapse-merge's conflictResolverCostUsd; default path (no prior cost) is byte-identical.
273
397
  const priorCost = priorMerge?.conflictResolverCostUsd ?? 0;
274
398
  const m = priorCost > 0 ? { ...mRaw, conflictResolverCostUsd: (mRaw.conflictResolverCostUsd ?? 0) + priorCost } : mRaw;
275
399
  const salvaged = await salvageNonCompleted(finalReports);
@@ -287,16 +411,22 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
287
411
  const sus1 = await surfaceSuspended(reports, reports);
288
412
  if (sus1)
289
413
  return sus1;
414
+ // C5 budget: fan-out overspent → stop fanning, single continues (no expire of anything — C7 falls out of
415
+ // the suspended check above winning first).
290
416
  if (deps.replan?.budgetUsd !== undefined) {
291
417
  const spent = reports.reduce((s, r) => s + (r.stats?.costMicroUsd ?? 0) / 1e6, 0);
292
418
  if (spent > deps.replan.budgetUsd) {
293
419
  return collapseToSingle("budget", `fan-out spent $${spent.toFixed(4)} > budget $${deps.replan.budgetUsd}`);
294
420
  }
295
421
  }
422
+ // C2 verify FAIL: the bounded repair was already spent INSIDE the verify loop (runWithVerification rounds /
423
+ // moduleGate repairs) — a worker still failing its module gate collapses, it is not redispatched.
296
424
  if (deps.replan && reports.some((r) => r.moduleJudge === "fail")) {
297
425
  const failed = reports.filter((r) => r.moduleJudge === "fail").map((r) => r.workerId);
298
426
  return collapseToSingle("verify-fail", `module verification failed after bounded repair: ${failed.join(", ")}`);
299
427
  }
428
+ // C1 worker failed: redispatch ×1, same spec, FRESH env + clean base (provisionWorker provisions anew; the
429
+ // crashed worker's half-written workspace is never reused) → still failed = collapse-remainder-to-single.
300
430
  if (deps.replan) {
301
431
  const failedIds = reports.filter((r) => r.status === "failed").map((r) => r.workerId);
302
432
  if (failedIds.length > 0) {
@@ -307,7 +437,7 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
307
437
  for (const id of failedIds) {
308
438
  const w = await deps.provisionWorker(subById.get(id));
309
439
  fresh.push(w);
310
- workers.push(w);
440
+ workers.push(w); // register IMMEDIATELY — a later provision throw must not orphan this env (council)
311
441
  }
312
442
  }
313
443
  catch (e) {
@@ -331,16 +461,28 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
331
461
  }
332
462
  }
333
463
  }
464
+ // merge(b): integrate + Coordinator push.
334
465
  const merge = await mergeBranches(reports, durableBaseSha, mergeDeps);
466
+ // C3 merge conflict: merge(b)'s sequential --3way apply IS the serial replay; a --3way failure means an
467
+ // architecture-level conflict → collapse to single + RECORD (the design/52 data feed).
335
468
  if (!merge.ok && merge.phase === "apply" && deps.replan) {
336
469
  deps.logger?.warn?.("replan_merge_conflict", { reason: merge.reason, quarantine: merge.quarantine ?? [] });
337
470
  return collapseToSingle("merge-conflict", merge.reason, merge);
338
471
  }
472
+ // design/74 Slice 6 (task#16): salvage the progress of workers that did NOT merge (failed / still-
473
+ // suspended). The belt auto-commit + diff-out ran on env teardown, so a non-empty patch exists (in S3 for a
474
+ // factory worker, or pullable from a still-alive static env, before the `finally` destroys it) — surface it
475
+ // so the work isn't silently lost (the migration-run loss: a network-failed worker's commits vanished).
476
+ // Best-effort: a fetch failure or an empty/paused-env diff is skipped, and it NEVER blocks the merge result.
339
477
  const salvaged = await salvageNonCompleted(reports);
340
478
  return {
341
479
  ok: merge.ok, reports, merge, cancelled, route,
342
480
  ...(redispatched ? { replan: { trigger: "worker-failed", redispatched } } : {}),
343
481
  ...(salvaged.length > 0 ? { salvaged } : {}),
482
+ // §10.6 — lift the single-agent repair loop's terminal (set by `runSolo` on the N=1 path) + the merge
483
+ // chokepoint's terminal onto the result so the HTTP status map (`endpoint.ts:75`) surfaces `needs_human`.
484
+ // `repairTerminal` (the loop's own) takes precedence over `merge.terminal` (the chokepoint's). Both undefined
485
+ // on the default path → byte-identical. The held `candidatePatch` (delimited at the wire) rides alongside.
344
486
  ...(repairTerminal ?? merge.terminal ? { repairTerminal: repairTerminal ?? merge.terminal } : {}),
345
487
  ...(candidatePatch
346
488
  ? { candidatePatch }
@@ -350,6 +492,11 @@ export async function runLeaderTask(task, durableBaseSha, deps) {
350
492
  };
351
493
  }
352
494
  finally {
495
+ // Static envs: the leader owns the lifecycle — destroy on EVERY path, EXCEPT a suspended worker's env
496
+ // (C4: destroying it kills the resume; its checkpoint + paused env belong to the single-agent resume path,
497
+ // orphan protection = the existing deadline reap). Factory envs carry no `destroy` (runner-owned).
498
+ // Keyed by sessionId, not workerId: a redispatched worker shares its predecessor's workerId — exempting by
499
+ // workerId would also spare the ORIGINAL failed worker's env (leak, council finding).
353
500
  const suspendedSessions = new Set(finalReports.filter((r) => r.status === "suspended").map((r) => r.sessionId));
354
501
  await Promise.allSettled(workers.filter((w) => w.destroy && !suspendedSessions.has(w.sessionId)).map((w) => w.destroy()));
355
502
  }