@humwick/server 0.130.2 → 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 (570) hide show
  1. package/bundled/prompts/manifest.json +1 -0
  2. package/bundled/prompts/task.hydration.md +1 -1
  3. package/bundled/roles/builder.md +1 -1
  4. package/docs/guides/sub-coordinators.md +12 -5
  5. package/docs/guides/tools-coordination.md +1 -0
  6. package/docs/guides/workflows.md +16 -0
  7. package/docs/openapi.json +73 -4
  8. package/package.json +8 -7
  9. package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
  10. package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
  11. package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
  12. package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
  13. package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
  14. package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
  15. package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
  16. package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
  17. package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
  18. package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
  19. package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
  20. package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
  21. package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
  22. package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
  23. package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
  24. package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
  25. package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
  26. package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
  27. package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
  28. package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
  29. package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
  30. package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
  31. package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
  32. package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
  33. package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
  34. package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
  35. package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
  36. package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
  37. package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
  38. package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
  39. package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
  40. package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
  41. package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
  42. package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
  43. package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
  44. package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
  45. package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
  46. package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
  47. package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
  48. package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
  49. package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
  50. package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
  51. package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
  52. package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
  53. package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
  54. package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
  55. package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
  56. package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
  57. package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
  58. package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
  59. package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
  60. package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
  61. package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
  62. package/public/assets/provider-display-BEeLXC_D.js +2 -0
  63. package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
  64. package/public/assets/run-card-Dt4I4jaP.js +2 -0
  65. package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
  66. package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
  67. package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
  68. package/public/assets/shipping-H6gzEeZB.js +2 -0
  69. package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
  70. package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
  71. package/public/assets/store-DKPDIZBe.js +9 -0
  72. package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
  73. package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
  74. package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
  75. package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
  76. package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
  77. package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
  78. package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
  79. package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
  80. package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
  81. package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
  82. package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
  83. package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
  84. package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
  85. package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
  86. package/public/cosmos.html +4 -4
  87. package/public/index.html +28 -28
  88. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  89. package/runner/src/adapters/claude-headless.ts +1 -1
  90. package/runner/src/adapters/claude-launch-exit.ts +26 -0
  91. package/runner/src/adapters/claude-session-probe.ts +1 -1
  92. package/runner/src/adapters/claude-tmux.ts +38 -10
  93. package/runner/src/adapters/claude.ts +28 -75
  94. package/runner/src/adapters/provider-quota-harvest.ts +20 -71
  95. package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
  96. package/runner/src/agent-runner/liveness-exchange.ts +104 -0
  97. package/runner/src/claude-system-prompt.ts +49 -0
  98. package/runner/src/launch-assembly.ts +14 -10
  99. package/runner/src/profile-home.ts +1 -1
  100. package/runner/src/project-instructions.ts +2 -2
  101. package/runner/src/provider-command.ts +18 -0
  102. package/runner/src/provider-setup.ts +2 -1
  103. package/runner/src/runner-core.ts +14 -15
  104. package/runner/src/runner-helpers.ts +0 -8
  105. package/runner/src/session-scratch.ts +6 -2
  106. package/runner/test-support/provisioning-context.ts +4 -2
  107. package/runner/test-support/runner-harness.ts +2 -1
  108. package/scripts/steward-policy-cleanup.ts +2 -2
  109. package/src/agent-authz.ts +2 -2
  110. package/src/agent-drive-arbiter.ts +3 -8
  111. package/src/agent-exit-cleanup-async.ts +2 -2
  112. package/src/agent-exit-cleanup.ts +23 -19
  113. package/src/agent-lifecycle-events.ts +112 -85
  114. package/src/agent-ref.ts +3 -2
  115. package/src/agent-status-events.ts +43 -14
  116. package/src/auth/password.ts +4 -3
  117. package/src/auth/session-refresh.ts +1 -1
  118. package/src/auth/session.test-fixture.ts +2 -2
  119. package/src/auth/session.ts +7 -7
  120. package/src/automations/crud.ts +8 -81
  121. package/src/automations/dispatch.ts +33 -58
  122. package/src/automations/index.ts +1 -1
  123. package/src/automations/persistence.ts +65 -0
  124. package/src/automations/precheck.ts +18 -16
  125. package/src/automations/read-async.ts +11 -0
  126. package/src/automations/reconcile.ts +30 -39
  127. package/src/automations/storage.ts +33 -10
  128. package/src/automations/write-async.ts +33 -0
  129. package/src/branch-land-notice.ts +3 -3
  130. package/src/branch-landed.ts +25 -23
  131. package/src/bus.ts +21 -19
  132. package/src/cd-deploy-notify.ts +2 -2
  133. package/src/ci/notifications.ts +4 -4
  134. package/src/ci/root-missing.ts +3 -3
  135. package/src/ci/transition-notify.ts +5 -5
  136. package/src/claude-app/oauth-http.ts +3 -3
  137. package/src/cli/workflow.ts +12 -3
  138. package/src/commands-db.ts +4 -4
  139. package/src/commands-write.ts +8 -0
  140. package/src/compaction-watch.ts +10 -8
  141. package/src/config-store-write.ts +2 -2
  142. package/src/config.ts +4 -11
  143. package/src/connectors.ts +10 -8
  144. package/src/context-advisory.ts +22 -21
  145. package/src/db/agent-action-write.ts +36 -0
  146. package/src/db/agent-control-async.ts +9 -0
  147. package/src/db/agent-control-write.ts +49 -0
  148. package/src/db/agent-effort-observe.ts +22 -0
  149. package/src/db/agent-meta.ts +14 -3
  150. package/src/db/agents-async.ts +8 -5
  151. package/src/db/agents.ts +15 -12
  152. package/src/db/auth-identities.ts +2 -2
  153. package/src/db/automation-read-ops.ts +11 -0
  154. package/src/db/automation-write-ops.ts +46 -0
  155. package/src/db/blackboard.ts +2 -2
  156. package/src/db/browser-session-write.ts +32 -0
  157. package/src/db/bus-outbox-write-ops.ts +3 -1
  158. package/src/db/checkout-refresh-schema.ts +47 -0
  159. package/src/db/checkout-refresh.ts +5 -5
  160. package/src/db/command-agent-profile-backfill.ts +39 -0
  161. package/src/db/command-agent-profiles.ts +5 -1
  162. package/src/db/command-retention.ts +126 -0
  163. package/src/db/commands-planner-stats.test-fixture.ts +8 -0
  164. package/src/db/commands-read-ops.ts +16 -0
  165. package/src/db/connection.ts +1 -182
  166. package/src/db/context-carry-write.ts +74 -0
  167. package/src/db/continuations.ts +4 -4
  168. package/src/db/db-error-registry.ts +12 -0
  169. package/src/db/gateway.ts +26 -133
  170. package/src/db/history-retention-ops.ts +13 -0
  171. package/src/db/inbox-async.ts +2 -2
  172. package/src/db/inbox-read-ops.ts +1 -1
  173. package/src/db/inbox.ts +9 -3
  174. package/src/db/issue-associations.ts +2 -2
  175. package/src/db/issue-refs-async.ts +4 -1
  176. package/src/db/issue-refs-read-ops.ts +6 -0
  177. package/src/db/issue-refs.ts +8 -8
  178. package/src/db/kernel-event-log-schema.ts +2 -0
  179. package/src/db/land-boundaries.ts +51 -5
  180. package/src/db/land-gate-attestations.ts +2 -2
  181. package/src/db/landing-receipts.ts +2 -2
  182. package/src/db/lifecycle-context-write.ts +5 -0
  183. package/src/db/lifecycle-tail-async.ts +76 -0
  184. package/src/db/lifecycle-tail-write-ops.ts +62 -0
  185. package/src/db/lifecycle-write-window.ts +2 -1
  186. package/src/db/lineage-pair-dedupe-sql.ts +3 -3
  187. package/src/db/main-connection-mode.ts +11 -0
  188. package/src/db/main-connection-writes.ts +20 -2
  189. package/src/db/maintenance-job-runs-async.ts +2 -2
  190. package/src/db/maintenance-job-write-ops.ts +1 -1
  191. package/src/db/maintenance-pauses.ts +2 -2
  192. package/src/db/message-send.ts +4 -0
  193. package/src/db/messages.ts +31 -25
  194. package/src/db/migrations.ts +18 -1
  195. package/src/db/notification-write-ops.ts +19 -0
  196. package/src/db/operator-answer-write.ts +19 -0
  197. package/src/db/orchestrators.ts +10 -4
  198. package/src/db/pairs-async.ts +22 -1
  199. package/src/db/pairs-write-ops.ts +8 -3
  200. package/src/db/pairs.ts +41 -48
  201. package/src/db/plan-dispatch-schema.ts +5 -1
  202. package/src/db/plan-ready-notices.ts +43 -0
  203. package/src/db/plan-tools-include-migration.ts +36 -0
  204. package/src/db/plans-write-ops.ts +2 -0
  205. package/src/db/presence-buffer.ts +5 -0
  206. package/src/db/presence-loop.ts +18 -23
  207. package/src/db/presence-write.ts +0 -6
  208. package/src/db/project-entries-async.ts +14 -0
  209. package/src/db/project-entries-read-ops.ts +5 -1
  210. package/src/db/project-entries-write-ops.ts +8 -0
  211. package/src/db/project-entries.ts +15 -12
  212. package/src/db/project-journal.ts +2 -2
  213. package/src/db/project-trust-approvals.ts +2 -2
  214. package/src/db/prompt-templates.ts +4 -4
  215. package/src/db/read-op-marshaling-fixtures.ts +18 -0
  216. package/src/db/read-ops.ts +4 -0
  217. package/src/db/retention.ts +13 -2
  218. package/src/db/review-publish-write.ts +8 -0
  219. package/src/db/runtime-admin-async.ts +19 -0
  220. package/src/db/runtime-admin-write-ops.ts +36 -0
  221. package/src/db/runtime-tail-async.ts +288 -0
  222. package/src/db/runtime-tail-write-ops.ts +97 -0
  223. package/src/db/schema.ts +4 -1
  224. package/src/db/spawn-budget.ts +5 -0
  225. package/src/db/spawn-delegation.ts +1 -11
  226. package/src/db/sql-audit-indexes.ts +3 -0
  227. package/src/db/stats-async.ts +5 -3
  228. package/src/db/task-entity.ts +5 -4
  229. package/src/db/team-claim-policy.ts +60 -0
  230. package/src/db/teams-async.ts +4 -0
  231. package/src/db/teams-write-ops.ts +4 -0
  232. package/src/db/terminal-events.ts +15 -0
  233. package/src/db/timer-cutover-bodies.ts +292 -0
  234. package/src/db/timer-cutover-core.ts +37 -278
  235. package/src/db/timer-cutover-state.ts +40 -0
  236. package/src/db/timer-cutover-write-ops.ts +1 -40
  237. package/src/db/token-db-write-ops.ts +2 -0
  238. package/src/db/token-standing-async.ts +12 -0
  239. package/src/db/token-standing.ts +6 -9
  240. package/src/db/token-usage-retention.ts +33 -0
  241. package/src/db/token-usage-write-ops.ts +1 -1
  242. package/src/db/token-usage.ts +4 -1
  243. package/src/db/user-invites-async.ts +13 -0
  244. package/src/db/user-invites.ts +3 -3
  245. package/src/db/users.ts +14 -6
  246. package/src/db/workspaces.ts +8 -5
  247. package/src/db/write-ops.ts +31 -12
  248. package/src/db/writer-fault-seam.ts +2 -9
  249. package/src/db/writer-fault-test-ops.ts +18 -0
  250. package/src/db/writer-gateway.ts +42 -46
  251. package/src/dev.ts +8 -3
  252. package/src/event-loop-lag.ts +4 -2
  253. package/src/event-loop-yield.ts +2 -2
  254. package/src/events.ts +10 -8
  255. package/src/host-provider-store.ts +5 -4
  256. package/src/hub-metrics-report.ts +5 -1
  257. package/src/hub-metrics.ts +38 -18
  258. package/src/injection-sweep-pacing.ts +6 -8
  259. package/src/land-gate-notifications.ts +11 -10
  260. package/src/land-gate-queue-progress.ts +3 -3
  261. package/src/land-settle-dispatch.ts +52 -92
  262. package/src/lifecycle-context-pressure.ts +11 -10
  263. package/src/lifecycle-manager.ts +104 -98
  264. package/src/maintenance/breaker.ts +18 -16
  265. package/src/maintenance/checkout-refresh.ts +18 -1
  266. package/src/maintenance/critical-job-watchdog.ts +3 -3
  267. package/src/maintenance/events.ts +3 -3
  268. package/src/maintenance/history-retention-job.ts +30 -0
  269. package/src/maintenance/jobs.ts +29 -67
  270. package/src/maintenance/long-running-work.ts +3 -1
  271. package/src/maintenance/offline-agent-prune-job.ts +28 -0
  272. package/src/maintenance/orphaned-sessions.ts +5 -4
  273. package/src/maintenance/pauses.ts +4 -10
  274. package/src/maintenance/plan-ready-notice-job.ts +71 -0
  275. package/src/maintenance/scheduler.ts +18 -13
  276. package/src/maintenance/stalled-delivery-pager.ts +4 -4
  277. package/src/maintenance/teams.ts +19 -30
  278. package/src/maintenance/workspaces.ts +17 -27
  279. package/src/managed-policy-escalation.ts +7 -7
  280. package/src/managed-policy.ts +3 -3
  281. package/src/managed-provider-gate.ts +5 -4
  282. package/src/managed-spawn-reservation.ts +5 -4
  283. package/src/mcp/index.ts +8 -8
  284. package/src/mcp/output-descriptions.ts +1 -1
  285. package/src/mcp/presentation.ts +2 -1
  286. package/src/mcp/runtime-output.ts +6 -1
  287. package/src/mcp/self-care-visibility.ts +2 -2
  288. package/src/mcp/spawn-targets-matrix.ts +10 -1
  289. package/src/mcp/tool-groups.ts +3 -2
  290. package/src/mcp/tool-roles.ts +81 -0
  291. package/src/mcp/tools-workspace.ts +1 -1
  292. package/src/mcp-blackboard-tools.ts +6 -5
  293. package/src/mcp-decision-tools.ts +7 -7
  294. package/src/mcp-egress-tools.ts +10 -9
  295. package/src/mcp-issue-activity-tools.ts +2 -2
  296. package/src/mcp-issue-association-tools.ts +4 -4
  297. package/src/mcp-issue-ref-tools.ts +3 -3
  298. package/src/mcp-merge-tools.ts +5 -5
  299. package/src/mcp-notification-subscription-tools.ts +14 -15
  300. package/src/mcp-output-levels.test-fixture.ts +1 -1
  301. package/src/mcp-profile-trust-tools.ts +1 -1
  302. package/src/mcp-project-journal-tools.ts +4 -12
  303. package/src/mcp-project-tools.ts +17 -18
  304. package/src/mcp-routing-policy-tools.ts +3 -2
  305. package/src/mcp-team-tools.ts +6 -6
  306. package/src/mcp-workflow-tools.ts +5 -3
  307. package/src/memory-area-injection.ts +13 -12
  308. package/src/memory-boundary-capture.ts +6 -6
  309. package/src/memory-injection.ts +45 -43
  310. package/src/merge-pause-maintenance.ts +5 -4
  311. package/src/notification-router.ts +44 -17
  312. package/src/notify.ts +5 -5
  313. package/src/observed-reset-refresh.ts +4 -4
  314. package/src/operator-alarm.ts +2 -5
  315. package/src/project-ingest.ts +6 -6
  316. package/src/project-instructions.ts +8 -1
  317. package/src/project-trust.ts +12 -11
  318. package/src/prompt-resolver.ts +3 -3
  319. package/src/provider-quota-async.ts +5 -7
  320. package/src/provider-timeline-event.ts +4 -7
  321. package/src/quota-band-delivery.ts +2 -2
  322. package/src/recipe-runner.ts +4 -3
  323. package/src/retention-config-store.ts +4 -3
  324. package/src/reviewer-pipeline.ts +11 -10
  325. package/src/routes/_route.ts +4 -4
  326. package/src/routes/_shared.ts +13 -12
  327. package/src/routes/agent-effort.ts +5 -5
  328. package/src/routes/agent-heartbeat-quota.ts +23 -0
  329. package/src/routes/agent-keep.ts +1 -1
  330. package/src/routes/agent-reporting.ts +1 -1
  331. package/src/routes/agent-self-effort.ts +5 -5
  332. package/src/routes/agent-sessions.ts +24 -24
  333. package/src/routes/agents-spawn.ts +1 -1
  334. package/src/routes/agents.ts +17 -119
  335. package/src/routes/auth.ts +14 -15
  336. package/src/routes/authority-audit.ts +2 -2
  337. package/src/routes/automations.ts +6 -5
  338. package/src/routes/channel-binding-delete.ts +1 -1
  339. package/src/routes/channel-output.ts +3 -3
  340. package/src/routes/claude-api-budget.ts +5 -5
  341. package/src/routes/commands-listing.ts +1 -1
  342. package/src/routes/commands.ts +29 -27
  343. package/src/routes/context-resets.ts +2 -2
  344. package/src/routes/coordinator-teams.ts +1 -1
  345. package/src/routes/decisions.ts +2 -2
  346. package/src/routes/host-secret-files.ts +1 -1
  347. package/src/routes/hosts.ts +11 -11
  348. package/src/routes/inbox.ts +3 -2
  349. package/src/routes/index.ts +2 -1
  350. package/src/routes/integrations.ts +9 -7
  351. package/src/routes/issue-activity.ts +2 -2
  352. package/src/routes/issue-associations.ts +4 -4
  353. package/src/routes/issue-refs.ts +3 -3
  354. package/src/routes/kernel-timers-operator.ts +1 -1
  355. package/src/routes/memory.ts +1 -1
  356. package/src/routes/merges.ts +11 -11
  357. package/src/routes/messages.ts +23 -17
  358. package/src/routes/orchestrator-bootstrap.ts +1 -1
  359. package/src/routes/orchestrator-host-registration.ts +2 -0
  360. package/src/routes/orchestrator-host-utilization.ts +2 -2
  361. package/src/routes/orchestrator-proxy.ts +2 -2
  362. package/src/routes/orchestrator.ts +27 -18
  363. package/src/routes/pairs.ts +8 -8
  364. package/src/routes/project-profile-instructions.ts +1 -1
  365. package/src/routes/project-trust.ts +1 -1
  366. package/src/routes/projects.ts +16 -16
  367. package/src/routes/prompt-templates.ts +12 -12
  368. package/src/routes/provider-quotas.ts +10 -10
  369. package/src/routes/run-command.ts +1 -1
  370. package/src/routes/secrets-backup.ts +2 -2
  371. package/src/routes/secrets-import.ts +1 -1
  372. package/src/routes/secrets-vault.ts +7 -7
  373. package/src/routes/settings.ts +1 -1
  374. package/src/routes/shipping.ts +9 -1
  375. package/src/routes/spawn-policy.ts +8 -7
  376. package/src/routes/sse.ts +2 -2
  377. package/src/routes/team-templates.ts +7 -7
  378. package/src/routes/teams.ts +10 -10
  379. package/src/routes/tokens.ts +18 -17
  380. package/src/routes/users.ts +24 -24
  381. package/src/routes/viewer-read.ts +3 -3
  382. package/src/routes/web-tool-calls.ts +4 -4
  383. package/src/routes/workflows.ts +2 -2
  384. package/src/routes/workspaces.ts +17 -16
  385. package/src/routing-policy-push.ts +6 -6
  386. package/src/runtime-grant.ts +17 -11
  387. package/src/runtime-tokens.ts +20 -28
  388. package/src/secrets-broker/config.ts +1 -1
  389. package/src/secrets-broker/service.ts +2 -2
  390. package/src/security.ts +3 -1
  391. package/src/self-resume-carry.ts +21 -110
  392. package/src/self-resume-supersede.ts +4 -3
  393. package/src/self-resume.ts +54 -66
  394. package/src/server-background.ts +1 -1
  395. package/src/server.ts +21 -22
  396. package/src/services/agent-action.ts +12 -31
  397. package/src/services/agent-effort.ts +7 -32
  398. package/src/services/agent-hang-watchdog-job.ts +2 -2
  399. package/src/services/agent-heartbeat.ts +166 -0
  400. package/src/services/agent-reporting.ts +1 -1
  401. package/src/services/browser-inventory.ts +3 -3
  402. package/src/services/browser-session-state.ts +3 -2
  403. package/src/services/browser-session.ts +21 -27
  404. package/src/services/bus-command-update.ts +9 -9
  405. package/src/services/checkout-refresh-state.ts +1 -0
  406. package/src/services/checkout-refresh.test-fixture.ts +3 -2
  407. package/src/services/command-host.ts +7 -2
  408. package/src/services/coordinator-digest.ts +3 -2
  409. package/src/services/dispatch-command.ts +12 -13
  410. package/src/services/effective-launch-driver.ts +14 -9
  411. package/src/services/host-changed-paths.test-fixture.ts +5 -6
  412. package/src/services/host-project-readiness.ts +2 -2
  413. package/src/services/host-providers.ts +1 -1
  414. package/src/services/host-utilization.ts +9 -9
  415. package/src/services/idle-agent-digest.ts +17 -12
  416. package/src/services/idle-epics.ts +4 -4
  417. package/src/services/interrupt-agent.ts +12 -9
  418. package/src/services/issue-activity.ts +3 -3
  419. package/src/services/issue-associations.ts +15 -18
  420. package/src/services/issue-lifecycle-comments.ts +3 -2
  421. package/src/services/issue-lifecycle.ts +14 -13
  422. package/src/services/issue-refs.ts +4 -5
  423. package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
  424. package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
  425. package/src/services/kernel-timers-ingress.ts +3 -3
  426. package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
  427. package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
  428. package/src/services/kernel-timers-outbox.ts +1 -1
  429. package/src/services/kernel-timers-stage10-operator.ts +1 -1
  430. package/src/services/kernel-timers.ts +4 -3
  431. package/src/services/land-gate-placement.ts +11 -2
  432. package/src/services/land-issue-relations.ts +5 -4
  433. package/src/services/land-restart-retry.ts +7 -6
  434. package/src/services/landed-ancestry.ts +6 -5
  435. package/src/services/legacy-landing-host.ts +4 -1
  436. package/src/services/legacy-landing-recovery.ts +8 -6
  437. package/src/services/managed-running.ts +17 -17
  438. package/src/services/memory-areas.ts +3 -3
  439. package/src/services/merge-pause.ts +9 -15
  440. package/src/services/operator-decisions.ts +37 -41
  441. package/src/services/orchestrator-registration-recovery.ts +6 -2
  442. package/src/services/orchestrator-upgrade.ts +14 -12
  443. package/src/services/permission-decision.ts +4 -3
  444. package/src/services/plan-ci-notice.ts +1 -1
  445. package/src/services/plan-conformance.ts +4 -4
  446. package/src/services/plan-dispatch-policy.ts +10 -3
  447. package/src/services/plan-dispatch.ts +35 -14
  448. package/src/services/plan-graph.ts +39 -261
  449. package/src/services/plan-import.ts +1 -1
  450. package/src/services/plan-live-bindings.ts +8 -37
  451. package/src/services/plan-task-create.ts +1 -1
  452. package/src/services/plan-terminal-refs.ts +2 -12
  453. package/src/services/plan-wake-digest.ts +8 -3
  454. package/src/services/profile-trust.ts +2 -2
  455. package/src/services/project.ts +11 -10
  456. package/src/services/prompt-templates.ts +6 -5
  457. package/src/services/provider-hold-nudge.ts +9 -9
  458. package/src/services/provider-hold-record.ts +13 -12
  459. package/src/services/provider-state-audit.ts +19 -18
  460. package/src/services/provisioning-harness/driver.ts +1 -1
  461. package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
  462. package/src/services/provisioning-harness/lifecycle.ts +24 -22
  463. package/src/services/provisioning-harness/prepare.ts +16 -17
  464. package/src/services/rate-limit-resume.ts +10 -9
  465. package/src/services/red-main-auto-revert.ts +7 -5
  466. package/src/services/red-main-controller-deps.ts +20 -3
  467. package/src/services/red-main-incident.ts +3 -1
  468. package/src/services/red-main-quarantine.ts +2 -3
  469. package/src/services/register-agent.ts +22 -22
  470. package/src/services/restart-project-role.ts +1 -1
  471. package/src/services/restart-spawn.ts +17 -16
  472. package/src/services/review-publish.ts +7 -24
  473. package/src/services/review-ref-reconcile.ts +29 -38
  474. package/src/services/runtime-dependency-alert.ts +27 -0
  475. package/src/services/scheduler-command.ts +11 -9
  476. package/src/services/scheduler.ts +5 -5
  477. package/src/services/self-effort-grant.ts +5 -25
  478. package/src/services/send-message.ts +16 -33
  479. package/src/services/shutdown-agent.ts +17 -14
  480. package/src/services/spawn-agent.ts +12 -41
  481. package/src/services/spawn-chain-inspector.ts +1 -1
  482. package/src/services/spawn-cwd-placement.ts +21 -5
  483. package/src/services/spawn-issue-activity.ts +8 -6
  484. package/src/services/spawn-launch.ts +17 -1
  485. package/src/services/spawn-loss-escalation.ts +1 -1
  486. package/src/services/spawn-registration-watchdog.ts +2 -2
  487. package/src/services/spawn-repo-probe.ts +7 -5
  488. package/src/services/spawn-tree-cleanup.ts +7 -8
  489. package/src/services/steward-reaper.ts +4 -4
  490. package/src/services/task-context-hydration.ts +25 -1
  491. package/src/services/task-delivery.ts +20 -34
  492. package/src/services/task-entity.ts +40 -203
  493. package/src/services/task-issue-link.ts +13 -20
  494. package/src/services/task-issue-weave.ts +12 -11
  495. package/src/services/task-lifecycle.ts +27 -31
  496. package/src/services/task-repo-cwd.ts +37 -0
  497. package/src/services/task-review-hold.ts +4 -17
  498. package/src/services/task-semantic-events.ts +13 -11
  499. package/src/services/task-state-reconcile.ts +3 -4
  500. package/src/services/task-validation.ts +2 -2
  501. package/src/services/team-templates.ts +5 -5
  502. package/src/services/team.ts +31 -98
  503. package/src/services/terminal-provider-exit.ts +6 -5
  504. package/src/services/timer-message-fire-chaos-worker.ts +7 -3
  505. package/src/services/timer-message-fire-outbox.ts +1 -1
  506. package/src/services/transient-agent-reaper.ts +22 -19
  507. package/src/services/turn-reconcile-audit.ts +9 -9
  508. package/src/services/user-onboarding.ts +8 -6
  509. package/src/services/user-profile.ts +6 -9
  510. package/src/services/work-finality.ts +16 -4
  511. package/src/services/workflow-auto-start.ts +2 -1
  512. package/src/services/workflow-caller.ts +61 -4
  513. package/src/services/workflow-child-proof-worker.ts +1 -1
  514. package/src/services/workflow-control-proof-worker.ts +1 -1
  515. package/src/services/workflow-coordinator.ts +8 -2
  516. package/src/services/workflow-decisions.ts +5 -5
  517. package/src/services/workflow-deferred-cleanup.ts +1 -1
  518. package/src/services/workflow-effect-driver.ts +42 -19
  519. package/src/services/workflow-effects.ts +41 -27
  520. package/src/services/workflow-pins.ts +7 -4
  521. package/src/services/workflow-reconcile.ts +1 -0
  522. package/src/services/workflow-resume-pins.ts +3 -3
  523. package/src/services/workflow-routing-defaults.ts +18 -0
  524. package/src/services/workflow-run-view.ts +4 -3
  525. package/src/services/workflow-run.test-fixture.ts +1 -1
  526. package/src/services/workflow-runs.ts +34 -22
  527. package/src/services/workflow-supervisor-state.ts +21 -1
  528. package/src/services/workflow-supervisor.ts +4 -3
  529. package/src/services/workspace-recovery.ts +4 -3
  530. package/src/spawn-admission.ts +10 -2
  531. package/src/spawn-placement.ts +27 -9
  532. package/src/spawn-targets.ts +8 -8
  533. package/src/sse-agent-status.ts +15 -6
  534. package/src/sse.ts +49 -24
  535. package/src/startup-context-injection.ts +61 -57
  536. package/src/steward-handoff.ts +4 -3
  537. package/src/steward-policy-cleanup.ts +9 -8
  538. package/src/steward.ts +2 -2
  539. package/src/task-dispatch-live.ts +5 -2
  540. package/src/task-dispatcher.ts +2 -2
  541. package/src/token-db.ts +2 -2
  542. package/src/token-usage-async.ts +2 -4
  543. package/src/user-awaiting-reply.ts +5 -5
  544. package/src/workspace-actions.ts +24 -29
  545. package/src/workspace-auto-merge.ts +14 -12
  546. package/src/workspace-changed-paths-client.ts +16 -5
  547. package/src/workspace-cleanup-stale.ts +30 -7
  548. package/src/workspace-command-settle.ts +24 -16
  549. package/src/workspace-config.ts +1 -1
  550. package/src/workspace-conflict-resolver.ts +9 -7
  551. package/src/workspace-dead-owner-recovery.ts +5 -4
  552. package/src/workspace-escalation.ts +12 -11
  553. package/src/workspace-human-escalation.ts +3 -3
  554. package/src/workspace-land-gate-watchdog.ts +3 -3
  555. package/src/workspace-land-refusal.ts +20 -0
  556. package/src/workspace-land-stopped.ts +1 -0
  557. package/src/workspace-merge.ts +10 -26
  558. package/src/workspace-nothing-to-land-notice.ts +2 -2
  559. package/src/workspace-orphans.ts +18 -37
  560. package/src/workspace-pr-completion.ts +10 -8
  561. package/src/workspace-rekey.ts +3 -3
  562. package/src/workspace-steward-failure.ts +2 -2
  563. package/src/workspace-steward-wake.ts +2 -2
  564. package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
  565. package/public/assets/provider-display-DsuWMvVL.js +0 -2
  566. package/public/assets/run-card-CpKqRbhg.js +0 -2
  567. package/public/assets/shipping-B9YtnwtG.js +0 -2
  568. package/public/assets/store-DcClXLH0.js +0 -9
  569. package/runner/src/agent-runner/http-liveness.ts +0 -85
  570. package/src/db/on-loop-write-transaction.ts +0 -34
