@humwick/server 0.130.2 → 0.130.4

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 (587) 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 +175 -4
  8. package/package.json +8 -7
  9. package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-BOkmEvgZ.js} +2 -2
  10. package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-BkaDJp0r.js} +2 -2
  11. package/public/assets/{TraceView-Wimm0Czv.js → TraceView-B99Uu2yT.js} +2 -2
  12. package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DUIfTTFF.js} +2 -2
  13. package/public/assets/{activity-CrSurn-r.js → activity-ZIX0N1El.js} +2 -2
  14. package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-kq9TPYFw.js} +2 -2
  15. package/public/assets/agent-liveness-DSQY1Aa_.js +2 -0
  16. package/public/assets/{agent-name-DKbiIhBo.js → agent-name-C_7F4DFR.js} +2 -2
  17. package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-BNOcrGcY.js} +2 -2
  18. package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-B6yAh70a.js} +2 -2
  19. package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-CcrhmOzF.js} +2 -2
  20. package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CXSLrKiq.js} +2 -2
  21. package/public/assets/{agents-B-v66C-4.js → agents-DIZG97_X.js} +2 -2
  22. package/public/assets/{analytics-BqCb-LKi.js → analytics-rasmoPjR.js} +2 -2
  23. package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-tBpTrEPb.js} +2 -2
  24. package/public/assets/{artifacts-DJevXcvg.js → artifacts-BNkrynP1.js} +2 -2
  25. package/public/assets/{artifacts-D32zyw4Y.js → artifacts-Bjq-ZyBA.js} +2 -2
  26. package/public/assets/{automation-BpRajx_5.js → automation-Cx422L3L.js} +2 -2
  27. package/public/assets/{backlog-D_UjTdzX.js → backlog-RuFQ8PUu.js} +2 -2
  28. package/public/assets/{busy-health-N3VEh4ao.js → busy-health-BvNQ9g5x.js} +2 -2
  29. package/public/assets/{channels-9jopungq.js → channels-DNbKAS0I.js} +2 -2
  30. package/public/assets/{chat-CSXrTB3C.js → chat-Bp3Fx73h.js} +3 -3
  31. package/public/assets/{code-preview-p1NnmqK0.js → code-preview-KIRZA6cz.js} +2 -2
  32. package/public/assets/{connectors-CZdqlDNL.js → connectors-k7vO4vvc.js} +2 -2
  33. package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BuVoq1aw.js} +2 -2
  34. package/public/assets/{crate-agent-30aXTKva.js → crate-agent-irqlt4NH.js} +2 -2
  35. package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-D_rurNBz.js} +2 -2
  36. package/public/assets/{deploys-DoN6bAb5.js → deploys-yzZqIpxE.js} +2 -2
  37. package/public/assets/{display-BrKWFGJz.js → display-BemJG1f_.js} +2 -2
  38. package/public/assets/{files-D6XEu8Ng.js → files-DXWcrxOz.js} +2 -2
  39. package/public/assets/{fleet-C7jQWbw2.js → fleet-TEuOCZXE.js} +2 -2
  40. package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BGoDAFI-.js} +2 -2
  41. package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-BB9eq9nN.js} +2 -2
  42. package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-qy2nTD_1.js} +3 -3
  43. package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-BGPHxuwT.js} +2 -2
  44. package/public/assets/{index-CRHep3M9.js → index-BC5XZc0z.js} +5 -5
  45. package/public/assets/{index-MYAIwYTX.css → index-D8Rp9pz2.css} +1 -1
  46. package/public/assets/{insights-CzrtkpOE.js → insights-C-KQG0h-.js} +2 -2
  47. package/public/assets/{integrations-aVsUmigt.js → integrations-ClPRPyKU.js} +2 -2
  48. package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-DbH8J9Ak.js} +2 -2
  49. package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-PH4zVn24.js} +2 -2
  50. package/public/assets/{maintenance-NfjqFZAk.js → maintenance-5lV43uTL.js} +2 -2
  51. package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-BdgU35aX.js} +2 -2
  52. package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-DNT4OUwQ.js} +3 -3
  53. package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CnCcPy0A.js} +2 -2
  54. package/public/assets/{memory-DNsCl6UX.js → memory--GgWH1gH.js} +2 -2
  55. package/public/assets/{messages-DopU1L1X.js → messages-CzFl_97O.js} +2 -2
  56. package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-CVvJVkzv.js} +2 -2
  57. package/public/assets/overview-DsrZvE86.js +2 -0
  58. package/public/assets/{pairs-DE_m6rrE.js → pairs-D2d0d2py.js} +2 -2
  59. package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-_SMuSbYF.js} +2 -2
  60. package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-Apn15y43.js} +2 -2
  61. package/public/assets/{projects-Br2Bd2h1.js → projects-D3B6kto5.js} +2 -2
  62. package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-DnPB6Ez6.js} +2 -2
  63. package/public/assets/provider-display-bWwiuedV.js +2 -0
  64. package/public/assets/{registry-Cw38_6gW.js → registry-D790cIhN.js} +2 -2
  65. package/public/assets/run-card-BCro-Odj.js +2 -0
  66. package/public/assets/{secrets-DxI-vzSq.js → secrets-CVXvfvbU.js} +2 -2
  67. package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-D3Xxqb9w.js} +2 -2
  68. package/public/assets/{settings-CKZTVGIx.js → settings-CoUC7Jci.js} +2 -2
  69. package/public/assets/shipping-D_Lp9n_J.js +2 -0
  70. package/public/assets/{stats-DyUBKyWI.js → stats-CXiNjB9S.js} +2 -2
  71. package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-C703YIy1.js} +2 -2
  72. package/public/assets/store-BgDALGIX.js +9 -0
  73. package/public/assets/{tasks-Bh7Chr4-.js → tasks-DO0WpJCx.js} +2 -2
  74. package/public/assets/{teams-bowI7qVY.js → teams-FGkdi_tL.js} +2 -2
  75. package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-Dh8dSC7e.js} +3 -3
  76. package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-B5Zriip3.js} +2 -2
  77. package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-CRUVDvLC.js} +2 -2
  78. package/public/assets/{use-decisions-samMQhQf.js → use-decisions-CoaqRh4l.js} +2 -2
  79. package/public/assets/{use-project-list-59LheVP7.js → use-project-list-X-BgT53X.js} +2 -2
  80. package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-0X_UZkk-.js} +2 -2
  81. package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-CkLhVBGu.js} +2 -2
  82. package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-BkTi7eim.js} +2 -2
  83. package/public/assets/{work-queue-CSvpuNLz.js → work-queue-DDOLEyKo.js} +2 -2
  84. package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-CzOsB8BM.js} +2 -2
  85. package/public/assets/{workflows-DdmxRSyg.js → workflows-DJilvmRM.js} +2 -2
  86. package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CHcfbLR3.js} +2 -2
  87. package/public/cosmos.html +4 -4
  88. package/public/index.html +29 -29
  89. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  90. package/runner/src/adapters/claude-api.ts +1 -1
  91. package/runner/src/adapters/claude-headless.ts +1 -1
  92. package/runner/src/adapters/claude-launch-exit.ts +26 -0
  93. package/runner/src/adapters/claude-session-probe.ts +1 -1
  94. package/runner/src/adapters/claude-tmux.ts +38 -10
  95. package/runner/src/adapters/claude.ts +28 -75
  96. package/runner/src/adapters/provider-quota-harvest.ts +20 -71
  97. package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
  98. package/runner/src/agent-runner/liveness-exchange.ts +104 -0
  99. package/runner/src/claude-system-prompt.ts +49 -0
  100. package/runner/src/launch-assembly.ts +14 -10
  101. package/runner/src/profile-home.ts +1 -1
  102. package/runner/src/project-instructions.ts +2 -2
  103. package/runner/src/provider-command.ts +18 -0
  104. package/runner/src/provider-setup.ts +3 -2
  105. package/runner/src/runner-core.ts +14 -15
  106. package/runner/src/runner-helpers.ts +0 -8
  107. package/runner/src/session-scratch.ts +6 -2
  108. package/runner/test-support/provisioning-context.ts +4 -2
  109. package/runner/test-support/runner-harness.ts +2 -1
  110. package/scripts/steward-policy-cleanup.ts +2 -2
  111. package/src/agent-authz.ts +2 -2
  112. package/src/agent-drive-arbiter.ts +3 -8
  113. package/src/agent-exit-cleanup-async.ts +2 -2
  114. package/src/agent-exit-cleanup.ts +23 -19
  115. package/src/agent-lifecycle-events.ts +112 -85
  116. package/src/agent-ref.ts +3 -2
  117. package/src/agent-status-events.ts +43 -14
  118. package/src/auth/login-link.ts +35 -0
  119. package/src/auth/password.ts +4 -3
  120. package/src/auth/session-refresh.ts +1 -1
  121. package/src/auth/session.test-fixture.ts +2 -2
  122. package/src/auth/session.ts +7 -7
  123. package/src/automations/crud.ts +8 -81
  124. package/src/automations/dispatch.ts +33 -58
  125. package/src/automations/index.ts +1 -1
  126. package/src/automations/persistence.ts +65 -0
  127. package/src/automations/precheck.ts +18 -16
  128. package/src/automations/read-async.ts +11 -0
  129. package/src/automations/reconcile.ts +30 -39
  130. package/src/automations/storage.ts +33 -10
  131. package/src/automations/write-async.ts +33 -0
  132. package/src/branch-land-notice.ts +3 -3
  133. package/src/branch-landed.ts +25 -23
  134. package/src/bus.ts +21 -19
  135. package/src/cd-deploy-notify.ts +2 -2
  136. package/src/ci/notifications.ts +4 -4
  137. package/src/ci/root-missing.ts +3 -3
  138. package/src/ci/transition-notify.ts +5 -5
  139. package/src/claude-app/oauth-http.ts +3 -3
  140. package/src/cli/index.ts +7 -1
  141. package/src/cli/init.ts +53 -0
  142. package/src/cli/orchestrator.ts +1 -7
  143. package/src/cli/setup.ts +6 -4
  144. package/src/cli/workflow.ts +12 -3
  145. package/src/commands-db.ts +4 -4
  146. package/src/commands-write.ts +8 -0
  147. package/src/compaction-watch.ts +10 -8
  148. package/src/config-store-write.ts +2 -2
  149. package/src/config.ts +4 -11
  150. package/src/connectors.ts +10 -8
  151. package/src/context-advisory.ts +22 -21
  152. package/src/db/agent-action-write.ts +36 -0
  153. package/src/db/agent-control-async.ts +9 -0
  154. package/src/db/agent-control-write.ts +49 -0
  155. package/src/db/agent-effort-observe.ts +22 -0
  156. package/src/db/agent-meta.ts +14 -3
  157. package/src/db/agents-async.ts +8 -5
  158. package/src/db/agents.ts +15 -12
  159. package/src/db/auth-identities.ts +2 -2
  160. package/src/db/automation-read-ops.ts +11 -0
  161. package/src/db/automation-write-ops.ts +46 -0
  162. package/src/db/blackboard.ts +2 -2
  163. package/src/db/browser-session-write.ts +32 -0
  164. package/src/db/bus-outbox-write-ops.ts +3 -1
  165. package/src/db/checkout-refresh-schema.ts +47 -0
  166. package/src/db/checkout-refresh.ts +5 -5
  167. package/src/db/command-agent-profile-backfill.ts +39 -0
  168. package/src/db/command-agent-profiles.ts +5 -1
  169. package/src/db/command-retention.ts +126 -0
  170. package/src/db/commands-planner-stats.test-fixture.ts +8 -0
  171. package/src/db/commands-read-ops.ts +16 -0
  172. package/src/db/connection.ts +1 -182
  173. package/src/db/context-carry-write.ts +74 -0
  174. package/src/db/continuations.ts +4 -4
  175. package/src/db/db-error-registry.ts +12 -0
  176. package/src/db/gateway.ts +26 -133
  177. package/src/db/history-retention-ops.ts +13 -0
  178. package/src/db/inbox-async.ts +2 -2
  179. package/src/db/inbox-read-ops.ts +1 -1
  180. package/src/db/inbox.ts +9 -3
  181. package/src/db/issue-associations.ts +2 -2
  182. package/src/db/issue-refs-async.ts +4 -1
  183. package/src/db/issue-refs-read-ops.ts +6 -0
  184. package/src/db/issue-refs.ts +8 -8
  185. package/src/db/kernel-event-log-schema.ts +2 -0
  186. package/src/db/land-boundaries.ts +51 -5
  187. package/src/db/land-gate-attestations.ts +2 -2
  188. package/src/db/landing-receipts.ts +2 -2
  189. package/src/db/lifecycle-context-write.ts +5 -0
  190. package/src/db/lifecycle-tail-async.ts +76 -0
  191. package/src/db/lifecycle-tail-write-ops.ts +62 -0
  192. package/src/db/lifecycle-write-window.ts +2 -1
  193. package/src/db/lineage-pair-dedupe-sql.ts +3 -3
  194. package/src/db/main-connection-mode.ts +11 -0
  195. package/src/db/main-connection-writes.ts +20 -2
  196. package/src/db/maintenance-job-runs-async.ts +2 -2
  197. package/src/db/maintenance-job-write-ops.ts +1 -1
  198. package/src/db/maintenance-pauses.ts +2 -2
  199. package/src/db/message-send.ts +4 -0
  200. package/src/db/messages.ts +31 -25
  201. package/src/db/migrations.ts +18 -1
  202. package/src/db/notification-write-ops.ts +19 -0
  203. package/src/db/operator-answer-write.ts +19 -0
  204. package/src/db/orchestrators.ts +10 -4
  205. package/src/db/pairs-async.ts +22 -1
  206. package/src/db/pairs-write-ops.ts +8 -3
  207. package/src/db/pairs.ts +41 -48
  208. package/src/db/plan-dispatch-schema.ts +5 -1
  209. package/src/db/plan-ready-notices.ts +43 -0
  210. package/src/db/plan-tools-include-migration.ts +36 -0
  211. package/src/db/plans-write-ops.ts +2 -0
  212. package/src/db/presence-buffer.ts +5 -0
  213. package/src/db/presence-loop.ts +18 -23
  214. package/src/db/presence-write.ts +0 -6
  215. package/src/db/project-entries-async.ts +14 -0
  216. package/src/db/project-entries-read-ops.ts +5 -1
  217. package/src/db/project-entries-write-ops.ts +8 -0
  218. package/src/db/project-entries.ts +15 -12
  219. package/src/db/project-journal.ts +2 -2
  220. package/src/db/project-trust-approvals.ts +2 -2
  221. package/src/db/prompt-templates.ts +4 -4
  222. package/src/db/read-op-marshaling-fixtures.ts +18 -0
  223. package/src/db/read-ops.ts +4 -0
  224. package/src/db/retention.ts +13 -2
  225. package/src/db/review-publish-write.ts +8 -0
  226. package/src/db/runtime-admin-async.ts +19 -0
  227. package/src/db/runtime-admin-write-ops.ts +36 -0
  228. package/src/db/runtime-tail-async.ts +288 -0
  229. package/src/db/runtime-tail-write-ops.ts +97 -0
  230. package/src/db/schema.ts +4 -1
  231. package/src/db/spawn-budget.ts +5 -0
  232. package/src/db/spawn-delegation.ts +3 -12
  233. package/src/db/sql-audit-indexes.ts +3 -0
  234. package/src/db/stats-async.ts +5 -3
  235. package/src/db/task-entity.ts +5 -4
  236. package/src/db/team-claim-policy.ts +60 -0
  237. package/src/db/teams-async.ts +4 -0
  238. package/src/db/teams-write-ops.ts +4 -0
  239. package/src/db/terminal-events.ts +15 -0
  240. package/src/db/timer-cutover-bodies.ts +292 -0
  241. package/src/db/timer-cutover-core.ts +37 -278
  242. package/src/db/timer-cutover-state.ts +40 -0
  243. package/src/db/timer-cutover-write-ops.ts +1 -40
  244. package/src/db/token-db-write-ops.ts +2 -0
  245. package/src/db/token-standing-async.ts +12 -0
  246. package/src/db/token-standing.ts +6 -9
  247. package/src/db/token-usage-retention.ts +33 -0
  248. package/src/db/token-usage-write-ops.ts +1 -1
  249. package/src/db/token-usage.ts +4 -1
  250. package/src/db/user-invites-async.ts +13 -0
  251. package/src/db/user-invites.ts +3 -3
  252. package/src/db/users.ts +14 -6
  253. package/src/db/workflow-execution.ts +3 -3
  254. package/src/db/workspaces.ts +8 -5
  255. package/src/db/write-ops.ts +31 -12
  256. package/src/db/writer-fault-seam.ts +2 -9
  257. package/src/db/writer-fault-test-ops.ts +18 -0
  258. package/src/db/writer-gateway.ts +42 -46
  259. package/src/dev.ts +12 -16
  260. package/src/event-loop-lag.ts +4 -2
  261. package/src/event-loop-yield.ts +2 -2
  262. package/src/events.ts +10 -8
  263. package/src/host-provider-store.ts +5 -4
  264. package/src/hub-metrics-report.ts +5 -1
  265. package/src/hub-metrics.ts +38 -18
  266. package/src/init.ts +299 -0
  267. package/src/injection-sweep-pacing.ts +6 -8
  268. package/src/invite-link.ts +16 -9
  269. package/src/land-gate-notifications.ts +11 -10
  270. package/src/land-gate-queue-progress.ts +3 -3
  271. package/src/land-settle-dispatch.ts +52 -92
  272. package/src/lifecycle-context-pressure.ts +11 -10
  273. package/src/lifecycle-manager.ts +104 -98
  274. package/src/maintenance/breaker.ts +18 -16
  275. package/src/maintenance/checkout-refresh.ts +18 -1
  276. package/src/maintenance/critical-job-watchdog.ts +3 -3
  277. package/src/maintenance/events.ts +3 -3
  278. package/src/maintenance/history-retention-job.ts +30 -0
  279. package/src/maintenance/jobs.ts +29 -67
  280. package/src/maintenance/long-running-work.ts +3 -1
  281. package/src/maintenance/offline-agent-prune-job.ts +28 -0
  282. package/src/maintenance/orphaned-sessions.ts +5 -4
  283. package/src/maintenance/pauses.ts +4 -10
  284. package/src/maintenance/plan-ready-notice-job.ts +71 -0
  285. package/src/maintenance/scheduler.ts +18 -13
  286. package/src/maintenance/stalled-delivery-pager.ts +4 -4
  287. package/src/maintenance/teams.ts +19 -30
  288. package/src/maintenance/workspaces.ts +17 -27
  289. package/src/managed-policy-escalation.ts +7 -7
  290. package/src/managed-policy.ts +3 -3
  291. package/src/managed-provider-gate.ts +5 -4
  292. package/src/managed-spawn-reservation.ts +5 -4
  293. package/src/mcp/index.ts +8 -8
  294. package/src/mcp/output-descriptions.ts +1 -1
  295. package/src/mcp/presentation.ts +2 -1
  296. package/src/mcp/runtime-output.ts +6 -1
  297. package/src/mcp/self-care-visibility.ts +2 -2
  298. package/src/mcp/spawn-targets-matrix.ts +10 -1
  299. package/src/mcp/tool-groups.ts +3 -2
  300. package/src/mcp/tool-roles.ts +81 -0
  301. package/src/mcp/tools-workspace.ts +1 -1
  302. package/src/mcp-blackboard-tools.ts +6 -5
  303. package/src/mcp-decision-tools.ts +7 -7
  304. package/src/mcp-egress-tools.ts +10 -9
  305. package/src/mcp-issue-activity-tools.ts +2 -2
  306. package/src/mcp-issue-association-tools.ts +4 -4
  307. package/src/mcp-issue-ref-tools.ts +3 -3
  308. package/src/mcp-merge-tools.ts +5 -5
  309. package/src/mcp-notification-subscription-tools.ts +14 -15
  310. package/src/mcp-output-levels.test-fixture.ts +1 -1
  311. package/src/mcp-profile-trust-tools.ts +1 -1
  312. package/src/mcp-project-journal-tools.ts +4 -12
  313. package/src/mcp-project-tools.ts +17 -18
  314. package/src/mcp-routing-policy-tools.ts +3 -2
  315. package/src/mcp-team-tools.ts +6 -6
  316. package/src/mcp-workflow-tools.ts +5 -3
  317. package/src/memory-area-injection.ts +13 -12
  318. package/src/memory-boundary-capture.ts +6 -6
  319. package/src/memory-injection.ts +45 -43
  320. package/src/merge-pause-maintenance.ts +5 -4
  321. package/src/notification-router.ts +44 -17
  322. package/src/notify.ts +5 -5
  323. package/src/observed-reset-refresh.ts +4 -4
  324. package/src/operator-alarm.ts +2 -5
  325. package/src/project-ingest.ts +6 -6
  326. package/src/project-instructions.ts +8 -1
  327. package/src/project-trust.ts +12 -11
  328. package/src/prompt-resolver.ts +3 -3
  329. package/src/provider-quota-async.ts +5 -7
  330. package/src/provider-timeline-event.ts +4 -7
  331. package/src/quota-band-delivery.ts +2 -2
  332. package/src/recipe-runner.ts +4 -3
  333. package/src/retention-config-store.ts +4 -3
  334. package/src/reviewer-pipeline.ts +11 -10
  335. package/src/routes/_route.ts +4 -4
  336. package/src/routes/_shared.ts +13 -12
  337. package/src/routes/agent-effort.ts +5 -5
  338. package/src/routes/agent-heartbeat-quota.ts +23 -0
  339. package/src/routes/agent-keep.ts +1 -1
  340. package/src/routes/agent-reporting.ts +1 -1
  341. package/src/routes/agent-self-effort.ts +5 -5
  342. package/src/routes/agent-sessions.ts +24 -24
  343. package/src/routes/agents-spawn.ts +1 -1
  344. package/src/routes/agents.ts +17 -119
  345. package/src/routes/auth.ts +44 -17
  346. package/src/routes/authority-audit.ts +2 -2
  347. package/src/routes/automations.ts +6 -5
  348. package/src/routes/channel-binding-delete.ts +1 -1
  349. package/src/routes/channel-output.ts +3 -3
  350. package/src/routes/claude-api-budget.ts +5 -5
  351. package/src/routes/commands-listing.ts +1 -1
  352. package/src/routes/commands.ts +29 -27
  353. package/src/routes/context-resets.ts +2 -2
  354. package/src/routes/coordinator-teams.ts +1 -1
  355. package/src/routes/decisions.ts +2 -2
  356. package/src/routes/host-providers.ts +18 -0
  357. package/src/routes/host-secret-files.ts +1 -1
  358. package/src/routes/hosts.ts +11 -11
  359. package/src/routes/inbox.ts +3 -2
  360. package/src/routes/index.ts +7 -3
  361. package/src/routes/integrations.ts +9 -7
  362. package/src/routes/issue-activity.ts +2 -2
  363. package/src/routes/issue-associations.ts +4 -4
  364. package/src/routes/issue-refs.ts +3 -3
  365. package/src/routes/kernel-timers-operator.ts +1 -1
  366. package/src/routes/memory.ts +1 -1
  367. package/src/routes/merges.ts +11 -11
  368. package/src/routes/messages.ts +23 -17
  369. package/src/routes/orchestrator-bootstrap.ts +3 -1
  370. package/src/routes/orchestrator-host-registration.ts +2 -0
  371. package/src/routes/orchestrator-host-utilization.ts +2 -2
  372. package/src/routes/orchestrator-proxy.ts +2 -2
  373. package/src/routes/orchestrator.ts +27 -18
  374. package/src/routes/pairs.ts +8 -8
  375. package/src/routes/project-profile-instructions.ts +1 -1
  376. package/src/routes/project-trust.ts +1 -1
  377. package/src/routes/projects.ts +16 -16
  378. package/src/routes/prompt-templates.ts +12 -12
  379. package/src/routes/provider-quotas.ts +10 -10
  380. package/src/routes/run-command.ts +1 -1
  381. package/src/routes/secrets-backup.ts +4 -5
  382. package/src/routes/secrets-import.ts +3 -4
  383. package/src/routes/secrets-vault.ts +12 -14
  384. package/src/routes/settings.ts +1 -1
  385. package/src/routes/shipping.ts +9 -1
  386. package/src/routes/spawn-policy.ts +8 -7
  387. package/src/routes/sse.ts +2 -2
  388. package/src/routes/team-templates.ts +7 -7
  389. package/src/routes/teams.ts +10 -10
  390. package/src/routes/tokens.ts +18 -17
  391. package/src/routes/users.ts +24 -24
  392. package/src/routes/viewer-read.ts +3 -3
  393. package/src/routes/web-tool-calls.ts +4 -4
  394. package/src/routes/workflows.ts +2 -2
  395. package/src/routes/workspaces.ts +17 -16
  396. package/src/routing-policy-push.ts +6 -6
  397. package/src/runtime-grant.ts +17 -11
  398. package/src/runtime-install.ts +30 -0
  399. package/src/runtime-tokens.ts +20 -28
  400. package/src/secrets-broker/config.ts +1 -1
  401. package/src/secrets-broker/service.ts +2 -2
  402. package/src/security.ts +3 -1
  403. package/src/self-resume-carry.ts +21 -110
  404. package/src/self-resume-supersede.ts +4 -3
  405. package/src/self-resume.ts +54 -66
  406. package/src/server-background.ts +1 -1
  407. package/src/server.ts +25 -26
  408. package/src/services/agent-action.ts +12 -31
  409. package/src/services/agent-effort.ts +7 -32
  410. package/src/services/agent-hang-watchdog-job.ts +2 -2
  411. package/src/services/agent-heartbeat.ts +166 -0
  412. package/src/services/agent-reporting.ts +1 -1
  413. package/src/services/auth-context.ts +6 -0
  414. package/src/services/browser-inventory.ts +3 -3
  415. package/src/services/browser-session-state.ts +3 -2
  416. package/src/services/browser-session.ts +21 -27
  417. package/src/services/bus-command-update.ts +9 -9
  418. package/src/services/checkout-refresh-state.ts +1 -0
  419. package/src/services/checkout-refresh.test-fixture.ts +3 -2
  420. package/src/services/command-host.ts +7 -2
  421. package/src/services/coordinator-digest.ts +3 -2
  422. package/src/services/dispatch-command.ts +12 -13
  423. package/src/services/effective-launch-driver.ts +14 -9
  424. package/src/services/host-changed-paths.test-fixture.ts +5 -6
  425. package/src/services/host-project-readiness.ts +2 -2
  426. package/src/services/host-providers.ts +1 -1
  427. package/src/services/host-utilization.ts +9 -9
  428. package/src/services/idle-agent-digest.ts +17 -12
  429. package/src/services/idle-epics.ts +4 -4
  430. package/src/services/interrupt-agent.ts +12 -9
  431. package/src/services/issue-activity.ts +3 -3
  432. package/src/services/issue-associations.ts +15 -18
  433. package/src/services/issue-lifecycle-comments.ts +3 -2
  434. package/src/services/issue-lifecycle.ts +14 -13
  435. package/src/services/issue-refs.ts +4 -5
  436. package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
  437. package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
  438. package/src/services/kernel-timers-ingress.ts +3 -3
  439. package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
  440. package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
  441. package/src/services/kernel-timers-outbox.ts +1 -1
  442. package/src/services/kernel-timers-stage10-operator.ts +1 -1
  443. package/src/services/kernel-timers.ts +4 -3
  444. package/src/services/land-gate-placement.ts +11 -2
  445. package/src/services/land-issue-relations.ts +5 -4
  446. package/src/services/land-restart-retry.ts +7 -6
  447. package/src/services/landed-ancestry.ts +6 -5
  448. package/src/services/legacy-landing-host.ts +4 -1
  449. package/src/services/legacy-landing-recovery.ts +8 -6
  450. package/src/services/managed-running.ts +17 -17
  451. package/src/services/memory-areas.ts +3 -3
  452. package/src/services/merge-pause.ts +9 -15
  453. package/src/services/operator-decisions.ts +37 -41
  454. package/src/services/orchestrator-registration-recovery.ts +6 -2
  455. package/src/services/orchestrator-upgrade.ts +14 -12
  456. package/src/services/permission-decision.ts +4 -3
  457. package/src/services/plan-ci-notice.ts +1 -1
  458. package/src/services/plan-conformance.ts +4 -4
  459. package/src/services/plan-dispatch-policy.ts +10 -3
  460. package/src/services/plan-dispatch.ts +35 -14
  461. package/src/services/plan-graph.ts +39 -261
  462. package/src/services/plan-import.ts +1 -1
  463. package/src/services/plan-live-bindings.ts +8 -37
  464. package/src/services/plan-task-create.ts +1 -1
  465. package/src/services/plan-terminal-refs.ts +2 -12
  466. package/src/services/plan-wake-digest.ts +8 -3
  467. package/src/services/profile-trust.ts +2 -2
  468. package/src/services/project.ts +11 -10
  469. package/src/services/prompt-templates.ts +6 -5
  470. package/src/services/provider-api-key.ts +73 -0
  471. package/src/services/provider-hold-nudge.ts +9 -9
  472. package/src/services/provider-hold-record.ts +13 -12
  473. package/src/services/provider-state-audit.ts +19 -18
  474. package/src/services/provisioning-harness/driver.ts +1 -1
  475. package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
  476. package/src/services/provisioning-harness/lifecycle.ts +24 -22
  477. package/src/services/provisioning-harness/prepare.ts +16 -17
  478. package/src/services/rate-limit-resume.ts +10 -9
  479. package/src/services/red-main-auto-revert.ts +7 -5
  480. package/src/services/red-main-controller-deps.ts +20 -3
  481. package/src/services/red-main-incident.ts +3 -1
  482. package/src/services/red-main-quarantine.ts +2 -3
  483. package/src/services/register-agent.ts +22 -22
  484. package/src/services/restart-project-role.ts +1 -1
  485. package/src/services/restart-spawn.ts +17 -16
  486. package/src/services/review-publish.ts +7 -24
  487. package/src/services/review-ref-reconcile.ts +29 -38
  488. package/src/services/runtime-dependency-alert.ts +27 -0
  489. package/src/services/scheduler-command.ts +11 -9
  490. package/src/services/scheduler.ts +5 -5
  491. package/src/services/self-effort-grant.ts +5 -25
  492. package/src/services/send-message.ts +16 -33
  493. package/src/services/shutdown-agent.ts +17 -14
  494. package/src/services/spawn-agent.ts +12 -41
  495. package/src/services/spawn-chain-inspector.ts +1 -1
  496. package/src/services/spawn-cwd-placement.ts +21 -5
  497. package/src/services/spawn-issue-activity.ts +8 -6
  498. package/src/services/spawn-launch.ts +17 -1
  499. package/src/services/spawn-loss-escalation.ts +1 -1
  500. package/src/services/spawn-registration-watchdog.ts +2 -2
  501. package/src/services/spawn-repo-probe.ts +7 -5
  502. package/src/services/spawn-tree-cleanup.ts +7 -8
  503. package/src/services/steward-reaper.ts +4 -4
  504. package/src/services/task-context-hydration.ts +25 -1
  505. package/src/services/task-delivery.ts +20 -34
  506. package/src/services/task-entity.ts +40 -203
  507. package/src/services/task-issue-link.ts +13 -20
  508. package/src/services/task-issue-weave.ts +12 -11
  509. package/src/services/task-lifecycle.ts +27 -31
  510. package/src/services/task-repo-cwd.ts +37 -0
  511. package/src/services/task-review-hold.ts +4 -17
  512. package/src/services/task-semantic-events.ts +13 -11
  513. package/src/services/task-state-reconcile.ts +3 -4
  514. package/src/services/task-validation.ts +2 -2
  515. package/src/services/team-templates.ts +5 -5
  516. package/src/services/team.ts +31 -98
  517. package/src/services/terminal-provider-exit.ts +6 -5
  518. package/src/services/timer-message-fire-chaos-worker.ts +7 -3
  519. package/src/services/timer-message-fire-outbox.ts +1 -1
  520. package/src/services/transient-agent-reaper.ts +22 -19
  521. package/src/services/turn-reconcile-audit.ts +9 -9
  522. package/src/services/user-onboarding.ts +8 -6
  523. package/src/services/user-profile.ts +6 -9
  524. package/src/services/work-finality.ts +16 -4
  525. package/src/services/workflow-auto-start.ts +2 -1
  526. package/src/services/workflow-caller.ts +61 -4
  527. package/src/services/workflow-child-proof-worker.ts +1 -1
  528. package/src/services/workflow-control-proof-worker.ts +1 -1
  529. package/src/services/workflow-coordinator.ts +8 -2
  530. package/src/services/workflow-decisions.ts +5 -5
  531. package/src/services/workflow-deferred-cleanup.ts +1 -1
  532. package/src/services/workflow-effect-driver.ts +42 -19
  533. package/src/services/workflow-effects.ts +41 -27
  534. package/src/services/workflow-pins.ts +7 -4
  535. package/src/services/workflow-reconcile.ts +1 -0
  536. package/src/services/workflow-resume-pins.ts +3 -3
  537. package/src/services/workflow-routing-defaults.ts +18 -0
  538. package/src/services/workflow-run-view.ts +4 -3
  539. package/src/services/workflow-run.test-fixture.ts +1 -1
  540. package/src/services/workflow-runs.ts +34 -22
  541. package/src/services/workflow-supervisor-state.ts +21 -1
  542. package/src/services/workflow-supervisor.ts +4 -3
  543. package/src/services/workspace-recovery.ts +4 -3
  544. package/src/setup.ts +47 -8
  545. package/src/spawn-admission.ts +10 -2
  546. package/src/spawn-placement.ts +27 -9
  547. package/src/spawn-targets.ts +8 -8
  548. package/src/sse-agent-status.ts +15 -6
  549. package/src/sse.ts +49 -24
  550. package/src/startup-context-injection.ts +61 -57
  551. package/src/steward-handoff.ts +4 -3
  552. package/src/steward-policy-cleanup.ts +9 -8
  553. package/src/steward.ts +2 -2
  554. package/src/task-dispatch-live.ts +5 -2
  555. package/src/task-dispatcher.ts +2 -2
  556. package/src/token-db.ts +2 -2
  557. package/src/token-usage-async.ts +2 -4
  558. package/src/user-awaiting-reply.ts +5 -5
  559. package/src/utils.ts +7 -0
  560. package/src/workspace-actions.ts +24 -29
  561. package/src/workspace-auto-merge.ts +14 -12
  562. package/src/workspace-changed-paths-client.ts +16 -5
  563. package/src/workspace-cleanup-stale.ts +30 -7
  564. package/src/workspace-command-settle.ts +24 -16
  565. package/src/workspace-config.ts +1 -1
  566. package/src/workspace-conflict-resolver.ts +9 -7
  567. package/src/workspace-dead-owner-recovery.ts +5 -4
  568. package/src/workspace-escalation.ts +12 -11
  569. package/src/workspace-human-escalation.ts +3 -3
  570. package/src/workspace-land-gate-watchdog.ts +3 -3
  571. package/src/workspace-land-refusal.ts +20 -0
  572. package/src/workspace-land-stopped.ts +1 -0
  573. package/src/workspace-merge.ts +10 -26
  574. package/src/workspace-nothing-to-land-notice.ts +2 -2
  575. package/src/workspace-orphans.ts +18 -37
  576. package/src/workspace-pr-completion.ts +10 -8
  577. package/src/workspace-rekey.ts +3 -3
  578. package/src/workspace-steward-failure.ts +2 -2
  579. package/src/workspace-steward-wake.ts +2 -2
  580. package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
  581. package/public/assets/overview-C1DCTzzV.js +0 -2
  582. package/public/assets/provider-display-DsuWMvVL.js +0 -2
  583. package/public/assets/run-card-CpKqRbhg.js +0 -2
  584. package/public/assets/shipping-B9YtnwtG.js +0 -2
  585. package/public/assets/store-DcClXLH0.js +0 -9
  586. package/runner/src/agent-runner/http-liveness.ts +0 -85
  587. package/src/db/on-loop-write-transaction.ts +0 -34
