@humwick/server 0.130.1 → 0.130.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (811) hide show
  1. package/README.md +5 -0
  2. package/bundled/prompts/manifest.json +1 -0
  3. package/bundled/prompts/task.hydration.md +1 -1
  4. package/bundled/roles/builder.md +1 -1
  5. package/docs/guides/sub-coordinators.md +12 -5
  6. package/docs/guides/tools-administration.md +4 -0
  7. package/docs/guides/tools-coordination.md +2 -0
  8. package/docs/guides/tools-tasks.md +8 -0
  9. package/docs/guides/workflows.md +74 -0
  10. package/docs/openapi.json +486 -4
  11. package/package.json +10 -18
  12. package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-Bq9kr21N.js} +2 -2
  13. package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-Dqiroy06.js} +2 -2
  14. package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-DYU962-H.js} +2 -2
  15. package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-DhPfzioE.js} +2 -2
  16. package/public/assets/{activity-yLztXEBt.js → activity-DzCcQTee.js} +2 -2
  17. package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-SgDt9i3T.js} +2 -2
  18. package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
  19. package/public/assets/{agent-name-CTZBrSD9.js → agent-name-CcY3Aijy.js} +2 -2
  20. package/public/assets/agent-profiles-cxtRBn6O.js +2 -0
  21. package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-DGYbIhaI.js} +2 -2
  22. package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-DHbftV0N.js} +2 -2
  23. package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-CY113sp-.js} +2 -2
  24. package/public/assets/{agents-BYDslkJc.js → agents-BPzY7IlQ.js} +2 -2
  25. package/public/assets/{analytics-B-XSbEMC.js → analytics-DENFPv_a.js} +2 -2
  26. package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-KRvSc7sl.js} +2 -2
  27. package/public/assets/{artifacts-DPN1q4pA.js → artifacts-C9gSmL3s.js} +2 -2
  28. package/public/assets/{artifacts-oBOqks-2.js → artifacts-DT-HkI5O.js} +2 -2
  29. package/public/assets/{automation-4KcRFXEu.js → automation-BsmjQhKD.js} +2 -2
  30. package/public/assets/{backlog-Cw9xPTCF.js → backlog-8NYH_62t.js} +2 -2
  31. package/public/assets/{busy-health-CTu32MZt.js → busy-health-D3hwvYb4.js} +2 -2
  32. package/public/assets/{channels-BiXzg1G9.js → channels-DCJ5WL7O.js} +2 -2
  33. package/public/assets/{chat-Ctk2qwvA.js → chat-DAIl357U.js} +3 -3
  34. package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-CzrZfr9U.js} +2 -2
  35. package/public/assets/{connectors-C36ax4Vw.js → connectors-xTxtlyou.js} +2 -2
  36. package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BpebFLK2.js} +2 -2
  37. package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-BHvI5wXC.js} +2 -2
  38. package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-DGT0o3wJ.js} +2 -2
  39. package/public/assets/{deploys-Bwfq146q.js → deploys-hqWOHSHE.js} +2 -2
  40. package/public/assets/{display-CfO7rTuF.js → display-CDeH4I8T.js} +2 -2
  41. package/public/assets/{files-DhhZI2Ih.js → files-BTeGVmTg.js} +2 -2
  42. package/public/assets/{fleet-B_rFEbnL.js → fleet-DgXtNgCa.js} +2 -2
  43. package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BHEt5yc_.js} +2 -2
  44. package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-MLtodyPp.js} +3 -3
  45. package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-CAe664Z8.js} +2 -2
  46. package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-mapF4Fj9.js} +2 -2
  47. package/public/assets/index-CqqgOI5R.js +15 -0
  48. package/public/assets/index-MYAIwYTX.css +2 -0
  49. package/public/assets/{insights-fH1EL-qZ.js → insights-DNyf7IzF.js} +2 -2
  50. package/public/assets/{integrations-C5Oix6ng.js → integrations-DlYOHq7T.js} +2 -2
  51. package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-CeWBNWn7.js} +2 -2
  52. package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-Cib8nqdE.js} +2 -2
  53. package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-DSn1cPm7.js} +2 -2
  54. package/public/assets/{managed-agents-egllbpij.js → managed-agents-C3CkM81m.js} +2 -2
  55. package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-W4VQQPAv.js} +3 -3
  56. package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
  57. package/public/assets/{memory-C8WmXsyr.js → memory-BV17qtO4.js} +2 -2
  58. package/public/assets/{messages-BzQdqlO6.js → messages-Bm_1AqSA.js} +2 -2
  59. package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Dg-vfP09.js} +2 -2
  60. package/public/assets/{overview-DCUnI4Z7.js → overview-DcYCrvlr.js} +2 -2
  61. package/public/assets/{pairs-ftCd2XcD.js → pairs-8o9nuG3V.js} +2 -2
  62. package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-BsRyBMea.js} +2 -2
  63. package/public/assets/project-profile-instructions-DETKFn_E.js +2 -0
  64. package/public/assets/projects-M_m6AHws.js +2 -0
  65. package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-C_mNCgeL.js} +2 -2
  66. package/public/assets/provider-display-BEeLXC_D.js +2 -0
  67. package/public/assets/{registry-DWCU5c8q.js → registry-DDHHHE5N.js} +2 -2
  68. package/public/assets/run-card-Dt4I4jaP.js +2 -0
  69. package/public/assets/scroll-text-BKXS1ahr.js +2 -0
  70. package/public/assets/{secrets-C7GIUATz.js → secrets-BkVwxI5O.js} +2 -2
  71. package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-Crq-6a-B.js} +2 -2
  72. package/public/assets/{settings-C6sZ9eBa.js → settings-CYcavMFu.js} +2 -2
  73. package/public/assets/shipping-H6gzEeZB.js +2 -0
  74. package/public/assets/{stats-V9Z-GxUd.js → stats-BJVeWkpV.js} +2 -2
  75. package/public/assets/{status-dot-CVv0iGHL.js → status-dot-BcHyw1Vw.js} +2 -2
  76. package/public/assets/store-DKPDIZBe.js +9 -0
  77. package/public/assets/{tasks-CXU75HRF.js → tasks-qJjlQPpx.js} +2 -2
  78. package/public/assets/{teams-BPf976zb.js → teams-Cd5Sk1uX.js} +2 -2
  79. package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-CpY5_m7W.js} +3 -3
  80. package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
  81. package/public/assets/token-estimate-Co-Jdphh.js +2 -0
  82. package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-0yJA_buM.js} +2 -2
  83. package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-uJXHf34W.js} +2 -2
  84. package/public/assets/use-project-list-CpWl6eHQ.js +2 -0
  85. package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BdxBW8mL.js} +2 -2
  86. package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-3IndfpOc.js} +2 -2
  87. package/public/assets/versioned-prompt-editor-CIVg7XB1.js +8 -0
  88. package/public/assets/{work-queue-TCjJxeT-.js → work-queue-B9rnLwHZ.js} +2 -2
  89. package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-X8wxyhzC.js} +2 -2
  90. package/public/assets/{workflows-CXQX20Qj.js → workflows-o5YyMFW7.js} +2 -2
  91. package/public/assets/{workspaces-qSYzKYMA.js → workspaces-CzEGoAng.js} +2 -2
  92. package/public/cosmos.html +4 -4
  93. package/public/index.html +31 -29
  94. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  95. package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
  96. package/runner/src/adapters/claude-effort.ts +2 -4
  97. package/runner/src/adapters/claude-headless.ts +1 -1
  98. package/runner/src/adapters/claude-launch-exit.ts +26 -0
  99. package/runner/src/adapters/claude-session-probe.ts +1 -1
  100. package/runner/src/adapters/claude-tmux.ts +38 -10
  101. package/runner/src/adapters/claude.ts +28 -75
  102. package/runner/src/adapters/codex-launch-config.ts +4 -5
  103. package/runner/src/adapters/codex.ts +1 -1
  104. package/runner/src/adapters/opencode-provider.ts +7 -22
  105. package/runner/src/adapters/opencode.ts +4 -4
  106. package/runner/src/adapters/provider-quota-harvest.ts +20 -71
  107. package/runner/src/agent-runner/credentials.ts +42 -12
  108. package/runner/src/agent-runner/inbox.ts +27 -0
  109. package/runner/src/agent-runner/lifecycle-milestones.ts +2 -4
  110. package/runner/src/agent-runner/liveness-exchange.ts +104 -0
  111. package/runner/src/bin/claude.ts +4 -0
  112. package/runner/src/bin/codex.ts +4 -0
  113. package/runner/src/bin/opencode.ts +4 -0
  114. package/runner/src/claude-system-prompt.ts +49 -0
  115. package/runner/src/index.ts +5 -2
  116. package/runner/src/launch-assembly.ts +14 -10
  117. package/runner/src/profile-home.ts +1 -1
  118. package/runner/src/project-instructions.ts +2 -2
  119. package/runner/src/provider-command.ts +18 -0
  120. package/runner/src/provider-setup.ts +35 -0
  121. package/runner/src/providers.ts +2 -1
  122. package/runner/src/runner-core.ts +32 -38
  123. package/runner/src/runner-helpers.ts +0 -8
  124. package/runner/src/session-scratch.ts +6 -2
  125. package/runner/src/spawn-input.ts +2 -1
  126. package/runner/src/test-run-dedup.ts +59 -56
  127. package/runner/test-support/provisioning-context.ts +4 -2
  128. package/runner/test-support/runner-harness.ts +2 -1
  129. package/scripts/cd-config.ts +8 -0
  130. package/scripts/gate-run-lease.ts +10 -7
  131. package/scripts/gate.sh +5 -1
  132. package/scripts/steward-policy-cleanup.ts +2 -2
  133. package/src/agent-authz.ts +2 -2
  134. package/src/agent-drive-arbiter.ts +3 -8
  135. package/src/agent-exit-cleanup-async.ts +2 -2
  136. package/src/agent-exit-cleanup.ts +23 -19
  137. package/src/agent-lifecycle-events.ts +112 -85
  138. package/src/agent-ref.ts +3 -2
  139. package/src/agent-status-events.ts +43 -14
  140. package/src/auth/password.ts +4 -3
  141. package/src/auth/session-refresh.ts +1 -1
  142. package/src/auth/session.test-fixture.ts +2 -2
  143. package/src/auth/session.ts +7 -7
  144. package/src/automations/crud.ts +8 -81
  145. package/src/automations/dispatch.ts +33 -58
  146. package/src/automations/index.ts +1 -1
  147. package/src/automations/persistence.ts +65 -0
  148. package/src/automations/precheck.ts +18 -16
  149. package/src/automations/read-async.ts +11 -0
  150. package/src/automations/reconcile.ts +30 -39
  151. package/src/automations/storage.ts +33 -10
  152. package/src/automations/write-async.ts +33 -0
  153. package/src/branch-land-notice.ts +93 -0
  154. package/src/branch-landed.ts +31 -98
  155. package/src/bus.ts +40 -39
  156. package/src/cd-deploy-notify.ts +32 -4
  157. package/src/cd-host-lag-notify.ts +7 -6
  158. package/src/ci/incidents.ts +2 -2
  159. package/src/ci/monitor.ts +5 -8
  160. package/src/ci/notifications.ts +4 -4
  161. package/src/ci/root-missing.ts +4 -9
  162. package/src/ci/transition-notify.ts +12 -44
  163. package/src/claude-app/oauth-http.ts +3 -3
  164. package/src/cli/cd-pauses.ts +19 -0
  165. package/src/cli/orchestrator.ts +1 -1
  166. package/src/cli/state.ts +2 -19
  167. package/src/cli/task-edit.ts +22 -0
  168. package/src/cli/task.ts +3 -1
  169. package/src/cli/workflow.ts +19 -4
  170. package/src/commands-db.ts +7 -7
  171. package/src/commands-write.ts +8 -0
  172. package/src/compaction-watch.ts +10 -8
  173. package/src/config-store-write.ts +13 -1
  174. package/src/config-store.ts +25 -14
  175. package/src/config.ts +4 -11
  176. package/src/connectors.ts +10 -8
  177. package/src/context-advisory.ts +22 -21
  178. package/src/db/activity-async.ts +6 -1
  179. package/src/db/activity-write-ops.ts +12 -1
  180. package/src/db/activity.ts +1 -14
  181. package/src/db/agent-action-write.ts +36 -0
  182. package/src/db/agent-control-async.ts +9 -0
  183. package/src/db/agent-control-write.ts +49 -0
  184. package/src/db/agent-effort-observe.ts +22 -0
  185. package/src/db/agent-meta.ts +14 -3
  186. package/src/db/agent-search.ts +1 -15
  187. package/src/db/agents-async.ts +59 -9
  188. package/src/db/agents-write-ops.ts +12 -3
  189. package/src/db/agents.ts +95 -65
  190. package/src/db/auth-identities.ts +2 -2
  191. package/src/db/automation-read-ops.ts +11 -0
  192. package/src/db/automation-write-ops.ts +46 -0
  193. package/src/db/blackboard.ts +2 -2
  194. package/src/db/browser-session-write.ts +32 -0
  195. package/src/db/bus-outbox-write-ops.ts +3 -1
  196. package/src/db/checkout-refresh-schema.ts +47 -0
  197. package/src/db/checkout-refresh.ts +5 -5
  198. package/src/db/ci-incidents-async.ts +5 -5
  199. package/src/db/ci-incidents-write-ops.ts +2 -2
  200. package/src/db/command-agent-profile-backfill.ts +39 -0
  201. package/src/db/command-agent-profiles.ts +5 -1
  202. package/src/db/command-retention.ts +126 -0
  203. package/src/db/command-row.ts +10 -2
  204. package/src/db/commands-list-query.ts +2 -0
  205. package/src/db/commands-planner-stats.test-fixture.ts +8 -0
  206. package/src/db/commands-read-ops.ts +16 -0
  207. package/src/db/commands-spawn-read.ts +1 -1
  208. package/src/db/config-store-write-ops.ts +7 -2
  209. package/src/db/connection.ts +1 -182
  210. package/src/db/context-carry-write.ts +74 -0
  211. package/src/db/continuation-archives-async.ts +5 -0
  212. package/src/db/continuation-archives-write-ops.ts +7 -0
  213. package/src/db/continuations.ts +6 -6
  214. package/src/db/db-error-registry.ts +12 -0
  215. package/src/db/db-writer-worker.ts +8 -1
  216. package/src/db/deploy-events-async.ts +1 -0
  217. package/src/db/deploy-events-read-ops.ts +2 -1
  218. package/src/db/deploy-events.ts +35 -4
  219. package/src/db/gateway.ts +26 -133
  220. package/src/db/history-retention-ops.ts +13 -0
  221. package/src/db/hosts-registration.ts +10 -2
  222. package/src/db/hosts.ts +9 -6
  223. package/src/db/inbox-async.ts +2 -2
  224. package/src/db/inbox-read-ops.ts +1 -1
  225. package/src/db/inbox.ts +9 -17
  226. package/src/db/index.ts +2 -0
  227. package/src/db/integrations-async.ts +8 -0
  228. package/src/db/integrations-ops.ts +15 -0
  229. package/src/db/integrations.ts +15 -21
  230. package/src/db/issue-associations.ts +2 -2
  231. package/src/db/issue-lifecycle.ts +3 -4
  232. package/src/db/issue-refs-async.ts +23 -0
  233. package/src/db/issue-refs-read-ops.ts +6 -0
  234. package/src/db/issue-refs-write-ops.ts +29 -0
  235. package/src/db/issue-refs.ts +15 -16
  236. package/src/db/kernel-event-log-schema.ts +2 -0
  237. package/src/db/land-boundaries.ts +51 -5
  238. package/src/db/land-gate-attestations.ts +2 -2
  239. package/src/db/landing-receipts.ts +2 -2
  240. package/src/db/lifecycle-context-write.ts +5 -0
  241. package/src/db/lifecycle-tail-async.ts +76 -0
  242. package/src/db/lifecycle-tail-write-ops.ts +62 -0
  243. package/src/db/lifecycle-write-window.ts +2 -1
  244. package/src/db/lineage-pair-dedupe-sql.ts +3 -3
  245. package/src/db/long-running-work.ts +2 -2
  246. package/src/db/main-connection-mode.ts +11 -0
  247. package/src/db/main-connection-writes.ts +41 -2
  248. package/src/db/maintenance-job-reconcile.ts +61 -0
  249. package/src/db/maintenance-job-runs-async.ts +14 -0
  250. package/src/db/maintenance-job-write-ops.ts +9 -0
  251. package/src/db/maintenance-pauses.ts +2 -2
  252. package/src/db/mappers.ts +2 -14
  253. package/src/db/merge-lease.ts +1 -15
  254. package/src/db/message-send.ts +4 -0
  255. package/src/db/messages.ts +31 -25
  256. package/src/db/migrations.ts +25 -16
  257. package/src/db/notification-write-ops.ts +19 -0
  258. package/src/db/operator-answer-write.ts +19 -0
  259. package/src/db/orchestrators.ts +14 -76
  260. package/src/db/pairs-async.ts +22 -1
  261. package/src/db/pairs-write-ops.ts +8 -3
  262. package/src/db/pairs.ts +42 -61
  263. package/src/db/plan-dispatch-schema.ts +5 -1
  264. package/src/db/plan-ready-notices.ts +43 -0
  265. package/src/db/plan-tools-include-migration.ts +36 -0
  266. package/src/db/plans-write-ops.ts +2 -0
  267. package/src/db/presence-buffer.ts +5 -0
  268. package/src/db/presence-loop.ts +18 -23
  269. package/src/db/presence-write.ts +0 -6
  270. package/src/db/project-entries-async.ts +14 -0
  271. package/src/db/project-entries-read-ops.ts +5 -1
  272. package/src/db/project-entries-write-ops.ts +8 -0
  273. package/src/db/project-entries.ts +15 -12
  274. package/src/db/project-journal.ts +2 -2
  275. package/src/db/project-profile-instructions.ts +50 -0
  276. package/src/db/project-trust-approvals.ts +2 -2
  277. package/src/db/prompt-templates.ts +4 -4
  278. package/src/db/prompt-versions.ts +9 -2
  279. package/src/db/provider-config-history.ts +8 -3
  280. package/src/db/provider-model-seed.ts +34 -0
  281. package/src/db/read-op-marshaling-fixtures.ts +23 -0
  282. package/src/db/read-ops.ts +8 -0
  283. package/src/db/retention.ts +13 -2
  284. package/src/db/review-publish-write.ts +8 -0
  285. package/src/db/routing-policy.ts +2 -3
  286. package/src/db/runtime-admin-async.ts +19 -0
  287. package/src/db/runtime-admin-write-ops.ts +36 -0
  288. package/src/db/runtime-tail-async.ts +288 -0
  289. package/src/db/runtime-tail-write-ops.ts +97 -0
  290. package/src/db/schema.ts +13 -4
  291. package/src/db/spawn-budget.ts +5 -0
  292. package/src/db/spawn-delegation-state.ts +11 -4
  293. package/src/db/spawn-delegation.ts +1 -11
  294. package/src/db/sql-audit-indexes.ts +3 -0
  295. package/src/db/stats-async.ts +9 -6
  296. package/src/db/task-entity.ts +28 -6
  297. package/src/db/task-list.ts +3 -1
  298. package/src/db/tasks.ts +1 -17
  299. package/src/db/team-claim-policy.ts +60 -0
  300. package/src/db/teams-async.ts +4 -0
  301. package/src/db/teams-write-ops.ts +4 -0
  302. package/src/db/terminal-events.ts +15 -0
  303. package/src/db/timer-cutover-bodies.ts +292 -0
  304. package/src/db/timer-cutover-core.ts +37 -278
  305. package/src/db/timer-cutover-state.ts +40 -0
  306. package/src/db/timer-cutover-write-ops.ts +1 -40
  307. package/src/db/timer-ingress.ts +7 -1
  308. package/src/db/token-db-write-ops.ts +19 -0
  309. package/src/db/token-standing-async.ts +12 -0
  310. package/src/db/token-standing.ts +21 -20
  311. package/src/db/token-usage-retention.ts +33 -0
  312. package/src/db/token-usage-write-ops.ts +1 -1
  313. package/src/db/token-usage.ts +4 -1
  314. package/src/db/user-invites-async.ts +13 -0
  315. package/src/db/user-invites.ts +3 -3
  316. package/src/db/users.ts +14 -6
  317. package/src/db/workflow-contact.ts +1 -1
  318. package/src/db/workflow-task-read-ops.ts +30 -0
  319. package/src/db/workspaces.ts +8 -5
  320. package/src/db/write-ops.ts +37 -12
  321. package/src/db/writer-fault-seam.ts +2 -9
  322. package/src/db/writer-fault-test-ops.ts +18 -0
  323. package/src/db/writer-gateway.ts +58 -56
  324. package/src/dev.ts +8 -3
  325. package/src/dispatch-availability.ts +10 -6
  326. package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
  327. package/src/event-loop-lag.ts +4 -2
  328. package/src/event-loop-yield.ts +2 -2
  329. package/src/events.ts +10 -8
  330. package/src/host/disk-alert.ts +121 -0
  331. package/src/host-provider-store.ts +5 -4
  332. package/src/hub-metrics-report.ts +5 -1
  333. package/src/hub-metrics.ts +38 -18
  334. package/src/injection-sweep-pacing.ts +6 -8
  335. package/src/land-gate-notifications.ts +11 -10
  336. package/src/land-gate-queue-progress.ts +3 -3
  337. package/src/land-settle-dispatch.ts +52 -92
  338. package/src/lifecycle-context-pressure.ts +11 -10
  339. package/src/lifecycle-manager.ts +107 -100
  340. package/src/maintenance/breaker.ts +18 -16
  341. package/src/maintenance/cd-watcher.ts +3 -3
  342. package/src/maintenance/checkout-refresh.ts +18 -1
  343. package/src/maintenance/critical-job-watchdog.ts +19 -20
  344. package/src/maintenance/events.ts +3 -3
  345. package/src/maintenance/history-retention-job.ts +30 -0
  346. package/src/maintenance/index.ts +1 -0
  347. package/src/maintenance/jobs.ts +32 -69
  348. package/src/maintenance/long-running-work.ts +3 -1
  349. package/src/maintenance/offline-agent-prune-job.ts +28 -0
  350. package/src/maintenance/orphaned-sessions.ts +5 -4
  351. package/src/maintenance/pauses.ts +4 -10
  352. package/src/maintenance/plan-ready-notice-job.ts +71 -0
  353. package/src/maintenance/scheduler.ts +98 -137
  354. package/src/maintenance/stalled-delivery-pager.ts +10 -9
  355. package/src/maintenance/teams.ts +19 -30
  356. package/src/maintenance/workspaces.ts +18 -28
  357. package/src/managed-policy-escalation.ts +7 -7
  358. package/src/managed-policy.ts +32 -28
  359. package/src/managed-provider-gate.ts +5 -4
  360. package/src/managed-spawn-reservation.ts +5 -4
  361. package/src/mcp/index.ts +12 -9
  362. package/src/mcp/output-descriptions.ts +8 -8
  363. package/src/mcp/presentation.ts +6 -5
  364. package/src/mcp/project-profile-instructions.ts +32 -0
  365. package/src/mcp/runtime-output.ts +6 -1
  366. package/src/mcp/self-care-visibility.ts +2 -2
  367. package/src/mcp/spawn-targets-matrix.ts +10 -1
  368. package/src/mcp/tool-groups.ts +4 -3
  369. package/src/mcp/tool-roles.ts +81 -0
  370. package/src/mcp/tools-spawn.ts +4 -3
  371. package/src/mcp/tools-workspace.ts +1 -1
  372. package/src/mcp-agent-action.ts +1 -2
  373. package/src/mcp-blackboard-tools.ts +6 -5
  374. package/src/mcp-decision-tools.ts +7 -7
  375. package/src/mcp-egress-tools.ts +10 -9
  376. package/src/mcp-issue-activity-tools.ts +2 -2
  377. package/src/mcp-issue-association-tools.ts +4 -4
  378. package/src/mcp-issue-ref-tools.ts +13 -12
  379. package/src/mcp-maintenance-tools.ts +2 -2
  380. package/src/mcp-merge-tools.ts +5 -5
  381. package/src/mcp-notification-subscription-tools.ts +14 -15
  382. package/src/mcp-output-levels.test-fixture.ts +1 -1
  383. package/src/mcp-profile-trust-tools.ts +5 -5
  384. package/src/mcp-project-journal-tools.ts +4 -12
  385. package/src/mcp-project-tools.ts +17 -18
  386. package/src/mcp-provider-catalog.ts +2 -2
  387. package/src/mcp-routing-policy-tools.ts +3 -2
  388. package/src/mcp-task-tools.ts +11 -5
  389. package/src/mcp-team-template-tools.ts +3 -3
  390. package/src/mcp-team-tools.ts +6 -6
  391. package/src/mcp-workflow-tools.ts +13 -4
  392. package/src/memory-area-injection.ts +13 -12
  393. package/src/memory-boundary-capture.ts +6 -6
  394. package/src/memory-injection.ts +45 -43
  395. package/src/merge-pause-maintenance.ts +5 -4
  396. package/src/notification-router.ts +44 -17
  397. package/src/notification-types.ts +2 -1
  398. package/src/notify.ts +5 -5
  399. package/src/observed-reset-refresh.ts +4 -4
  400. package/src/operator-alarm.ts +23 -11
  401. package/src/project-ingest.ts +6 -6
  402. package/src/project-instructions.ts +12 -1
  403. package/src/project-profile-instruction-text.ts +6 -0
  404. package/src/project-profile-instructions.ts +20 -0
  405. package/src/project-trust.ts +12 -11
  406. package/src/prompt-resolver.ts +3 -3
  407. package/src/provider-catalog-store.ts +3 -49
  408. package/src/provider-config-store.ts +12 -11
  409. package/src/provider-model-seed.ts +1 -18
  410. package/src/provider-quota-async.ts +5 -7
  411. package/src/provider-quota-config-store.ts +5 -4
  412. package/src/provider-secrets.test-fixture.ts +3 -3
  413. package/src/provider-timeline-event.ts +4 -7
  414. package/src/quota-band-delivery.ts +2 -2
  415. package/src/recipe-runner.ts +6 -5
  416. package/src/repo-config-source.ts +10 -4
  417. package/src/retention-config-store.ts +4 -3
  418. package/src/reviewer-pipeline.ts +11 -10
  419. package/src/routes/_route.ts +4 -4
  420. package/src/routes/_shared.ts +13 -12
  421. package/src/routes/agent-effort.ts +5 -5
  422. package/src/routes/agent-heartbeat-quota.ts +23 -0
  423. package/src/routes/agent-keep.ts +1 -1
  424. package/src/routes/agent-profiles.ts +6 -6
  425. package/src/routes/agent-reporting.ts +1 -1
  426. package/src/routes/agent-self-effort.ts +5 -5
  427. package/src/routes/agent-sessions.ts +24 -24
  428. package/src/routes/agents-spawn.ts +2 -2
  429. package/src/routes/agents.ts +19 -121
  430. package/src/routes/auth.ts +14 -15
  431. package/src/routes/authority-audit.ts +2 -2
  432. package/src/routes/automations.ts +6 -5
  433. package/src/routes/channel-binding-delete.ts +1 -1
  434. package/src/routes/channel-output.ts +3 -3
  435. package/src/routes/claude-api-budget.ts +5 -5
  436. package/src/routes/commands-listing.ts +5 -1
  437. package/src/routes/commands.ts +31 -29
  438. package/src/routes/context-resets.ts +2 -2
  439. package/src/routes/continuation-archives.ts +2 -2
  440. package/src/routes/coordinator-teams.ts +1 -1
  441. package/src/routes/decisions.ts +2 -2
  442. package/src/routes/host-secret-files.ts +1 -1
  443. package/src/routes/hosts.ts +11 -11
  444. package/src/routes/inbox.ts +3 -2
  445. package/src/routes/index.ts +12 -2
  446. package/src/routes/integrations.ts +32 -56
  447. package/src/routes/issue-activity.ts +2 -2
  448. package/src/routes/issue-associations.ts +4 -4
  449. package/src/routes/issue-refs.ts +9 -9
  450. package/src/routes/kernel-timers-operator.ts +1 -1
  451. package/src/routes/memory.ts +1 -1
  452. package/src/routes/merges.ts +11 -11
  453. package/src/routes/messages.ts +23 -17
  454. package/src/routes/orchestrator-bootstrap.ts +2 -2
  455. package/src/routes/orchestrator-host-registration.ts +4 -2
  456. package/src/routes/orchestrator-host-utilization.ts +5 -3
  457. package/src/routes/orchestrator-proxy.ts +4 -4
  458. package/src/routes/orchestrator.ts +28 -19
  459. package/src/routes/pairs.ts +8 -8
  460. package/src/routes/project-profile-instructions.ts +27 -0
  461. package/src/routes/project-trust.ts +3 -3
  462. package/src/routes/projects.ts +16 -16
  463. package/src/routes/prompt-templates.ts +12 -12
  464. package/src/routes/provider-config.ts +6 -6
  465. package/src/routes/provider-quota-config.ts +2 -2
  466. package/src/routes/provider-quotas.ts +10 -10
  467. package/src/routes/run-command.ts +1 -1
  468. package/src/routes/secrets-backup.ts +2 -2
  469. package/src/routes/secrets-import.ts +1 -1
  470. package/src/routes/secrets-vault.ts +7 -7
  471. package/src/routes/settings.ts +6 -6
  472. package/src/routes/shipping.ts +9 -1
  473. package/src/routes/spawn-policy.ts +8 -7
  474. package/src/routes/sse.ts +2 -2
  475. package/src/routes/stats.ts +6 -6
  476. package/src/routes/task-http.ts +15 -1
  477. package/src/routes/task-issues.ts +11 -26
  478. package/src/routes/tasks.ts +22 -53
  479. package/src/routes/team-templates.ts +12 -12
  480. package/src/routes/teams-config.ts +2 -2
  481. package/src/routes/teams.ts +10 -10
  482. package/src/routes/tokens.ts +30 -22
  483. package/src/routes/users.ts +24 -24
  484. package/src/routes/viewer-read.ts +3 -3
  485. package/src/routes/web-tool-calls.ts +4 -4
  486. package/src/routes/workflows.ts +22 -7
  487. package/src/routes/workspaces.ts +17 -16
  488. package/src/routing-policy-normalize.ts +1 -2
  489. package/src/routing-policy-push.ts +6 -6
  490. package/src/routing-step-defaults.ts +0 -2
  491. package/src/runner-token-mint-limit.ts +63 -0
  492. package/src/runtime-grant.ts +21 -13
  493. package/src/runtime-tokens.ts +59 -35
  494. package/src/secrets-broker/config.ts +1 -1
  495. package/src/secrets-broker/service.ts +2 -2
  496. package/src/security.ts +16 -21
  497. package/src/self-resume-carry.ts +21 -110
  498. package/src/self-resume-supersede.ts +4 -3
  499. package/src/self-resume.ts +54 -66
  500. package/src/server-background.ts +2 -2
  501. package/src/server.ts +26 -24
  502. package/src/services/agent-action.ts +12 -31
  503. package/src/services/agent-effort.ts +7 -32
  504. package/src/services/agent-hang-watchdog-job.ts +2 -2
  505. package/src/services/agent-heartbeat.ts +166 -0
  506. package/src/services/agent-reporting.ts +1 -1
  507. package/src/services/browser-inventory.ts +3 -3
  508. package/src/services/browser-session-state.ts +3 -2
  509. package/src/services/browser-session.ts +21 -27
  510. package/src/services/bus-command-update.ts +9 -9
  511. package/src/services/checkout-refresh-state.ts +1 -0
  512. package/src/services/checkout-refresh.test-fixture.ts +3 -2
  513. package/src/services/command-host.ts +7 -2
  514. package/src/services/coordinator-digest.ts +3 -2
  515. package/src/services/dispatch-command.ts +12 -13
  516. package/src/services/effective-launch-driver.ts +14 -9
  517. package/src/services/host-changed-paths.test-fixture.ts +5 -6
  518. package/src/services/host-project-readiness.ts +2 -2
  519. package/src/services/host-providers.ts +1 -1
  520. package/src/services/host-utilization.ts +27 -4
  521. package/src/services/idle-agent-digest.ts +17 -12
  522. package/src/services/idle-epics.ts +9 -10
  523. package/src/services/interrupt-agent.ts +12 -9
  524. package/src/services/issue-activity.ts +3 -3
  525. package/src/services/issue-associations.ts +15 -18
  526. package/src/services/issue-lifecycle-comments.ts +3 -2
  527. package/src/services/issue-lifecycle.ts +69 -72
  528. package/src/services/issue-refs.ts +10 -15
  529. package/src/services/kernel-timers-cutover-chaos-worker.ts +11 -8
  530. package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
  531. package/src/services/kernel-timers-ingress.ts +4 -4
  532. package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
  533. package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
  534. package/src/services/kernel-timers-outbox.ts +1 -1
  535. package/src/services/kernel-timers-stage10-operator.ts +1 -1
  536. package/src/services/kernel-timers.ts +4 -3
  537. package/src/services/land-gate-placement.ts +11 -2
  538. package/src/services/land-issue-relations.ts +5 -4
  539. package/src/services/land-restart-retry.ts +7 -6
  540. package/src/services/landed-ancestry.ts +25 -8
  541. package/src/services/legacy-landing-host.ts +4 -1
  542. package/src/services/legacy-landing-recovery.ts +8 -6
  543. package/src/services/managed-running.ts +17 -17
  544. package/src/services/memory-areas.ts +17 -53
  545. package/src/services/merge-pause.ts +9 -15
  546. package/src/services/operator-decisions.ts +37 -41
  547. package/src/services/orchestrator-registration-recovery.ts +6 -2
  548. package/src/services/orchestrator-upgrade.ts +14 -12
  549. package/src/services/permission-decision.ts +4 -3
  550. package/src/services/plan-ci-notice.ts +57 -0
  551. package/src/services/plan-ci-recovery.ts +2 -55
  552. package/src/services/plan-conformance.ts +4 -4
  553. package/src/services/plan-dispatch-policy.ts +10 -3
  554. package/src/services/plan-dispatch.ts +35 -14
  555. package/src/services/plan-graph.ts +39 -261
  556. package/src/services/plan-import.ts +1 -1
  557. package/src/services/plan-live-bindings.ts +8 -37
  558. package/src/services/plan-task-create.ts +1 -1
  559. package/src/services/plan-terminal-refs.ts +2 -12
  560. package/src/services/plan-wake-digest.ts +9 -3
  561. package/src/services/profile-trust.ts +6 -5
  562. package/src/services/project-config-read.ts +70 -0
  563. package/src/services/project-profile-instructions.ts +54 -0
  564. package/src/services/project.ts +11 -10
  565. package/src/services/prompt-templates.ts +6 -5
  566. package/src/services/provider-hold-nudge.ts +9 -9
  567. package/src/services/provider-hold-record.ts +13 -12
  568. package/src/services/provider-state-audit.ts +19 -18
  569. package/src/services/provisioning-harness/budget-baseline.json +4 -4
  570. package/src/services/provisioning-harness/driver.ts +1 -1
  571. package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
  572. package/src/services/provisioning-harness/lifecycle.ts +24 -22
  573. package/src/services/provisioning-harness/prepare.ts +16 -17
  574. package/src/services/rate-limit-resume.ts +10 -9
  575. package/src/services/red-main-auto-revert.ts +7 -5
  576. package/src/services/red-main-controller-deps.ts +20 -3
  577. package/src/services/red-main-incident.ts +3 -1
  578. package/src/services/red-main-quarantine.ts +2 -3
  579. package/src/services/register-agent.ts +22 -22
  580. package/src/services/restart-project-role.ts +1 -1
  581. package/src/services/restart-spawn.ts +74 -61
  582. package/src/services/review-publish.ts +7 -24
  583. package/src/services/review-ref-reconcile.ts +29 -38
  584. package/src/services/runtime-dependency-alert.ts +27 -0
  585. package/src/services/scheduler-command.ts +11 -9
  586. package/src/services/scheduler.ts +5 -5
  587. package/src/services/self-care-state.ts +2 -1
  588. package/src/services/self-effort-grant.ts +5 -25
  589. package/src/services/self-effort.ts +5 -5
  590. package/src/services/send-message.ts +21 -34
  591. package/src/services/shutdown-agent.ts +17 -14
  592. package/src/services/spawn-agent.ts +25 -43
  593. package/src/services/spawn-chain-inspector.ts +7 -14
  594. package/src/services/spawn-cwd-placement.ts +21 -5
  595. package/src/services/spawn-issue-activity.ts +8 -6
  596. package/src/services/spawn-launch.ts +17 -1
  597. package/src/services/spawn-loss-escalation.ts +1 -1
  598. package/src/services/spawn-policy.ts +68 -0
  599. package/src/services/spawn-registration-watchdog.ts +2 -2
  600. package/src/services/spawn-repo-probe.ts +7 -5
  601. package/src/services/spawn-tree-cleanup.ts +8 -9
  602. package/src/services/steward-reaper.ts +4 -4
  603. package/src/services/task-context-hydration.ts +25 -1
  604. package/src/services/task-delivery.ts +20 -34
  605. package/src/services/task-dispatch.ts +3 -0
  606. package/src/services/task-entity.ts +40 -203
  607. package/src/services/task-issue-link.ts +13 -20
  608. package/src/services/task-issue-weave.ts +12 -11
  609. package/src/services/task-lifecycle.ts +27 -31
  610. package/src/services/task-repo-cwd.ts +37 -0
  611. package/src/services/task-review-hold.ts +4 -17
  612. package/src/services/task-semantic-events.ts +13 -11
  613. package/src/services/task-state-reconcile.ts +8 -17
  614. package/src/services/task-validation.ts +2 -2
  615. package/src/services/team-templates.ts +12 -11
  616. package/src/services/team.ts +31 -98
  617. package/src/services/terminal-provider-exit.ts +6 -5
  618. package/src/services/timer-message-fire-chaos-worker.ts +7 -3
  619. package/src/services/timer-message-fire-outbox.ts +1 -1
  620. package/src/services/transient-agent-reaper.ts +25 -20
  621. package/src/services/turn-reconcile-audit.ts +9 -9
  622. package/src/services/user-onboarding.ts +8 -6
  623. package/src/services/user-profile.ts +6 -9
  624. package/src/services/work-finality.ts +16 -4
  625. package/src/services/workflow-auto-start.ts +26 -13
  626. package/src/services/workflow-caller.ts +61 -4
  627. package/src/services/workflow-child-proof-worker.ts +1 -1
  628. package/src/services/workflow-ci-main.ts +1 -1
  629. package/src/services/workflow-control-proof-worker.ts +1 -1
  630. package/src/services/workflow-coordinator.ts +8 -2
  631. package/src/services/workflow-decisions.ts +5 -5
  632. package/src/services/workflow-deferred-cleanup.ts +5 -3
  633. package/src/services/workflow-effect-driver.ts +42 -17
  634. package/src/services/workflow-effects.ts +58 -37
  635. package/src/services/workflow-land-notice.ts +10 -0
  636. package/src/services/workflow-pause-text.ts +43 -0
  637. package/src/services/workflow-pins.ts +7 -4
  638. package/src/services/workflow-reconcile.ts +14 -11
  639. package/src/services/workflow-resume-pins.ts +3 -3
  640. package/src/services/workflow-routing-defaults.ts +18 -0
  641. package/src/services/workflow-run-view.ts +6 -3
  642. package/src/services/workflow-run.test-fixture.ts +1 -1
  643. package/src/services/workflow-runs.ts +61 -33
  644. package/src/services/workflow-supervisor-state.ts +26 -1
  645. package/src/services/workflow-supervisor.ts +11 -6
  646. package/src/services/workspace-recovery.ts +4 -3
  647. package/src/settings/registry.ts +1 -2
  648. package/src/spawn-admission.ts +10 -2
  649. package/src/spawn-command.ts +4 -4
  650. package/src/spawn-models.ts +10 -12
  651. package/src/spawn-placement.ts +28 -10
  652. package/src/spawn-targets.ts +9 -9
  653. package/src/sse-agent-status.ts +15 -6
  654. package/src/sse.ts +49 -24
  655. package/src/startup-context-injection.ts +62 -57
  656. package/src/state-adoption/cd-cutover.ts +53 -7
  657. package/src/state-adoption/fleet-cutover.ts +35 -0
  658. package/src/state-adoption/fleet-plan.ts +36 -0
  659. package/src/state-adoption/index.ts +2 -2
  660. package/src/state-adoption/linux-plan.ts +2 -2
  661. package/src/state-adoption/linux.ts +2 -2
  662. package/src/state-adoption/macos-plan.ts +2 -2
  663. package/src/state-adoption/macos.ts +1 -1
  664. package/src/steward-handoff.ts +4 -3
  665. package/src/steward-policy-cleanup.ts +9 -8
  666. package/src/steward.ts +9 -8
  667. package/src/task-dispatch-live.ts +6 -3
  668. package/src/task-dispatcher.ts +3 -3
  669. package/src/teams-config-store.ts +4 -3
  670. package/src/token-db-write.ts +10 -0
  671. package/src/token-db.ts +2 -2
  672. package/src/token-usage-async.ts +2 -4
  673. package/src/user-awaiting-reply.ts +5 -5
  674. package/src/workspace-actions.ts +24 -29
  675. package/src/workspace-auto-merge.ts +14 -12
  676. package/src/workspace-changed-paths-client.ts +16 -5
  677. package/src/workspace-cleanup-stale.ts +30 -7
  678. package/src/workspace-command-settle.ts +26 -17
  679. package/src/workspace-config.ts +1 -1
  680. package/src/workspace-conflict-resolver.ts +9 -7
  681. package/src/workspace-dead-owner-recovery.ts +5 -4
  682. package/src/workspace-escalation.ts +12 -11
  683. package/src/workspace-human-escalation.ts +3 -3
  684. package/src/workspace-land-gate-watchdog.ts +3 -3
  685. package/src/workspace-land-refusal.ts +20 -0
  686. package/src/workspace-land-stopped.ts +1 -0
  687. package/src/workspace-merge.ts +10 -26
  688. package/src/workspace-nothing-to-land-notice.ts +2 -2
  689. package/src/workspace-orphans.ts +18 -37
  690. package/src/workspace-pr-completion.ts +10 -8
  691. package/src/workspace-rekey.ts +3 -3
  692. package/src/workspace-steward-failure.ts +2 -2
  693. package/src/workspace-steward-wake.ts +4 -4
  694. package/node_modules/@humwick/kernel/LICENSE +0 -167
  695. package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
  696. package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
  697. package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
  698. package/node_modules/@humwick/kernel/config.ts +0 -111
  699. package/node_modules/@humwick/kernel/contract.ts +0 -572
  700. package/node_modules/@humwick/kernel/control-authz.ts +0 -281
  701. package/node_modules/@humwick/kernel/control.ts +0 -645
  702. package/node_modules/@humwick/kernel/effects.ts +0 -493
  703. package/node_modules/@humwick/kernel/event-log.ts +0 -319
  704. package/node_modules/@humwick/kernel/http-transport.ts +0 -384
  705. package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
  706. package/node_modules/@humwick/kernel/identity.ts +0 -248
  707. package/node_modules/@humwick/kernel/index.ts +0 -28
  708. package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
  709. package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
  710. package/node_modules/@humwick/kernel/landing.ts +0 -953
  711. package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
  712. package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
  713. package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
  714. package/node_modules/@humwick/kernel/message-authority.ts +0 -281
  715. package/node_modules/@humwick/kernel/module-host.ts +0 -722
  716. package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
  717. package/node_modules/@humwick/kernel/package.json +0 -39
  718. package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
  719. package/node_modules/@humwick/kernel/persistence.ts +0 -510
  720. package/node_modules/@humwick/kernel/registry.ts +0 -60
  721. package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
  722. package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
  723. package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
  724. package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
  725. package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
  726. package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
  727. package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
  728. package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
  729. package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
  730. package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
  731. package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
  732. package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
  733. package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
  734. package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
  735. package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
  736. package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
  737. package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
  738. package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
  739. package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
  740. package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
  741. package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
  742. package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
  743. package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
  744. package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
  745. package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
  746. package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
  747. package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
  748. package/node_modules/@humwick/offload/LICENSE +0 -167
  749. package/node_modules/@humwick/offload/README.md +0 -57
  750. package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
  751. package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
  752. package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
  753. package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
  754. package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
  755. package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
  756. package/node_modules/@humwick/offload/dist/envelope.js +0 -80
  757. package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
  758. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
  759. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
  760. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
  761. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
  762. package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
  763. package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
  764. package/node_modules/@humwick/offload/dist/index.js +0 -5
  765. package/node_modules/@humwick/offload/dist/index.js.map +0 -1
  766. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
  767. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
  768. package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
  769. package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
  770. package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
  771. package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
  772. package/node_modules/@humwick/offload/dist/types.js +0 -176
  773. package/node_modules/@humwick/offload/dist/types.js.map +0 -1
  774. package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
  775. package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
  776. package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
  777. package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
  778. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
  779. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
  780. package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
  781. package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
  782. package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
  783. package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
  784. package/node_modules/@humwick/offload/dist/worker.js +0 -1
  785. package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
  786. package/node_modules/@humwick/offload/package.json +0 -42
  787. package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
  788. package/node_modules/@humwick/offload/src/envelope.ts +0 -92
  789. package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
  790. package/node_modules/@humwick/offload/src/index.ts +0 -4
  791. package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
  792. package/node_modules/@humwick/offload/src/types.ts +0 -235
  793. package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
  794. package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
  795. package/node_modules/@humwick/offload/src/worker.ts +0 -5
  796. package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
  797. package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
  798. package/public/assets/index-B7ZerHLY.css +0 -2
  799. package/public/assets/index-BU3uWo2t.js +0 -15
  800. package/public/assets/projects-B_lmcqfO.js +0 -2
  801. package/public/assets/provider-display-DbLWpP3j.js +0 -2
  802. package/public/assets/run-card-CO_bguQf.js +0 -2
  803. package/public/assets/shipping-Bu8p1gEw.js +0 -2
  804. package/public/assets/store-BvtFdlGX.js +0 -9
  805. package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
  806. package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
  807. package/runner/src/agent-runner/http-liveness.ts +0 -85
  808. package/runner/src/gate-run-lease-probe.ts +0 -38
  809. package/src/db/claude-catalog-reconcile.ts +0 -27
  810. package/src/db/on-loop-write-transaction.ts +0 -34
  811. package/src/routing-model-aliases.ts +0 -21