@@ -1,29 +1,20 @@
1
- import { createCommand } from "../commands-db";
2
- import { getAgent, getTaskAsync, listAgents, listOrchestrators, sendMessage, updateTaskStatusAsync } from "../db";
1
+ import { updateRunAsync } from "./write-async";
2
+ import { sendMessageAsync } from "../db/message-send";
3
+ import { createCommandAsync } from "../commands-write";
4
+
5
+ import { getAgent, getTaskAsync, listAgents, listOrchestrators, updateTaskStatusAsync } from "../db";
3
6
  import { renderTemplate } from "../prompt-resolver";
4
7
  import { CLOSED_TASK_STATUS } from "./constants";
5
8
  import { settleAutomationPrechecks } from "./precheck";
6
- import {
7
- ensureAutomationTables,
8
- getAutomation,
9
- getAutomationRun,
10
- rowToAutomationRun,
11
- updateRun,
12
- db,
13
- } from "./storage";
9
+ import { listReconcilableRunsAsync } from "./read-async";
10
+ import { ensureAutomationTables, getAutomation, getAutomationRun } from "./storage";
14
11
  import type { AutomationReconcileResult } from "./types";
15
12
  import type { AgentCard, AutomationRun, AutomationRunStatus, AutomationRuntimeBudget, Command, Message, Task } from "../types";