@@ -0,0 +1,62 @@
1
+ import { createAgentControlBody, grantSelfEffortBody, type AgentControlWrite, type SelfEffortGrantWrite } from "./agent-control-write";
2
+ import { redactCommandSecrets } from "../command-secrets";
3
+ import { admitAgentActionBody, type AgentActionWrite } from "./agent-action-write";
4
+ import { startBrowserBody, stopBrowserBody, type StartBrowserWrite } from "./browser-session-write";
5
+ import { transitionBrowserSession } from "./browser-sessions";
6
+ import { flushWorkFinalReportsFromQueue } from "./messages";
7
+ import type { MessageWorkFinalitySource, Command } from "../types";
8
+ import { insertOperatorDecision } from "./operator-decisions";
9
+ import { persistAdvisoryContext } from "./lifecycle-context-write";
10
+ import { createReviewPublishBody } from "./review-publish-write";
11
+ import { answerOperatorDecisionBody, fileWorkflowDecisionBody } from "./operator-answer-write";
12
+ import { observeEffortBody } from "./agent-effort-observe";
13
+ import { recordContextResetBody, settleContextResetCarryBody } from "./context-carry-write";
14
+ import { openRecoveryObligation, attachRecoveryCommand, type ContextResetFact } from "./context-reset-carry";
15
+ import { clearAgentNotice, recordTerminalEvent } from "./terminal-events";
16
+ import { recordCrashReport } from "./crash-reports";
17
+ import { stampSpawnPrincipal } from "./agent-ownership";
18
+ import { markSpawnRegistrationConfirmed } from "../commands-db";
19
+ import { seedSpawnPromptMirror } from "./message-reads";
20
+ import { resolveQueuedPolicyMessages, resolveQueuedDirectMessages } from "./delivery";
21
+ import { resolveQueuedCoordinatorMessages } from "./coordinator-delivery";
22
+ import { upsertManagedAgentState, updateManagedAgentState } from "../config-store";
23
+ import { deleteWorkspace } from "./workspaces";
24
+ import { addSubscription, removeSubscription, removeSubscriptionsForTask } from "./notification-subscriptions";
25
+ import type { WriterOpSpec } from "./write-ops";
26
+
27
+ export const LIFECYCLE_TAIL_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
28
+ "lifecycleTail.upsertManagedAgentState": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof upsertManagedAgentState>) => upsertManagedAgentState(...args) },
29
+ "agents.createControl": { offLoop: true, idempotent: false, fn: (a: AgentControlWrite, ctx) => createAgentControlBody(a, ctx.now), serializeIdempotencyResult: value => { const result = value as ReturnType<typeof createAgentControlBody>; return { ...result, ...(result.command ? { command: redactCommandSecrets(result.command) } : {}) }; } },
30
+ "agents.grantSelfEffort": { offLoop: true, idempotent: false, fn: (a: SelfEffortGrantWrite, ctx) => grantSelfEffortBody(a, ctx.now), serializeIdempotencyResult: value => redactCommandSecrets(value as import("../types").Command) },
31
+ "agents.admitAction": { offLoop: true, idempotent: false, serializeIdempotencyResult: value => { const result = value as ReturnType<typeof admitAgentActionBody>; return { ...result, command: redactCommandSecrets(result.command) }; }, fn: (args: AgentActionWrite, ctx) => admitAgentActionBody(args, ctx.now) },
32
+ "browser.start": { offLoop: true, idempotent: false, fn: (args: StartBrowserWrite, ctx) => startBrowserBody(args, ctx.now) },
33
+ "browser.stop": { offLoop: true, idempotent: false, fn: (args: Parameters<typeof stopBrowserBody>[0], ctx) => stopBrowserBody(args, ctx.now) },
34
+ "browser.transition": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof transitionBrowserSession>) => transitionBrowserSession(...args) ?? null },
35
+ "notifications.subscriptions.addBatch": { offLoop: true, idempotent: false,
36
+ fn: (a: { inputs: Array<Parameters<typeof addSubscription>[0]> }, ctx) => a.inputs.map(input => addSubscription({ ...input, now: ctx.now })) },
37
+ "messages.flushWorkFinal": { offLoop: true, idempotent: true, fn: (a: { agentId: string; queue: number[]; source: MessageWorkFinalitySource; options: { includeStaleCompletedFinals?: boolean } }, ctx) => flushWorkFinalReportsFromQueue(a.agentId, a.queue, a.source, a.options, ctx.now) },
38
+ "operatorDecisions.insert": { offLoop: true, idempotent: false, fn: insertOperatorDecision },
39
+ "operatorDecisions.fileWorkflow": { offLoop: true, idempotent: true, fn: fileWorkflowDecisionBody },
40
+ "agents.persistAdvisoryContext": { offLoop: true, idempotent: true, fn: (a: Parameters<typeof persistAdvisoryContext>) => persistAdvisoryContext(...a) ?? null },
41
+ "commands.createReviewPublish": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof createReviewPublishBody>[0], ctx) => createReviewPublishBody(args, ctx.now) },
42
+ "operatorDecisions.answer": { offLoop: true, idempotent: true, fn: answerOperatorDecisionBody },
43
+ "agents.observeEffort": { offLoop: true, idempotent: true, fn: observeEffortBody },
44
+ "contextCarry.open": { offLoop: true, idempotent: true, fn: (a: { agentId: string; generation: number; now: number }) => openRecoveryObligation(a.agentId, a.generation, a.now) ?? null },
45
+ "contextCarry.attach": { offLoop: true, idempotent: true, fn: (a: { agentId: string; generation: number; commandId: string }) => attachRecoveryCommand(a.agentId, a.generation, a.commandId) ?? null },
46
+ "contextCarry.reset": { offLoop: true, idempotent: true, fn: (a: { fact: ContextResetFact }, ctx) => recordContextResetBody(a.fact, ctx.now) },
47
+ "contextCarry.settle": { offLoop: true, idempotent: true, fn: (a: { command: Command }, ctx) => settleContextResetCarryBody(a.command, ctx.now) },
48
+ "lifecycleTail.clearAgentNotice": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof clearAgentNotice>) => clearAgentNotice(...args) ?? null },
49
+ "lifecycleTail.recordTerminalEvent": { offLoop: true, idempotent: false, fn: (args: Parameters<typeof recordTerminalEvent>) => recordTerminalEvent(...args) ?? null },
50
+ "lifecycleTail.recordCrashReport": { offLoop: true, idempotent: false, fn: (args: Parameters<typeof recordCrashReport>) => recordCrashReport(...args) ?? null },
51
+ "lifecycleTail.stampSpawnPrincipal": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof stampSpawnPrincipal>) => stampSpawnPrincipal(...args) ?? null },
52
+ "lifecycleTail.markSpawnRegistrationConfirmed": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof markSpawnRegistrationConfirmed>) => markSpawnRegistrationConfirmed(...args) ?? null },
53
+ "lifecycleTail.seedSpawnPromptMirror": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof seedSpawnPromptMirror>) => seedSpawnPromptMirror(...args) ?? null },
54
+ "lifecycleTail.resolveQueuedPolicyMessages": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof resolveQueuedPolicyMessages>) => resolveQueuedPolicyMessages(...args) ?? null },
55
+ "lifecycleTail.resolveQueuedDirectMessages": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof resolveQueuedDirectMessages>) => resolveQueuedDirectMessages(...args) ?? null },
56
+ "lifecycleTail.resolveQueuedCoordinatorMessages": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof resolveQueuedCoordinatorMessages>) => resolveQueuedCoordinatorMessages(...args) ?? null },
57
+ "lifecycleTail.updateManagedAgentState": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof updateManagedAgentState>) => updateManagedAgentState(...args) ?? null },
58
+ "lifecycleTail.deleteWorkspace": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof deleteWorkspace>) => deleteWorkspace(...args) ?? null },
59
+ "lifecycleTail.addSubscription": { offLoop: true, idempotent: false, fn: (args: Parameters<typeof addSubscription>) => addSubscription(...args) ?? null },
60
+ "lifecycleTail.removeSubscription": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof removeSubscription>) => removeSubscription(...args) ?? null },
61
+ "lifecycleTail.removeSubscriptionsForTask": { offLoop: true, idempotent: true, fn: (args: Parameters<typeof removeSubscriptionsForTask>) => removeSubscriptionsForTask(...args) ?? null },
62
+ });
@@ -1,3 +1,4 @@
1
+ import { framed } from "../hub-metrics";
1
2
  import { assertMainThreadState, mainThreadRegistry } from "./main-thread-state";