@@ -4,6 +4,7 @@ import { spawnTreeContains } from "../db/spawn-tree";
4
4
  import { cleanSpawnBudget } from "../spawn-budget";
5
5
  import { readWorkflowRunBudgetAsync, reconcileRunBudgetAsync } from "../token-usage-async";
6
6
  import { getRoutingPolicyEnvelope } from "../routing-policy-service";
7
+ import { resolveWorkflowRoutingDefaults } from "./workflow-routing-defaults";
7
8
 
8
9
  // #3045 — the workflow supervisor: mounts the kernel `workflow` module, starts runs, and pumps them.
9
10
  // A pass recovers crashed drivers, signals each waiting run from durable src facts (level-triggered,
@@ -14,10 +15,10 @@ import { errMessage, fireAndForget, stringValue, type WorkflowRunAgent, type Wor
14
15
  import { validateWorkflowValue } from "@humwick/kernel/workflow-values";
15
16
  import { OpError } from "@humwick/kernel";
16
17
 
17
- import { admitWorkflowCaller, assertWorkflowCallerLive } from "./workflow-caller";
18
+ import { admitWorkflowCaller, admitWorkflowTaskOwner, assertWorkflowCallerLive, canControlWorkflowTask } from "./workflow-caller";
18
19
  import { taskVerificationCheck } from "../task-verification";
19
20
 
20
- import { workflow, workflowEffectId, type WorkflowEffect, type WorkflowRunRecord } from "@humwick/kernel/workflow.pilot";
21
+ import { assertWorkflowFuturePins, workflow, workflowEffectId, type WorkflowEffect, type WorkflowRunRecord } from "@humwick/kernel/workflow.pilot";
21
22
  import { getAgent, getTaskDetailAsync, ValidationError } from "../db";
22
23
  import type { WorkflowRunCursor, WorkflowRunTaskRow } from "../db/workflow-task-read-ops";
23
24
  import { getGateway } from "../db/gateway";
@@ -31,7 +32,6 @@ import { McpNotFoundError } from "../mcp-errors";
31
32
  import { ServiceAuthError } from "./errors";
32
33
  import { canSpawn, spawnLineageAgentId, taskLinkedRepoCwd } from "./spawn-agent";
33
34
  import { resolveSpawnProjectWorkflow } from "./spawn-project-role";
34
- import { canControlTaskReviewHold } from "./task-review-hold";
35
35
  import { updateTaskEntityAsync } from "./task-entity";
36
36
 
37
37
  import { releaseRunHold } from "./workflow-effects";
@@ -43,6 +43,7 @@ import { leanRunView, runView } from "./workflow-run-view";
43
43
  import type { AuthContext } from "./auth-context";
44
44
 
45
45
  import { invoke, live, runAgents, requestPump, serialized, ensureSupervisor, type Supervisor } from "./workflow-supervisor";
46
+ import { supervisorNow } from "./workflow-supervisor-state";
46
47
  export { workflowAgentObligation } from "./workflow-agent-obligation";
47
48
  import { reconcileRun } from "./workflow-reconcile";
48
49
  import { holdWorkflowVerification } from "./workflow-verification";
@@ -76,19 +77,19 @@ export async function prepareWorkflowRun(input: { workflow: string; taskId: numb
76
77
  if (!task || task.kind !== "deliverable") throw new ValidationError("task not found");
77
78
  if (task.status === "canceled") throw new ValidationError(`task ${task.id} is canceled; a workflow runs on a Task that is still wanted`);
78
79
  const caller = admitWorkflowCaller(ctx, task);
79
- if (!caller && !canControlTaskReviewHold(ctx, task)) {
80
+ if (!caller && !canControlWorkflowTask(ctx, task)) {
80
81
  throw new ServiceAuthError(`starting a workflow on task ${task.id} is coordinator-only: the run sets the review hold and clears it on GO — ${COORDINATOR_AUTHORITY_HINT}`);
81
82
  }
82
83
  if (!caller && !canSpawn(ctx)) throw new ServiceAuthError("starting a workflow dispatches its roles, so it requires the command:spawn scope");
83
84
  const lineageId = spawnLineageAgentId(ctx, task);
84
85
  const lineage = lineageId ? getAgent(lineageId) : null;
85
- const cwd = input.cwd ?? await taskLinkedRepoCwd(task.id, stringValue(lineage?.meta?.cwd));
86
+ const cwd = input.cwd ?? await taskLinkedRepoCwd(task.id, stringValue(lineage?.meta?.cwd), lineage ?? undefined);
86
87
  const read = await resolveSpawnProjectWorkflow({ workflow: input.workflow, cwd, orchestratorId: input.orchestratorId, preferHost: lineage?.machine, allowedOrchestratorIds: ctx.constraints?.orchestrators });
87
88
  return { task, cwd, read };
88
89
  }
89
90
 
90
91
  /** relay_workflow_start: read the landed workflow and its roles, check every step's pin, start one run on the Task. */
91
- export async function startWorkflowRun(input: { workflow: string; taskId: number; pins?: WorkflowPins; inputs?: Json; requestKey?: string; budget?: unknown }, ctx: AuthContext): Promise<Json> {
92
+ export async function startWorkflowRun(input: { workflow: string; taskId: number; cwd?: string; pins?: WorkflowPins; inputs?: Json; requestKey?: string; budget?: unknown }, ctx: AuthContext): Promise<Json> {
92
93
  return launchWorkflowRun(await prepareWorkflowRun(input, ctx), input, ctx);
93
94
  }
94
95
 
@@ -98,18 +99,17 @@ export async function launchWorkflowRun(prepared: PreparedWorkflowRun, input: {
98
99
  const { task, cwd, read } = prepared;
99
100
  const budget = cleanSpawnBudget(input.budget);
100
101
  const { definition } = read.workflow;
102
+ // #3769 — a Task a delegated sub-coordinator owns runs as its run, whoever starts it: the step spawns' lineage and the run's origin agree.
103
+ const caller = admitWorkflowCaller(ctx, task, read.workflow) ?? admitWorkflowTaskOwner(task, read.workflow);
101
104
  await getGateway().read("spawnTree.validateTarget", { type: "agent.spawn", source: ctx.actor.id, target: read.orchestratorId,
102
- params: { spawnedBy: ctx.callerAgentId, taskId: task.id, cwd, orchestratorId: read.orchestratorId, profile: "worker", workflowRunId: "preflight" } });
103
- const caller = admitWorkflowCaller(ctx, task, read.workflow);
105
+ params: { spawnedBy: caller?.callerAgentId ?? ctx.callerAgentId, taskId: task.id, cwd, orchestratorId: read.orchestratorId, profile: "worker", workflowRunId: "preflight" } });
104
106
  const capabilityError = workflowCapabilityError(definition);
105
107
  if (capabilityError) throw new ValidationError(capabilityError);
106
108
  validateWorkflowValue(definition.inputs, input.inputs ?? {}, "INPUT_INVALID");
107
109
  if (Object.values(definition.steps).some(step => step.verify) && !taskVerificationCheck(task.doneWhen)) throw new ValidationError(`T${task.id} needs a nonempty verify: section in doneWhen`);
108
110
  const pins = input.pins ? stampPins(definition, input.pins, "start") : undefined;
109
111
  const defaults = (await getRoutingPolicyEnvelope()).policy.stepDefaults;
110
- const coordinatorId = ctx.callerAgentId ?? task.createdBy;
111
- const teamId = task.teamId ?? (coordinatorId ? getAgent(coordinatorId)?.teamId : undefined);
112
- const routingDefaults = defaults ? { global: defaults.global, ...(teamId ? { team: defaults.teams?.[teamId], teamId } : {}) } : undefined;
112
+ const routingDefaults = resolveWorkflowRoutingDefaults(defaults, task, ctx.callerAgentId);
113
113
  await assertStepLaunches({ definition, pins, routingDefaults, steps: Object.keys(definition.steps), roles: read.workflow.roles, inputTask: task }, ctx);
114
114
  for (const [name, snapshot] of Object.entries(read.workflow.closure ?? {})) {
115
115
  if (name === read.workflow.name) continue;
@@ -146,7 +146,7 @@ export async function launchWorkflowRun(prepared: PreparedWorkflowRun, input: {
146
146
  });
147
147
  if (!created && run.workflow !== read.workflow.name) throw new ValidationError(`task ${task.id} already runs workflow "${run.workflow}" (${run.id}); a Task has one open run`);
148
148
  if (!created && pins && !sameCallPins(run.pins, pins)) {
149
- throw new ValidationError(`task ${task.id} already runs ${run.id} with other pins; a running run keeps its pins, and relay_workflow_resume changes them after an escalation`);
149
+ throw new ValidationError(`task ${task.id} already runs ${run.id} with other pins; use relay_workflow_resume with pins to change not-yet-started steps`);
150
150
  }
151
151
  if (!created && budget && budget.tokenCap !== run.tokenBudget?.tokenCap) {
152
152
  throw new ValidationError(`task ${task.id} already runs ${run.id} with another budget; a run keeps its original token cap`);
@@ -180,9 +180,9 @@ async function settleRefusable(sup: Supervisor, run: WorkflowRunRecord): Promise
180
180
  throw error;
181
181
  }
182
182
 
183
- /** A run is visible to its coordinator, the input Task's coordinators and admins. */
184
- export function canViewRun(ctx: AuthContext, coordinator: string, task: Parameters<typeof canControlTaskReviewHold>[1] | null): boolean {
185
- return ctx.callerAgentId === coordinator || Boolean(ctx.callerAgentId && spawnTreeContains(ctx.callerAgentId, coordinator)) || Boolean(task && canControlTaskReviewHold(ctx, task));
183
+ /** A run is visible to its coordinator, the input Task's coordinators, its owning sub-coordinator and admins. */
184
+ export function canViewRun(ctx: AuthContext, coordinator: string, task: Parameters<typeof canControlWorkflowTask>[1] | null): boolean {
185
+ return ctx.callerAgentId === coordinator || Boolean(ctx.callerAgentId && spawnTreeContains(ctx.callerAgentId, coordinator)) || Boolean(task && canControlWorkflowTask(ctx, task));
186
186
  }
187
187
 
188
188
  /** #3352 — the run's cap and observed spend, as admission counts them. */
@@ -190,7 +190,7 @@ export async function readWorkflowRunBudget(runId: string, ctx: AuthContext): Pr
190
190
  const sup = await ensureSupervisor();
191
191
  const run = await readRun(sup, runId);
192
192
  if (!canViewRun(ctx, run.coordinator, await getTaskDetailAsync(run.taskId))) {
193
- throw new ServiceAuthError(`workflow run ${runId} is visible to its coordinator, the Task's coordinators and admins — ${COORDINATOR_AUTHORITY_HINT}`);
193
+ throw new ServiceAuthError(`workflow run ${runId} is visible to its coordinator, the Task's coordinators, its owning sub-coordinator and admins — ${COORDINATOR_AUTHORITY_HINT}`);
194
194
  }
195
195
  if (!run.tokenBudget) throw new McpNotFoundError(`workflow run ${runId} has no token budget`);
196
196
  return await readWorkflowRunBudgetAsync(run.id, run.tokenBudget.tokenCap) as unknown as Json;
@@ -198,12 +198,7 @@ export async function readWorkflowRunBudget(runId: string, ctx: AuthContext): Pr
198
198
 
199
199
  /** #3352 — a coordinator amends a live run's cap; new spawns see it at their next admission. */
200
200
  export async function amendWorkflowRunBudget(input: { runId: string; tokenCap: number }, ctx: AuthContext): Promise<Json> {
201
- const sup = await ensureSupervisor();
202
- const run = await readRun(sup, input.runId);
203
- const task = await getTaskDetailAsync(run.taskId);
204
- if (!task || !(ctx.callerAgentId === run.callerAgentId || canControlTaskReviewHold(ctx, task))) {
205
- throw new ServiceAuthError(`amending the budget of workflow run ${run.id} is coordinator-only — ${COORDINATOR_AUTHORITY_HINT}`);
206
- }
201
+ const { sup, run } = await controlledRun(input.runId, ctx, "amending the budget of");
207
202
  const amended = await serialized(sup, () => invoke<WorkflowRunRecord>(sup, "amendTokenBudget", { runId: run.id, tokenCap: input.tokenCap })).catch((error: unknown) => {
208
203
  if (error instanceof OpError && error.code === "conflict") throw new ValidationError(error.message);
209
204
  throw error;
@@ -222,7 +217,7 @@ async function readRun(sup: Supervisor, runId: string): Promise<WorkflowRunRecor
222
217
  }
223
218
 
224
219
  /** relay_workflow_resume: answer the run's escalation by re-entering it at its escalated step or a named one (#3045 H2),
225
- * replacing the pins of each step `pins` names (#3121). */
220
+ * replacing the pins of each step `pins` names (#3121); pins alone on a running or paused run update future steps (#3806). */
226
221
  export async function resumeWorkflowRun(input: { runId: string; activationId?: string; step?: string; note?: string; pins?: WorkflowPins; decision?: WorkflowDecisionResponse }, ctx: AuthContext): Promise<Json> {
227
222
  const sup = await ensureSupervisor();
228
223
  const run = await readRun(sup, input.runId);
@@ -236,14 +231,27 @@ export async function resumeWorkflowRun(input: { runId: string; activationId?: s
236
231
  return { ...runView(await readRun(sup, run.id)), resumed: input.decision.action === "answer" };
237
232
  }
238
233
  const task = await getTaskDetailAsync(run.taskId);
239
- if (!task || !(ctx.callerAgentId === run.callerAgentId || canControlTaskReviewHold(ctx, task))) {
234
+ if (!task || !(ctx.callerAgentId === run.callerAgentId || canControlWorkflowTask(ctx, task))) {
240
235
  throw new ServiceAuthError(`resuming workflow run ${run.id} is coordinator-only: the run sets the review hold and clears it on GO — ${COORDINATOR_AUTHORITY_HINT}`);
241
236
  }
242
237
  if (run.callerAgentId && ctx.actor.kind !== "system") assertWorkflowCallerLive(run.callerAgentId);
243
238
  if (!run.callerAgentId && !canSpawn(ctx)) throw new ServiceAuthError("resuming a workflow can dispatch its roles, so it requires the command:spawn scope");
244
239
  if (task.status === "canceled") throw new ValidationError(`T${task.id} is canceled, so its run ${run.id} cannot resume`);
245
240
  const pins = input.pins ? stampPins(run.definition, input.pins, "resume") : undefined;
246
- if (pins) await assertResumePins(run, pins, task, ctx, await runAgents(sup, run.id));
241
+ if (pins && !input.step && !input.activationId && run.status === "running") {
242
+ await serialized(sup, async () => {
243
+ const latest = await readRun(sup, run.id);
244
+ assertWorkflowFuturePins(latest, pins);
245
+ await assertResumePins(latest, pins, task, ctx, await runAgents(sup, run.id), (op, args) => invoke(sup, op, args));
246
+ await invoke(sup, "amendPins", { runId: run.id, pins, by: ctx.callerAgentId ?? ctx.actor.id, note: input.note });
247
+ }).catch((error: unknown) => {
248
+ if (error instanceof OpError && (error.code === "conflict" || error.code === "invalid_input")) throw new ValidationError(error.message);
249
+ throw error;
250
+ });
251
+ await requestPump(sup);
252
+ return { ...runView(await readRun(sup, run.id)), resumed: false, pinsUpdated: true };
253
+ }
254
+ if (pins) await assertResumePins(run, pins, task, ctx, await runAgents(sup, run.id), (op, args) => invoke(sup, op, args));
247
255
  // Between passes, so no pass is performing the end-of-run reap the resume voids. A fact that already ends the
248
256
  // current wait (a delivery, a land) is signaled first and wins: the resume then refuses.
249
257
  const resume = serialized(sup, async () => {
@@ -270,13 +278,7 @@ export async function resumeWorkflowRun(input: { runId: string; activationId?: s
270
278
  /** relay_workflow_cancel (#3166): end a running or escalated run cancelled. A running run ends at once, its step
271
279
  * agents reaped per their `reap`; the Task, its review hold, any delivery and an armed land stay as they are. */
272
280
  export async function cancelWorkflowRun(input: { runId: string; reason?: string }, ctx: AuthContext): Promise<Json> {
273
- const sup = await ensureSupervisor();
274
- const run = await readRun(sup, input.runId);
275
- const task = await getTaskDetailAsync(run.taskId);
276
- if (!task || !(ctx.callerAgentId === run.callerAgentId || canControlTaskReviewHold(ctx, task))) {
277
- throw new ServiceAuthError(`cancelling workflow run ${run.id} is coordinator-only — ${COORDINATOR_AUTHORITY_HINT}`);
278
- }
279
- const by = ctx.callerAgentId ?? ctx.actor.id;
281
+ const { sup, run, by } = await controlledRun(input.runId, ctx, "cancelling");
280
282
  const reason = `cancelled by ${by}${input.reason ? `: ${input.reason}` : ""}`;
281
283
  // Between passes, so the cancel lands before the next routing.
282
284
  const { cancelled } = await serialized(sup, () => invoke<{ cancelled: boolean }>(sup, "cancel", { runId: run.id, reason, by })).catch((error: unknown) => {
@@ -287,6 +289,32 @@ export async function cancelWorkflowRun(input: { runId: string; reason?: string
287
289
  return { ...runView(await readRun(sup, run.id)), cancelled };
288
290
  }
289
291
 
292
+ /** The run a coordinator-only control acts on: its caller, the input Task's coordinators, its owning sub-coordinator and admins may. */
293
+ async function controlledRun(runId: string, ctx: AuthContext, verb: string): Promise<{ sup: Supervisor; run: WorkflowRunRecord; by: string }> {
294
+ const sup = await ensureSupervisor();
295
+ const run = await readRun(sup, runId);
296
+ const task = await getTaskDetailAsync(run.taskId);
297
+ if (!task || !(ctx.callerAgentId === run.callerAgentId || canControlWorkflowTask(ctx, task))) {
298
+ throw new ServiceAuthError(`${verb} workflow run ${run.id} is coordinator-only — ${COORDINATOR_AUTHORITY_HINT}`);
299
+ }
300
+ return { sup, run, by: ctx.callerAgentId ?? ctx.actor.id };
301
+ }
302
+
303
+ /** #3757 — pause a running run at its next seam (reason required) or unpause it; its agents keep working meanwhile. */
304
+ export async function pauseWorkflowRun(input: { runId: string; pause: boolean; reason?: string }, ctx: AuthContext): Promise<Json> {
305
+ const reason = input.reason?.trim();
306
+ if (input.pause && !reason) throw new ValidationError("pausing a workflow run needs a reason (MCP: note): say why it waits and for what");
307
+ const { sup, run, by } = await controlledRun(input.runId, ctx, input.pause ? "pausing" : "unpausing");
308
+ // Between passes, so no pass routes or performs with a stale view of the pause.
309
+ await serialized(sup, () => invoke(sup, input.pause ? "pause" : "unpause", { runId: run.id, by, now: supervisorNow(), ...(input.pause ? { reason } : {}) }))
310
+ .catch((error: unknown) => {
311
+ if (error instanceof OpError && (error.code === "conflict" || error.code === "invalid_input")) throw new ValidationError(error.message);
312
+ throw error;
313
+ });
314
+ await requestPump(sup);
315
+ return runView(await readRun(sup, run.id));
316
+ }
317
+
290
318
  /** relay_workflow_get: the run's visible record, after every pass already scheduled. */
291
319
  export async function getWorkflowRun(runId: string, ctx: AuthContext, options: WorkflowRunReadOptions = {}): Promise<Json> {
292
320
  const sup = await ensureSupervisor();
@@ -294,7 +322,7 @@ export async function getWorkflowRun(runId: string, ctx: AuthContext, options: W
294
322
  await sup.notes;
295
323
  const run = await readRun(sup, runId);
296
324
  if (!canViewRun(ctx, run.coordinator, await getTaskDetailAsync(run.taskId))) {
297
- throw new ServiceAuthError(`workflow run ${runId} is visible to its coordinator, the Task's coordinators and admins — ${COORDINATOR_AUTHORITY_HINT}`);
325
+ throw new ServiceAuthError(`workflow run ${runId} is visible to its coordinator, the Task's coordinators, its owning sub-coordinator and admins — ${COORDINATOR_AUTHORITY_HINT}`);
298
326
  }
299
327
  const scripts = options.verbose && Object.values(run.definition.steps).some(step => step.script)
300
328
  ? await invoke<{ items: Array<WorkflowScriptRun & { id: string; runId: string }>; cursor?: string }>(sup, "scriptAttempts", { runId, ...(options.scriptCursor ? { cursor: options.scriptCursor } : {}) }) : undefined;
@@ -1,7 +1,7 @@
1
1
  import { errMessage } from "@humwick/sdk";
2
2
  import type { ModuleHost, ModuleHostOptions } from "@humwick/kernel";
3
3
  import type { WorkflowRuntime } from "@humwick/kernel/workflow-runtime";
4
- import { workflow, type WorkflowAgent } from "@humwick/kernel/workflow.pilot";
4
+ import { workflow, type WorkflowAgent, type WorkflowEffect } from "@humwick/kernel/workflow.pilot";
5
5
  import { getDbGeneration } from "../db";
6
6
  import { emitRelayEvent } from "../events";
7
7
 
@@ -45,6 +45,31 @@ let stopped = Promise.resolve();
45
45
  let changeTimer: Timer | undefined;
46
46
  export let testOptions: SupervisorTestOptions = {};
47
47
 
48
+ /** The supervisor's clock: deadlines are read and a pause is stamped against it. */
49
+ export function supervisorNow(): number {
50
+ return (testOptions.now ?? Date.now)();
51
+ }
52
+
53
+ const QUICK_RETRIES = 3;
54
+ const RETRY_BASE_MS = 1000;
55
+ const RETRY_MAX_MS = 60_000;
56
+
57
+ /** #3827 — a retried effect's result with its next attempt. A stop still in flight (`inFlight`) is re-read next
58
+ * pass; consecutive terminal misses (a failed stop, a gone target, a stop without proof) get a few quick retries,
59
+ * then exponential backoff to a minute, so an effect that never converges costs one attempt a minute, not one a pass. */
60
+ export function retryResult(previous: Json | undefined, result: Json, now: number): Json {
61
+ if (result.inFlight === true) return result;
62
+ const failures = (typeof previous?.failures === "number" ? previous.failures : 0) + 1;
63
+ const delay = failures <= QUICK_RETRIES ? 0 : Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** Math.min(failures - QUICK_RETRIES - 1, 6));
64
+ return { ...result, failures, nextAttemptAt: now + delay };
65
+ }
66
+
67
+ /** Whether a pending effect's backoff has run out. */
68
+ export function effectDue(effect: WorkflowEffect, now: number): boolean {
69
+ const at = effect.result?.nextAttemptAt;
70
+ return typeof at !== "number" || at <= now;
71
+ }
72
+
48
73
  /** The supervisor bound to the current database handle (a test that swaps the handle rebuilds it). */
49
74
  export function live(): Supervisor | undefined {
50
75
  return current && current.generation === getDbGeneration() ? current : undefined;
@@ -1,4 +1,5 @@
1
1
  // #3045 — drives durable workflow transitions, reconciliation and external effects.
2
+ import { framed } from "../hub-metrics";
2
3
  import { errMessage, fireAndForget, isRecord, stringValue } from "@humwick/sdk";
3
4
  import { createModuleHost, type ModuleHost } from "@humwick/kernel";
4
5
  import { workflow } from "@humwick/kernel/workflow.pilot";
@@ -25,9 +26,13 @@ function startSupervisor(): Supervisor {
25
26
  persistence: createGatewayKernelPersistence(),
26
27
  leaseTtlMs: testOptions.leaseTtlMs ?? LEASE_TTL_MS,
27
28
  opCommitFaults: testOptions.opCommitFaults,
28
- // A wait is satisfied by its signal row: one keyed read instead of the default event-log scan.
29
- workflowWaitEvaluator: async (waitFor) => waitFor.kind === "event" && waitFor.correlationId !== undefined
30
- && ((await host.invoke(workflow, "hasSignal", SUPERVISOR, { key: waitFor.correlationId })) as { present: boolean }).present,
29
+ // A wait is satisfied by its signal row: one keyed read instead of the default event-log scan. A paused run's
30
+ // signal waits for its unpause (#3757).
31
+ workflowWaitEvaluator: async (waitFor) => {
32
+ if (waitFor.kind !== "event" || waitFor.correlationId === undefined) return false;
33
+ const wait = await host.invoke(workflow, "hasSignal", SUPERVISOR, { key: waitFor.correlationId }) as { present: boolean; paused?: boolean };
34
+ return wait.present && !wait.paused;
35
+ },
31
36
  });
32
37
  host.register(workflow);
33
38
  const sup: Supervisor = {
@@ -53,10 +58,10 @@ function startSupervisor(): Supervisor {
53
58
  }),
54
59
  landed: new Map(), tail: predecessor, queued: undefined, notes: predecessor, refusable: new Map(),
55
60
  };
56
- sup.ticker = setInterval(() => {
57
- if (live() === sup) void fireAndForget("[workflow] supervisor pump", () => requestPump(sup));
61
+ sup.ticker = setInterval(framed("timer workflow-supervisor", () => {
62
+ if (live() === sup) return fireAndForget("[workflow] supervisor pump", () => requestPump(sup));
58
63
  else if (sup.ticker) clearInterval(sup.ticker);
59
- }, workflowScriptsEnabled() ? 1000 : SCHEDULER_TICK_MS);
64
+ }), workflowScriptsEnabled() ? 1000 : SCHEDULER_TICK_MS);
60
65
  sup.ticker.unref?.();
61
66
  setSupervisor(sup);
62
67
  return sup;
@@ -1,3 +1,4 @@
1
+ import { insertRecoveredWorkspaceAsync } from "../db/runtime-admin-async";
1
2
  // #1502 — server-authoritative self-heal of a dropped/never-written isolated-workspace registration.
2
3
  //
3
4
  // A live worker holds its own workspace descriptor in AGENT_RELAY_WORKSPACE_JSON, but the workspace
@@ -18,7 +19,7 @@
18
19
  // 404), never a best-effort guess, because the output is a landing authorization.
19
20
 
20
21
  import { resolve } from "node:path";
21
- import { getDb, getOrchestrator, insertRecoveredWorkspace, workspaceLandMetadataFrom, type RecoveredWorkspaceInput } from "../db";
22
+ import { getDb, getOrchestrator, workspaceLandMetadataFrom, type RecoveredWorkspaceInput } from "../db";
22
23
  import { parseJson, isPathWithinBase } from "../utils";
23
24
  import { sanitizeFsName } from "@humwick/sdk/fs-name";
24
25
  import { hasScope } from "@humwick/sdk/types";
@@ -69,7 +70,7 @@ function resolveOwningOrchestrator(ctx: AuthContext, params: Record<string, unkn
69
70
  return null;
70
71
  }
71
72
 
72
- export function recoverIsolatedWorkspace(ctx: AuthContext, hint: WorkspaceRecoveryHint | undefined, pathId: string | undefined): WorkspaceRecovery {
73
+ export async function recoverIsolatedWorkspace(ctx: AuthContext, hint: WorkspaceRecoveryHint | undefined, pathId: string | undefined): Promise<WorkspaceRecovery> {
73
74
  const caller = ctx.callerAgentId;
74
75
  if (!caller) return REFUSE;
75
76
  // Minting a land/merge target is a privileged write — require command:write, not baseline identity
@@ -163,6 +164,6 @@ export function recoverIsolatedWorkspace(ctx: AuthContext, hint: WorkspaceRecove
163
164
  ownerAgentId: caller,
164
165
  landMetadata: workspaceLandMetadataFrom(params),
165
166
  };
166
- const result = insertRecoveredWorkspace(input);
167
+ const result = (await insertRecoveredWorkspaceAsync(input));
167
168
  return { ok: true, workspace: result.workspace, created: result.created };
168
169
  }
@@ -32,7 +32,6 @@ import {
32
32
  SPAWN_PROVIDERS,
33
33
  TEAM_IDLE_THRESHOLD_MINUTES_MAX,
34
34
  TEAM_IDLE_THRESHOLD_MINUTES_MIN,
35
- VALID_EFFORTS,
36
35
  type JSONSchema,
37
36
  type SettingDescriptor,
38
37
  type SettingScope,
@@ -166,7 +165,7 @@ const STEWARD_SCHEMA: JSONSchema = {
166
165
  enabled: { type: "boolean" },
167
166
  provider: { type: "string", enum: [...SPAWN_PROVIDERS] },
168
167
  model: { type: "string", maxLength: 120 },
169
- effort: { type: "string", enum: [...VALID_EFFORTS] },
168
+ effort: { type: "string", maxLength: 120 },
170
169
  permissionMode: { type: "string", enum: [...APPROVAL_MODES] },
171
170
  keepaliveSeconds: { type: "integer", minimum: 0, maximum: 2_592_000 },
172
171
  },
@@ -1,11 +1,18 @@
1
1
  import type { Orchestrator, SpawnProvider } from "./types";
2
+ import { ValidationError } from "@humwick/sdk";
3
+
4
+ export class PinnedHostCapacityError extends ValidationError {
5
+ constructor(message: string, readonly orchestratorId: string) {
6
+ super(message);
7
+ }
8
+ }
2
9
 
3
10
  export interface AdmissionReason {
4
11
  check: "host" | "provider" | "auth" | "capacity";
5
12
  code: string;
6
13
  message: string;
7
14
  }
8
- export interface Admission { eligible: boolean; refusals: AdmissionReason[]; uncertainties: AdmissionReason[] }
15
+ export interface Admission { eligible: boolean; refusals: AdmissionReason[]; uncertainties: AdmissionReason[]; agentCapOnly?: boolean }
9
16
 
10
17
  /** Interpret all probe legs independently: a failure on one never hides another leg's timeout. */
11
18
  export function providerProbeAdmission(item: Orchestrator, provider: SpawnProvider, pinned = false): Admission {
@@ -40,7 +47,8 @@ export function providerProbeAdmission(item: Orchestrator, provider: SpawnProvid
40
47
 
41
48
  export function assessSpawnAdmission(item: Orchestrator, provider: SpawnProvider, checks: AdmissionReason[] = [], pinned = false): Admission {
42
49
  const probe = providerProbeAdmission(item, provider, pinned);
43
- return { eligible: probe.eligible && checks.length === 0, refusals: [...checks, ...probe.refusals], uncertainties: probe.uncertainties };
50
+ return { eligible: probe.eligible && checks.length === 0, refusals: [...checks, ...probe.refusals], uncertainties: probe.uncertainties,
51
+ agentCapOnly: probe.eligible && checks.length > 0 && checks.every(reason => reason.code === "agent_cap") };
44
52
  }
45
53
 
46
54
  export function admissionMessages(admission: Admission): string {
@@ -112,11 +112,12 @@ export function resolveSpawnModelParams(
112
112
  // #2599 — the full record is server-computed once from the effective-catalog selection:
113
113
  // qualified runtime name + both windows + the explicit threshold. Same positive-int gates
114
114
  // as the legacy window (never 0/NaN/negative), via the shared builder.
115
- const record = runnerSupportsModelRecord(opts.runnerProtocol)
115
+ const record = runnerSupportsModelRecord(opts.runnerProtocol ?? MODEL_RECORD_PROTOCOL_VERSION)
116
116
  ? resolvedModelRecordFromSelection({
117
117
  alias: selection.modelAlias,
118
118
  providerModel: selection.providerModel,
119
119
  effort: selection.effort,
120
+ efforts: selection.model?.efforts,
120
121
  qualifiedModel: qualifyServerModelName(provider, selection.providerModel, effectiveProviderCatalogList()),
121
122
  limits: selection.model?.limits,
122
123
  ...(selection.model?.contextThreshold ? { contextThreshold: selection.model.contextThreshold } : {}),
@@ -135,7 +136,6 @@ export function resolveSpawnModelParams(
135
136
  ...(record ? { modelRecord: record } : {}),
136
137
  };
137
138
  } catch (error) {
138
- if (opts.modelSource === "runtime") return { ...(model ? { model } : {}), ...(effort ? { effort } : {}) };
139
139
  throw new ValidationError(errMessage(error));
140
140
  }
141
141
  }
@@ -157,11 +157,12 @@ export async function resolveSpawnModelParamsAsync(
157
157
  );
158
158
  const windowTokens = selection.model?.limits?.contextWindowTokens?.value;
159
159
  // #2599 — same full-record twin as the sync path (see its comment).
160
- const record = runnerSupportsModelRecord(opts.runnerProtocol)
160
+ const record = runnerSupportsModelRecord(opts.runnerProtocol ?? MODEL_RECORD_PROTOCOL_VERSION)
161
161
  ? resolvedModelRecordFromSelection({
162
162
  alias: selection.modelAlias,
163
163
  providerModel: selection.providerModel,
164
164
  effort: selection.effort,
165
+ efforts: selection.model?.efforts,
165
166
  qualifiedModel: qualifyServerModelName(provider, selection.providerModel, liveCatalog),
166
167
  limits: selection.model?.limits,
167
168
  ...(selection.model?.contextThreshold ? { contextThreshold: selection.model.contextThreshold } : {}),
@@ -176,7 +177,6 @@ export async function resolveSpawnModelParamsAsync(
176
177
  ...(record ? { modelRecord: record } : {}),
177
178
  };
178
179
  } catch (error) {
179
- if (opts.modelSource === "runtime") return { ...(model ? { model } : {}), ...(effort ? { effort } : {}) };
180
180
  throw new ValidationError(errMessage(error));
181
181
  }
182
182
  }
@@ -2,21 +2,19 @@ import { isOpenAiApiModel } from "@humwick/sdk";
2
2
  import type { ProviderCatalogEntry } from "@humwick/sdk/provider-catalog";
3
3
  import type { Orchestrator, SpawnProvider } from "./types";
4
4
 
5
- /** A missing report preserves compatibility with older orchestrators; a reported catalog is authoritative. */
6
- export function hostSupportsModel(host: Orchestrator, provider: SpawnProvider, model?: string, effort?: string): boolean {
7
- const catalog = host.providerCatalog?.find((entry) => entry.provider === provider);
8
- if (!model || !catalog) return !isOpenAiApiModel(provider, model);
9
- const status = catalog.models.find((entry) => entry.alias === model || entry.providerModel === model);
10
- return status !== undefined && !status.disabled
11
- && (!effort || status.efforts.includes(effort));
5
+ /** Hosts report local capabilities; model definitions and efforts belong to the hub catalog. */
6
+ export function hostSupportsModel(host: Orchestrator, provider: SpawnProvider, model?: string): boolean {
7
+ if (!isOpenAiApiModel(provider, model)) return true;
8
+ const ready = host.providerStatus?.find((entry) => entry.name === provider)?.features?.openaiApi;
9
+ if (ready !== undefined) return ready;
10
+ // Older hosts encoded credential readiness by including the paid model in their catalog.
11
+ return host.providerCatalog?.find((entry) => entry.provider === provider)?.models
12
+ .some((entry) => isOpenAiApiModel(provider, entry.alias) && !entry.disabled) ?? false;
12
13
  }
13
14
 
14
- /** Keep Relay's model definitions and settings, intersected with the host's reported capabilities. */
15
+ /** Project the hub catalog onto the host's genuinely local capabilities. */
15
16
  export function hostRunnableCatalog(entry: ProviderCatalogEntry, host: Orchestrator): ProviderCatalogEntry {
16
17
  const models = entry.models.filter((model) => !model.disabled && !model.unavailable
17
- && hostSupportsModel(host, entry.provider, model.alias)).map((model) => {
18
- const efforts = model.efforts.filter((effort) => hostSupportsModel(host, entry.provider, model.alias, effort));
19
- return { ...model, efforts, defaultEffort: model.defaultEffort && efforts.includes(model.defaultEffort) ? model.defaultEffort : undefined };
20
- });
18
+ && hostSupportsModel(host, entry.provider, model.alias));
21
19
  return { ...entry, models };
22
20
  }
@@ -13,7 +13,7 @@ import { HOST_BAND_CONFIG } from "./config";
13
13
  import { hostProviderRefusal, liveHostDisabledProviders } from "./host-provider-store";
14
14
 
15
15
  import { hostSupportsModel } from "./spawn-models";
16
- import { admissionMessages, assessSpawnAdmission, type AdmissionReason, type Admission } from "./spawn-admission";
16
+ import { admissionMessages, assessSpawnAdmission, PinnedHostCapacityError, type AdmissionReason, type Admission } from "./spawn-admission";
17
17
 
18
18
  const MATCHED_HOST_IDENTITY: HostIdentity = Object.freeze({ matched: true });
19
19
 
@@ -180,10 +180,14 @@ export function selectSpawnPlacement(
180
180
  const orchestrator = getOrchestrator(orchestratorId);
181
181
  if (!orchestrator) throw new McpNotFoundError(`orchestrator ${orchestratorId} not found`);
182
182
  const view = orchestrator.hostId ? byId.get(orchestrator.hostId) : undefined;
183
- const admission = hostSpawnAdmission(orchestrator, view, identities, provider, model, effort, liveHostDisabledProviders(), true, spawnHostCapAdmission(capOpts)(view), repoPlatformAdmission(view, placementPlatforms));
183
+ const admission = hostSpawnAdmission(orchestrator, view, identities, provider, model, effort, liveHostDisabledProviders(), true, spawnHostCapAdmission(capOpts)(view), [
184
+ ...repoPlatformAdmission(view, placementPlatforms), ...workspaceHostAdmission(orchestrator, view, workspaceMode, canLand, capOpts, true),
185
+ ]);
184
186
  const detail = admissionMessages(admission);
185
187
  if (!admission.eligible) {
186
- throw new ValidationError(spawnPlacementRefusal(listOrchestrators(), views, provider, model, effort, orchestratorId, capOpts, admission));
188
+ const message = spawnPlacementRefusal(listOrchestrators(), views, provider, model, effort, orchestratorId, capOpts, admission);
189
+ if (admission.agentCapOnly) throw new PinnedHostCapacityError(message, orchestratorId);
190
+ throw new ValidationError(message);
187
191
  }
188
192
  return { orchestrator, reason: `Explicit host pin: ${orchestrator.hostname} (${orchestrator.id})${detail ? `; ${detail}` : ""}.` };
189
193
  }
@@ -241,7 +245,25 @@ function headroomSummary(view: HostView | undefined): string {
241
245
  return `(${round(cores)} free cores, ${round(freeThreadsOf(view)!)} free threads, band ${view.band})`;
242
246
  }
243
247
 
244
- export interface SpawnCapOptions { callerAgentId?: string; attach?: boolean }
248
+ export interface SpawnCapOptions {
249
+ callerAgentId?: string;
250
+ attach?: boolean;
251
+ buildWork?: boolean;
252
+ workspaceDepsDisabledHosts?: readonly string[];
253
+ }
254
+
255
+ /** Pins and landBlocked cannot turn isolated dependency/build work into a light hub probe (#3805). */
256
+ function workspaceHostAdmission(item: Orchestrator, view: HostView | undefined, mode: WorkspaceMode | undefined, canLand: boolean, opts: SpawnCapOptions, pinned = false): AdmissionReason[] {
257
+ if (mode !== "isolated") return [];
258
+ const hubWork = (opts.buildWork ?? canLand) || (!opts.attach && !opts.workspaceDepsDisabledHosts?.includes(item.id));
259
+ if (hubWork && view?.policy.noLandingWorkspaces !== false && isRelayHost(item, view)) {
260
+ return [{ check: "host", code: "hub_workspace", message: `no builders on the hub: Relay server host ${item.hostname} (${item.id}) refuses isolated build or dependency-install workspaces, including pinned spawns and workflow steps; choose a non-hub host or set Fleet > Edit host > Isolated workspaces to Include this host (noLandingWorkspaces=false)` }];
261
+ }
262
+ if (pinned || !canLand) return [];
263
+ const landing = view?.policy.noLandingWorkspaces === true ? "host excludes landing workspaces"
264
+ : view?.policy.noLandingWorkspaces !== false && isRelayHost(item, view) ? "Relay server host excluded by default" : undefined;
265
+ return landing ? [{ check: "host", code: "landing", message: landing }] : [];
266
+ }
245
267
 
246
268
  // Repository tools must run on the host even when the agent cannot land or pins a host (#3563).
247
269
  function repoPlatformAdmission(view: HostView | undefined, platforms?: readonly string[] | null): AdmissionReason[] {
@@ -282,11 +304,7 @@ export function spawnPlacementCandidates(
282
304
  const extra = repoPlatformAdmission(view, placementPlatforms);
283
305
  const capacity = capBlock(view);
284
306
  if (capacity) extra.push({ check: "capacity", code: "agent_cap", message: capacity });
285
- if (isolatedAutoPlacement) {
286
- const landing = view?.policy.noLandingWorkspaces === true ? "host excludes landing workspaces"
287
- : view?.policy.noLandingWorkspaces !== false && isRelayHost(item, view) ? "Relay server host excluded by default" : undefined;
288
- if (landing) extra.push({ check: "host", code: "landing", message: landing });
289
- }
307
+ extra.push(...workspaceHostAdmission(item, view, workspaceMode, canLand, capOpts));
290
308
  const admission = hostSpawnAdmission(item, view, identities, provider, model, effort, hostDisabled, false, undefined, extra);
291
309
  if (!admission.eligible) exclusions.push(`${item.hostname}: ${admissionMessages(admission)}`);
292
310
  else if (admission.uncertainties.length) warnings.push(`${item.hostname}: ${admissionMessages(admission)}`);
@@ -321,7 +339,7 @@ export function hostSpawnAdmission(
321
339
  if (view?.policy.spawnEnabled === false) add("host", "draining", `host ${item.hostname} (${item.id}) is draining: new spawns disabled`);
322
340
  if (!pinned && view && (!view.enabled || view.state === "unavailable" || view.state === "retired" || view.band === "blocked")) add("host", "unavailable", "host unavailable or blocked");
323
341
  if (!pinned && view && view.aggregates.agentSlotsMax !== 0 && view.aggregates.agentSlotsUsed >= view.aggregates.agentSlotsMax) add("capacity", "slots", "host spawn slots full");
324
- if (!pinned && !hostSupportsModel(item, provider, model, effort)) add("provider", "model", `provider '${provider}' does not support requested model or effort`);
342
+ if (!pinned && !hostSupportsModel(item, provider, model)) add("provider", "model", `provider '${provider}' does not support requested model or effort`);
325
343
  if (capacity) add("capacity", "agent_cap", `host ${item.hostname} (${item.id}) is ${capacity}`);
326
344
  return assessSpawnAdmission(item, provider, checks, pinnedAuth);
327
345
  }
@@ -1,6 +1,6 @@
1
1
  import { apiBudgetStatus } from "./db/claude-api-budget";
2
2
  import { apiBudgetStatusAsync } from "./claude-api-budget-async";
3
- import { isOpenAiApiModel, type ApiBudgetStatus } from "@humwick/sdk";
3
+ import { API_BUDGET_IDS, isOpenAiApiModel, type ApiBudgetStatus } from "@humwick/sdk";
4
4
  import { collapseProviderQuotaRows } from "@humwick/sdk/provider-quota-order";
5
5
  import { resolveQuotaPacing, subscriptionExpiryForWindow, subscriptionExpiryPreference, type ResolvedQuotaPacing } from "./quota-pacing";
6
6
  import { countLiveSpawnedAgents, countLiveSpawnedAgentsAsync, getAgent, getAgentAsync, listOrchestrators, listOrchestratorsAsync, listProviderQuotas, providerQuotaRoutingSnapshotAsync } from "./db";
@@ -53,7 +53,7 @@ export function buildSpawnTargets(input: { callerId?: string; quota: number }):
53
53
  const me = input.callerId ? getAgent(input.callerId) : undefined;
54
54
  return buildSpawnTargetsFrom(input, {
55
55
  me,
56
- openaiBudget: apiBudgetStatus(now, "openai-api"),
56
+ apiBudgets: API_BUDGET_IDS.map((id) => apiBudgetStatus(now, id)),
57
57
  orchestrators: listOrchestrators(),
58
58
  hostViews: listHostViews(now),
59
59
  liveChildren: input.callerId ? countLiveSpawnedAgents(input.callerId) : 0,
@@ -67,17 +67,17 @@ export function buildSpawnTargets(input: { callerId?: string; quota: number }):
67
67
  /** Worker-safe discovery path: every durable input is read through the reader gateway. */
68
68
  export async function buildSpawnTargetsAsync(input: { callerId?: string; quota: number }): Promise<Record<string, unknown>> {
69
69
  const now = Date.now();
70
- const [me, orchestrators, hostViews, liveChildren, snapshot, openaiBudget] = await Promise.all([
70
+ const [me, orchestrators, hostViews, liveChildren, snapshot, apiBudgets] = await Promise.all([
71
71
  input.callerId ? getAgentAsync(input.callerId) : Promise.resolve(null),
72
72
  listOrchestratorsAsync(),
73
73
  listHostViewsAsync(),
74
74
  input.callerId ? countLiveSpawnedAgentsAsync(input.callerId) : Promise.resolve(0),
75
75
  providerQuotaRoutingSnapshotAsync(now),
76
- apiBudgetStatusAsync("openai-api"),
76
+ Promise.all(API_BUDGET_IDS.map((id) => apiBudgetStatusAsync(id))),
77
77
  ]);
78
78
  return buildSpawnTargetsFrom(input, {
79
79
  me: me ?? undefined,
80
- openaiBudget,
80
+ apiBudgets,
81
81
  orchestrators,
82
82
  hostViews,
83
83
  liveChildren,
@@ -90,7 +90,7 @@ export async function buildSpawnTargetsAsync(input: { callerId?: string; quota:
90
90
 
91
91
  function buildSpawnTargetsFrom(input: { callerId?: string; quota: number }, data: {
92
92
  me?: ReturnType<typeof getAgent>;
93
- openaiBudget: ApiBudgetStatus;
93
+ apiBudgets: ApiBudgetStatus[];
94
94
  orchestrators: Orchestrator[];
95
95
  hostViews: readonly HostView[];
96
96
  liveChildren: number;
@@ -130,10 +130,10 @@ function buildSpawnTargetsFrom(input: { callerId?: string; quota: number }, data
130
130
  ...(o.utilization && Number.isFinite(o.utilization.agentSlotsUsedThisDaemon) && Number.isFinite(o.utilization.agentSlotsMaxThisDaemon) && o.utilization.agentSlotsMaxThisDaemon > 0
131
131
  ? { spawn_slots: { used: o.utilization.agentSlotsUsedThisDaemon, max: o.utilization.agentSlotsMaxThisDaemon } }
132
132
  : {}),
133
- providers: providerMatrixFor(o, data.quotaAdvisories, data.catalog, data.profiles, hostDisabled, data.openaiBudget),
133
+ providers: providerMatrixFor(o, data.quotaAdvisories, data.catalog, data.profiles, hostDisabled, data.apiBudgets.find((budget) => budget.budgetId === "openai-api")),
134
134
  };
135
135
  }),
136
- apiBudgets: [data.openaiBudget],
136
+ apiBudgets: data.apiBudgets.map((budget) => ({ ...budget, source: "relay-accounting" })),
137
137
  ...operatorDisabledProviders(data.catalog),
138
138
  profiles: spawnProfilesSummary(data.profiles),
139
139
  // #3327 — preferences steer automatic spawns inside the dispatcher; never copy them into explicit pins.
@@ -290,7 +290,7 @@ function providerMatrixFor(
290
290
  const providers = [...new Set([...o.providers, ...(o.providerStatus ?? []).filter((s) => s.degraded || s.cli?.transient || s.runner?.transient || s.auth?.transient).map((s) => s.name)])];
291
291
  return providers.filter((provider) => !disabledProviders.has(provider) && !hostDisabledFor?.has(provider)).map((provider) => {
292
292
  const globalEntry = global.find((e) => e.provider === provider);
293
- // Relay owns model settings; the heartbeat limits what this host can run (#3202).
293
+ // The hub owns models and efforts; hosts contribute only local capabilities.
294
294
  const cat = globalEntry ? hostRunnableCatalog(globalEntry, o) : undefined;
295
295
  const quotaAdvisory = quotaAdvisories.get(provider) ?? defaultQuotaAdvisory(provider);
296
296
  // #932 — advertise the SAME default a bare spawn would actually resolve to. resolveDefaultModel