16
13
 
17
14
  export async function reconcileAutomationRuns(now = Date.now()): Promise<AutomationReconcileResult[]> {
18
15
  ensureAutomationTables();
19
16
  const results: AutomationReconcileResult[] = await settleAutomationPrechecks(now);
20
- const rows = db().query(`
21
- SELECT * FROM automation_runs
22
- WHERE status IN ('scheduled', 'dispatching', 'waiting_agent', 'running') AND task_id IS NOT NULL
23
- ORDER BY created_at ASC
24
- `).all() as any[];
25
- for (const row of rows) {
26
- const run = rowToAutomationRun(row);
17
+ for (const run of await listReconcilableRunsAsync()) {
27
18
  const task = run.taskId ? await getTaskAsync(run.taskId) : null;
28
19
  if (!task) continue;
29
20
 
@@ -31,12 +22,12 @@ export async function reconcileAutomationRuns(now = Date.now()): Promise<Automat
31
22
  const hasRuntimeMetaChange = hasMetaChanges(run.meta, runtimeMeta);
32
23
  const nextOpenStatus: AutomationRunStatus = task.status === "open" ? "waiting_agent" : "running";
33
24
  if ((task.claimedBy && task.claimedBy !== run.targetAgentId) || run.status !== nextOpenStatus || hasRuntimeMetaChange) {
34
- updateRun(run.id, {
25
+ (await updateRunAsync(run.id, {
35
26
  status: nextOpenStatus,
36
27
  targetAgentId: task.claimedBy ?? run.targetAgentId,
37
28
  spawnedAgentId: run.spawnedAgentId ?? task.claimedBy,
38
29
  meta: hasRuntimeMetaChange ? { ...run.meta, ...runtimeMeta } : undefined,
39
- }, now);
30
+ }, now));
40
31
  }
41
32
 
42
33
  if (!CLOSED_TASK_STATUS.has(task.status)) {
@@ -52,22 +43,22 @@ export async function reconcileAutomationRuns(now = Date.now()): Promise<Automat
52
43
  results.push(timedOut);
53
44
  continue;
54
45
  }
55
- const warning = maybeWarnRuntimeBudget(updated, task, now);
46
+ const warning = (await maybeWarnRuntimeBudget(updated, task, now));
56
47
  results.push({ run: getAutomationRun(run.id) ?? updated, task, message: warning });
57
48
  continue;
58
49
  }
59
50
 
60
51
  const status: AutomationRunStatus = task.status === "done" ? "succeeded" : task.status === "canceled" ? "canceled" : "failed";
61
- updateRun(run.id, {
52
+ (await updateRunAsync(run.id, {
62
53
  status,
63
54
  finishedAt: now,
64
55
  result: { taskStatus: task.status, result: task.result ?? null },
65
56
  targetAgentId: task.claimedBy ?? run.targetAgentId,
66
57
  spawnedAgentId: run.spawnedAgentId ?? task.claimedBy,
67
58
  meta: hasMetaChanges(run.meta, runtimeMeta) ? { ...run.meta, ...runtimeMeta } : undefined,
68
- }, now);
59
+ }, now));
69
60
  const updated = getAutomationRun(run.id)!;
70
- const command = maybeShutdownOnDemandAgent(updated, task, now);
61
+ const command = (await maybeShutdownOnDemandAgent(updated, task, now));
71
62
  results.push({ run: getAutomationRun(run.id)!, task, command });
72
63
  }
73
64
  return results;
@@ -140,7 +131,7 @@ function runtimeWarningAt(run: AutomationRun, budget: AutomationRuntimeBudget):
140
131
  return run.startedAt + budget.warnAtMs;
141
132
  }