2
3
  // #2111 — short-window write coalescing for the hot agent lifecycle / presence / registration writes.
3
4
  //
@@ -116,7 +117,7 @@ export function coalesceLifecycleWrite(op: WriteOp, args: unknown, options: Coal
116
117
  return;
117
118
  }
118
119
  if (!window.timer && windowMs() !== Infinity) {
119
- window.timer = setTimeout(() => flushWindow(op), windowMs());
120
+ window.timer = setTimeout(framed("timer lifecycle-write-window", () => flushWindow(op)), windowMs());
120
121
  window.timer.unref?.();
121
122
  }
122
123
  });
@@ -1,11 +1,11 @@
1
- import { MSG_SELECT } from "./mappers.ts";
2
1
  import { MIRROR_LOOKBACK_ROWS, notReportSuppressedSql } from "./report-suppression.ts";
3
2
 
4
3
  // #3644 — the child→parent chat dedupe reads behind a turn-final forward (db/messages.ts). Pinned
5
4
  // to the pair index: unpinned, the planner ranges idx_msg_to_id over the parent's whole inbox
6
5
  // (600k rows for `user`) and json_extracts every payload on the main thread. Each query must keep
7
- // `m.from_agent = ?`, `m.to_target = ?` and `m.kind = 'chat'` (the partial index predicate).
8
- const PAIR_CHAT_SELECT = `${MSG_SELECT} INDEXED BY idx_msg_pair_chat
6
+ // `m.from_agent = ?`, `m.to_target = ?`, `m.kind = 'chat'` (the partial index predicate).
7
+ // #3617: id + body only, no read/reaction rollups per candidate row; callers hydrate the winner via getMessage.
8
+ const PAIR_CHAT_SELECT = `SELECT m.id, m.body FROM messages m INDEXED BY idx_msg_pair_chat
9
9
  WHERE m.from_agent = ?
