@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
@@ -41,7 +41,7 @@ export async function notifyCdDeployLive(input: CdDeployLiveInput = {}): Promise
41
41
  const version = input.version ?? VERSION;
42
42
  const gitSha = input.gitSha ?? reportedGitSha();
43
43
  if (!gitSha) {
44
- routeNotification({ type: "cd.deploy_live", scope: {}, recipients: [], message: {
44
+ await routeNotification({ type: "cd.deploy_live", scope: {}, recipients: [], message: {
45
45
  body: `Humwick v${version} is now running.`, payload: { kind: "cd.deploy-live", version },
46
46
  idempotencyKey: `release-deploy-live:${version}`, replyExpected: false,
47
47
  } });
@@ -50,7 +50,7 @@ export async function notifyCdDeployLive(input: CdDeployLiveInput = {}): Promise
50
50
  const shortSha = gitSha.slice(0, 12);
51
51
  const contents = await deployNoticeContents(gitSha, input.repoRoot ?? resolve(import.meta.dir, ".."));
52
52
 
53
- routeNotification({
53
+ await routeNotification({
54
54
  type: "cd.deploy_live",
55
55
  scope: {},
56
56
  ttlMs: null,
@@ -120,13 +120,13 @@ export interface RouteCiIncidentNotificationResult {
120
120
  * through routeNotification so its TTL, idempotency, routing explanation, and
121
121
  * Activity audit behavior stay identical to every other Relay notification.
122
122
  */
123
- export function routeCiIncidentNotification(input: RouteCiIncidentNotificationInput): RouteCiIncidentNotificationResult {
123
+ export async function routeCiIncidentNotification(input: RouteCiIncidentNotificationInput): Promise<RouteCiIncidentNotificationResult> {
124
124
  const { payload } = input;
125
125
  const subject = input.subject ?? defaultSubject(input.type, payload.repository, payload.branch);
126
126
  const body = input.body ?? defaultBody(input);
127
127
  const recipients = input.recipients ?? [payload.coordinatorAgentId];
128
128
  const idempotencyKey = input.idempotencyKey ?? defaultIdempotencyKey(input);
129
- const messages = routeNotification({
129
+ const messages = await routeNotification({
130
130
  type: input.type,
131
131
  scope: {
132
132
  repoRoot: payload.repoRoot ?? payload.repository,
@@ -148,14 +148,14 @@ export function routeCiIncidentNotification(input: RouteCiIncidentNotificationIn
148
148
  });
149
149
 
150
150
  if (!input.alertHuman) return { messages };
151
- const humanFallback = notifyWorkspaceHumanEscalation({
151
+ const humanFallback = (await notifyWorkspaceHumanEscalation({
152
152
  subject,
153
153
  body,
154
154
  payload: { kind: input.type, ...payload },
155
155
  priority: humanAlertPriority(input.type),
156
156
  tags: ["agent-relay", "ci", humanAlertTag(input.type)],
157
157
  source: "ci-incident",
158
- });
158
+ }));
159
159
  return { messages, humanFallback };
160
160
  }
161
161
 
@@ -11,11 +11,11 @@ export interface CiRootMissing {
11
11
 
12
12
  type Deps = Pick<CiTransitionNotifyDeps, "resolveCoordinator" | "route" | "now">;
13
13
 
14
- function notify(input: CiRootMissing, deps: Deps, fired: boolean): boolean {
14
+ async function notify(input: CiRootMissing, deps: Deps, fired: boolean): Promise<boolean> {
15
15
  if (!fired) return false;
16
16
  const route = deps.route ?? routeCiIncidentNotification;
17
17
  const observedAt = deps.now ?? Date.now();
18
- route({
18
+ await route({
19
19
  type: "ci.root_missing",
20
20
  payload: { provider: "github-actions", repository: input.repository, repoRoot: input.rootPath, branch: "*", coordinatorAgentId: resolveCoordinator(deps), observedAt },
21
21
  alertHuman: true,
@@ -26,5 +26,5 @@ function notify(input: CiRootMissing, deps: Deps, fired: boolean): boolean {
26
26
  }
27
27
 
28
28
  export async function notifyCiRootMissing(input: CiRootMissing, deps: Deps = {}): Promise<boolean> {
29
- return notify(input, deps, await markCiRootMissingNotifiedAsync(input.repository, deps.now));
29
+ return await notify(input, deps, await markCiRootMissingNotifiedAsync(input.repository, deps.now));
30
30
  }
@@ -42,7 +42,7 @@ export const CI_MAIN_WATCH_COORDINATOR = "cd-watcher";
42
42
 
43
43
  export interface CiTransitionNotifyDeps {
44
44
  ingest?: (observation: CiObservation, now?: number) => CiIncidentIngestResult | Promise<CiIncidentIngestResult>;
45
- route?: (input: Parameters<typeof routeCiIncidentNotification>[0]) => RouteCiIncidentNotificationResult;
45
+ route?: (input: Parameters<typeof routeCiIncidentNotification>[0]) => RouteCiIncidentNotificationResult | Promise<RouteCiIncidentNotificationResult>;
46
46
  /** Resolve the coordinator/owner agent the relay message addresses. Defaults to the configured
47
47
  * steward fallback, then the system watch actor. */
48
48
  resolveCoordinator?: () => string | undefined;
@@ -93,7 +93,7 @@ export async function notifyCiTransition(
93
93
  failingRunIds: observation.failingRuns.map((run) => run.id),
94
94
  failingJobNames: failingJobNames(observation),
95
95
  };
96
- const routed = route({
96
+ const routed = await route({
97
97
  type: "ci.failed",
98
98
  payload,
99
99
  alertHuman: true,
@@ -117,7 +117,7 @@ export async function notifyCiTransition(
117
117
  greenHeadSha: observation.headSha,
118
118
  ...(result.incident.resolution ? { resolution: result.incident.resolution } : {}),
119
119
  };
120
- const routed = route({
120
+ const routed = await route({
121
121
  type: "ci.recovered",
122
122
  payload,
123
123
  alertHuman: true,
@@ -138,7 +138,7 @@ export async function notifyCiTransition(
138
138
  firstSeenAt: result.firstSeenAt,
139
139
  observedAt: observation.observedAt,
140
140
  };
141
- const routed = route({
141
+ const routed = await route({
142
142
  type: "ci.never_matched",
143
143
  payload,
144
144
  alertHuman: true,
@@ -149,7 +149,7 @@ export async function notifyCiTransition(
149
149
  }
150
150
 
151
151
  if (result.kind === "config_mismatch") {
152
- const routed = route(configMismatchRoute(observation, resolveCoordinator(deps), result.unmatchedJobs));
152
+ const routed = await route(configMismatchRoute(observation, resolveCoordinator(deps), result.unmatchedJobs));
153
153
  return { transition: "config_mismatch", notified: true, messages: routed.messages.length, ...(routed.humanFallback ? { humanFallback: routed.humanFallback } : {}) };
154
154
  }
155
155
 
@@ -68,12 +68,12 @@ async function getRuntime(): Promise<Runtime> {
68
68
  removeShutdownHook = onShutdown("claude-app-oauth", stopClaudeAppOAuth);
69
69
  outcome = { status: "ok", detail: "OAuth available" };
70
70
  return { provider, server, base: `http://127.0.0.1:${address.port}` };
71
- })().catch(error => withRelayEventDrain(() => {
71
+ })().catch(error => withRelayEventDrain(async () => {
72
72
  runtime = undefined;
73
73
  const detail = `OAuth unavailable: ${errMessage(error)}`;
74
74
  outcome = { status: "error", detail };
75
- raiseOperatorAlarm({ clientId: `claude-app-oauth:${detail}`, source: "claude-app-oauth",
76
- subject: "Claude app OAuth unavailable", detail, view: "overview", dedupeEvent: true });
75
+ (await raiseOperatorAlarm({ clientId: `claude-app-oauth:${detail}`, source: "claude-app-oauth",
76
+ subject: "Claude app OAuth unavailable", detail, view: "overview", dedupeEvent: true }));
77
77
  throw error;
78
78
  }));
79
79
  }
@@ -1,7 +1,7 @@
1
1
  import { apiRequest } from "./_shared";
2
2
  import { probeWorkflowDeployment } from "../../scripts/wait-for-deploy";
3
3
 
4
- export const WORKFLOW_USAGE = "Usage: humwick workflow start <workflow> <taskId> [--json] | workflow get <runId> [--verbose] [--include-held] [--results-ref <id>] [--results-cursor <cursor>] [--json] | workflow resume <runId> [--activation <id>] | workflow pause <runId> --reason <text> | workflow unpause <runId>";
4
+ export const WORKFLOW_USAGE = "Usage: humwick workflow start <workflow> <taskId> [--json] | workflow get <runId> [--verbose] [--include-held] [--results-ref <id>] [--results-cursor <cursor>] [--json] | workflow resume <runId> [--activation <id>] [--step <step>] [--pins <json>] [--note <text>] | workflow pause <runId> --reason <text> | workflow unpause <runId>";
5
5
 
6
6
  export async function handleWorkflowCommand(args: string[]): Promise<void> {
7
7
  const [command, runId, ...flags] = args;
@@ -33,8 +33,17 @@ export async function handleWorkflowCommand(args: string[]): Promise<void> {
33
33
  return;
34
34
  }
35
35
  if (command === "resume") {
36
- if (flags.length && (flags[0] !== "--activation" || flags.length !== 2 || !flags[1])) throw new Error(WORKFLOW_USAGE);
37
- console.log(JSON.stringify(await apiRequest("POST", `/api/workflows/runs/${encodeURIComponent(runId)}/resume`, { ...(flags[1] ? { activationId: flags[1] } : {}) }), null, 2));
36
+ const body: Record<string, unknown> = {};
37
+ const fields: Record<string, string> = { "--activation": "activationId", "--step": "step", "--pins": "pins", "--note": "note" };
38
+ for (let index = 0; index < flags.length; index++) {
39
+ const flag = flags[index]!;
40
+ if (flag === "--json") continue;
41
+ const field = fields[flag];
42
+ const value = flags[++index];
43
+ if (!field || !value || value.startsWith("--")) throw new Error(WORKFLOW_USAGE);
44
+ body[field] = field === "pins" ? JSON.parse(value) : value;
45
+ }
46
+ console.log(JSON.stringify(await apiRequest("POST", `/api/workflows/runs/${encodeURIComponent(runId)}/resume`, body), null, 2));
38
47
  return;
39
48
  }
40
49
  const query = new URLSearchParams();
@@ -834,13 +834,13 @@ export function deleteCommand(id: string): boolean {
834
834
 
835
835
  // Race the host claim on the same pending row; only the winning cancellation records stop intent.
836
836
  // Legacy landing cancellation stays confined to its unfenced rows.
837
- export function cancelPendingCommand(id: string, expectedType: string, reason = "canceled before dispatch"): boolean {
837
+ export function cancelPendingCommand(id: string, expectedType: string, reason = "canceled before dispatch", submittedAt: number = Date.now()): boolean {
838
838
  if (expectedType === "workspace.merge") {
839
839
  const existing = getCommand(id);
840
840
  if (!existing || !isLegacyUnfencedWorkspaceMerge(existing)) return false;
841
841
  }
842
842
  return inWriteTransaction(() => {
843
- const now = Date.now();
843
+ const now = submittedAt;
844
844
  const changes = getDb()
845
845
  .query(`UPDATE commands SET status = 'canceled', result = ${canceledSpawnResultSql()}, error = ?, updated_at = ? WHERE id = ? AND status = 'pending' AND type = ?`)
846
846
  .run(reason, now, id, expectedType).changes;
@@ -978,7 +978,7 @@ export const EXPIRED_PENDING_COMMANDS_SQL = `SELECT * FROM commands WHERE (type
978
978
 
979
979
  export function expireCommands(
980
980
  now: number = Date.now(),
981
- opts: { isTargetGone?: (command: Command) => boolean } = {},
981
+ opts: { isTargetGone?: (command: Command) => boolean; update?: typeof updateCommand } = {},
982
982
  ): Command[] {
983
983
  const activeRows = getDb().query(EXPIRED_CLAIMED_COMMANDS_SQL).all(now, ...CLAIMED_ACTIVE_STATUSES) as CommandRow[];
984
984
  const pendingCandidates = getDb().query(EXPIRED_PENDING_COMMANDS_SQL).all(now) as CommandRow[];
@@ -998,7 +998,7 @@ export function expireCommands(
998
998
  // #1452 round-13 — the TTL sweep is an AUTHORIZED terminalizer of a claimed publish (executor:true):
999
999
  // it is the fail-closed path that lets the reconciler clean a host-death-after-claim, and timed_out is
1000
1000
  // ambiguous (ref retained), never a ref-drop. External surfaces get no such flag (see updateCommand).
1001
- updateCommand(row.id, {
1001
+ (opts.update ?? updateCommand)(row.id, {
1002
1002
  status: "timed_out",
1003
1003
  error: row.status === "pending"
1004
1004
  ? ((row.type === "agent.spawn" || row.type === "agent.restart") && hostSpawnsDrained(row.target) ? "host draining: spawns disabled; expired before dispatch" : "command target gone; expired before dispatch")
@@ -49,6 +49,10 @@ export async function createCommandAsync(
49
49
  vaultProjectId?: string,
50
50
  ): Promise<Command> {
51
51
  const args = await prepareCommandWriteAsync(input, options, vaultActor, vaultProjectId);
52
+ return submitPreparedCommandAsync(args);
53
+ }
54
+
55
+ export function submitPreparedCommandAsync(args: CreateCommandWriteArgs): Promise<Command> {
52
56
  return getGateway().coalesce(
53
57
  "commands.create",
54
58
  args,
@@ -82,6 +86,10 @@ export function getCommandAsync(id: string): Promise<Command | null> {
82
86
  return getGateway().read("commands.get", { id }) as unknown as Promise<Command | null>;
83
87
  }
84
88
 
89
+ export function findLatestCommandByCorrelationAsync(type: string, correlationId: string): Promise<Command | null> {
90
+ return getGateway().read("commands.latestByCorrelation", { type, correlationId }) as unknown as Promise<Command | null>;
91
+ }
92
+
85
93
  /** #2969 — an agent's confirmed effort changes within a chat window's time range, read off-loop. */
86
94
  export function listEffortChangesAsync(agentId: string, from: number, to: number, after?: EffortChangeCursor): Promise<{ changes: EffortChange[]; next?: EffortChangeCursor }> {
87
95
  return getGateway().read("commands.effortChanges", { agentId, from, to, ...(after ? { after } : {}) }) as unknown as Promise<{ changes: EffortChange[]; next?: EffortChangeCursor }>;
@@ -1,6 +1,8 @@
1
+ import { framed } from "./hub-metrics";
2
+ import { createActivityEventAsync } from "./db/activity-async";
1
3
  import { timePostBindPhase } from "./post-bind-startup";
2
4
  import { guardedInterval, isRecord } from "@humwick/sdk";
3
- import { getAgent, createActivityEvent } from "./db";
5
+ import { getAgent } from "./db";
4
6
  import { emitRelayEvent } from "./events";
5
7
  import { isContinuationSelfResumeCommand } from "./self-resume-command";
6
8
  import type { AgentCard, Command } from "./types";
@@ -74,7 +76,7 @@ export class CompactionWatch {
74
76
  start(): void {
75
77
  if (this.timer) return;
76
78
  // #3643 — the tick writes an activity event; a BUSY from a bare timer would exit the hub.
77
- this.timer = guardedInterval("[compaction-watch] tick", this.tickMs, () => timePostBindPhase("compaction-watch.tick", () => this.tick()));
79
+ this.timer = guardedInterval("[compaction-watch] tick", this.tickMs, framed("timer compaction-watch", () => timePostBindPhase("compaction-watch.tick", async () => (await this.tick()))));
78
80
  }
79
81
 
80
82
  stop(): void {
@@ -116,7 +118,7 @@ export class CompactionWatch {
116
118
  this.pending.delete(agentId);
117
119
  }
118
120
 
119
- tick(): void {
121
+ async tick(): Promise<void> {
120
122
  const now = this.now();
121
123
  for (const [agentId, watch] of this.pending) {
122
124
  if (watch.deadline > now) continue;
@@ -138,15 +140,15 @@ export class CompactionWatch {
138
140
  continue;
139
141
  }
140
142
  this.pending.delete(agentId);
141
- this.emitStalled(watch, true);
143
+ (await this.emitStalled(watch, true));
142
144
  continue;
143
145
  }
144
146
  this.pending.delete(agentId);
145
- this.emitStalled(watch);
147
+ (await this.emitStalled(watch));
146
148
  }
147
149
  }
148
150
 
149
- private emitStalled(watch: PendingWatch, busyCapped = false): void {
151
+ private async emitStalled(watch: PendingWatch, busyCapped = false): Promise<void> {
150
152
  const verb = watch.kind === "compact" ? "Compaction" : "Context clear";
151
153
  // #2043 F3 — the busy-capped variant means the agent is STILL taking turns (not stuck at a menu)
152
154
  // yet the compaction never started after a bounded wait — the runaway shape from #2043.
@@ -159,7 +161,7 @@ export class CompactionWatch {
159
161
  subject: watch.agentId,
160
162
  data: { agentId: watch.agentId, commandId: watch.commandId, kind: watch.kind, detail, busyCapped },
161
163
  });
162
- createActivityEvent({
164
+ (await createActivityEventAsync({
163
165
  clientId: `command-stalled-${watch.commandId}-${this.now()}-${++this.seq}`,
164
166
  kind: "state",
165
167
  title: `${verb} stalled: ${watch.agentId}`,
@@ -168,7 +170,7 @@ export class CompactionWatch {
168
170
  view: "agents",
169
171
  agentId: watch.agentId,
170
172
  metadata: { source: "compaction-watch", commandId: watch.commandId, kind: watch.kind, stalled: true, detail, busyCapped },
171
- });
173
+ }));
172
174
  }
173
175
  }
174
176
 
@@ -45,7 +45,7 @@ export async function setAgentProfileAsync(profile: AgentProfile, updatedBy?: st
45
45
  }
46
46
 
47
47
  /** `deleteAgentProfile` on the writer thread (#1870 S7). */
48
- export function deleteAgentProfileAsync(name: string, updatedBy?: string, opts: { resetBuiltInOverride?: boolean } = {}): Promise<boolean> {
48
+ export async function deleteAgentProfileAsync(name: string, updatedBy?: string, opts: { resetBuiltInOverride?: boolean } = {}): Promise<boolean> {
49
49
  const target = agentProfileDeleteTarget(name, opts);
50
- return deleteConfigAsync(target.namespace, target.key, updatedBy);
50
+ return (await deleteConfigAsync(target.namespace, target.key, updatedBy));
51
51
  }
package/src/config.ts CHANGED
@@ -637,21 +637,14 @@ export const DB_READER_JOB_TIMEOUT_MS = envPositiveInt("AGENT_RELAY_DB_READER_JO
637
637
  export const DB_READER_MARSHAL_IN_PROCESS =
638
638
  process.env.NODE_ENV === "test" || relayEnv(process.env, "AGENT_RELAY_DB_MARSHAL") === "1";
639
639
 
640
- /**
641
- * Phase-R rollout gate (#1960 T2 — ADR 0001 §7 Phase 1) for the gateway's READER half only. The
642
- * writer stays in-process unconditionally: Phase W (a worker writer taking the sole RW connection) is
643
- * a separate, much larger burn-down (#1870) and is deliberately NOT wired here. Any value other than
644
- * the literal `"worker"` — unset included — resolves to `"in-process"`, so this is behavior-preserving
645
- * by default; an operator opts in explicitly per the same string-literal convention as
646
- * `parseKernelTimersMode`.
647
- */
640
+ /** Explicit reader placement override. Otherwise file databases use workers (#3339). */
648
641
  export type GatewayReaderBackendMode = "in-process" | "worker";
649
642
 
650
- export function parseGatewayReaderBackend(value: string | undefined): GatewayReaderBackendMode {
651
- return value === "worker" ? "worker" : "in-process";
643
+ export function parseGatewayReaderBackend(value: string | undefined): GatewayReaderBackendMode | undefined {
644
+ return value === "worker" || value === "in-process" ? value : undefined;
652
645
  }
653
646
 
654
- export function gatewayReaderBackendFromEnv(): GatewayReaderBackendMode {
647
+ export function gatewayReaderBackendFromEnv(): GatewayReaderBackendMode | undefined {
655
648
  return parseGatewayReaderBackend(relayEnv(process.env, "AGENT_RELAY_GATEWAY_READER_BACKEND"));
656
649
  }
657
650
 
package/src/connectors.ts CHANGED
@@ -1,10 +1,12 @@
1
+ import { framed } from "./hub-metrics";
2
+ import { upsertAgentAsync } from "./db/agents-async";
1
3
  import { writeChildEnv } from "@humwick/sdk/env";
2
4
  import { timePostBindPhase } from "./post-bind-startup";
3
5
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
4
6
  import { homedir } from "node:os";
5
7
  import { dirname, join, resolve } from "node:path";
6
8
  import type { ConnectorAction, ConnectorActionResult, ConnectorManifest, ConnectorSummary } from "./types";
7
- import { upsertAgent, ValidationError } from "./db";
9
+ import { ValidationError } from "./db";
8
10
  import { CHANNELS_HOST_SECRETS } from "@humwick/sdk/channels-host-service";
9
11
  import { fireAndForget, guardedInterval, isRecord } from "@humwick/sdk";
10
12
  import { registerConnectorConfigSetting, validateConnectorConfig } from "./settings/modules";
@@ -274,11 +276,11 @@ export function startConnectorStatusPoller(): void {
274
276
  // deploy that took down the relay/orchestrator tree) BEFORE the first status
275
277
  // poll overwrites their persisted "running" flag with the now-dead reality.
276
278
  void fireAndForget("[connectors] boot reconcile", async () => {
277
- await fireAndForget("[connectors] ensure channels host", () => timePostBindPhase("connectors.ensureChannelsHostConnector", () => ensureChannelsHostOnBoot()));
279
+ await fireAndForget("[connectors] ensure channels host", () => timePostBindPhase("connectors.ensureChannelsHostConnector", async () => (await ensureChannelsHostOnBoot())));
278
280
  await fireAndForget("[connectors] reconcile on boot", () => timePostBindPhase("connectors.reconcileConnectorsOnBoot", reconcileConnectorsOnBoot));
279
281
  await timePostBindPhase("connectors.refreshAllConnectorStatuses", refreshAllConnectorStatuses);
280
282
  });
281
- guardedInterval("[connectors] status poll", STATUS_POLL_INTERVAL_MS, () => timePostBindPhase("connectors.refreshAllConnectorStatuses", refreshAllConnectorStatuses));
283
+ guardedInterval("[connectors] status poll", STATUS_POLL_INTERVAL_MS, framed("timer connector-status", () => timePostBindPhase("connectors.refreshAllConnectorStatuses", refreshAllConnectorStatuses)));
282
284
  }
283
285
 
284
286
  const CHANNELS_HOST_ID = "channels-host";
@@ -386,14 +388,14 @@ function configuredNtfyTopic(): string | null {
386
388
  * adapter's own gate — an unconfigured relay genuinely has no escalation target and must
387
389
  * still warn. Returns true when the row was (re)registered.
388
390
  */
389
- export function ensureEscalationChannelRegistered(): boolean {
391
+ export async function ensureEscalationChannelRegistered(): Promise<boolean> {
390
392
  if (isEphemeralMode()) return false;
391
393
  const topic = configuredNtfyTopic();
392
394
  if (!topic) return false;
393
395
  // Shape matches the channels-host adapter's registration (channels-host/src/relay.ts
394
396
  // registerChannel + adapters/ntfy.ts channels()), so its later re-registration updates
395
397
  // the same row in place rather than churning it.
396
- upsertAgent({
398
+ (await upsertAgentAsync({
397
399
  id: ESCALATION_NTFY_CHANNEL_ID,
398
400
  name: "ntfy",
399
401
  kind: "channel",
@@ -411,7 +413,7 @@ export function ensureEscalationChannelRegistered(): boolean {
411
413
  displayName: "ntfy",
412
414
  topicChannels: [topic],
413
415
  },
414
- });
416
+ }));
415
417
  return true;
416
418
  }
417
419
 
@@ -429,7 +431,7 @@ export async function ensureChannelsHostConnector(entry = resolveChannelsHostEnt
429
431
  // Register the escalation channel row now that config (incl. any legacy-migrated topic)
430
432
  // is persisted, so the escalation-target check passes without waiting for the async
431
433
  // channels-host SSE connect (#1510).
432
- ensureEscalationChannelRegistered();
434
+ (await ensureEscalationChannelRegistered());
433
435
 
434
436
 
435
437
  }
@@ -437,7 +439,7 @@ export async function ensureChannelsHostConnector(entry = resolveChannelsHostEnt
437
439
  /** Boot wrapper: a failed bring-up is logged with its stack and raised to /api/health, never swallowed (#3393). */
438
440
  export async function ensureChannelsHostOnBoot(entry?: string | null): Promise<void> {
439
441
  try {
440
- await (entry === undefined ? ensureChannelsHostConnector() : ensureChannelsHostConnector(entry));
442
+ await (entry === undefined ? (await ensureChannelsHostConnector()) : (await ensureChannelsHostConnector(entry)));
441
443
  clearChannelsHostEnsureFailure();
442
444
  } catch (error) {
443
445
  console.error("[connectors] ensureChannelsHostConnector failed:", error instanceof Error ? (error.stack ?? error.message) : error);
@@ -1,5 +1,6 @@
1
+ import { getGateway } from "./db/gateway";
1
2
  import { deriveContextThresholdFromWindowTokens, findProviderCatalogModel, resolveProviderContextThreshold, type ProviderModelCatalogEntry, type ResolvedProviderContextThreshold } from "@humwick/sdk/provider-catalog";
2
- import { isRecord, isSpawnProvider } from "@humwick/sdk";
3
+ import { fireAndForget, isRecord, isSpawnProvider } from "@humwick/sdk";
3
4
  import { HARD_BACKSTOP_BUSY_GRACE_MS } from "./config";
4
5
  import { getConfig } from "./config-store";
5
6
  import { getToken } from "./token-db";
@@ -39,7 +40,7 @@ interface EffectiveContextThreshold extends ResolvedProviderContextThreshold {
39
40
  * #315 — context pressure is a relay-native signal: durable event for observers,
40
41
  * plus an agent-facing system push when lifecycle notifications are enabled.
41
42
  */
42
- function notifyContextAdvisory(input: ContextAdvisoryInput): void {
43
+ async function notifyContextAdvisory(input: ContextAdvisoryInput): Promise<void> {
43
44
  const payload = {
44
45
  kind: "agent.context_threshold",
45
46
  agentId: input.agentId,
@@ -63,20 +64,20 @@ function notifyContextAdvisory(input: ContextAdvisoryInput): void {
63
64
 
64
65
  // Short default TTL (per-type): a stale context advisory is misleading — the band may have moved
65
66
  // by the time the agent next polls, so old advice shouldn't wake it.
66
- routeNotification({
67
+ await routeNotification({
67
68
  type: "agent.context_threshold",
68
69
  scope: { agentId: input.agentId },
69
70
  recipients: [input.agentId],
70
71
  message: {
71
72
  subject: input.stage === "warn" ? "Context threshold warning" : "Context self-compact threshold reached",
72
- body: contextAdvisoryBody(input),
73
+ body: (await contextAdvisoryBody(input)),
73
74
  payload,
74
75
  replyExpected: false,
75
76
  },
76
77
  });
77
78
  }
78
79
 
79
- function contextAdvisoryBody(input: ContextAdvisoryInput): string {
80
+ async function contextAdvisoryBody(input: ContextAdvisoryInput): Promise<string> {
80
81
  const tokens = `${formatTokens(input.tokens)} / ${formatTokens(input.windowTokens)} tokens used`;
81
82
  const percent = `${input.percent}% of window, ${input.band}% band`;
82
83
  const threshold = `resolved self-compact threshold ${input.selfCompactPercent}% (${input.thresholdSource})`;
@@ -96,7 +97,7 @@ function contextAdvisoryBody(input: ContextAdvisoryInput): string {
96
97
  threshold,
97
98
  hardBackstop: `${input.hardBackstopPercent}%`,
98
99
  });
99
- return withPreBoundaryCapture(advisory, input.agentId);
100
+ return (await withPreBoundaryCapture(advisory, input.agentId));
100
101
  }
101
102
 
102
103
  /**
@@ -110,8 +111,8 @@ function contextAdvisoryBody(input: ContextAdvisoryInput): string {
110
111
  * Appended rather than woven into the advisory templates so a blank slug leaves the advisory body
111
112
  * BYTE-IDENTICAL to the pre-P5 one.
112
113
  */
113
- function withPreBoundaryCapture(advisory: string, agentId: string): string {
114
- const capture = boundaryCaptureClause({ seam: "pre", agentId });
114
+ async function withPreBoundaryCapture(advisory: string, agentId: string): Promise<string> {
115
+ const capture = (await boundaryCaptureClause({ seam: "pre", agentId }));
115
116
  return capture ? `${advisory}\n\n${capture}` : advisory;
116
117
  }
117
118
 
@@ -123,12 +124,12 @@ function contextAdvisoryBand(utilization: number, threshold: EffectiveContextThr
123
124
  return { band: utilizationPercent(threshold.warnUtilization), stage: "warn" };
124
125
  }
125
126
 
126
- export function handleContextPressure(input: {
127
+ export async function handleContextPressure(input: {
127
128
  agent: AgentCard;
128
129
  now: () => number;
129
130
  hasActiveCommand: (target: string, type: string) => boolean;
130
- compact: (reason: string) => Command | null;
131
- }): boolean {
131
+ compact: (reason: string) => Command | null | Promise<Command | null>;
132
+ }): Promise<boolean> {
132
133
  const { agent, now } = input;
133
134
  const context = agent.context;
134
135
  if (!context) return false;
@@ -138,7 +139,7 @@ export function handleContextPressure(input: {
138
139
  const advisory = contextAdvisoryBand(context.utilization, threshold);
139
140
  if (advisory === null) {
140
141
  if (context.lastContextAdvisoryBand !== undefined || context.lastContextAdvisoryAt !== undefined || context.hardBackstopDeferredAt !== undefined) {
141
- persistContextState(agent.id, clearContextAdvisory(context));
142
+ (await persistContextState(agent.id, clearContextAdvisory(context)));
142
143
  }
143
144
  return false;
144
145
  }
@@ -160,8 +161,8 @@ export function handleContextPressure(input: {
160
161
  // mid-turn (the runner waits for the live turn to clear before submitting the keystrokes).
161
162
  const graceElapsed = deferredAt !== undefined && now() - deferredAt >= HARD_BACKSTOP_BUSY_GRACE_MS;
162
163
  if (!busy || graceElapsed) {
163
- input.compact(busy ? "context-hard-backstop-busy" : "context-hard-backstop");
164
- if (deferredAt !== undefined) persistContextState(agent.id, clearHardBackstopDefer(context));
164
+ await input.compact(busy ? "context-hard-backstop-busy" : "context-hard-backstop");
165
+ if (deferredAt !== undefined) (await persistContextState(agent.id, clearHardBackstopDefer(context)));
165
166
  return true;
166
167
  }
167
168
  // Busy and within grace: start the bounded defer clock (once), then fall through so the
@@ -169,19 +170,19 @@ export function handleContextPressure(input: {
169
170
  // the forced backstop.
170
171
  if (deferredAt === undefined) {
171
172
  state = { ...context, hardBackstopDeferredAt: now() };
172
- persistContextState(agent.id, state);
173
+ (await persistContextState(agent.id, state));
173
174
  }
174
175
  } else if (context.hardBackstopDeferredAt !== undefined) {
175
176
  // Dropped below the hard backstop (or a forced compaction is already in flight): reset the clock
176
177
  // so a later re-crossing starts a fresh grace window rather than firing immediately.
177
178
  state = clearHardBackstopDefer(context);
178
- persistContextState(agent.id, state);
179
+ (await persistContextState(agent.id, state));
179
180
  }
180
181
  if (state.lastContextAdvisoryBand === advisory.band) return false;
181
182
  const tokens = finiteNumber(context.tokensUsed);
182
183
  const windowTokens = finiteNumber(context.tokensMax);
183
184
  if (tokens === undefined || windowTokens === undefined) return false;
184
- notifyContextAdvisory({
185
+ await fireAndForget(`[context] advisory ${input.agent.id}`, async () => (await notifyContextAdvisory({
185
186
  agentId: agent.id,
186
187
  agent,
187
188
  tokens,
@@ -193,8 +194,8 @@ export function handleContextPressure(input: {
193
194
  selfCompactPercent: utilizationPercent(threshold.selfCompactUtilization),
194
195
  hardBackstopPercent: utilizationPercent(threshold.hardBackstopUtilization),
195
196
  thresholdSource: threshold.source,
196
- });
197
- persistContextState(agent.id, { ...state, lastContextAdvisoryBand: advisory.band, lastContextAdvisoryAt: now() });
197
+ })));
198
+ (await persistContextState(agent.id, { ...state, lastContextAdvisoryBand: advisory.band, lastContextAdvisoryAt: now() }));
198
199
  return true;
199
200
  }
200
201
 
@@ -258,8 +259,8 @@ function clearHardBackstopDefer(context: ContextState): ContextState {
258
259
  return rest;
259
260
  }
260
261
 
261
- function persistContextState(agentId: string, context: ContextState): void {
262
- getDb().query("UPDATE agents SET context_state = ? WHERE id = ?").run(JSON.stringify(context), agentId);
262
+ async function persistContextState(agentId: string, context: ContextState): Promise<void> {
263
+ await getGateway().write("agents.persistAdvisoryContext", [agentId, context]);
263
264
  }
264
265
 
265
266
  function finiteNumber(value: unknown): number | undefined {
@@ -0,0 +1,36 @@
1
+ import { ValidationError } from "@humwick/sdk";
2
+ import { createCommandInternal, getCommand } from "../commands-db";
3
+ import { assertSelfEffortAllowed } from "../services/self-effort";
4
+ import { admitDesiredEffortInternal, getAgentEffortState } from "./agent-effort-state";
5
+ import { getAgent } from "./agents";
6
+ import { sendMessageWithResultInternal } from "./messages";
7
+ import type { AgentCard, CreateCommandInput, SendMessageInput } from "../types";
8
+ import type { EffortChangeActorRole } from "@humwick/sdk";
9
+
10
+ export interface AgentActionWrite {
11
+ agent: AgentCard;
12
+ commandId: string;
13
+ commandInput: Omit<CreateCommandInput, "params"> & { params: Record<string, unknown> };
14
+ requestId?: string;
15
+ effort?: string;
16
+ role: EffortChangeActorRole;
17
+ selfEffort?: { level: string; efforts?: readonly string[] };
18
+ message?: SendMessageInput;
19
+ }
20
+
21
+ export function admitAgentActionBody(input: AgentActionWrite, now: number) {
22
+ const prior = input.requestId ? getCommand(input.requestId) : null;
23
+ if (prior) {
24
+ if (prior.type !== "agent.setEffort" || prior.target !== input.agent.id) throw new ValidationError("requestId belongs to another request");
25
+ return { command: prior, raced: true, effortState: getAgentEffortState(input.agent.id) };
26
+ }
27
+ const current = getAgent(input.agent.id);
28
+ if (!current || current.instanceId !== input.agent.instanceId || current.epoch !== input.agent.epoch) throw new ValidationError("agent instance changed while the action audit was committing");
29
+ if (input.selfEffort) assertSelfEffortAllowed(current, input.selfEffort.level, input.selfEffort.efforts);
30
+ const sent = input.message ? sendMessageWithResultInternal(input.message, false, {}, now) : undefined;
31
+ if (sent) Object.assign(input.commandInput.params, { messageId: sent.message.id, from: sent.message.from });
32
+ const admitted = input.effort ? admitDesiredEffortInternal({ agentId: current.id, effort: input.effort, role: input.role, commandId: input.commandId, now }) : undefined;
33
+ if (admitted) input.commandInput.params.effortVersion = admitted.state.desiredVersion;
34
+ const command = createCommandInternal({ input: input.commandInput, id: input.commandId }, now);
35
+ return { command, raced: false, admitted, sessionMessage: sent?.message };
36
+ }
@@ -0,0 +1,9 @@
1
+ import { getGateway } from "./gateway";
2
+ import type { AgentControlWrite, SelfEffortGrantWrite, createAgentControlBody, grantSelfEffortBody } from "./agent-control-write";
3
+
4
+ export function createAgentControlAsync(input: AgentControlWrite): Promise<ReturnType<typeof createAgentControlBody>> {
5
+ return getGateway().write("agents.createControl", input, { idempotencyKey: input.commandId, critical: true }) as unknown as Promise<ReturnType<typeof createAgentControlBody>>;
6
+ }
7
+ export function grantSelfEffortAsync(input: SelfEffortGrantWrite): Promise<ReturnType<typeof grantSelfEffortBody>> {
8
+ return getGateway().write("agents.grantSelfEffort", input, { idempotencyKey: input.commandId }) as unknown as Promise<ReturnType<typeof grantSelfEffortBody>>;
9
+ }
@@ -0,0 +1,49 @@
1
+ import { ValidationError } from "@humwick/sdk";
2
+ import { createCommandInternal, updateCommandInternal } from "../commands-db";
3
+ import { agentProviderState } from "../provider-state";
4
+ import { stopRefusal, type SafeCandidate } from "../services/idle-agent-digest";
5
+ import { selfEffortIdentity, type SelfEffortGrant, type SelfEffortPolicy } from "../services/self-effort";
6
+ import { getAgent } from "./agents";
7
+ import { SELF_EFFORT_BAND, setSelfEffortCeilingInternal } from "./self-effort-permissions";
8
+ import type { AgentCard, Command, CreateCommandInput } from "../types";
9
+
10
+ export interface AgentControlWrite {
11
+ agent?: AgentCard | null;
12
+ commandId: string;
13
+ commandInput: CreateCommandInput;
14
+ approvalId?: string;
15
+ idleCandidate?: SafeCandidate;
16
+ }
17
+ export function createAgentControlBody(input: AgentControlWrite, now: number): { command?: Command; refused?: string } {
18
+ if (input.agent) {
19
+ const current = getAgent(input.agent.id);
20
+ if (!current || current.instanceId !== input.agent.instanceId || current.epoch !== input.agent.epoch) throw new ValidationError("agent instance changed while the action audit was committing");
21
+ if (input.approvalId) {
22
+ const state = agentProviderState(current);
23
+ if (state?.state !== "blocked" || state.pendingApproval?.id !== input.approvalId) throw new ValidationError("approval request is no longer current");
24
+ }
25
+ if (input.idleCandidate) {
26
+ const refusal = stopRefusal(input.idleCandidate, current, now);
27
+ if (refusal) return { refused: refusal.reason };
28
+ }
29
+ }
30
+ return { command: createCommandInternal({ input: input.commandInput, id: input.commandId }, now) };
31
+ }
32
+
33
+ export const SELF_EFFORT_GRANT_COMMAND = "agent.grantSelfEffort";
34
+ export interface SelfEffortGrantWrite {
35
+ agent: AgentCard; grant?: SelfEffortGrant; requestedBy: string; commandId: string; spawnRequestId?: string;
36
+ input: { requestedVia: "mcp" | "http"; requestedByUser?: string };
37
+ selfEffort: SelfEffortPolicy | null; previous: SelfEffortPolicy | null;
38
+ }
39
+ export function grantSelfEffortBody({ agent, grant, requestedBy, commandId, spawnRequestId, input, selfEffort, previous }: SelfEffortGrantWrite, now: number): Command {
40
+ const current = getAgent(agent.id);
41
+ if (!current || current.instanceId !== agent.instanceId || current.epoch !== agent.epoch) throw new ValidationError("agent instance changed while the action audit was committing");
42
+ const identity = selfEffortIdentity(current);
43
+ setSelfEffortCeilingInternal(identity, !grant ? null : "band" in grant ? SELF_EFFORT_BAND : grant.ceiling, requestedBy, now);
44
+ createCommandInternal({ id: commandId, input: { type: SELF_EFFORT_GRANT_COMMAND, source: "system", target: agent.id,
45
+ ...(spawnRequestId ? { correlationId: spawnRequestId } : {}), params: { agentId: agent.id,
46
+ ...(spawnRequestId ? { spawnRequestId } : {}), permission: identity, selfEffort, previousSelfEffort: previous, requestedBy,
47
+ ...(input.requestedByUser ? { requestedByUser: input.requestedByUser } : {}), requestedVia: input.requestedVia, requestedAt: now } } }, now);
48
+ return updateCommandInternal(commandId, { status: "succeeded", result: { selfEffort } }, {}, now).command!;
49
+ }