142
133
 
143
- function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Message | undefined {
134
+ async function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Promise<Message | undefined> {
144
135
  if (run.meta.runtimeBudgetWarnedAt) return undefined;
145
136
  const budget = runtimeBudgetForRun(run);
146
137
  if (!budget) return undefined;
@@ -150,7 +141,7 @@ function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Me
150
141
  const target = runtimeBudgetMessageTarget(run, task);
151
142
  if (!target) return undefined;
152
143
  const remainingMinutes = Math.max(1, Math.ceil((deadline - now) / 60_000));
153
- const message = sendMessage({
144
+ const message = (await sendMessageAsync({
154
145
  from: "system",
155
146
  to: target,
156
147
  kind: "control",
@@ -173,15 +164,15 @@ function maybeWarnRuntimeBudget(run: AutomationRun, task: Task, now: number): Me
173
164
  automationRunId: run.id,
174
165
  runtimeBudgetWarning: true,
175
166
  },
176
- });
177
- updateRun(run.id, {
167
+ }));
168
+ (await updateRunAsync(run.id, {
178
169
  meta: {
179
170
  ...run.meta,
180
171
  runtimeBudgetWarnedAt: now,
181
172
  runtimeBudgetWarningMessageId: message.id,
182
173
  runtimeBudgetDeadlineAt: deadline,
183
174
  },
184
- }, now);
175
+ }, now));
185
176
  return message;
186
177
  }