10
10
  AND m.to_target = ?
11
11
  AND m.kind = 'chat'`;
@@ -0,0 +1,11 @@
1
+ import { relayEnv } from "@humwick/sdk/env";
2
+ import { getDb, getDbPath } from "./connection";
3
+
4
+ /** Seal the hub handle after all boot writes, immediately before bind (#1870 S8).
5
+ * Opt in during the soak; standalone tools and :memory: fixtures retain their own write handles. */
6
+ export function configureMainConnectionForServing(env = process.env): boolean {
7
+ if (!Bun.isMainThread || getDbPath() === ":memory:" || !getDbPath()) return false;
8
+ if (relayEnv(env, "AGENT_RELAY_MAIN_DB_QUERY_ONLY") !== "1") return false;
9
+ getDb().run("PRAGMA query_only = ON");
10
+ return true;
11
+ }
@@ -1,4 +1,5 @@
1
1
  // #1870: bounded, minute-bucketed census of main-connection write attempts, including failed SQL.
2
+ import { configureMainConnectionForServing } from "./main-connection-mode";
2
3
  const MINUTE = 60_000;
3
4
  const WINDOW_BUCKETS = 60;
4
5
  const MAX_LABELS = 512;
@@ -42,7 +43,7 @@ export function resetMainConnectionWrites(): void {
42
43
  let booting = false;
43
44
  let bootWrites = 0;
44
45
  export function beginMainWriteBootPhase(): void { booting = true; }
45
- export function endMainWriteBootPhase(): void { booting = false; }
46
+ export function endMainWriteBootPhase(): void { configureMainConnectionForServing(); booting = false; }
46
47
  export function mainConnectionBootWrites(): number { return bootWrites; }
47
48
  // The first sighting of each label per process logs its caller once, so the remaining raw writers are named
48
49
  // from hub logs without a debugger. Bounded by the counter's own label cap.
@@ -52,14 +53,31 @@ function logFirstSighting(label: string): void {
52
53
  loggedLabels.add(label);
53
54
  const site = (new Error().stack ?? "").split("\n").filter((line) => line.includes(" at ") && !/connection|main-connection-writes/.test(line)).slice(0, 4)
54
55
  .map((line) => line.trim().replace(/^at /, "").replace(/\(?\/[^)]*\/(src\/[^):]+:\d+)[^)]*\)?/, "$1")).join(" < ");
55
- console.log(`[relay] #1870 main-connection write: ${label} :: ${site}`);
56
+ // Maintenance subprocesses reserve stdout for their JSON result (#3800).
57
+ console.error(`[relay] #1870 main-connection write: ${label} :: ${site}`);
56
58
  }