187
178
 
@@ -205,7 +196,7 @@ async function maybeFailNeverReadyOfflineTarget(run: AutomationRun, task: Task,
205
196
  },
206
197
  }, { privileged: true });
207
198
  const updatedTask = taskResult.task ?? (await getTaskAsync(task.id)) ?? task;
208
- updateRun(run.id, {
199
+ (await updateRunAsync(run.id, {
209
200
  status: "failed",
210
201
  finishedAt: now,
211
202
  error: reason,
@@ -225,7 +216,7 @@ async function maybeFailNeverReadyOfflineTarget(run: AutomationRun, task: Task,
225
216
  runtimeTargetOfflineAt: now,
226
217
  runtimeTargetNeverReady: true,
227
218
  },
228
- }, now);
219
+ }, now));
229
220
  return { run: getAutomationRun(run.id)!, task: (await getTaskAsync(task.id)) ?? updatedTask };
230
221
  }
231
222
 
@@ -251,8 +242,8 @@ async function maybeTimeoutRuntimeBudget(run: AutomationRun, task: Task, now: nu
251
242
  },
252
243
  }, { privileged: true });
253
244
  const updatedTask = taskResult.task ?? (await getTaskAsync(task.id)) ?? task;
254
- const command = requestOnDemandAgentShutdown(run, updatedTask, now, "runtime-budget-timeout");
255
- updateRun(run.id, {
245
+ const command = (await requestOnDemandAgentShutdown(run, updatedTask, now, "runtime-budget-timeout"));
246
+ (await updateRunAsync(run.id, {
256
247
  status: "timed_out",
257
248
  finishedAt: now,
258
249
  error: "Automation runtime budget elapsed",
@@ -273,7 +264,7 @@ async function maybeTimeoutRuntimeBudget(run: AutomationRun, task: Task, now: nu
273
264
  runtimeBudgetDeadlineAt: deadline,
274
265
  ...(command ? { shutdownCommandId: command.id } : {}),
275
266
  },
276
- }, now);
267
+ }, now));
277
268
  return { run: getAutomationRun(run.id)!, task: (await getTaskAsync(task.id)) ?? updatedTask, command };
278
269
  }
279
270
 
@@ -285,19 +276,19 @@ function runtimeBudgetMessageTarget(run: AutomationRun, task: Task): string | un
285
276
  return undefined;
286
277
  }
287
278
 
288
- function maybeShutdownOnDemandAgent(run: AutomationRun, task: Task, now: number): Command | undefined {
279
+ async function maybeShutdownOnDemandAgent(run: AutomationRun, task: Task, now: number): Promise<Command | undefined> {
289
280
  if (run.shutdownRequestedAt) return undefined;
290
281
  const automation = getAutomation(run.automationId);
291
282
  if (!automation || automation.targetPolicy.mode !== "on_demand_agent" || automation.targetPolicy.keepAlive) return undefined;
292
- const command = requestOnDemandAgentShutdown(run, task, now, "task-complete");
293
- if (command) updateRun(run.id, { shutdownRequestedAt: now, meta: { ...run.meta, shutdownCommandId: command.id } }, now);
283
+ const command = (await requestOnDemandAgentShutdown(run, task, now, "task-complete"));
284
+ if (command) (await updateRunAsync(run.id, { shutdownRequestedAt: now, meta: { ...run.meta, shutdownCommandId: command.id } }, now));
294
285
  return command;
295
286
  }
296
287
 
297
- function requestOnDemandAgentShutdown(run: AutomationRun, task: Task, now: number, reason: string): Command | undefined {
288
+ async function requestOnDemandAgentShutdown(run: AutomationRun, task: Task, now: number, reason: string): Promise<Command | undefined> {
298
289
  const agentId = task.claimedBy ?? run.targetAgentId ?? run.spawnedAgentId;
299
290
  if (!agentId) return undefined;
300
- return createCommand({
291
+ return (await createCommandAsync({
301
292
  type: "agent.shutdown",
302
293
  source: "automation",
303
294
  target: agentId,
@@ -310,5 +301,5 @@ function requestOnDemandAgentShutdown(run: AutomationRun, task: Task, now: numbe
310
301
  automationRunId: run.id,
311
302
  reason,
312
303
  },
313
- });
304
+ }));
314
305
  }
@@ -70,8 +70,8 @@ export function listAutomations(): Automation[] {
70
70
  .map(rowToAutomation);
71
71
  }
72
72
 
73
- export function listAutomationRuns(filter: { automationId?: string; status?: string; limit?: number } = {}): AutomationRun[] {
74
- ensureAutomationTables();
73
+ /** Listing SQL, exported so the query-plan gate pins the production statement (#3799). */
74
+ export function buildListAutomationRunsQuery(filter: { automationId?: string; status?: string; limit?: number } = {}): { sql: string; params: (string | number)[] } {
75
75
  const clauses: string[] = [];
76
76
  const params: (string | number)[] = [];
77
77
  if (filter.automationId) {
@@ -84,8 +84,13 @@ export function listAutomationRuns(filter: { automationId?: string; status?: str
84
84
  }
85
85
  const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
86
86
  params.push(filter.limit ?? 100);
87
- return (db().query(`SELECT * FROM automation_runs ${where} ORDER BY created_at DESC LIMIT ?`).all(...params) as any[])
88
- .map(rowToAutomationRun);
87
+ return { sql: `SELECT * FROM automation_runs ${where} ORDER BY created_at DESC LIMIT ?`, params };
88
+ }
89
+
90
+ export function listAutomationRuns(filter: { automationId?: string; status?: string; limit?: number } = {}): AutomationRun[] {
91
+ ensureAutomationTables();
92
+ const { sql, params } = buildListAutomationRunsQuery(filter);
93
+ return (db().query(sql).all(...params) as any[]).map(rowToAutomationRun);
89
94
  }
90
95
 
91
96
  export function getAutomationRun(id: string): AutomationRun | null {
@@ -176,25 +181,43 @@ export function cancelActiveRuns(automationId: string, now: number, reason: stri
176
181
  .run(now, reason, now, automationId, ...OPEN_RUN_STATUSES);
177
182
  }
178
183
 
184
+ /** Enabled automations whose next fire time has passed; indexed on (enabled, next_run_at). */
185
+ export const DUE_AUTOMATIONS_SQL = "SELECT * FROM automations WHERE enabled = 1 AND next_run_at IS NOT NULL AND next_run_at <= ? ORDER BY next_run_at ASC LIMIT 25";
186
+ export function listDueAutomations(now: number): Automation[] {
187
+ return (db().query(DUE_AUTOMATIONS_SQL).all(now) as any[]).map(rowToAutomation);
188
+ }
189
+
179
190
  export function rescheduleAutomation(automation: Automation, nextRunAt: number | undefined, now: number): void {
180
191
  db().query("UPDATE automations SET next_run_at = ?, updated_at = ? WHERE id = ?").run(nextRunAt ?? null, now, automation.id);
181
192
  }
182
193
 
183
194
  /** #3175 — runs whose precheck command has been dispatched but not yet settled. */
184
- export function listPendingPrecheckRuns(): AutomationRun[] {
185
- return (db().query(`
195
+ export const PENDING_PRECHECK_RUNS_SQL = `
186
196
  SELECT * FROM automation_runs
187
197
  WHERE status = 'running' AND task_id IS NULL AND json_extract(meta, '$.precheck.status') = 'running'
188
198
  ORDER BY created_at ASC LIMIT 100
189
- `).all() as any[]).map(rowToAutomationRun);
199
+ `;
200
+ export function listPendingPrecheckRuns(): AutomationRun[] {
201
+ return (db().query(PENDING_PRECHECK_RUNS_SQL).all() as any[]).map(rowToAutomationRun);
202
+ }
203
+
204
+ /** Open runs bound to a task: the reconcile pass walks these against the task's live state. */
205
+ export const RECONCILABLE_RUNS_SQL = `
206
+ SELECT * FROM automation_runs
207
+ WHERE status IN ('scheduled', 'dispatching', 'waiting_agent', 'running') AND task_id IS NOT NULL
208
+ ORDER BY created_at ASC
209
+ `;
210
+ export function listReconcilableRuns(): AutomationRun[] {
211
+ return (db().query(RECONCILABLE_RUNS_SQL).all() as any[]).map(rowToAutomationRun);
190
212
  }
191
213
 
192
214
  /** Queued runs ready to dispatch. A run whose precheck already reported hits was accepted while the
193
215
  * automation was runnable (Run now works on disabled automations), so it continues regardless. */
194
- export function listDispatchableQueuedRuns(): AutomationRun[] {
195
- return (db().query(`
216
+ export const DISPATCHABLE_QUEUED_RUNS_SQL = `
196
217
  SELECT r.* FROM automation_runs r JOIN automations a ON a.id = r.automation_id
197
218
  WHERE r.status = 'scheduled' AND (a.enabled = 1 OR json_extract(r.meta, '$.precheck.status') = 'hits')
198
219
  ORDER BY r.scheduled_for ASC LIMIT 25
199
- `).all() as any[]).map(rowToAutomationRun);
220
+ `;
221
+ export function listDispatchableQueuedRuns(): AutomationRun[] {
222
+ return (db().query(DISPATCHABLE_QUEUED_RUNS_SQL).all() as any[]).map(rowToAutomationRun);
200
223
  }
@@ -0,0 +1,33 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { getGateway } from "../db/gateway";
3
+ import type { insertAutomation, updateAutomationNormalized } from "./persistence";
4
+ import type { Automation, AutomationRun } from "../types";
5
+ import type { insertRun, enqueueAutomationRun, updateRun, cancelActiveRuns, rescheduleAutomation } from "./storage";
6
+
7
+ export function insertAutomationAsync(normalized: Parameters<typeof insertAutomation>[0], now: number): Promise<Automation> {
8
+ return getGateway().write("automations.create", { normalized, now }, { idempotencyKey: randomUUID() }) as unknown as Promise<Automation>;
9
+ }
10
+ export function updateAutomationNormalizedAsync(id: string, normalized: Parameters<typeof updateAutomationNormalized>[1], expected: Automation, now: number): Promise<Automation> {
11
+ return getGateway().write("automations.update", { id, normalized, expected, now }, { idempotencyKey: randomUUID() }) as unknown as Promise<Automation>;
12
+ }
13
+ export function deleteAutomationAsync(id: string): Promise<boolean> {
14
+ return getGateway().write("automations.delete", { id }) as unknown as Promise<boolean>;
15
+ }
16
+ export function admitAutomationRunAsync(input: { automationId: string; now: number; manual?: boolean; queuedRunId?: string }): Promise<{ automation: Automation; run: AutomationRun } | null> {
17
+ return getGateway().write("automations.admitRun", input, { idempotencyKey: randomUUID() }) as unknown as Promise<{ automation: Automation; run: AutomationRun } | null>;
18
+ }
19
+ export function insertRunAsync(...args: Parameters<typeof insertRun>): Promise<ReturnType<typeof insertRun>> {
20
+ return getGateway().write("automations.insertRun", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof insertRun>>;
21
+ }
22
+ export function enqueueAutomationRunAsync(...args: Parameters<typeof enqueueAutomationRun>): Promise<ReturnType<typeof enqueueAutomationRun>> {
23
+ return getGateway().write("automations.enqueueRun", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof enqueueAutomationRun>>;
24
+ }
25
+ export function updateRunAsync(...args: Parameters<typeof updateRun>): Promise<void> {
26
+ return getGateway().write("automations.updateRun", args, { idempotencyKey: randomUUID() }) as unknown as Promise<void>;
27
+ }
28
+ export function cancelActiveRunsAsync(...args: Parameters<typeof cancelActiveRuns>): Promise<void> {
29
+ return getGateway().write("automations.cancelRuns", args, { idempotencyKey: randomUUID() }) as unknown as Promise<void>;
30
+ }
31
+ export function rescheduleAutomationAsync(...args: Parameters<typeof rescheduleAutomation>): Promise<void> {
32
+ return getGateway().write("automations.reschedule", args, { idempotencyKey: randomUUID() }) as unknown as Promise<void>;
33
+ }
@@ -15,7 +15,7 @@ export async function announceVerifiedLand(input: BranchLandedInput, landedTask:
15
15
  const verification = input.mergedSha && input.landVerifiedSha === input.mergedSha
16
16
  ? "confirmed" : await verifyPublishedLand(workspace.repoRoot, input.mergedSha, workspace.baseRef);
17
17
  if (verification !== "confirmed") {
18
- notifyLandUnconfirmed({ workspace, sha: input.mergedSha, targetRef: base.startsWith("origin/") ? base : `origin/${base}`, kind: verification });
18
+ await notifyLandUnconfirmed({ workspace, sha: input.mergedSha, targetRef: base.startsWith("origin/") ? base : `origin/${base}`, kind: verification });
19
19
  return;
20
20
  }
21
21
  const landedBranch = workspace.branch;
@@ -47,7 +47,7 @@ export async function announceVerifiedLand(input: BranchLandedInput, landedTask:
47
47
  : " Worktree reclaimed.";
48
48
  // Durable (ttl null): the author's own branch landing must reach them even after they go
49
49
  // offline (store-ahead #234) — not a bystander notice that goes stale.
50
- const notices = routeNotification({
50
+ const notices = await routeNotification({
51
51
  type: "branch.landed",
52
52
  scope: { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
53
53
  recipients: [author],
@@ -75,7 +75,7 @@ export async function announceVerifiedLand(input: BranchLandedInput, landedTask:
75
75
  const mainScope = { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id, teamId: landedTask?.teamId ?? (author ? getAgent(author)?.teamId : undefined), coordinatorAgentIds: [...new Set([resolveCoordinatorAgentId(author), landedTask && resolveTaskOwnerAgentId(getTaskDetail(landedTask.taskId))].filter((id): id is string => !!id && !isHumanAgentId(id)))] };
76
76
  const branchLabel = landedBranch ? `\`${landedBranch}\`` : "A branch";
77
77
  const authorLabel = author ? ` by \`${author}\`` : "";
78
- const notices = routeNotification({
78
+ const notices = await routeNotification({
79
79
  type: "branch.landed",
80
80
  scope: mainScope, ...audienceWithTaskOwnerRole("branch.landed", mainScope, landedTask?.taskId), // #2862
81
81
  ttlMs: INFORMATIONAL_TTL_MS,
@@ -1,10 +1,12 @@
1
+ import { insertLandingReceiptAsync } from "./db/runtime-tail-async";
2
+ import { createActivityEventAsync } from "./db/activity-async";
1
3
  import { announceVerifiedLand } from "./branch-land-notice";
2
4
  import { errMessage, isHumanAgentId, type BaseWorktreeSyncResult } from "@humwick/sdk";
3
5
  import { emitRelayEvent } from "./events";
4
6
  import { routeNotification, INFORMATIONAL_TTL_MS } from "./notification-router";
5
7
  import { stampLifecycleSignal, taskSignalKey } from "./lifecycle-signal-registry";
6
8
  import { registerDefaultAudienceRules, audiencePredicates } from "./notification-rules";
7
- import { createActivityEvent, getAgent, getOrchestrator, getProject, getTaskDetail, insertLandingReceipt, markWorkspaceLanded, patchWorkspaceMetadataAsync, resolveProjectForCwd, updateWorkspaceStatusAsync, markWorkspaceLandedAsync} from "./db";
9
+ import { getAgent, getOrchestrator, getProject, getTaskDetail, markWorkspaceLanded, patchWorkspaceMetadataAsync, resolveProjectForCwd, updateWorkspaceStatusAsync, markWorkspaceLandedAsync } from "./db";
8
10
  import { renderTemplate } from "./prompt-resolver";
9
11
  import { resolveCoordinatorAgentId } from "./steward-identity";
10
12
  import { stewardFallbackTarget } from "./config";
@@ -209,9 +211,9 @@ function landedNotificationIdempotencyKey(input: BranchLandedInput, landedTask:
209
211
  * the announcement; this combined entry preserves the original all-synchronous behavior for the
210
212
  * maintenance reconcile path (reconcileLandedWorkspace) and direct callers/tests.
211
213
  */
212
- export function notifyBranchLanded(input: BranchLandedInput): void {
213
- recordLandingReceipt(input);
214
- announceBranchLanded(input);
214
+ export async function notifyBranchLanded(input: BranchLandedInput): Promise<void> {
215
+ (await recordLandingReceipt(input));
216
+ await announceBranchLanded(input);
215
217
  }
216
218
 
217
219
  /**
@@ -222,7 +224,7 @@ export function notifyBranchLanded(input: BranchLandedInput): void {
222
224
  * row with no receipt. The branch is already landed, so a receipt failure is loud (CRITICAL log) but
223
225
  * can never unwind or mask it.
224
226
  */
225
- export function recordLandingReceipt(input: BranchLandedInput): void {
227
+ export async function recordLandingReceipt(input: BranchLandedInput): Promise<void> {
226
228
  const { workspace } = input;
227
229
  // #1620 — a land that introduced ZERO commits is not a land: no receipt (see announceBranchLanded).
228
230
  if (input.landedCommitCount === 0) return;
@@ -237,7 +239,7 @@ export function recordLandingReceipt(input: BranchLandedInput): void {
237
239
  const mergedSha = cleanRef(input.mergedSha);
238
240
  const commitShas = [...new Set((input.commitShas ?? []).map(cleanRef).filter((sha): sha is string => Boolean(sha)))];
239
241
  if (commitShas.length === 0 && mergedSha) commitShas.push(mergedSha);
240
- insertLandingReceipt({
242
+ (await insertLandingReceiptAsync({
241
243
  ...(landedTask?.projectId ?? project?.id ? { projectId: landedTask?.projectId ?? project!.id } : {}),
242
244
  repo: landedTask?.repo ?? project?.issueRepo ?? repoFromGitRemote(workspace.repoRoot) ?? workspace.repoRoot,
243
245
  ref: workspace.baseRef ?? "base",
@@ -253,7 +255,7 @@ export function recordLandingReceipt(input: BranchLandedInput): void {
253
255
  ...(landedTask?.teamId ?? worker?.teamId ? { teamId: landedTask?.teamId ?? worker!.teamId } : {}),
254
256
  ...(workspace.orchestratorId ? { orchestratorId: workspace.orchestratorId } : {}),
255
257
  ...(orchestrator?.hostname ?? worker?.machine ?? worker?.rig ? { host: orchestrator?.hostname ?? worker?.machine ?? worker!.rig } : {}),
256
- });
258
+ }));
257
259
  } catch (error) {
258
260
  console.error(`[landing-receipt] CRITICAL: failed to persist landed branch ${workspace.id}: ${errMessage(error)}`);
259
261
  }
@@ -265,7 +267,7 @@ export function recordLandingReceipt(input: BranchLandedInput): void {
265
267
  * the issue/Task lifecycle drives. #1790 — the settle path DEFERS this off its synchronous critical
266
268
  * path; the durable receipt is recorded separately + synchronously by {@link recordLandingReceipt}.
267
269
  */
268
- export function announceBranchLanded(input: BranchLandedInput): void {
270
+ export async function announceBranchLanded(input: BranchLandedInput): Promise<void> {
269
271
  const { workspace } = input;
270
272
  const base = workspace.baseRef ?? "base";
271
273
  // #1620 — a land that introduced ZERO commits is not a land. It happens when a reconciliation
@@ -365,10 +367,10 @@ export function announceBranchLanded(input: BranchLandedInput): void {
365
367
  * the checkout. Human WIP is never auto-clobbered; `preservedWipPaths` flags paths to merge by
366
368
  * hand rather than blind-restore.
367
369
  */
368
- export function notifyBaseWorktreeStrand(input: {
370
+ export async function notifyBaseWorktreeStrand(input: {
369
371
  workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "ownerAgentId">;
370
372
  sync: BaseWorktreeSyncResult;
371
- }): void {
373
+ }): Promise<void> {
372
374
  const { workspace, sync } = input;
373
375
  if (sync.reconciled) return;
374
376
  const base = workspace.baseRef ?? "base";
@@ -397,7 +399,7 @@ export function notifyBaseWorktreeStrand(input: {
397
399
 
398
400
  emitRelayEvent({ type: "workspace.base_checkout_strand", source: "server", subject: workspace.id, data: payload });
399
401
 
400
- createActivityEvent({
402
+ (await createActivityEventAsync({
401
403
  clientId: `workspace-base-strand-${workspace.id}-${Date.now()}`,
402
404
  kind: "state",
403
405
  title: "Base checkout stranded after land (mixed state)",
@@ -406,13 +408,13 @@ export function notifyBaseWorktreeStrand(input: {
406
408
  icon: "ti-alert-octagon",
407
409
  view: "orchestrators",
408
410
  metadata: { source: "server", maintenanceJobId: "workspace-base-strand", workspaceId: workspace.id, repoRoot: workspace.repoRoot, unsyncedPaths: unsynced, preservedWipPaths: preservedWip },
409
- });
411
+ }));
410
412
 
411
413
  // Durable (ttl null) push to the owner and its coordinator — whoever works in the shared
412
414
  // checkout must learn it's stale before acting on it. Fallback steward covers a teamless land.
413
415
  const recipients = [...new Set([owner, coordinator, fallback].filter((r): r is string => Boolean(r)))];
414
416
  if (recipients.length) {
415
- routeNotification({
417
+ await routeNotification({
416
418
  type: "workspace.base_checkout_strand",
417
419
  scope: { author: owner, parent: coordinator ?? undefined, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
418
420
  recipients,
@@ -432,12 +434,12 @@ export function notifyBaseWorktreeStrand(input: {
432
434
  * steward-task/conflict pings: it tells the worker that its post-ready idle wait ended without
433
435
  * a completed land, so it can inspect/report instead of silently staying parked forever.
434
436
  */
435
- export function notifyBranchLandFailed(input: {
437
+ export async function notifyBranchLandFailed(input: {
436
438
  workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "ownerAgentId">;
437
439
  commandId?: string;
438
440
  recipients?: string[];
439
441
  reason?: string;
440
- }): void {
442
+ }): Promise<void> {
441
443
  const { workspace } = input;
442
444
  const base = workspace.baseRef ?? "base";
443
445
  const author = workspace.ownerAgentId;
@@ -464,7 +466,7 @@ export function notifyBranchLandFailed(input: {
464
466
  const recipients = withWorkspaceTaskOwnerRoles(input.recipients ?? [author, coordinator], workspace); // #2862
465
467
  if (!recipients.length) return;
466
468
  const branchLabel = workspace.branch ? `\`${workspace.branch}\`` : "Your branch";
467
- routeNotification({
469
+ await routeNotification({
468
470
  type: "landed-failure",
469
471
  scope: { author, parent: coordinator ?? undefined, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
470
472
  recipients,
@@ -494,7 +496,7 @@ export { notifyLandGateFailed, notifyLandGateWarnings, notifyLandGateSkipped } f
494
496
  * The steward id is the managed steward's policy name (reachable via `policy:<name>`) or an
495
497
  * elected steward's agent id, whichever the caller has in scope.
496
498
  */
497
- export function notifyStewardHandoff(input: {
499
+ export async function notifyStewardHandoff(input: {
498
500
  workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "ownerAgentId">;
499
501
  /** The steward now holding the merge — managed steward policy name or elected agent id. */
500
502
  stewardId: string;
@@ -502,7 +504,7 @@ export function notifyStewardHandoff(input: {
502
504
  coordinatorAgentId?: string | null;
503
505
  /** Why it was handed over ("conflict", "merge state unknown", auto-merge back-off, …). */
504
506
  reason?: string;
505
- }): void {
507
+ }): Promise<void> {
506
508
  const { workspace } = input;
507
509
  const base = workspace.baseRef ?? "base";
508
510
  const owner = workspace.ownerAgentId;
@@ -527,7 +529,7 @@ export function notifyStewardHandoff(input: {
527
529
  // thinking the branch silently failed. Durable (ttl null): the owner must learn this
528
530
  // even if it went idle. Mirror the "don't touch main" guardrail of the landed-failure wake.
529
531
  if (owner) {
530
- routeNotification({
532
+ await routeNotification({
531
533
  type: "workspace.steward_handoff",
532
534
  scope: { author: owner, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
533
535
  recipients: [owner],
@@ -550,7 +552,7 @@ export function notifyStewardHandoff(input: {
550
552
  // (it spawned the branch agent and owns the merge landing). Skip when the coordinator IS
551
553
  // the owner (no real lineage) to avoid a duplicate ping.
552
554
  if (coordinator && coordinator !== owner) {
553
- routeNotification({
555
+ await routeNotification({
554
556
  type: "workspace.steward_handoff",
555
557
  scope: { author: owner, parent: coordinator, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
556
558
  recipients: [coordinator],
@@ -671,7 +673,7 @@ export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: Wor
671
673
  const closure = ownerAlive
672
674
  ? `owner \`${ws.ownerAgentId}\` is still running, so the workspace stays non-terminal and usable at ${nextStatus}${nextStatus === ws.status ? "" : ` (was ${ws.status} — out of the land queue, #1662)`} (#1631); steward/strand and no-progress bookkeeping cleared`
673
675
  : `marking merged${landedCommitCount === 0 ? "; nothing was landed" : ""}`;
674
- createActivityEvent({
676
+ (await createActivityEventAsync({
675
677
  clientId: "server-workspace-" + ws.id + "-merged-" + Date.now(),
676
678
  kind: "state",
677
679
  title: ownerAlive
@@ -682,9 +684,9 @@ export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: Wor
682
684
  icon: "ti-git-merge",
683
685
  view: "orchestrators",
684
686
  metadata: { source: "server", maintenanceJobId: "workspace-conflict-scan", workspaceId: ws.id, fromStatus: ws.status, toStatus: nextStatus, ...(ownerAlive ? { ownerAlive: true, keptLive: true } : {}), ...(sha ? { landedSha: sha } : {}), ...(landedCommitCount === 0 ? { landedCommitCount: 0 } : {}) },
685
- });
687
+ }));
686
688
  try {
687
- notifyBranchLanded({ workspace: ws, mergedSha: sha, landVerifiedSha, landedTipSha: sha, commitShas: sha ? [sha] : [], pushed: true, prLand: preview.prMerged === true, ...(landedCommitCount === 0 ? { landedCommitCount } : {}) });
689
+ await notifyBranchLanded({ workspace: ws, mergedSha: sha, landVerifiedSha, landedTipSha: sha, commitShas: sha ? [sha] : [], pushed: true, prLand: preview.prMerged === true, ...(landedCommitCount === 0 ? { landedCommitCount } : {}) });
688
690
  } catch {
689
691
  // Notification is best-effort; the status change + activity event still stand.
690
692
  }
package/src/bus.ts CHANGED
@@ -11,7 +11,7 @@ import { announceSpawnedAgentReady, registerAgent } from "./services/register-ag
11
11
  import { authContextFromBus } from "./services/auth-context";
12
12
  import { commandAuthorizationResource, dispatchCommandAsync } from "./services/dispatch-command";
13
13
  import { withRelayEventDrain } from "./relay-event-drain";
14
- import { runAsCaller } from "./hub-metrics";
14
+ import { framed, runAsCaller } from "./hub-metrics";
15
15
  import { auditProviderStateTransition } from "./services/provider-state-audit";
16
16
  import { agentProviderTimelineEvent, auditRunnerTimelineEvent } from "./provider-timeline-event";
17
17
  import { auditProviderTurnEmpty, auditProviderTurnWatchdog, auditReconciledProviderTurn } from "./services/turn-reconcile-audit";
@@ -19,6 +19,7 @@ import { ServiceAuthError } from "./services/errors";
19
19
  import { ShutdownAuthError, ShutdownTargetError, shutdownAgent, shutdownInputFromBusFrame } from "./services/shutdown-agent";
20
20
  import { flushQueuedDirectMessages } from "./services/managed-running";
21
21
  import { updateCommandFromBus } from "./services/bus-command-update";
22
+ import { heartbeatFromBus } from "./services/agent-heartbeat";
22
23
  import { isAgentUnavailable, reservedAgentIdSql } from "./db/agent-predicates";
23
24
  import { messageMatchesAgent, targetMatchesAgent } from "./agent-ref";
24
25
  import { probeWorkspaceOnTurnEnd } from "./workspace-probe";
@@ -76,7 +77,7 @@ const liveBusSocketIds = new Set<string>();
76
77
  // stalls unrelated agents.
77
78
  const busFrameQueues = new Map<string, Promise<void>>();
78
79
 
79
- subscribeRelayEvents((event) => broadcastRelayEvent(event));
80
+ subscribeRelayEvents(broadcastRelayEvent);
80
81
 
81
82
  export function handleBusUpgrade(req: Request, server: Server<BusSocketData>): Response | undefined {
82
83
  if (!isOriginAllowed(req)) {
@@ -95,11 +96,11 @@ export function handleBusUpgrade(req: Request, server: Server<BusSocketData>): R
95
96
  return undefined;
96
97
  }
97
98
 
98
- export function busHandleOpen(ws: BusWebSocket): void {
99
+ export const busHandleOpen = framed("WS open", (ws: BusWebSocket): void => {
99
100
  liveBusSocketIds.add(ws.data.id);
100
101
  // Registration is explicit. The socket is not visible to projections until
101
102
  // a valid register frame establishes identity and subscriptions.
102
- }
103
+ });
103
104
 
104
105
  export function busHandleMessage(ws: BusWebSocket, data: string | Buffer): void {
105
106
  if (!liveBusSocketIds.has(ws.data.id)) return;
@@ -127,7 +128,7 @@ export function busHandleMessage(ws: BusWebSocket, data: string | Buffer): void
127
128
  busFrameQueues.set(ws.data.id, queued);
128
129
  }
129
130
 
130
- export function busHandleClose(ws: BusWebSocket): void {
131
+ export const busHandleClose = framed("WS close", (ws: BusWebSocket): void => {
131
132
  liveBusSocketIds.delete(ws.data.id);
132
133
  busFrameQueues.delete(ws.data.id);
133
134
  const conn = busConnections.get(ws.data.id);
@@ -145,7 +146,7 @@ export function busHandleClose(ws: BusWebSocket): void {
145
146
  });
146
147
  }
147
148
  }
148
- }
149
+ });
149
150
 
150
151
  export function getBusConnectionCount(): number {
151
152
  return busConnections.size;
@@ -210,7 +211,7 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
210
211
  // #416 — flush queued messages if the agent transitioned from unavailable to available.
211
212
  if (wasUnavailable) {
212
213
  const after = getAgent(conn.agentId);
213
- if (after && !isAgentUnavailable(after)) flushQueuedDirectMessages(conn.agentId);
214
+ if (after && !isAgentUnavailable(after)) (await flushQueuedDirectMessages(conn.agentId));
214
215
  }
215
216
  }
216
217
  }
@@ -249,27 +250,27 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
249
250
  const after = applied.after;
250
251
  await auditProviderStateTransition(conn.agentId, before, after);
251
252
  const timelineEvent = agentProviderTimelineEvent(after);
252
- auditRunnerTimelineEvent(conn.agentId, timelineEvent);
253
+ (await auditRunnerTimelineEvent(conn.agentId, timelineEvent));
253
254
  // #1621 — a turn the runner proved was cancelled out of band is a real state change the
254
255
  // waiting coordinator has to hear about, not just an activity-feed row.
255
- auditReconciledProviderTurn(conn.agentId, after, timelineEvent);
256
+ await auditReconciledProviderTurn(conn.agentId, after, timelineEvent);
256
257
  // #1980 — the busy backstop is HOLDING a long turn it can't prove idle (not cancelling);
257
258
  // tell the waiting coordinator the turn is still live rather than leaving it to guess.
258
259
  // #2010 — but only when there's no positive busy evidence already saying so (see the
259
260
  // busy-health gate inside auditProviderTurnWatchdog); a demonstrably working agent needs
260
261
  // no wake.
261
- auditProviderTurnWatchdog(conn.agentId, after, timelineEvent);
262
+ await auditProviderTurnWatchdog(conn.agentId, after, timelineEvent);
262
263
  // #2389 — a turn that ended clean and produced nothing is the least visible failure of the
263
264
  // three: the card reads healthy and idle. Tell the parent once the runner's own nudge has
264
265
  // failed to recover it.
265
- auditProviderTurnEmpty(conn.agentId, after, timelineEvent);
266
+ await auditProviderTurnEmpty(conn.agentId, after, timelineEvent);
266
267
  // #2432 — a first ready that arrives over a status frame (children whose register kept the
267
268
  // row not-ready, e.g. ox/opencode builders) must stamp readiness exactly like the HTTP and
268
269
  // registration seams, or the child later reaps as a false `agent.spawn_failed`.
269
- if (readyTransition) announceSpawnedAgentReady(conn.agentId, "bus-ready");
270
+ if (readyTransition) await announceSpawnedAgentReady(conn.agentId, "bus-ready");
270
271
  // A parked continuation consumes one retry on a genuine ready/idle transition only.
271
272
  const replayEpoch = continuationReplayEpoch(conn, before, after);
272
- if (replayEpoch) replayParkedContinuationInjections(conn.agentId, replayEpoch);
273
+ if (replayEpoch) (await replayParkedContinuationInjections(conn.agentId, replayEpoch));
273
274
  // A real PreCompact/SessionStart hook arrives as a timelineEvent in the
274
275
  // merged meta — clears any pending stall watch (stale events ignored).
275
276
  noteAgentTimelineEvent(conn.agentId, timelineEvent);
@@ -279,7 +280,7 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
279
280
  // #633 — silent clean-exit: a runner that stays alive after its provider terminally exited
280
281
  // marks the offline edge with `terminalProviderExit`; the owning service turns that into a
281
282
  // terminal event + #636 diagnosis (and clears the hold on a genuine resume).
282
- reconcileTerminalProviderExit(conn.agentId, before, after);
283
+ await reconcileTerminalProviderExit(conn.agentId, before, after);
283
284
  });
284
285
  return;
285
286
  case "ack":
@@ -305,8 +306,9 @@ async function handleCommandFrame(
305
306
  target: string,
306
307
  params: Record<string, unknown>,
307
308
  ): Promise<void> {
309
+ if (commandType === "agent.heartbeat") return withRelayEventDrain(() => heartbeatFromBus(conn, target, params)).then((o) => sendCommandResult(ws, frameId, o.status, o.result, o.error));
308
310
  if (commandType === "command.update") {
309
- return withRelayEventDrain(() => updateCommandFromBus({ target, params, componentAuth: conn.componentAuth }))
311
+ return withRelayEventDrain(async () => (await updateCommandFromBus({ target, params, componentAuth: conn.componentAuth })))
310
312
  .then((result) => sendCommandResult(ws, frameId, result.status, result.result, result.error))
311
313
  .catch((error) => sendError(ws, frameId, "FRAME_FAILED", errMessage(error)));
312
314
  }
@@ -333,10 +335,10 @@ async function handleCommandFrame(
333
335
  // busCommandAuthorized gate), createCommand, and the "command.requested" emit. The bus
334
336
  // adapter only translates the typed ServiceAuthError into a rejected result frame.
335
337
  try {
336
- const command = await withRelayEventDrain(() => dispatchCommandAsync(
338
+ const command = await withRelayEventDrain(async () => (await dispatchCommandAsync(
337
339
  { type: commandType, source: conn.agentId ?? conn.componentId, target, params },
338
340
  authContextFromBus(conn.componentAuth),
339
- ));
341
+ )));
340
342
  sendCommandResult(ws, frameId, "succeeded", { command });
341
343
  } catch (e) {
342
344
  if (e instanceof ServiceAuthError) {
@@ -385,7 +387,7 @@ async function handleRegister(ws: BusWebSocket, frame: RegisterFrame): Promise<v
385
387
  ...(lifecycle === "transient" || lifecycle === "persistent" ? { lifecycle } : {}),
386
388
  meta: payload.meta,
387
389
  };
388
- const agent = registerAgent(input, authContextFromBus(ws.data.componentAuth), { emitStatus: false });
390
+ const agent = await registerAgent(input, authContextFromBus(ws.data.componentAuth), { emitStatus: false });
389
391
  epoch = agent.epoch;
390
392
  }
391
393
 
@@ -429,7 +431,7 @@ async function handleRegister(ws: BusWebSocket, frame: RegisterFrame): Promise<v
429
431
  epoch,
430
432
  cursor: getOutboxCursor(),
431
433
  sessionId: ws.data.id,
432
- features: { heartbeatAck: true },
434
+ features: { heartbeatAck: true, liveness: true },
433
435
  },
434
436
  });
435
437
  }