57
59
  export function recordMainConnectionWrite(label: string | undefined): void {
58
60
  if (!Bun.isMainThread || !label) return;
59
61
  if (booting) { bootWrites++; return; }
60
62
  counter.record(label, Date.now());
63
+ if (forbidRawWrites) { forbiddenWriteAttempts++; throw new Error(`#1870 raw main-connection write: ${label}`); }
61
64
  logFirstSighting(label);
62
65
  }
63
66
  export function mainConnectionWrites(now: number = Date.now()): Record<string, number> {
64
67
  return counter.snapshot(now);
65
68
  }
69
+
70
+ let forbidRawWrites = false;
71
+ let forbiddenWriteAttempts = 0;
72
+ /** Test ratchet for real service/route replay on the file-backed gateway. */
73
+ export async function withRawMainWritesForbidden<T>(run: () => Promise<T>): Promise<T> {
74
+ const previous = forbidRawWrites;
75
+ const attempts = forbiddenWriteAttempts;
76
+ forbidRawWrites = true;
77
+ try {
78
+ const result = await run();
79
+ if (forbiddenWriteAttempts !== attempts) throw new Error("#1870 raw main-connection write was caught inside the replay");
80
+ return result;
81
+ }
82
+ finally { forbidRawWrites = previous; }
83
+ }
@@ -19,8 +19,8 @@ export const finishMaintenanceRunAsync = (args: MaintenanceRunOutcome) =>
19
19
  export async function ensureMaintenanceJobsAsync(jobs: MaintenanceJobSpec[]): Promise<void> {
20
20
  await getGateway().write("maintenanceJobs.ensure", { jobs }, { critical: true });
21
21
  }
22
- export async function rescheduleRunOnStartJobsAsync(): Promise<void> {
23
- await getGateway().write("maintenanceJobs.rescheduleRunOnStart", {}, { critical: true });
22
+ export async function rescheduleRunOnStartJobsAsync(now?: number): Promise<void> {
23
+ await getGateway().write("maintenanceJobs.rescheduleRunOnStart", { now }, { critical: true });
24
24
  }
25
25
  export async function reclaimDeadLeasesAsync(leases: DeadLease[]): Promise<void> {
26
26
  if (leases.length) await getGateway().write("maintenanceJobs.reclaimDeadLeases", { leases }, { critical: true });
@@ -11,7 +11,7 @@ export const MAINTENANCE_JOB_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> =
11
11
  "maintenanceJobs.heartbeat": { offLoop: true, idempotent: true, fn: (args: { id: string; runToken: string }, ctx) => heartbeatMaintenanceRun(args, ctx.now) },
12
12
  // Reconcile is a re-assertion of code-owned columns, so a replay changes nothing.
13
13
  "maintenanceJobs.ensure": { offLoop: true, idempotent: true, fn: (args: { jobs: MaintenanceJobSpec[] }, ctx) => upsertMaintenanceJobs(args.jobs, ctx.now) },
14
- "maintenanceJobs.rescheduleRunOnStart": { offLoop: true, idempotent: true, fn: (_args: Record<string, never>, ctx) => rescheduleRunOnStartJobs(ctx.now) },
14
+ "maintenanceJobs.rescheduleRunOnStart": { offLoop: true, idempotent: true, fn: (args: { now?: number }, ctx) => rescheduleRunOnStartJobs(args.now ?? ctx.now) },
15
15
  "maintenanceJobs.reclaimDeadLeases": { offLoop: true, idempotent: true, fn: (args: { leases: DeadLease[] }, ctx) => reclaimDeadLeases(args.leases, ctx.now) },
16
16
  // A compare-and-set on the observed lease, so a replay finds nothing left to reset.
17
17
  "maintenanceJobs.resetExpiredCritical": { offLoop: true, idempotent: true, fn: (args: { now: number }) => resetExpiredCriticalMaintenanceRuns(args.now) },
@@ -123,8 +123,8 @@ export interface PauseMaintenanceJobInput {
123
123
  /** Acquire a pause. An existing ACTIVE pause is returned as a conflict rather than having its
124
124
  * holder replaced — same contract as acquireMergePause, so one operator's hold plus its reason
125
125
  * cannot be quietly overwritten by another's. A LAPSED row is replaced. */
126
- export function pauseMaintenanceJob(input: PauseMaintenanceJobInput): { ok: boolean; pause: MaintenanceJobPauseRecord } {
127
- const now = input.now ?? Date.now();
126
+ export function pauseMaintenanceJob(input: PauseMaintenanceJobInput, submittedAt: number = Date.now()): { ok: boolean; pause: MaintenanceJobPauseRecord } {
127
+ const now = input.now ?? submittedAt;
128
128
  const expiresAt = input.indefinite ? null : now + (input.ttlMs ?? DEFAULT_MAINTENANCE_PAUSE_TTL_MS);
129
129
  return writeTransaction(() => {
130
130
  const existing = getMaintenanceJobPause(input.jobId, now);
@@ -74,3 +74,7 @@ export function sendMessagesBatchWithResultAsync(
74
74
  SendMessageResult[]
75
75
  >;
76
76
  }
77
+
78
+ export async function sendMessageAsync(input: SendMessageInput) {
79
+ return (await sendMessageWithResultAsync(input)).message;
80
+ }
@@ -59,9 +59,9 @@ export { runningAgentForPolicy } from "./policy-runtime.ts";
59
59
 
60
60
  export function findMessageByIdempotencyKey(from: string, key: string): Message | null {
61
61
  const row = getDb()
62
- .query(`${MSG_SELECT} WHERE m.from_agent = ? AND m.idempotency_key = ? LIMIT 1`)
63
- .get(from, key) as any;
64
- return row ? rowToMessage(row) : null;
62
+ .query("SELECT m.id FROM messages m WHERE m.from_agent = ? AND m.idempotency_key = ? LIMIT 1")
63
+ .get(from, key) as { id: number } | null;
64
+ return row ? getMessage(row.id) : null;
65
65
  }
66
66
 
67
67
  function sessionStepId(payload: Record<string, unknown> | undefined): string | undefined {
@@ -162,7 +162,7 @@ function findRecentDuplicateReply(input: SendMessageInput, threadId: number | nu
162
162
  if (!input.replyTo || threadId === null || hasAttachments) return null;
163
163
  const kind = inferMessageKind(input);
164
164
  const row = getDb().query(`
165
- ${MSG_SELECT}
165
+ SELECT m.id FROM messages m
166
166
  WHERE m.from_agent = ?
167
167
  AND m.to_target = ?
168
168
  AND m.kind = ?
@@ -183,8 +183,8 @@ function findRecentDuplicateReply(input: SendMessageInput, threadId: number | nu
183
183
  input.subject ?? null,
184
184
  input.channel ?? null,
185
185
  now - REPLY_DUPLICATE_WINDOW_MS,
186
- ) as any;
187
- return row ? rowToMessage(row) : null;
186
+ ) as { id: number } | null;
187
+ return row ? getMessage(row.id) : null;
188
188
  }
189
189
 
190
190
  function sessionMeta(input: Message | SendMessageInput): Record<string, unknown> | undefined {
@@ -252,8 +252,8 @@ function findLineageReportByTurn(input: {
252
252
  lineageKey,
253
253
  `response-report:${input.from}:%:${input.turnId}`,
254
254
  input.turnId,
255
- ) as any;
256
- return row ? rowToMessage(row) : null;
255
+ ) as { id: number } | null;
256
+ return row ? getMessage(row.id) : null;
257
257
  }
258
258
 
259
259
  function findRecentLineageReport(input: SendMessageInput, now: number): Message | null {
@@ -275,8 +275,8 @@ function findRecentLineageReport(input: SendMessageInput, now: number): Message
275
275
  if (duplicate) return duplicate;
276
276
  }
277
277
  if (responseCapture) return null;
278
- const row = getDb().query(RECENT_LINEAGE_REPORT_SQL).get(from, to, input.body, now - LINEAGE_REPORT_DUPLICATE_WINDOW_MS, `response-report:${from}:%`) as any;
279
- return row ? rowToMessage(row) : null;
278
+ const row = getDb().query(RECENT_LINEAGE_REPORT_SQL).get(from, to, input.body, now - LINEAGE_REPORT_DUPLICATE_WINDOW_MS, `response-report:${from}:%`) as { id: number } | null;
279
+ return row ? getMessage(row.id) : null;
280
280
  }
281
281
 
282
282
  // T4458 (Edin's rule #2844 1a) — the sender's currently-open provider turn: the newest
@@ -340,10 +340,10 @@ function findSameTurnExplicitReport(input: {
340
340
  input.to,
341
341
  ...(input.turnId ? [input.from, input.turnId, fallback] : [fallback]),
342
342
  input.at + LINEAGE_REPORT_DUPLICATE_WINDOW_MS,
343
- ) as any[];
343
+ ) as Array<{ id: number; body: string | null }>;
344
344
  for (const row of rows) {
345
345
  const explicit = normBody(String(row?.body ?? ""));
346
- if (explicit.length >= SAME_TURN_MIN_CHARS && explicit.includes(body)) return rowToMessage(row);
346
+ if (explicit.length >= SAME_TURN_MIN_CHARS && explicit.includes(body)) return getMessage(row.id);
347
347
  }
348
348
  return null;
349
349
  }
@@ -361,9 +361,9 @@ function findTurnExplicitReport(input: {
361
361
  captureLen: number;
362
362
  captureOccurredAt: number;
363
363
  }): Message | null {
364
- const row = getDb().query(TURN_EXPLICIT_REPORT_SQL).get(input.from, input.to, input.turnId, input.before) as any;
365
- if (!row) return null;
366
- const message = rowToMessage(row);
364
+ const row = getDb().query(TURN_EXPLICIT_REPORT_SQL).get(input.from, input.to, input.turnId, input.before) as { id: number } | null;
365
+ const message = row ? getMessage(row.id) : null;
366
+ if (!message) return null;
367
367
  const explicitLen = normBody(String(message.body ?? "")).length;
368
368
  if (explicitLen < SAME_TURN_MIN_CHARS || explicitLen < 0.5 * input.captureLen) return null;
369
369
  // MED-1 (r1 review): a stamp is turn inference and can go stale — t1's late final can land
@@ -409,8 +409,8 @@ function findRecentExplicitLineageDuplicate(input: {
409
409
  input.to,
410
410
  input.body,
411
411
  input.since,
412
- ) as any;
413
- return row ? rowToMessage(row) : null;
412
+ ) as { id: number } | null;
413
+ return row ? getMessage(row.id) : null;
414
414
  }
415
415
 
416
416
  // #1084/#3304 — reporting a definitive provider completion does not close its work window.
@@ -418,9 +418,14 @@ function findRecentExplicitLineageDuplicate(input: {
418
418
  const LINEAGE_FINAL_GROUP_RECENCY_MS = 10 * 60 * 1000;
419
419
  export { __resetDeferredLineageReports, restoreDeferredLineageReports, takeDeferredLineageReports } from "./deferred-lineage-reports.ts";
420
420
 
421
+ export interface LineageReportResult {
422
+ message: Message;
423
+ created: boolean;
424
+ lifecycleSignals?: Array<{ recipient: string; subjectKey: string }>;
425
+ }
421
426
  export interface WorkFinalFlushResult {
422
427
  /** The chat report(s) forwarded (or found already-forwarded) to the spawner, oldest first. */
423
- forwarded: Array<{ message: Message; created: boolean }>;
428
+ forwarded: LineageReportResult[];
424
429
  /** The original session-mirror captures retroactively tagged `payload.finality` (for the
425
430
  * `message.finalized` SSE upgrade of already-rendered bubbles). */
426
431
  finalizedOriginals: Message[];
@@ -533,12 +538,11 @@ function edgeFallbackReportScore(body: string): number {
533
538
  // redundant "Task status pulse" for the same child/task is suppressed rather than double-waking.
534
539
  // #1038 — a report-up conveys "the child is progressing", so it is state-keyed to `working`: it
535
540
  // supersedes only a redundant `working` pulse, never a later distinct milestone (committed/landed/done).
536
- function stampReportUpLifecycleSignal(parent: string, child: AgentCard): void {
537
- stampLifecycleSignal(parent, childSignalKey(child.id));
538
- for (const taskId of childTaskIds(child)) stampLifecycleSignal(parent, taskSignalKey(taskId, LIFECYCLE_STATE_WORKING));
541
+ export function applyLineageReportEffects(result: LineageReportResult | null): void {
542
+ for (const signal of result?.lifecycleSignals ?? []) stampLifecycleSignal(signal.recipient, signal.subjectKey);
539
543
  }
540
544
 
541
- export function promoteLineageCapturedResponse(message: Message): { message: Message; created: boolean } | null {
545
+ export function promoteLineageCapturedResponse(message: Message, deferred?: Array<{ childId: string; messageId: number }>): LineageReportResult | null {
542
546
  if (message.kind !== "session" || isReportSuppressed(message)) return null;
543
547
  const session = sessionMeta(message);
544
548
  if (!session) return null;
@@ -556,7 +560,8 @@ export function promoteLineageCapturedResponse(message: Message): { message: Mes
556
560
  // #3304 — provider completion is enough to report a turn, without declaring the Task done.
557
561
  // Keep the ring for later work-final metadata; addressed captures already have a runner reply.
558
562
  if (stream === "responses" && verbosity !== "verbose") {
559
- deferLineageReport(child.id, message.id);
563
+ if (deferred) deferred.push({ childId: child.id, messageId: message.id });
564
+ else deferLineageReport(child.id, message.id);
560
565
  if (session.confidence !== "definitive" || session.endedBy !== "completed" || message.replyTo) return null;
561
566
  if (lineageDeliveryCoversCapture(message, child, parent, message.createdAt)) return null;
562
567
  }
@@ -576,7 +581,7 @@ function forwardLineageStreamCapture(
576
581
  child: AgentCard,
577
582
  parent: string,
578
583
  finality?: MessageWorkFinality,
579
- ): { message: Message; created: boolean } | null {
584
+ ): LineageReportResult | null {
580
585
  const parentAgentId = parent;
581
586
  parent = canonicalLineageReportTarget(child, parent);
582
587
  const idempotencyKey = lineageStreamReportKey(message, session, stream);
@@ -679,7 +684,8 @@ function forwardLineageStreamCapture(
679
684
  occurredAt: message.occurredAt ?? message.createdAt,
680
685
  });
681
686
  if (stream === "responses" && result.created) {
682
- stampReportUpLifecycleSignal(parentAgentId, child);
687
+ return { ...result, lifecycleSignals: [childSignalKey(child.id), ...childTaskIds(child).map(id => taskSignalKey(id, LIFECYCLE_STATE_WORKING))]
688
+ .map(subjectKey => ({ recipient: parentAgentId, subjectKey })) };
683
689
  }
684
690
  return result;
685
691
  }
@@ -1,3 +1,6 @@
1
+ import { COMMAND_RETENTION_SCHEMA, ensureCommandRetentionReferenceIndexes } from "./command-retention";
2
+ import { migrateCheckoutRefreshHeads } from "./checkout-refresh-schema";
3
+ import { TOKEN_USAGE_RETENTION_SCHEMA } from "./token-usage-retention";
1
4
  import { PLAN_DISPATCH_SCHEMA_SQL } from "./plan-dispatch-schema";
2
5
  import { PLAN_IMPORT_SCHEMA_SQL } from "./plan-import-schema";
3
6
  import { ensureDurablePayloadSchema } from "./durable-payloads"; import { redactProviderConfigHistory } from "./provider-config-history"; import { retireMemoryStorage } from "./memory-retirement";
@@ -66,6 +69,7 @@ import { migrateTeamProjectSeats } from "./team-project.ts";
66
69
  import { ensureArtifactCreatorAgentColumn } from "./artifacts.ts";
67
70
  import { rewriteEmptyToolGroupsToAbsent } from "./tool-groups-empty-migration.ts";
68
71
  import { backfillProjectMemoryToolGroup } from "./project-memory-group-migration.ts";
72
+ import { backfillPlanToolsIntoToolIncludes } from "./plan-tools-include-migration.ts";
69
73
  import { removeLegacyProfileProjectInstructions } from "./profile-legacy-project-instructions-migration.ts";
70
74
  import { migrateProfileHostSources } from "./profile-host-sources-migration.ts";
71
75
  import { migrateProfileProjectAcks } from "./profile-project-ack-migration.ts";
@@ -169,7 +173,15 @@ export function applyMigrations(): void {
169
173
  )
170
174
  `);
171
175
  getDb().run("CREATE INDEX IF NOT EXISTS idx_issue_refs_external ON issue_refs(provider, repo, external_key)");
172
- getDb().run("CREATE INDEX IF NOT EXISTS idx_issue_refs_updated ON issue_refs(updated_at DESC)");
176
+ // #3799 — matches the listing ORDER BY exactly, so a list is a bounded index walk with no sort; supersedes (updated_at DESC).
177
+ getDb().run("CREATE INDEX IF NOT EXISTS idx_issue_refs_listing ON issue_refs(updated_at DESC, created_at DESC, id DESC)");
178
+ getDb().run("DROP INDEX IF EXISTS idx_issue_refs_updated");
179
+ // #3799 — automation_runs list/scan indexes: status+created_at supersedes the plain status index, created_at serves the
180
+ // unfiltered listing, and the partial index holds exactly the open task-bound runs the reconcile pass walks.
181
+ getDb().run("CREATE INDEX IF NOT EXISTS idx_automation_runs_status_created ON automation_runs(status, created_at)");
182
+ getDb().run("DROP INDEX IF EXISTS idx_automation_runs_status");
183
+ getDb().run("CREATE INDEX IF NOT EXISTS idx_automation_runs_created ON automation_runs(created_at DESC)");
184
+ getDb().run("CREATE INDEX IF NOT EXISTS idx_automation_runs_open ON automation_runs(created_at) WHERE status IN ('scheduled', 'dispatching', 'waiting_agent', 'running') AND task_id IS NOT NULL");
173
185
  // #2520 — the GitHub close classification (completed|not_planned) cached beside the status so
174
186
  // plan-node terminal propagation can tell a completed close from a not-planned one. The guarded
175
187
  // ALTER converges databases created before the column existed with the CREATE above.
@@ -666,6 +678,7 @@ export function applyMigrations(): void {
666
678
  ensureIngestedMemoryIndex();
667
679
  rewriteEmptyToolGroupsToAbsent(); // #1963 N2 — persisted relay.tools.groups:[] meant ALL; honoring [] as NONE requires rewriting existing [] → absent first
668
680
  backfillProjectMemoryToolGroup(); // #2154 follow-up — stored/overridden profiles do not pick up the built-in `project-memory` group on their own
681
+ backfillPlanToolsIntoToolIncludes(); // #3812 — lean per-tool allowlists (coordinator) never gained relay_plan_start/import
669
682
  removeLegacyProfileProjectInstructions(); // #2133 — remove retired profile policy fields before profile override migration reads legacy rows
670
683
  backfillCustomProfileArtifacts(); // #3171 — Artifact is off by default now; keep the approved custom brainstorm exception
671
684
  migrateAgentProfileOverridesToV2(); // #1963 N10 — back up + migrate persisted override rows to the v2 matrix (D-T=off; G6/G7 leave-untouched-and-report; flag-gated rollback)
@@ -1733,6 +1746,10 @@ export function applyMigrations(): void {
1733
1746
  getDb().run(AGENT_EXIT_REPORT_SCHEMA);
1734
1747
  getDb().run(CONTEXT_RESET_SCHEMA); // #3398
1735
1748
  getDb().run(TASK_TOKEN_TOTALS_SCHEMA);
1749
+ getDb().run(TOKEN_USAGE_RETENTION_SCHEMA);
1750
+ getDb().run(COMMAND_RETENTION_SCHEMA);
1751
+ migrateCheckoutRefreshHeads(getDb());
1752
+ ensureCommandRetentionReferenceIndexes(getDb());
1736
1753
  getDb().run(SHIPPING_STATS_SCHEMA);
1737
1754
  getDb().run(CI_GATE_BACKFILL_SCHEMA); getDb().run(AGENT_GATE_RUNS_SCHEMA); ensureAgentGateCommandSchema(); repairRerunGateTimings(); ensureCiShaObservationsSchema();
1738
1755
  migrateOperatorActionsSchema();
@@ -0,0 +1,19 @@
1
+ import { sendMessageWithResultInternal } from "./messages";
2
+ import { insertAgentNoticeSlot, type AgentNoticeSlot } from "./terminal-events";
3
+ import type { SendMessageInput } from "../types";
4
+ import type { WriterOpContext, WriterOpSpec } from "./write-ops";
5
+
6
+ const send = (inputs: SendMessageInput[], now: number) => inputs.map(input => sendMessageWithResultInternal(input, false, {}, now));
7
+ export const NOTIFICATION_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
8
+ "notifications.route": {
9
+ offLoop: true, idempotent: false,
10
+ fn: ({ inputs }: { inputs: SendMessageInput[] }, ctx: WriterOpContext) => send(inputs, ctx.now),
11
+ },
12
+ "notifications.agentNotice": {
13
+ offLoop: true, idempotent: false,
14
+ fn: ({ slot, inputs }: { slot: AgentNoticeSlot; inputs: SendMessageInput[] }, ctx: WriterOpContext) => {
15
+ const created = insertAgentNoticeSlot(slot, ctx.now);
16
+ return { created, results: created ? send(inputs, ctx.now) : [] };
17
+ },
18
+ },
19
+ });
@@ -0,0 +1,19 @@
1
+ import { answerOpenOperatorDecision, getOperatorDecision, getWorkflowOperatorDecision, insertOperatorDecision, setOperatorDecisionAnswerMessage } from "./operator-decisions";
2
+ import { sendMessageWithResultInternal } from "./messages";
3
+ import type { SendMessageInput } from "../types";
4
+ export interface OperatorAnswerWrite {
5
+ id: number;
6
+ answer: Parameters<typeof answerOpenOperatorDecision>[1];
7
+ message: SendMessageInput;
8
+ }
9
+ export function answerOperatorDecisionBody({ id, answer, message }: OperatorAnswerWrite) {
10
+ if (!answerOpenOperatorDecision(id, answer)) return null;
11
+ const result = sendMessageWithResultInternal(message, false, {}, answer.now);
12
+ setOperatorDecisionAnswerMessage(id, result.message.id);
13
+ return { decision: getOperatorDecision(id)!, result };
14
+ }
15
+
16
+ export function fileWorkflowDecisionBody(input: Parameters<typeof insertOperatorDecision>[0]) {
17
+ const existing = getWorkflowOperatorDecision(input.workflow!.effectId);
18
+ return existing ? { decision: existing, created: false } : { decision: insertOperatorDecision(input), created: true };
19
+ }
@@ -11,7 +11,7 @@ import {
11
11
  type RuntimeContracts,
12
12
  } from "../contracts";
13
13
  import { STALE_TTL_MS } from "../config";
14
- import { deleteAgent, heartbeat, upsertAgent, upsertAgentInternal, type UpsertAgentTxResult } from "./agents.ts";
14
+ import { deleteAgentInternal, heartbeat, upsertAgent, upsertAgentInternal, type UpsertAgentTxResult } from "./agents.ts";
15
15
  import { evictPendingPresence } from "./presence-buffer.ts";
16
16
  import { getDb, writeTransaction } from "./connection.ts";
17
17
  import { fencedColumnSql, nextLifecycleSeq } from "./lifecycle-seq.ts";
@@ -386,11 +386,17 @@ export function reportOrchestratorRosterRow(id: string, agents: ManagedAgent[],
386
386
  }
387
387
 
388
388
  export function deleteOrchestrator(id: string): boolean {
389
+ const result = deleteOrchestratorRow(id, Date.now());
390
+ if (result.agentId) evictPendingPresence(result.agentId);
391
+ return result.deleted;
392
+ }
393
+
394
+ export function deleteOrchestratorRow(id: string, now: number): { deleted: boolean; agentId?: string } {
389
395
  const orch = getOrchestrator(id);
390
- if (!orch) return false;
396
+ if (!orch) return { deleted: false };
391
397
  getDb().query("DELETE FROM orchestrators WHERE id = ?").run(id);
392
- deleteAgent(orch.agentId);
393
- return true;
398
+ deleteAgentInternal(orch.agentId, now);
399
+ return { deleted: true, agentId: orch.agentId };
394
400
  }
395
401
 
396
402
  export function hasStaleOrchestrator(cutoff: number): boolean {
@@ -1,5 +1,6 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { createPair, acceptPair, rejectPair, endPair, sendPairMessage, getPair, listPairs } from "./pairs";
1
3
  import { getGateway } from "./gateway";
2
- import type { getPair, listPairs } from "./pairs";
3
4
 
4
5
  export function getPairAsync(id: string): Promise<ReturnType<typeof getPair>> {
5
6
  return getGateway().write("pairs.getCurrent", { id }) as Promise<ReturnType<typeof getPair>>;
@@ -8,3 +9,23 @@ export function getPairAsync(id: string): Promise<ReturnType<typeof getPair>> {
8
9
  export function listPairsAsync(filter?: Parameters<typeof listPairs>[0]): Promise<ReturnType<typeof listPairs>> {
9
10
  return getGateway().write("pairs.listCurrent", filter) as unknown as Promise<ReturnType<typeof listPairs>>;
10
11
  }
12
+
13
+ export function createPairAsync(...args: Parameters<typeof createPair>): Promise<ReturnType<typeof createPair>> {
14
+ return getGateway().write("pairs.createPair", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof createPair>>;
15
+ }
16
+
17
+ export function acceptPairAsync(...args: Parameters<typeof acceptPair>): Promise<ReturnType<typeof acceptPair>> {
18
+ return getGateway().write("pairs.acceptPair", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof acceptPair>>;
19
+ }
20
+
21
+ export function rejectPairAsync(...args: Parameters<typeof rejectPair>): Promise<ReturnType<typeof rejectPair>> {
22
+ return getGateway().write("pairs.rejectPair", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof rejectPair>>;
23
+ }
24
+
25
+ export function endPairAsync(...args: Parameters<typeof endPair>): Promise<ReturnType<typeof endPair>> {
26
+ return getGateway().write("pairs.endPair", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof endPair>>;
27
+ }
28
+
29
+ export function sendPairMessageAsync(...args: Parameters<typeof sendPairMessage>): Promise<ReturnType<typeof sendPairMessage>> {
30
+ return getGateway().write("pairs.sendPairMessage", args, { idempotencyKey: randomUUID() }) as unknown as Promise<ReturnType<typeof sendPairMessage>>;
31
+ }
@@ -1,8 +1,13 @@
1
- import { getPair, listPairs } from "./pairs";
1
+ import { createPair, acceptPair, rejectPair, endPair, sendPairMessage, getPair, listPairs } from "./pairs";
2
2
  import type { WriterOpSpec } from "./write-ops";
3
3
 
4
4
  // Pair reads settle expired requests before returning the current view.
5
5
  export const PAIRS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = {
6
- "pairs.getCurrent": { idempotent: true, offLoop: true, fn: (args: { id: string }) => getPair(args.id) },
7
- "pairs.listCurrent": { idempotent: true, offLoop: true, fn: (args: Parameters<typeof listPairs>[0]) => listPairs(args) },
6
+ "pairs.getCurrent": { idempotent: true, offLoop: true, fn: (args: { id: string }, ctx) => getPair(args.id, ctx.now) },
7
+ "pairs.listCurrent": { idempotent: true, offLoop: true, fn: (args: Parameters<typeof listPairs>[0], ctx) => listPairs(args, ctx.now) },
8
+ "pairs.createPair": { offLoop: true, idempotent: false, fn: (a: Parameters<typeof createPair>, ctx) => createPair(a[0], a[1] ?? ctx.now) },
9
+ "pairs.acceptPair": { offLoop: true, idempotent: false, fn: (a: Parameters<typeof acceptPair>, ctx) => acceptPair(a[0], a[1], a[2] ?? ctx.now) },
10
+ "pairs.rejectPair": { offLoop: true, idempotent: false, fn: (a: Parameters<typeof rejectPair>, ctx) => rejectPair(a[0], a[1], a[2] ?? ctx.now) },
11
+ "pairs.endPair": { offLoop: true, idempotent: false, fn: (a: Parameters<typeof endPair>, ctx) => endPair(a[0], a[1], a[2] ?? ctx.now) },
12
+ "pairs.sendPairMessage": { offLoop: true, idempotent: false, fn: (a: Parameters<typeof sendPairMessage>, ctx) => sendPairMessage(a[0], a[1], a[2] ?? ctx.now) },
8
13
  };