@humwick/server 0.130.2 → 0.130.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (570) hide show
  1. package/bundled/prompts/manifest.json +1 -0
  2. package/bundled/prompts/task.hydration.md +1 -1
  3. package/bundled/roles/builder.md +1 -1
  4. package/docs/guides/sub-coordinators.md +12 -5
  5. package/docs/guides/tools-coordination.md +1 -0
  6. package/docs/guides/workflows.md +16 -0
  7. package/docs/openapi.json +73 -4
  8. package/package.json +8 -7
  9. package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
  10. package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
  11. package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
  12. package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
  13. package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
  14. package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
  15. package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
  16. package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
  17. package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
  18. package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
  19. package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
  20. package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
  21. package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
  22. package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
  23. package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
  24. package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
  25. package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
  26. package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
  27. package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
  28. package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
  29. package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
  30. package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
  31. package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
  32. package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
  33. package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
  34. package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
  35. package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
  36. package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
  37. package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
  38. package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
  39. package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
  40. package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
  41. package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
  42. package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
  43. package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
  44. package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
  45. package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
  46. package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
  47. package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
  48. package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
  49. package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
  50. package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
  51. package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
  52. package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
  53. package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
  54. package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
  55. package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
  56. package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
  57. package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
  58. package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
  59. package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
  60. package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
  61. package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
  62. package/public/assets/provider-display-BEeLXC_D.js +2 -0
  63. package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
  64. package/public/assets/run-card-Dt4I4jaP.js +2 -0
  65. package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
  66. package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
  67. package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
  68. package/public/assets/shipping-H6gzEeZB.js +2 -0
  69. package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
  70. package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
  71. package/public/assets/store-DKPDIZBe.js +9 -0
  72. package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
  73. package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
  74. package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
  75. package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
  76. package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
  77. package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
  78. package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
  79. package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
  80. package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
  81. package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
  82. package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
  83. package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
  84. package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
  85. package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
  86. package/public/cosmos.html +4 -4
  87. package/public/index.html +28 -28
  88. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  89. package/runner/src/adapters/claude-headless.ts +1 -1
  90. package/runner/src/adapters/claude-launch-exit.ts +26 -0
  91. package/runner/src/adapters/claude-session-probe.ts +1 -1
  92. package/runner/src/adapters/claude-tmux.ts +38 -10
  93. package/runner/src/adapters/claude.ts +28 -75
  94. package/runner/src/adapters/provider-quota-harvest.ts +20 -71
  95. package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
  96. package/runner/src/agent-runner/liveness-exchange.ts +104 -0
  97. package/runner/src/claude-system-prompt.ts +49 -0
  98. package/runner/src/launch-assembly.ts +14 -10
  99. package/runner/src/profile-home.ts +1 -1
  100. package/runner/src/project-instructions.ts +2 -2
  101. package/runner/src/provider-command.ts +18 -0
  102. package/runner/src/provider-setup.ts +2 -1
  103. package/runner/src/runner-core.ts +14 -15
  104. package/runner/src/runner-helpers.ts +0 -8
  105. package/runner/src/session-scratch.ts +6 -2
  106. package/runner/test-support/provisioning-context.ts +4 -2
  107. package/runner/test-support/runner-harness.ts +2 -1
  108. package/scripts/steward-policy-cleanup.ts +2 -2
  109. package/src/agent-authz.ts +2 -2
  110. package/src/agent-drive-arbiter.ts +3 -8
  111. package/src/agent-exit-cleanup-async.ts +2 -2
  112. package/src/agent-exit-cleanup.ts +23 -19
  113. package/src/agent-lifecycle-events.ts +112 -85
  114. package/src/agent-ref.ts +3 -2
  115. package/src/agent-status-events.ts +43 -14
  116. package/src/auth/password.ts +4 -3
  117. package/src/auth/session-refresh.ts +1 -1
  118. package/src/auth/session.test-fixture.ts +2 -2
  119. package/src/auth/session.ts +7 -7
  120. package/src/automations/crud.ts +8 -81
  121. package/src/automations/dispatch.ts +33 -58
  122. package/src/automations/index.ts +1 -1
  123. package/src/automations/persistence.ts +65 -0
  124. package/src/automations/precheck.ts +18 -16
  125. package/src/automations/read-async.ts +11 -0
  126. package/src/automations/reconcile.ts +30 -39
  127. package/src/automations/storage.ts +33 -10
  128. package/src/automations/write-async.ts +33 -0
  129. package/src/branch-land-notice.ts +3 -3
  130. package/src/branch-landed.ts +25 -23
  131. package/src/bus.ts +21 -19
  132. package/src/cd-deploy-notify.ts +2 -2
  133. package/src/ci/notifications.ts +4 -4
  134. package/src/ci/root-missing.ts +3 -3
  135. package/src/ci/transition-notify.ts +5 -5
  136. package/src/claude-app/oauth-http.ts +3 -3
  137. package/src/cli/workflow.ts +12 -3
  138. package/src/commands-db.ts +4 -4
  139. package/src/commands-write.ts +8 -0
  140. package/src/compaction-watch.ts +10 -8
  141. package/src/config-store-write.ts +2 -2
  142. package/src/config.ts +4 -11
  143. package/src/connectors.ts +10 -8
  144. package/src/context-advisory.ts +22 -21
  145. package/src/db/agent-action-write.ts +36 -0
  146. package/src/db/agent-control-async.ts +9 -0
  147. package/src/db/agent-control-write.ts +49 -0
  148. package/src/db/agent-effort-observe.ts +22 -0
  149. package/src/db/agent-meta.ts +14 -3
  150. package/src/db/agents-async.ts +8 -5
  151. package/src/db/agents.ts +15 -12
  152. package/src/db/auth-identities.ts +2 -2
  153. package/src/db/automation-read-ops.ts +11 -0
  154. package/src/db/automation-write-ops.ts +46 -0
  155. package/src/db/blackboard.ts +2 -2
  156. package/src/db/browser-session-write.ts +32 -0
  157. package/src/db/bus-outbox-write-ops.ts +3 -1
  158. package/src/db/checkout-refresh-schema.ts +47 -0
  159. package/src/db/checkout-refresh.ts +5 -5
  160. package/src/db/command-agent-profile-backfill.ts +39 -0
  161. package/src/db/command-agent-profiles.ts +5 -1
  162. package/src/db/command-retention.ts +126 -0
  163. package/src/db/commands-planner-stats.test-fixture.ts +8 -0
  164. package/src/db/commands-read-ops.ts +16 -0
  165. package/src/db/connection.ts +1 -182
  166. package/src/db/context-carry-write.ts +74 -0
  167. package/src/db/continuations.ts +4 -4
  168. package/src/db/db-error-registry.ts +12 -0
  169. package/src/db/gateway.ts +26 -133
  170. package/src/db/history-retention-ops.ts +13 -0
  171. package/src/db/inbox-async.ts +2 -2
  172. package/src/db/inbox-read-ops.ts +1 -1
  173. package/src/db/inbox.ts +9 -3
  174. package/src/db/issue-associations.ts +2 -2
  175. package/src/db/issue-refs-async.ts +4 -1
  176. package/src/db/issue-refs-read-ops.ts +6 -0
  177. package/src/db/issue-refs.ts +8 -8
  178. package/src/db/kernel-event-log-schema.ts +2 -0
  179. package/src/db/land-boundaries.ts +51 -5
  180. package/src/db/land-gate-attestations.ts +2 -2
  181. package/src/db/landing-receipts.ts +2 -2
  182. package/src/db/lifecycle-context-write.ts +5 -0
  183. package/src/db/lifecycle-tail-async.ts +76 -0
  184. package/src/db/lifecycle-tail-write-ops.ts +62 -0
  185. package/src/db/lifecycle-write-window.ts +2 -1
  186. package/src/db/lineage-pair-dedupe-sql.ts +3 -3
  187. package/src/db/main-connection-mode.ts +11 -0
  188. package/src/db/main-connection-writes.ts +20 -2
  189. package/src/db/maintenance-job-runs-async.ts +2 -2
  190. package/src/db/maintenance-job-write-ops.ts +1 -1
  191. package/src/db/maintenance-pauses.ts +2 -2
  192. package/src/db/message-send.ts +4 -0
  193. package/src/db/messages.ts +31 -25
  194. package/src/db/migrations.ts +18 -1
  195. package/src/db/notification-write-ops.ts +19 -0
  196. package/src/db/operator-answer-write.ts +19 -0
  197. package/src/db/orchestrators.ts +10 -4
  198. package/src/db/pairs-async.ts +22 -1
  199. package/src/db/pairs-write-ops.ts +8 -3
  200. package/src/db/pairs.ts +41 -48
  201. package/src/db/plan-dispatch-schema.ts +5 -1
  202. package/src/db/plan-ready-notices.ts +43 -0
  203. package/src/db/plan-tools-include-migration.ts +36 -0
  204. package/src/db/plans-write-ops.ts +2 -0
  205. package/src/db/presence-buffer.ts +5 -0
  206. package/src/db/presence-loop.ts +18 -23
  207. package/src/db/presence-write.ts +0 -6
  208. package/src/db/project-entries-async.ts +14 -0
  209. package/src/db/project-entries-read-ops.ts +5 -1
  210. package/src/db/project-entries-write-ops.ts +8 -0
  211. package/src/db/project-entries.ts +15 -12
  212. package/src/db/project-journal.ts +2 -2
  213. package/src/db/project-trust-approvals.ts +2 -2
  214. package/src/db/prompt-templates.ts +4 -4
  215. package/src/db/read-op-marshaling-fixtures.ts +18 -0
  216. package/src/db/read-ops.ts +4 -0
  217. package/src/db/retention.ts +13 -2
  218. package/src/db/review-publish-write.ts +8 -0
  219. package/src/db/runtime-admin-async.ts +19 -0
  220. package/src/db/runtime-admin-write-ops.ts +36 -0
  221. package/src/db/runtime-tail-async.ts +288 -0
  222. package/src/db/runtime-tail-write-ops.ts +97 -0
  223. package/src/db/schema.ts +4 -1
  224. package/src/db/spawn-budget.ts +5 -0
  225. package/src/db/spawn-delegation.ts +1 -11
  226. package/src/db/sql-audit-indexes.ts +3 -0
  227. package/src/db/stats-async.ts +5 -3
  228. package/src/db/task-entity.ts +5 -4
  229. package/src/db/team-claim-policy.ts +60 -0
  230. package/src/db/teams-async.ts +4 -0
  231. package/src/db/teams-write-ops.ts +4 -0
  232. package/src/db/terminal-events.ts +15 -0
  233. package/src/db/timer-cutover-bodies.ts +292 -0
  234. package/src/db/timer-cutover-core.ts +37 -278
  235. package/src/db/timer-cutover-state.ts +40 -0
  236. package/src/db/timer-cutover-write-ops.ts +1 -40
  237. package/src/db/token-db-write-ops.ts +2 -0
  238. package/src/db/token-standing-async.ts +12 -0
  239. package/src/db/token-standing.ts +6 -9
  240. package/src/db/token-usage-retention.ts +33 -0
  241. package/src/db/token-usage-write-ops.ts +1 -1
  242. package/src/db/token-usage.ts +4 -1
  243. package/src/db/user-invites-async.ts +13 -0
  244. package/src/db/user-invites.ts +3 -3
  245. package/src/db/users.ts +14 -6
  246. package/src/db/workspaces.ts +8 -5
  247. package/src/db/write-ops.ts +31 -12
  248. package/src/db/writer-fault-seam.ts +2 -9
  249. package/src/db/writer-fault-test-ops.ts +18 -0
  250. package/src/db/writer-gateway.ts +42 -46
  251. package/src/dev.ts +8 -3
  252. package/src/event-loop-lag.ts +4 -2
  253. package/src/event-loop-yield.ts +2 -2
  254. package/src/events.ts +10 -8
  255. package/src/host-provider-store.ts +5 -4
  256. package/src/hub-metrics-report.ts +5 -1
  257. package/src/hub-metrics.ts +38 -18
  258. package/src/injection-sweep-pacing.ts +6 -8
  259. package/src/land-gate-notifications.ts +11 -10
  260. package/src/land-gate-queue-progress.ts +3 -3
  261. package/src/land-settle-dispatch.ts +52 -92
  262. package/src/lifecycle-context-pressure.ts +11 -10
  263. package/src/lifecycle-manager.ts +104 -98
  264. package/src/maintenance/breaker.ts +18 -16
  265. package/src/maintenance/checkout-refresh.ts +18 -1
  266. package/src/maintenance/critical-job-watchdog.ts +3 -3
  267. package/src/maintenance/events.ts +3 -3
  268. package/src/maintenance/history-retention-job.ts +30 -0
  269. package/src/maintenance/jobs.ts +29 -67
  270. package/src/maintenance/long-running-work.ts +3 -1
  271. package/src/maintenance/offline-agent-prune-job.ts +28 -0
  272. package/src/maintenance/orphaned-sessions.ts +5 -4
  273. package/src/maintenance/pauses.ts +4 -10
  274. package/src/maintenance/plan-ready-notice-job.ts +71 -0
  275. package/src/maintenance/scheduler.ts +18 -13
  276. package/src/maintenance/stalled-delivery-pager.ts +4 -4
  277. package/src/maintenance/teams.ts +19 -30
  278. package/src/maintenance/workspaces.ts +17 -27
  279. package/src/managed-policy-escalation.ts +7 -7
  280. package/src/managed-policy.ts +3 -3
  281. package/src/managed-provider-gate.ts +5 -4
  282. package/src/managed-spawn-reservation.ts +5 -4
  283. package/src/mcp/index.ts +8 -8
  284. package/src/mcp/output-descriptions.ts +1 -1
  285. package/src/mcp/presentation.ts +2 -1
  286. package/src/mcp/runtime-output.ts +6 -1
  287. package/src/mcp/self-care-visibility.ts +2 -2
  288. package/src/mcp/spawn-targets-matrix.ts +10 -1
  289. package/src/mcp/tool-groups.ts +3 -2
  290. package/src/mcp/tool-roles.ts +81 -0
  291. package/src/mcp/tools-workspace.ts +1 -1
  292. package/src/mcp-blackboard-tools.ts +6 -5
  293. package/src/mcp-decision-tools.ts +7 -7
  294. package/src/mcp-egress-tools.ts +10 -9
  295. package/src/mcp-issue-activity-tools.ts +2 -2
  296. package/src/mcp-issue-association-tools.ts +4 -4
  297. package/src/mcp-issue-ref-tools.ts +3 -3
  298. package/src/mcp-merge-tools.ts +5 -5
  299. package/src/mcp-notification-subscription-tools.ts +14 -15
  300. package/src/mcp-output-levels.test-fixture.ts +1 -1
  301. package/src/mcp-profile-trust-tools.ts +1 -1
  302. package/src/mcp-project-journal-tools.ts +4 -12
  303. package/src/mcp-project-tools.ts +17 -18
  304. package/src/mcp-routing-policy-tools.ts +3 -2
  305. package/src/mcp-team-tools.ts +6 -6
  306. package/src/mcp-workflow-tools.ts +5 -3
  307. package/src/memory-area-injection.ts +13 -12
  308. package/src/memory-boundary-capture.ts +6 -6
  309. package/src/memory-injection.ts +45 -43
  310. package/src/merge-pause-maintenance.ts +5 -4
  311. package/src/notification-router.ts +44 -17
  312. package/src/notify.ts +5 -5
  313. package/src/observed-reset-refresh.ts +4 -4
  314. package/src/operator-alarm.ts +2 -5
  315. package/src/project-ingest.ts +6 -6
  316. package/src/project-instructions.ts +8 -1
  317. package/src/project-trust.ts +12 -11
  318. package/src/prompt-resolver.ts +3 -3
  319. package/src/provider-quota-async.ts +5 -7
  320. package/src/provider-timeline-event.ts +4 -7
  321. package/src/quota-band-delivery.ts +2 -2
  322. package/src/recipe-runner.ts +4 -3
  323. package/src/retention-config-store.ts +4 -3
  324. package/src/reviewer-pipeline.ts +11 -10
  325. package/src/routes/_route.ts +4 -4
  326. package/src/routes/_shared.ts +13 -12
  327. package/src/routes/agent-effort.ts +5 -5
  328. package/src/routes/agent-heartbeat-quota.ts +23 -0
  329. package/src/routes/agent-keep.ts +1 -1
  330. package/src/routes/agent-reporting.ts +1 -1
  331. package/src/routes/agent-self-effort.ts +5 -5
  332. package/src/routes/agent-sessions.ts +24 -24
  333. package/src/routes/agents-spawn.ts +1 -1
  334. package/src/routes/agents.ts +17 -119
  335. package/src/routes/auth.ts +14 -15
  336. package/src/routes/authority-audit.ts +2 -2
  337. package/src/routes/automations.ts +6 -5
  338. package/src/routes/channel-binding-delete.ts +1 -1
  339. package/src/routes/channel-output.ts +3 -3
  340. package/src/routes/claude-api-budget.ts +5 -5
  341. package/src/routes/commands-listing.ts +1 -1
  342. package/src/routes/commands.ts +29 -27
  343. package/src/routes/context-resets.ts +2 -2
  344. package/src/routes/coordinator-teams.ts +1 -1
  345. package/src/routes/decisions.ts +2 -2
  346. package/src/routes/host-secret-files.ts +1 -1
  347. package/src/routes/hosts.ts +11 -11
  348. package/src/routes/inbox.ts +3 -2
  349. package/src/routes/index.ts +2 -1
  350. package/src/routes/integrations.ts +9 -7
  351. package/src/routes/issue-activity.ts +2 -2
  352. package/src/routes/issue-associations.ts +4 -4
  353. package/src/routes/issue-refs.ts +3 -3
  354. package/src/routes/kernel-timers-operator.ts +1 -1
  355. package/src/routes/memory.ts +1 -1
  356. package/src/routes/merges.ts +11 -11
  357. package/src/routes/messages.ts +23 -17
  358. package/src/routes/orchestrator-bootstrap.ts +1 -1
  359. package/src/routes/orchestrator-host-registration.ts +2 -0
  360. package/src/routes/orchestrator-host-utilization.ts +2 -2
  361. package/src/routes/orchestrator-proxy.ts +2 -2
  362. package/src/routes/orchestrator.ts +27 -18
  363. package/src/routes/pairs.ts +8 -8
  364. package/src/routes/project-profile-instructions.ts +1 -1
  365. package/src/routes/project-trust.ts +1 -1
  366. package/src/routes/projects.ts +16 -16
  367. package/src/routes/prompt-templates.ts +12 -12
  368. package/src/routes/provider-quotas.ts +10 -10
  369. package/src/routes/run-command.ts +1 -1
  370. package/src/routes/secrets-backup.ts +2 -2
  371. package/src/routes/secrets-import.ts +1 -1
  372. package/src/routes/secrets-vault.ts +7 -7
  373. package/src/routes/settings.ts +1 -1
  374. package/src/routes/shipping.ts +9 -1
  375. package/src/routes/spawn-policy.ts +8 -7
  376. package/src/routes/sse.ts +2 -2
  377. package/src/routes/team-templates.ts +7 -7
  378. package/src/routes/teams.ts +10 -10
  379. package/src/routes/tokens.ts +18 -17
  380. package/src/routes/users.ts +24 -24
  381. package/src/routes/viewer-read.ts +3 -3
  382. package/src/routes/web-tool-calls.ts +4 -4
  383. package/src/routes/workflows.ts +2 -2
  384. package/src/routes/workspaces.ts +17 -16
  385. package/src/routing-policy-push.ts +6 -6
  386. package/src/runtime-grant.ts +17 -11
  387. package/src/runtime-tokens.ts +20 -28
  388. package/src/secrets-broker/config.ts +1 -1
  389. package/src/secrets-broker/service.ts +2 -2
  390. package/src/security.ts +3 -1
  391. package/src/self-resume-carry.ts +21 -110
  392. package/src/self-resume-supersede.ts +4 -3
  393. package/src/self-resume.ts +54 -66
  394. package/src/server-background.ts +1 -1
  395. package/src/server.ts +21 -22
  396. package/src/services/agent-action.ts +12 -31
  397. package/src/services/agent-effort.ts +7 -32
  398. package/src/services/agent-hang-watchdog-job.ts +2 -2
  399. package/src/services/agent-heartbeat.ts +166 -0
  400. package/src/services/agent-reporting.ts +1 -1
  401. package/src/services/browser-inventory.ts +3 -3
  402. package/src/services/browser-session-state.ts +3 -2
  403. package/src/services/browser-session.ts +21 -27
  404. package/src/services/bus-command-update.ts +9 -9
  405. package/src/services/checkout-refresh-state.ts +1 -0
  406. package/src/services/checkout-refresh.test-fixture.ts +3 -2
  407. package/src/services/command-host.ts +7 -2
  408. package/src/services/coordinator-digest.ts +3 -2
  409. package/src/services/dispatch-command.ts +12 -13
  410. package/src/services/effective-launch-driver.ts +14 -9
  411. package/src/services/host-changed-paths.test-fixture.ts +5 -6
  412. package/src/services/host-project-readiness.ts +2 -2
  413. package/src/services/host-providers.ts +1 -1
  414. package/src/services/host-utilization.ts +9 -9
  415. package/src/services/idle-agent-digest.ts +17 -12
  416. package/src/services/idle-epics.ts +4 -4
  417. package/src/services/interrupt-agent.ts +12 -9
  418. package/src/services/issue-activity.ts +3 -3
  419. package/src/services/issue-associations.ts +15 -18
  420. package/src/services/issue-lifecycle-comments.ts +3 -2
  421. package/src/services/issue-lifecycle.ts +14 -13
  422. package/src/services/issue-refs.ts +4 -5
  423. package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
  424. package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
  425. package/src/services/kernel-timers-ingress.ts +3 -3
  426. package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
  427. package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
  428. package/src/services/kernel-timers-outbox.ts +1 -1
  429. package/src/services/kernel-timers-stage10-operator.ts +1 -1
  430. package/src/services/kernel-timers.ts +4 -3
  431. package/src/services/land-gate-placement.ts +11 -2
  432. package/src/services/land-issue-relations.ts +5 -4
  433. package/src/services/land-restart-retry.ts +7 -6
  434. package/src/services/landed-ancestry.ts +6 -5
  435. package/src/services/legacy-landing-host.ts +4 -1
  436. package/src/services/legacy-landing-recovery.ts +8 -6
  437. package/src/services/managed-running.ts +17 -17
  438. package/src/services/memory-areas.ts +3 -3
  439. package/src/services/merge-pause.ts +9 -15
  440. package/src/services/operator-decisions.ts +37 -41
  441. package/src/services/orchestrator-registration-recovery.ts +6 -2
  442. package/src/services/orchestrator-upgrade.ts +14 -12
  443. package/src/services/permission-decision.ts +4 -3
  444. package/src/services/plan-ci-notice.ts +1 -1
  445. package/src/services/plan-conformance.ts +4 -4
  446. package/src/services/plan-dispatch-policy.ts +10 -3
  447. package/src/services/plan-dispatch.ts +35 -14
  448. package/src/services/plan-graph.ts +39 -261
  449. package/src/services/plan-import.ts +1 -1
  450. package/src/services/plan-live-bindings.ts +8 -37
  451. package/src/services/plan-task-create.ts +1 -1
  452. package/src/services/plan-terminal-refs.ts +2 -12
  453. package/src/services/plan-wake-digest.ts +8 -3
  454. package/src/services/profile-trust.ts +2 -2
  455. package/src/services/project.ts +11 -10
  456. package/src/services/prompt-templates.ts +6 -5
  457. package/src/services/provider-hold-nudge.ts +9 -9
  458. package/src/services/provider-hold-record.ts +13 -12
  459. package/src/services/provider-state-audit.ts +19 -18
  460. package/src/services/provisioning-harness/driver.ts +1 -1
  461. package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
  462. package/src/services/provisioning-harness/lifecycle.ts +24 -22
  463. package/src/services/provisioning-harness/prepare.ts +16 -17
  464. package/src/services/rate-limit-resume.ts +10 -9
  465. package/src/services/red-main-auto-revert.ts +7 -5
  466. package/src/services/red-main-controller-deps.ts +20 -3
  467. package/src/services/red-main-incident.ts +3 -1
  468. package/src/services/red-main-quarantine.ts +2 -3
  469. package/src/services/register-agent.ts +22 -22
  470. package/src/services/restart-project-role.ts +1 -1
  471. package/src/services/restart-spawn.ts +17 -16
  472. package/src/services/review-publish.ts +7 -24
  473. package/src/services/review-ref-reconcile.ts +29 -38
  474. package/src/services/runtime-dependency-alert.ts +27 -0
  475. package/src/services/scheduler-command.ts +11 -9
  476. package/src/services/scheduler.ts +5 -5
  477. package/src/services/self-effort-grant.ts +5 -25
  478. package/src/services/send-message.ts +16 -33
  479. package/src/services/shutdown-agent.ts +17 -14
  480. package/src/services/spawn-agent.ts +12 -41
  481. package/src/services/spawn-chain-inspector.ts +1 -1
  482. package/src/services/spawn-cwd-placement.ts +21 -5
  483. package/src/services/spawn-issue-activity.ts +8 -6
  484. package/src/services/spawn-launch.ts +17 -1
  485. package/src/services/spawn-loss-escalation.ts +1 -1
  486. package/src/services/spawn-registration-watchdog.ts +2 -2
  487. package/src/services/spawn-repo-probe.ts +7 -5
  488. package/src/services/spawn-tree-cleanup.ts +7 -8
  489. package/src/services/steward-reaper.ts +4 -4
  490. package/src/services/task-context-hydration.ts +25 -1
  491. package/src/services/task-delivery.ts +20 -34
  492. package/src/services/task-entity.ts +40 -203
  493. package/src/services/task-issue-link.ts +13 -20
  494. package/src/services/task-issue-weave.ts +12 -11
  495. package/src/services/task-lifecycle.ts +27 -31
  496. package/src/services/task-repo-cwd.ts +37 -0
  497. package/src/services/task-review-hold.ts +4 -17
  498. package/src/services/task-semantic-events.ts +13 -11
  499. package/src/services/task-state-reconcile.ts +3 -4
  500. package/src/services/task-validation.ts +2 -2
  501. package/src/services/team-templates.ts +5 -5
  502. package/src/services/team.ts +31 -98
  503. package/src/services/terminal-provider-exit.ts +6 -5
  504. package/src/services/timer-message-fire-chaos-worker.ts +7 -3
  505. package/src/services/timer-message-fire-outbox.ts +1 -1
  506. package/src/services/transient-agent-reaper.ts +22 -19
  507. package/src/services/turn-reconcile-audit.ts +9 -9
  508. package/src/services/user-onboarding.ts +8 -6
  509. package/src/services/user-profile.ts +6 -9
  510. package/src/services/work-finality.ts +16 -4
  511. package/src/services/workflow-auto-start.ts +2 -1
  512. package/src/services/workflow-caller.ts +61 -4
  513. package/src/services/workflow-child-proof-worker.ts +1 -1
  514. package/src/services/workflow-control-proof-worker.ts +1 -1
  515. package/src/services/workflow-coordinator.ts +8 -2
  516. package/src/services/workflow-decisions.ts +5 -5
  517. package/src/services/workflow-deferred-cleanup.ts +1 -1
  518. package/src/services/workflow-effect-driver.ts +42 -19
  519. package/src/services/workflow-effects.ts +41 -27
  520. package/src/services/workflow-pins.ts +7 -4
  521. package/src/services/workflow-reconcile.ts +1 -0
  522. package/src/services/workflow-resume-pins.ts +3 -3
  523. package/src/services/workflow-routing-defaults.ts +18 -0
  524. package/src/services/workflow-run-view.ts +4 -3
  525. package/src/services/workflow-run.test-fixture.ts +1 -1
  526. package/src/services/workflow-runs.ts +34 -22
  527. package/src/services/workflow-supervisor-state.ts +21 -1
  528. package/src/services/workflow-supervisor.ts +4 -3
  529. package/src/services/workspace-recovery.ts +4 -3
  530. package/src/spawn-admission.ts +10 -2
  531. package/src/spawn-placement.ts +27 -9
  532. package/src/spawn-targets.ts +8 -8
  533. package/src/sse-agent-status.ts +15 -6
  534. package/src/sse.ts +49 -24
  535. package/src/startup-context-injection.ts +61 -57
  536. package/src/steward-handoff.ts +4 -3
  537. package/src/steward-policy-cleanup.ts +9 -8
  538. package/src/steward.ts +2 -2
  539. package/src/task-dispatch-live.ts +5 -2
  540. package/src/task-dispatcher.ts +2 -2
  541. package/src/token-db.ts +2 -2
  542. package/src/token-usage-async.ts +2 -4
  543. package/src/user-awaiting-reply.ts +5 -5
  544. package/src/workspace-actions.ts +24 -29
  545. package/src/workspace-auto-merge.ts +14 -12
  546. package/src/workspace-changed-paths-client.ts +16 -5
  547. package/src/workspace-cleanup-stale.ts +30 -7
  548. package/src/workspace-command-settle.ts +24 -16
  549. package/src/workspace-config.ts +1 -1
  550. package/src/workspace-conflict-resolver.ts +9 -7
  551. package/src/workspace-dead-owner-recovery.ts +5 -4
  552. package/src/workspace-escalation.ts +12 -11
  553. package/src/workspace-human-escalation.ts +3 -3
  554. package/src/workspace-land-gate-watchdog.ts +3 -3
  555. package/src/workspace-land-refusal.ts +20 -0
  556. package/src/workspace-land-stopped.ts +1 -0
  557. package/src/workspace-merge.ts +10 -26
  558. package/src/workspace-nothing-to-land-notice.ts +2 -2
  559. package/src/workspace-orphans.ts +18 -37
  560. package/src/workspace-pr-completion.ts +10 -8
  561. package/src/workspace-rekey.ts +3 -3
  562. package/src/workspace-steward-failure.ts +2 -2
  563. package/src/workspace-steward-wake.ts +2 -2
  564. package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
  565. package/public/assets/provider-display-DsuWMvVL.js +0 -2
  566. package/public/assets/run-card-CpKqRbhg.js +0 -2
  567. package/public/assets/shipping-B9YtnwtG.js +0 -2
  568. package/public/assets/store-DcClXLH0.js +0 -9
  569. package/runner/src/agent-runner/http-liveness.ts +0 -85
  570. package/src/db/on-loop-write-transaction.ts +0 -34
@@ -1,20 +1,6 @@
1
- import {
2
- getTaskDetail,
3
- getWorkspace,
4
- insertTaskEvent,
5
- markTaskDeliverableEffectsCompleteAsync,
6
- ownedIsolatedWorkspace,
7
- recordGateAsync,
8
- recordTaskDeliverableAsync,
9
- recordTaskDeliverableWithLandingIngressAsync,
10
- setTaskStage,
11
- setTaskStatus,
12
- setTaskStatusAsync,
13
- transitionWorkspaceLandStateAsync,
14
- workspaceLandAuthorization, workspaceLandAuthorizationWithdrawn,
15
- ValidationError,
16
- type CompleteDeliveryArmOutcome,
17
- } from "../db";
1
+ import { setTaskStatusAsync, setTaskStageAsync } from "../db/task-entity-async";
2
+ import { insertTaskEventAsync } from "../db/runtime-tail-async";
3
+ import { getTaskDetail, getWorkspace, markTaskDeliverableEffectsCompleteAsync, ownedIsolatedWorkspace, recordGateAsync, recordTaskDeliverableAsync, recordTaskDeliverableWithLandingIngressAsync, transitionWorkspaceLandStateAsync, workspaceLandAuthorization, workspaceLandAuthorizationWithdrawn, ValidationError, type CompleteDeliveryArmOutcome } from "../db";
18
4
  import { refreshWorkspaceGitState } from "../workspace-probe";
19
5
  import { pinWorkspaceDeliveryTip } from "../workspace-delivery-tip";
20
6
  import { recoverIsolatedWorkspace, type WorkspaceRecoveryHint } from "./workspace-recovery";
@@ -25,7 +11,7 @@ import { emitTaskChanged, emitNewMessages } from "../sse";
25
11
  import { agentBoundTaskIds, hasTaskReadAdminScope } from "../task-authz";
26
12
  import { applyWorkspaceAction } from "../workspace-actions";
27
13
  import { LAND_IN_FLIGHT_STATUSES, LAND_REQUEST_STALE_ON_HEAD_ADVANCE_STATUSES } from "../workspace-phase";
28
- import { findLatestCommandByCorrelation } from "../commands-db";
14
+ import { findLatestCommandByCorrelationAsync } from "../commands-write";
29
15
  import { mergeCommandNeedsRetry } from "../workspace-merge-progress";
30
16
  import { workspaceLandNeedsRearm } from "../workspace-land-retry";
31
17
  import { emitTaskSemanticNotification } from "./task-semantic-events";
@@ -120,7 +106,7 @@ function shouldRebindToWorkspace(task: TaskDetail, ws: WorkspaceRecord | undefin
120
106
  return Boolean(task.branch && ws?.branch && task.branch !== ws.branch);
121
107
  }
122
108
 
123
- function resolveWorkspace(ctx: AuthContext, input: Pick<DeliverTaskInput, "workspaceId" | "workspace" | "idempotencyKey">, taskId: number, opts: { allowRebind?: boolean } = {}): WorkspaceRecord | undefined {
109
+ async function resolveWorkspace(ctx: AuthContext, input: Pick<DeliverTaskInput, "workspaceId" | "workspace" | "idempotencyKey">, taskId: number, opts: { allowRebind?: boolean } = {}): Promise<WorkspaceRecord | undefined> {
124
110
  const caller = ctx.callerAgentId;
125
111
  const explicit = input.workspaceId?.trim();
126
112
  let ws = explicit ? getWorkspace(explicit) : caller ? ownedIsolatedWorkspace(caller) : undefined;
@@ -133,7 +119,7 @@ function resolveWorkspace(ctx: AuthContext, input: Pick<DeliverTaskInput, "works
133
119
  // server-authoritative recovery (signed spawn-request association + immutable agent.spawn params +
134
120
  // orchestrator baseDir containment); the descriptor is an untrusted hint, never trusted verbatim.
135
121
  if (!ws && input.workspace) {
136
- const recovery = recoverIsolatedWorkspace(ctx, input.workspace, explicit);
122
+ const recovery = (await recoverIsolatedWorkspace(ctx, input.workspace, explicit));
137
123
  if (recovery.ok) ws = recovery.workspace;
138
124
  }
139
125
  if (!ws) return undefined;
@@ -149,18 +135,18 @@ function resolveWorkspace(ctx: AuthContext, input: Pick<DeliverTaskInput, "works
149
135
  return ws;
150
136
  }
151
137
 
152
- function rebindTaskToWorkspaceIfNeeded(task: TaskDetail, ws: WorkspaceRecord | undefined, actor: string): TaskDetail {
138
+ async function rebindTaskToWorkspaceIfNeeded(task: TaskDetail, ws: WorkspaceRecord | undefined, actor: string): Promise<TaskDetail> {
153
139
  if (!shouldRebindToWorkspace(task, ws)) return task;
154
- setTaskStatus(task.id, {
140
+ (await setTaskStatusAsync(task.id, {
155
141
  status: "in_progress",
156
142
  note: `fix-forward rebind to workspace ${ws.id} (${ws.branch})`,
157
143
  actor,
158
- });
159
- return setTaskStage(task.id, {
144
+ }));
145
+ return (await setTaskStageAsync(task.id, {
160
146
  deliverableStage: "committed-on-branch",
161
147
  branch: ws.branch,
162
148
  actor,
163
- });
149
+ }));
164
150
  }
165
151
 
166
152
  function cleanReason(value: unknown, disposition: "blocked" | "failed"): string {
@@ -189,7 +175,7 @@ function skippedRequiredGateReports(reason: string): Required<Pick<TaskDeliveryG
189
175
  // Non-landing dispositions (blocked/failed/needs-review, and a verdict-only complete that closes on
190
176
  // delivery with no land) keep their honest existing wording. #2518 adds the third shape: a complete
191
177
  // delivery ACCEPTED but HELD for coordinator review — it says exactly that and never claims landing.
192
- function notifyDelivery(taskId: number, eventId: number, metadata: TaskDeliverableEventMetadata, landing: boolean): void {
178
+ async function notifyDelivery(taskId: number, eventId: number, metadata: TaskDeliverableEventMetadata, landing: boolean): Promise<void> {
193
179
  const task = getTaskDetail(taskId);
194
180
  if (!task) return;
195
181
  const linkedIssues = task.issues.map((issue) => ({ provider: issue.provider, repo: issue.repo, externalKey: issue.externalKey, title: issue.title, status: issue.status }));
@@ -227,7 +213,7 @@ function notifyDelivery(taskId: number, eventId: number, metadata: TaskDeliverab
227
213
  const notArmedWarning = metadata.landNotArmedReason && unmergedAhead > 0
228
214
  ? `\n⚠ NOT landed: ${unmergedAhead} unmerged commit(s) remain on ${metadata.workspaceId ?? "the workspace"} (no land armed — ${metadata.landNotArmedReason}). Land it explicitly if this work belongs on main.`
229
215
  : "";
230
- const delivered = routeNotification({
216
+ const delivered = await routeNotification({
231
217
  type: "task.deliverable",
232
218
  scope: {
233
219
  taskId: String(taskId),
@@ -309,7 +295,7 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
309
295
  // `complete` changes, from a hard reject to the same owner-authorized resolve the land path had.
310
296
  // The TASK-record rebind itself (rebindTaskToWorkspaceIfNeeded) is still gated on `wantsLand`.
311
297
  let workspace = input.disposition === "complete" || input.workspaceId
312
- ? resolveWorkspace(ctx, input, taskId, { allowRebind: input.disposition === "complete" })
298
+ ? (await resolveWorkspace(ctx, input, taskId, { allowRebind: input.disposition === "complete" }))
313
299
  : undefined;
314
300
  // A workspace that could actually carry a land: isolated, live on disk, and on a branch. Mirrors
315
301
  // the preconditions enforced below (:live isolated workspace / :exact resolved source ref), so a
@@ -459,7 +445,7 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
459
445
  }
460
446
  if (ahead > 0) landNotArmed = { reason: workspaceLandBlocked(workspace) ? "workspace-land-blocked" : landDecision.reason, unmergedAhead: ahead };
461
447
  }
462
- const currentTask = wantsLand && !noWork ? rebindTaskToWorkspaceIfNeeded(before, workspace, actor) : before;
448
+ const currentTask = wantsLand && !noWork ? (await rebindTaskToWorkspaceIfNeeded(before, workspace, actor)) : before;
463
449
  const sourceRef = wantsLand ? replayLand?.sourceRef ?? workspace?.branch?.trim() : undefined;
464
450
  // Only the HEAD returned by THIS host probe can authorize ingress. Persisted metadata may be
465
451
  // stale, and the caller's commit list is a self-report; neither is authority for a mutable ref.
@@ -520,7 +506,7 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
520
506
  // Pin the delivered tip captured at delivery; the host publishes it ONLY if reachable from the
521
507
  // verified workspace tip, else REFUSES (H1 — fail closed), so no unrelated local commit rides in.
522
508
  const deliveredSha = input.commits?.length ? input.commits[input.commits.length - 1]?.sha : undefined;
523
- reviewPublish = dispatchReviewPublish(reviewWorkspace, { requestedBy: actor, taskId, sha: deliveredSha, emit: emitCommand });
509
+ reviewPublish = (await dispatchReviewPublish(reviewWorkspace, { requestedBy: actor, taskId, sha: deliveredSha, emit: emitCommand }));
524
510
  }
525
511
  const deliveryInput = {
526
512
  ...input,
@@ -617,9 +603,9 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
617
603
  const detail = getTaskDetail(taskId) ?? currentTask;
618
604
  if (detail) {
619
605
  emitTaskChanged(detail, "task.deliverable");
620
- notifyDelivery(taskId, delivery.event.id, eventMeta ?? (delivery.event.metadata as unknown as TaskDeliverableEventMetadata), wantsLand && armOutcome === "armed");
606
+ await notifyDelivery(taskId, delivery.event.id, eventMeta ?? (delivery.event.metadata as unknown as TaskDeliverableEventMetadata), wantsLand && armOutcome === "armed");
621
607
  if (input.disposition === "failed") {
622
- emitTaskSemanticNotification({ task: detail, transition: "gate-failed", actor, occurrenceKey: `event:${delivery.event.id}`, outcome: { disposition: "failed" } });
608
+ await emitTaskSemanticNotification({ task: detail, transition: "gate-failed", actor, occurrenceKey: `event:${delivery.event.id}`, outcome: { disposition: "failed" } });
623
609
  }
624
610
  }
625
611
  }
@@ -685,7 +671,7 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
685
671
  // into same-head `already-requested`; only terminal non-PR attempts qualify,
686
672
  // so a currently running merge or a PR waiting on GitHub is never doubled.
687
673
  const priorMerge = LAND_IN_FLIGHT_STATUSES.has(liveWorkspace.status)
688
- ? findLatestCommandByCorrelation("workspace.merge", liveWorkspace.id)
674
+ ? await findLatestCommandByCorrelationAsync("workspace.merge", liveWorkspace.id)
689
675
  : null;
690
676
  const retryableMergePlan = mergeCommandNeedsRetry(priorMerge);
691
677
  const withdrawnLand = !hadLandAuthorization
@@ -697,7 +683,7 @@ export async function deliverTask(input: DeliverTaskInput, ctx: AuthContext): Pr
697
683
  // exhausted. applyWorkspaceAction clears the old retry incident before re-arming it.
698
684
  || retryableMergePlan || workspaceLandNeedsRearm(liveWorkspace) || withdrawnLand;
699
685
  if (reenterLand) {
700
- markAgentWorkFinal(actor, "task-deliver");
686
+ (await markAgentWorkFinal(actor, "task-deliver"));
701
687
  const result = await applyWorkspaceAction(liveWorkspace, {
702
688
  action: "ready",
703
689
  agentId: actor,
@@ -1,54 +1,11 @@
1
+ import { setTaskStatusAsync, setTaskStageAsync, markTaskAgentReapedAsync } from "../db/task-entity-async";
2
+ import { confirmWorkspaceCarryPendingForTaskAsync } from "../db/runtime-tail-async";
3
+ import { removeSubscriptionsForTaskAsync } from "../db/lifecycle-tail-async";
1
4
  // #834 — service facade for the durable Task entity. Transports (HTTP routes, MCP tools)
2
5
  // call THIS, not the db writers directly (transport-thinness, epic #342): the service owns
3
6
  // the db mutation + the SSE emission so the transport stays thin. The kind partition and all
4
7
  // validation live in the db layer (src/db/task-entity.ts); this layer adds eventing.
5
- import {
6
- addTaskDependencyAsync,
7
- addTaskRelationAsync,
8
- assignTaskAgent,
9
- assignTaskAgentAsync,
10
- clearTaskParentAsync,
11
- confirmWorkspaceCarryPendingForTask,
12
- createDeliverableTask,
13
- createDeliverableTaskAsync,
14
- deliverableTaskIdsByOwnerAgent,
15
- deliverableTaskIdsByOwnerAgentAsync,
16
- deliverableTaskIdsBySpawnRequestId,
17
- deliverableTaskIdsBySpawnRequestIdAsync,
18
- getAgent,
19
- getTaskDetail,
20
- getTaskDetailAsync, getTaskViewAsync,
21
- listAgents,
22
- listDeliverableTaskSummariesAsync,
23
- listDeliverableTasksAsync,
24
- listTaskEvents,
25
- listTaskEventsAsync,
26
- listWorkspaces,
27
- markTaskAgentReaped,
28
- markTaskAgentReapedAsync,
29
- recordGate,
30
- recordGateAsync,
31
- recordTaskDispatchDecisionAsync,
32
- removeTaskDependencyAsync,
33
- removeTaskRefAsync,
34
- removeTaskRelationAsync,
35
- setTaskParentAsync,
36
- setTaskStage,
37
- setTaskStageAsync,
38
- setTaskStatus,
39
- setTaskStatusAsync,
40
- updateDeliverableTask,
41
- updateDeliverableTaskAsync,
42
- ValidationError,
43
- type ListDeliverableTasksFilter,
44
- type RecordTaskDispatchDecisionInput,
45
- type RecordGateInput,
46
- type RemoveTaskRefInput,
47
- type SetTaskStageInput,
48
- type SetTaskStatusInput,
49
- type TaskEntityWriteOptions,
50
- type UpdateDeliverableTaskInput,
51
- } from "../db";
8
+ import { addTaskDependencyAsync, addTaskRelationAsync, assignTaskAgent, assignTaskAgentAsync, clearTaskParentAsync, createDeliverableTask, createDeliverableTaskAsync, deliverableTaskIdsByOwnerAgent, deliverableTaskIdsByOwnerAgentAsync, deliverableTaskIdsBySpawnRequestId, deliverableTaskIdsBySpawnRequestIdAsync, getAgent, getTaskDetail, getTaskDetailAsync, getTaskViewAsync, listAgents, listDeliverableTaskSummariesAsync, listDeliverableTasksAsync, listTaskEvents, listTaskEventsAsync, listWorkspaces, recordGate, recordGateAsync, recordTaskDispatchDecisionAsync, removeTaskDependencyAsync, removeTaskRefAsync, removeTaskRelationAsync, setTaskParentAsync, updateDeliverableTask, updateDeliverableTaskAsync, ValidationError, type ListDeliverableTasksFilter, type RecordTaskDispatchDecisionInput, type RecordGateInput, type RemoveTaskRefInput, type SetTaskStageInput, type SetTaskStatusInput, type TaskEntityWriteOptions, type UpdateDeliverableTaskInput } from "../db";
52
9
 
53
10
  import { validationCompletionStatus } from "../task-completion.ts";
54
11
  import { findSpawnCommandByRequestId } from "../commands-db";
@@ -56,7 +13,6 @@ import { findSpawnCommandByRequestId } from "../commands-db";
56
13
  import { emitTaskChanged } from "../sse";
57
14
  import { isCarryPendingBlocker } from "./carry-pending";
58
15
  import type { CommandStatus, Task, TaskBlocker, TaskCommitRef, TaskDeliverableEventMetadata, TaskDetail, TaskEvent, TaskGateState, TaskListItem, TaskStatus, TaskTerminalStage, WorkspaceRecord } from "../types";
59
- import { removeSubscriptionsForTask } from "../db/notification-subscriptions";
60
16
  import { emitRelayEvent } from "../events";
61
17
  import { routeNotification } from "../notification-router";
62
18
  import { isAgentExitDoneWhen } from "./task-done-when";
@@ -73,19 +29,8 @@ import { taskOwnerTarget } from "../task-owner";
73
29
  export type { CreateTaskEntityInput } from "./task-issue-link";
74
30
  export { addTaskEntityRef, addTaskEntityRefAsync, attachTaskRefs } from "./task-issue-link";
75
31
 
76
- export function createTaskEntity(input: CreateTaskEntityInput): TaskDetail {
77
- cleanIssueRefRelation(input.relation);
78
- const created = createDeliverableTask(input);
79
- const detail = addInitialIssueRefs(created.id, input);
80
- autoSubscribeTaskCoordinator(input.createdBy, detail.id);
81
- emitTaskChanged(detail, "task.created");
82
- emitTaskSemanticNotification({
83
- task: detail,
84
- transition: "created",
85
- actor: input.createdBy,
86
- occurrenceKey: latestTaskEventOccurrence(detail.id, "task.created"),
87
- });
88
- return detail;
32
+ export async function createTaskEntity(input: CreateTaskEntityInput): Promise<TaskDetail> {
33
+ return createTaskEntityAsync(input);
89
34
  }
90
35
 
91
36
  /** The off-loop twin of createTaskEntity (S3.2 L-D2 #1904) — the sanctioned HTTP/MCP create path. */
@@ -93,9 +38,9 @@ export async function createTaskEntityAsync(input: CreateTaskEntityInput, option
93
38
  cleanIssueRefRelation(input.relation);
94
39
  const created = await createDeliverableTaskAsync(input, options);
95
40
  const detail = await addInitialIssueRefsAsync(created.id, input, options);
96
- autoSubscribeTaskCoordinator(input.createdBy, detail.id);
41
+ (await autoSubscribeTaskCoordinator(input.createdBy, detail.id));
97
42
  emitTaskChanged(detail, "task.created");
98
- emitTaskSemanticNotification({
43
+ await emitTaskSemanticNotification({
99
44
  task: detail,
100
45
  transition: "created",
101
46
  actor: input.createdBy,
@@ -118,10 +63,8 @@ export function listTaskEntitySummariesAsync(filter: ListDeliverableTasksFilter
118
63
  return listDeliverableTaskSummariesAsync(filter);
119
64
  }
120
65
 
121
- export function updateTaskEntity(id: number, input: UpdateDeliverableTaskInput): TaskDetail {
122
- const detail = updateDeliverableTask(id, input);
123
- emitTaskChanged(detail, "task.updated");
124
- return detail;
66
+ export async function updateTaskEntity(id: number, input: UpdateDeliverableTaskInput): Promise<TaskDetail> {
67
+ return updateTaskEntityAsync(id, input);
125
68
  }
126
69
 
127
70
  /** The off-loop twin of updateTaskEntity (S3.2 L-D2 #1904). */
@@ -136,30 +79,22 @@ export async function updateTaskEntityAsync(id: number, input: UpdateDeliverable
136
79
  // interface that cannot yet await, S3.2 L-D2 #1904 follow-up) and the off-loop path
137
80
  // (setTaskEntityStatusAsync) apply IDENTICAL business logic over their differently-sourced `before`/
138
81
  // `detail` rows, instead of forking the notification/work-finality logic in two places.
139
- export function emitStatusChangeEffects(before: TaskDetail | null, detail: TaskDetail, actor: string | undefined, occurrenceKey: string | undefined): void {
82
+ export async function emitStatusChangeEffects(before: TaskDetail | null, detail: TaskDetail, actor: string | undefined, occurrenceKey: string | undefined): Promise<void> {
140
83
  emitTaskChanged(detail, "task.status");
141
84
  const transition = taskTransitionForStatus(detail.status, detail.blockedBy);
142
85
  if (actor !== "task-lifecycle" && transition && shouldEmitStatusTransition(before, detail, transition)) {
143
- emitTaskSemanticNotification({ task: detail, transition, actor, occurrenceKey });
86
+ await emitTaskSemanticNotification({ task: detail, transition, actor, occurrenceKey });
144
87
  }
145
- if (isTerminalTaskStatus(detail.status)) removeSubscriptionsForTask(detail.id);
88
+ if (isTerminalTaskStatus(detail.status)) await removeSubscriptionsForTaskAsync(detail.id);
146
89
  // #1084 — a task reaching `done` is an explicit, platform-owned completion signal for its
147
90
  // owning agent's work window: close it, forwarding only the held final group. The #2520
148
91
  // plan-ref propagation trigger lives with its CALLERS (below): the sync twin runs the
149
92
  // in-process op body; the async path awaits the gateway-backed seam.
150
- if (before?.status !== "done" && detail.status === "done") markAgentWorkFinal(detail.ownerAgentId, "task-done");
93
+ if (before?.status !== "done" && detail.status === "done") (await markAgentWorkFinal(detail.ownerAgentId, "task-done"));
151
94
  }
152
95
 
153
- export function setTaskEntityStatus(id: number, input: SetTaskStatusInput): TaskDetail {
154
- const before = getTaskDetail(id);
155
- const detail = setTaskStatus(id, input);
156
- emitStatusChangeEffects(before, detail, input.actor, latestTaskEventOccurrence(detail.id, `status:${detail.status}`));
157
- if (before?.status !== "done" && detail.status === "done") {
158
- // #2520 — durable status=done trigger for ref-driven plan-node terminal propagation
159
- // (in-process twin: the bus-dispatcher seam cannot await; no fire-and-forget promises).
160
- advanceTerminalPlanRefs({ taskId: detail.id, actor: input.actor });
161
- }
162
- return detail;
96
+ export async function setTaskEntityStatus(id: number, input: SetTaskStatusInput): Promise<TaskDetail> {
97
+ return setTaskEntityStatusAsync(id, input);
163
98
  }
164
99
 
165
100
  /**
@@ -175,7 +110,7 @@ export function setTaskEntityStatus(id: number, input: SetTaskStatusInput): Task
175
110
  export async function setTaskEntityStatusAsync(id: number, input: SetTaskStatusInput, options?: TaskEntityWriteOptions): Promise<TaskDetail> {
176
111
  const before = await getTaskDetailAsync(id);
177
112
  const detail = await setTaskStatusAsync(id, input, options);
178
- emitStatusChangeEffects(before, detail, input.actor, await latestTaskEventOccurrenceAsync(detail.id, `status:${detail.status}`));
113
+ await emitStatusChangeEffects(before, detail, input.actor, await latestTaskEventOccurrenceAsync(detail.id, `status:${detail.status}`));
179
114
  if (before?.status !== "done" && detail.status === "done") {
180
115
  // #2520 — awaited on the sanctioned async path so the trigger's plan writes settle in order.
181
116
  await advanceTerminalPlanRefsAsync({ taskId: detail.id, actor: input.actor });
@@ -188,33 +123,14 @@ export function isTerminalTaskStatus(status: Task["status"]): boolean {
188
123
  }
189
124
 
190
125
  // #1456 — the un-bypassable carry-pending landing gate is enforced in the LOWEST stage writer
191
- // (`db/task-entity.ts` setTaskStage), so it covers EVERY entrypoint — the land pipeline, the
126
+ // (`db/task-entity.ts` setTaskStageAsync), so it covers EVERY entrypoint — the land pipeline, the
192
127
  // no-mergedSha out-of-band reconciliation, PR/squash, a manual `relay_task_set_stage`, and the
193
128
  // deploy path (`stampDeployedTasks`, which calls the primitive directly). This service wrapper adds
194
129
  // only eventing; it does NOT re-check (guarding the wrapper too would be a second, drift-prone code
195
130
  // path — round-4: guard the primitive, not the wrapper). The land pipeline (driveTaskOnLand)
196
131
  // short-circuits earlier with a superseded event; the primitive throw is the backstop for the rest.
197
- export function setTaskEntityStage(id: number, input: SetTaskStageInput): TaskDetail {
198
- const before = getTaskDetail(id);
199
- let detail = setTaskStage(id, input);
200
- emitTaskChanged(detail, "task.stage");
201
- const transition = taskTransitionForStage(detail.deliverableStage);
202
- if (input.actor !== "task-lifecycle" && transition && before?.deliverableStage !== detail.deliverableStage) {
203
- emitTaskSemanticNotification({
204
- task: detail,
205
- transition,
206
- actor: input.actor,
207
- branch: detail.branch,
208
- occurrenceKey: latestTaskEventOccurrence(detail.id, `stage:${detail.deliverableStage}`),
209
- });
210
- }
211
- const deliverableStage = detail.deliverableStage ?? "none";
212
- if (LANDED_STAGES.has(deliverableStage)) {
213
- // #2520 — a landed/deploying/deployed stage is terminal success for ref-driven propagation.
214
- advanceTerminalPlanRefs({ taskId: detail.id, actor: input.actor });
215
- }
216
- if (before?.status !== detail.status) emitStatusChangeEffects(before, detail, input.actor, undefined);
217
- return detail;
132
+ export async function setTaskEntityStage(id: number, input: SetTaskStageInput): Promise<TaskDetail> {
133
+ return setTaskEntityStageAsync(id, input);
218
134
  }
219
135
 
220
136
  /** The off-loop twin of setTaskEntityStage (S3.2 L-D2 #1904). */
@@ -224,7 +140,7 @@ export async function setTaskEntityStageAsync(id: number, input: SetTaskStageInp
224
140
  emitTaskChanged(detail, "task.stage");
225
141
  const transition = taskTransitionForStage(detail.deliverableStage);
226
142
  if (input.actor !== "task-lifecycle" && transition && before?.deliverableStage !== detail.deliverableStage) {
227
- emitTaskSemanticNotification({
143
+ await emitTaskSemanticNotification({
228
144
  task: detail,
229
145
  transition,
230
146
  actor: input.actor,
@@ -237,7 +153,7 @@ export async function setTaskEntityStageAsync(id: number, input: SetTaskStageInp
237
153
  // #2520 — the off-loop stage trigger for ref-driven plan-node terminal propagation.
238
154
  await advanceTerminalPlanRefsAsync({ taskId: detail.id, actor: input.actor });
239
155
  }
240
- if (before?.status !== detail.status) emitStatusChangeEffects(before, detail, input.actor, undefined);
156
+ if (before?.status !== detail.status) await emitStatusChangeEffects(before, detail, input.actor, undefined);
241
157
  return detail;
242
158
  }
243
159
 
@@ -254,39 +170,11 @@ export async function setTaskEntityStageAsync(id: number, input: SetTaskStageInp
254
170
  // #831). The `deliverable.superseded` event already alerts the coordinator, who handles any
255
171
  // issue-close/reap manually in the rare revert window. Automatic host-side tree-level carry
256
172
  // verification (and lifecycle re-drive) is tracked as the #1458 follow-up.
257
- export function confirmTaskCarry(id: number, opts: { actor?: string; note?: string; commit?: TaskCommitRef; branch?: string } = {}): TaskDetail {
258
- const task = getTaskDetail(id);
259
- if (!task) throw new ValidationError("task not found");
260
- const blockers = task.blockedBy ?? [];
261
- const remaining = blockers.filter((b: TaskBlocker) => !isCarryPendingBlocker(b));
262
- const hadCarryPending = remaining.length !== blockers.length;
263
- const note = opts.note?.trim() || "delivered change confirmed carried onto the current base (#1456)";
264
- let detail = task;
265
- if (hadCarryPending) {
266
- // `allowCarryPendingClear` authorizes the primitive latch (BLOCKER 1) to drop the carry-pending
267
- // blocker(s) — this confirm is the ONLY path that may. Scoped: preserves unrelated blockers.
268
- detail = remaining.length > 0
269
- ? setTaskEntityStatus(id, { status: "blocked", blockedBy: remaining, note, actor: opts.actor, allowCarryPendingClear: true })
270
- : setTaskEntityStatus(id, { status: "in_progress", note, actor: opts.actor, allowCarryPendingClear: true });
271
- }
272
- // Clear the workspace-durable marker too (round-4 BLOCKER 3): a late-bound Task can be gated purely
273
- // by the workspace's unconfirmed head with no task-level blocker, and the marker would otherwise
274
- // re-gate the very land this confirm authorizes. Cleared for the Task's bound workspace(s).
275
- confirmWorkspaceCarryPendingForTask(task);
276
- // Optionally complete the land the carry-pending gate refused. Both obligation carriers are cleared
277
- // above, so the stage gate now permits the advance; doneWhen closes the Task as usual.
278
- if (opts.commit) {
279
- detail = setTaskEntityStage(id, {
280
- deliverableStage: "landed-on-main",
281
- ...(opts.branch ? { branch: opts.branch } : {}),
282
- commit: opts.commit,
283
- actor: opts.actor,
284
- });
285
- }
286
- return detail;
173
+ export async function confirmTaskCarry(id: number, opts: { actor?: string; note?: string; commit?: TaskCommitRef; branch?: string } = {}): Promise<TaskDetail> {
174
+ return confirmTaskCarryAsync(id, opts);
287
175
  }
288
176
 
289
- /** The off-loop twin of confirmTaskCarry (S3.2 L-D2 #1904). `confirmWorkspaceCarryPendingForTask`
177
+ /** The off-loop twin of confirmTaskCarry (S3.2 L-D2 #1904). `confirmWorkspaceCarryPendingForTaskAsync`
290
178
  * (workspaces/carry-pending-marker.ts) is a genuinely cross-domain, not-yet-migrated write — left on the
291
179
  * sync facade like the retained sync callers elsewhere in this migration; it is a single small metadata
292
180
  * write, not a hot path, so it does not defeat the point of awaiting the task-entity writes around it. */
@@ -303,7 +191,7 @@ export async function confirmTaskCarryAsync(id: number, opts: { actor?: string;
303
191
  ? await setTaskEntityStatusAsync(id, { status: "blocked", blockedBy: remaining, note, actor: opts.actor, allowCarryPendingClear: true })
304
192
  : await setTaskEntityStatusAsync(id, { status: "in_progress", note, actor: opts.actor, allowCarryPendingClear: true });
305
193
  }
306
- confirmWorkspaceCarryPendingForTask(task);
194
+ (await confirmWorkspaceCarryPendingForTaskAsync(task));
307
195
  if (opts.commit) {
308
196
  detail = await setTaskEntityStageAsync(id, {
309
197
  deliverableStage: "landed-on-main",
@@ -335,20 +223,8 @@ function shouldEmitStatusTransition(before: TaskDetail | null, detail: TaskDetai
335
223
  return false;
336
224
  }
337
225
 
338
- export function recordTaskEntityGate(id: number, input: RecordGateInput): { gate: TaskGateState; gates: TaskGateState[] } {
339
- const gate = recordGate(id, input);
340
- const detail = getTaskDetail(id);
341
- if (detail) emitTaskChanged(detail, "task.gate");
342
- if (detail && gate.status === "fail") {
343
- emitTaskSemanticNotification({
344
- task: detail,
345
- transition: "gate-failed",
346
- actor: input.actor,
347
- occurrenceKey: latestTaskEventOccurrence(detail.id, `gate:${gate.gate}`),
348
- outcome: { gate: gate.gate, status: gate.status, ...(gate.detail ? { detail: gate.detail } : {}) },
349
- });
350
- }
351
- return { gate, gates: detail?.gates ?? [] };
226
+ export async function recordTaskEntityGate(id: number, input: RecordGateInput): Promise<{ gate: TaskGateState; gates: TaskGateState[] }> {
227
+ return recordTaskEntityGateAsync(id, input);
352
228
  }
353
229
 
354
230
  /** The off-loop twin of recordTaskEntityGate (S3.2 L-D2 #1904). */
@@ -357,7 +233,7 @@ export async function recordTaskEntityGateAsync(id: number, input: RecordGateInp
357
233
  const detail = await getTaskDetailAsync(id);
358
234
  if (detail) emitTaskChanged(detail, "task.gate");
359
235
  if (detail && gate.status === "fail") {
360
- emitTaskSemanticNotification({
236
+ await emitTaskSemanticNotification({
361
237
  task: detail,
362
238
  transition: "gate-failed",
363
239
  actor: input.actor,
@@ -419,10 +295,8 @@ export async function removeTaskEntityRefAsync(id: number, input: RemoveTaskRefI
419
295
  * `registerAgent` — the same synchronous plugin/hook constraint as `setTaskEntityStatus` above. Every
420
296
  * other production caller (routes/tasks.ts, the MCP task tools) now calls `assignTaskEntityAgentAsync`.
421
297
  */
422
- export function assignTaskEntityAgent(id: number, agentId: string, role?: string, actor?: string): TaskDetail {
423
- const detail = assignTaskAgent(id, agentId, role, actor);
424
- emitTaskChanged(detail, "task.updated");
425
- return detail;
298
+ export async function assignTaskEntityAgent(id: number, agentId: string, role?: string, actor?: string): Promise<TaskDetail> {
299
+ return assignTaskEntityAgentAsync(id, agentId, role, actor);
426
300
  }
427
301
 
428
302
  /** The off-loop twin of assignTaskEntityAgent (S3.2 L-D2 #1904) — the sanctioned HTTP/MCP path. */
@@ -600,10 +474,10 @@ async function latestDeliverableEventAsync(taskId: number): Promise<TaskEvent |
600
474
  return [...(await listTaskEventsAsync(taskId))].reverse().find((event) => event.type === "deliverable");
601
475
  }
602
476
 
603
- function restoreDeliveredDisposition(task: TaskDetail, event: TaskEvent): void {
477
+ async function restoreDeliveredDisposition(task: TaskDetail, event: TaskEvent): Promise<void> {
604
478
  const metadata = event.metadata as unknown as Partial<TaskDeliverableEventMetadata>;
605
479
  if (metadata.disposition === "failed" && task.status !== "failed") {
606
- setTaskEntityStatus(task.id, {
480
+ await setTaskEntityStatus(task.id, {
607
481
  status: "failed",
608
482
  ...(typeof metadata.reason === "string" && metadata.reason.trim() ? { note: metadata.reason } : {}),
609
483
  actor: "task-lifecycle",
@@ -611,7 +485,7 @@ function restoreDeliveredDisposition(task: TaskDetail, event: TaskEvent): void {
611
485
  return;
612
486
  }
613
487
  if (metadata.disposition === "blocked" && task.status !== "blocked" && Array.isArray(metadata.blockedBy) && metadata.blockedBy.length > 0) {
614
- setTaskEntityStatus(task.id, {
488
+ await setTaskEntityStatus(task.id, {
615
489
  status: "blocked",
616
490
  blockedBy: metadata.blockedBy,
617
491
  ...(typeof metadata.reason === "string" && metadata.reason.trim() ? { note: metadata.reason } : {}),
@@ -643,46 +517,9 @@ async function restoreDeliveredDispositionAsync(task: TaskDetail, event: TaskEve
643
517
  // #889 — finalize bound tasks for a reaped agent whose doneWhen is "agent-exit" / "reaped".
644
518
  // Called by the transient reaper after requesting shutdown so ephemeral run-and-exit workers
645
519
  // don't leave their auto-scaffolded Task stuck in_progress forever.
646
- // Never overrides an already-terminal status. Idempotent (reapedAt guard inside markTaskAgentReaped).
647
- export function finalizeEphemeralTasksOnReap(agentId: string, opts: { spawnRequestId?: string; reason?: string; producedWork?: boolean; evidence?: string } = {}): number[] {
648
- const ids = new Set<number>();
649
- for (const id of deliverableTaskIdsByOwnerAgent(agentId)) ids.add(id);
650
- if (opts.spawnRequestId) {
651
- for (const id of deliverableTaskIdsBySpawnRequestId(opts.spawnRequestId)) ids.add(id);
652
- }
653
- const finalized: number[] = [];
654
- for (const taskId of ids) {
655
- const task = getTaskDetail(taskId);
656
- if (!task) continue;
657
- if (task.status === "done" || task.status === "failed" || task.status === "canceled") continue;
658
- if (!isAgentExitDoneWhen(task.doneWhen)) continue;
659
- if (opts.producedWork === false) {
660
- try {
661
- const deliverable = latestDeliverableEvent(taskId);
662
- if (deliverable) {
663
- if (!task.reapedAt) markTaskAgentReaped(taskId, { agentId, reason: opts.reason ?? "agent-exit" });
664
- restoreDeliveredDisposition(task, deliverable);
665
- finalized.push(taskId);
666
- continue;
667
- }
668
- if (!task.reapedAt) markTaskAgentReaped(taskId, { agentId, reason: opts.reason ?? "agent-exit" });
669
- setTaskEntityStatus(taskId, { status: "canceled", note: "worker reaped without landing or producing work; task canceled", actor: "task-lifecycle" });
670
- notifyEmptyTransientReap(agentId, task, opts);
671
- finalized.push(taskId);
672
- } catch {
673
- // best-effort; failures must not surface into the reaper scan
674
- }
675
- continue;
676
- }
677
- try {
678
- if (!task.reapedAt) markTaskAgentReaped(taskId, { agentId, reason: opts.reason ?? "agent-exit" });
679
- setTaskEntityStatus(taskId, { status: validationCompletionStatus(task.validationItems), note: "doneWhen=agent-exit satisfied by worker reap", actor: "task-lifecycle" });
680
- finalized.push(taskId);
681
- } catch {
682
- // best-effort; failures must not surface into the reaper scan
683
- }
684
- }
685
- return finalized;
520
+ // Never overrides an already-terminal status. Idempotent (reapedAt guard inside markTaskAgentReapedAsync).
521
+ export async function finalizeEphemeralTasksOnReap(agentId: string, opts: { spawnRequestId?: string; reason?: string; producedWork?: boolean; evidence?: string } = {}): Promise<number[]> {
522
+ return finalizeEphemeralTasksOnReapAsync(agentId, opts);
686
523
  }
687
524
 
688
525
  /** The off-loop twin of finalizeEphemeralTasksOnReap (S3.2 L-D2 #1904) — the sanctioned scheduled-job
@@ -710,7 +547,7 @@ export async function finalizeEphemeralTasksOnReapAsync(agentId: string, opts: {
710
547
  }
711
548
  if (!task.reapedAt) await markTaskAgentReapedAsync(taskId, { agentId, reason: opts.reason ?? "agent-exit" });
712
549
  await setTaskEntityStatusAsync(taskId, { status: "canceled", note: "worker reaped without landing or producing work; task canceled", actor: "task-lifecycle" });
713
- notifyEmptyTransientReap(agentId, task, opts);
550
+ await notifyEmptyTransientReap(agentId, task, opts);
714
551
  finalized.push(taskId);
715
552
  } catch {
716
553
  // best-effort; failures must not surface into the reaper scan
@@ -728,7 +565,7 @@ export async function finalizeEphemeralTasksOnReapAsync(agentId: string, opts: {
728
565
  return finalized;
729
566
  }
730
567
 
731
- function notifyEmptyTransientReap(agentId: string, task: TaskDetail, opts: { spawnRequestId?: string; reason?: string; evidence?: string }): void {
568
+ async function notifyEmptyTransientReap(agentId: string, task: TaskDetail, opts: { spawnRequestId?: string; reason?: string; evidence?: string }): Promise<void> {
732
569
  const agent = getAgent(agentId);
733
570
  const parent = agent?.spawnedBy;
734
571
  const recipients = [...new Set([parent, taskOwnerTarget(task)].filter((value): value is string => Boolean(value && value.trim())))];
@@ -743,7 +580,7 @@ function notifyEmptyTransientReap(agentId: string, task: TaskDetail, opts: { spa
743
580
  evidence: opts.evidence ?? "no-produced-work",
744
581
  };
745
582
  emitRelayEvent({ type: "agent.transient_empty_reap", source: "task-lifecycle", subject: agentId, data: payload });
746
- routeNotification({
583
+ await routeNotification({
747
584
  type: "agent.transient_empty_reap",
748
585
  scope: { agentId, parent, taskId: String(task.id) },
749
586
  recipients,
@@ -1,3 +1,5 @@
1
+ import { addTaskRefAsync } from "../db/task-entity-async";
2
+ import { insertTaskEventAsync } from "../db/runtime-tail-async";
1
3
  // #834/#2214 — the Task ↔ issue ATTACH seam: everything that turns "this Task is about issue N"
2
4
  // into a real `issue_associations` row, split out of the task-entity service (which owns status /
3
5
  // stage / gates / attribution) so both stay under the file-size ratchet and this rule has one home.
@@ -11,18 +13,9 @@
11
13
  // - after create — `relay_task_add_ref` / `POST /api/tasks/:id/refs` via attachTaskRefs.
12
14
  // Both resolve a bare `#N` through the same default-repo chain (see issueRepoForCreate).
13
15
  import { errMessage } from "@humwick/sdk";
14
- import {
15
- addTaskRef,
16
- addTaskRefAsync,
17
- getTaskDetail,
18
- getTaskDetailAsync,
19
- ValidationError,
20
- type AddTaskRefInput,
21
- type CreateDeliverableTaskInput,
22
- type TaskEntityWriteOptions,
23
- } from "../db";
16
+ import { getTaskDetail, getTaskDetailAsync, ValidationError, type AddTaskRefInput, type CreateDeliverableTaskInput, type TaskEntityWriteOptions } from "../db";
24
17
  import { isBareIssueRef } from "../db/issue-refs";
25
- import { insertTaskEvent } from "../db/task-core";
18
+
26
19
  import { resolveActorIssueRepo } from "../agent-issue-repo";
27
20
  import { emitTaskChanged } from "../sse";
28
21
  import { cleanIssueRefRelation } from "../db/task-issue-relation";
@@ -54,31 +47,31 @@ export function issueRepoForCreate(input: CreateTaskEntityInput): string | undef
54
47
  // A ref the caller ASKED for that could not be linked must not vanish into a server log: record it
55
48
  // on the Task's own ledger so it shows up in history (and in a spawned worker's hydrated brief).
56
49
  // Creation itself still succeeds — a Task without its issue link is degraded, not invalid.
57
- function recordIssueLinkFailure(taskId: number, issue: string, defaultRepo: string | undefined, error: unknown): void {
50
+ async function recordIssueLinkFailure(taskId: number, issue: string, defaultRepo: string | undefined, error: unknown): Promise<void> {
58
51
  const message = errMessage(error);
59
52
  console.warn(`task ${taskId} issue ref '${issue}' could not be linked on create: ${message}`);
60
53
  try {
61
- insertTaskEvent(taskId, {
54
+ (await insertTaskEventAsync(taskId, {
62
55
  source: "agent-relay",
63
56
  type: "ref.issue.link_failed",
64
57
  severity: "warning",
65
58
  title: `Issue ref '${issue}' could not be linked`,
66
59
  body: message,
67
60
  metadata: { issue, ...(defaultRepo ? { defaultRepo } : {}) },
68
- }, Date.now());
61
+ }, Date.now()));
69
62
  } catch (eventError) {
70
63
  console.warn(`task ${taskId} could not record issue-link failure: ${errMessage(eventError)}`);
71
64
  }
72
65
  }
73
66
 
74
- export function addInitialIssueRefs(taskId: number, input: CreateTaskEntityInput): TaskDetail {
67
+ export async function addInitialIssueRefs(taskId: number, input: CreateTaskEntityInput): Promise<TaskDetail> {
75
68
  const defaultRepo = issueRepoForCreate(input);
76
69
  let detail = getTaskDetail(taskId)!;
77
70
  for (const { issue, relation } of initialIssueRefs(input)) {
78
71
  try {
79
- detail = addTaskRef(taskId, { issue, relation, defaultRepo, actor: input.createdBy });
72
+ detail = (await addTaskRefAsync(taskId, { issue, relation, defaultRepo, actor: input.createdBy }));
80
73
  } catch (error) {
81
- recordIssueLinkFailure(taskId, issue, defaultRepo, error);
74
+ (await recordIssueLinkFailure(taskId, issue, defaultRepo, error));
82
75
  }
83
76
  }
84
77
  return detail;
@@ -95,7 +88,7 @@ export async function addInitialIssueRefsAsync(taskId: number, input: CreateTask
95
88
  ...(options?.idempotencyKey ? { idempotencyKey: `${options.idempotencyKey}:initial-ref:${index}` } : {}),
96
89
  });
97
90
  } catch (error) {
98
- recordIssueLinkFailure(taskId, issue, defaultRepo, error);
91
+ (await recordIssueLinkFailure(taskId, issue, defaultRepo, error));
99
92
  }
100
93
  }
101
94
  return detail;
@@ -115,8 +108,8 @@ function needsIssueRepo(input: AddTaskRefInput): boolean {
115
108
  return isBareIssueRef(input.issue) && !input.defaultRepo?.trim();
116
109
  }
117
110
 
118
- export function addTaskEntityRef(id: number, input: AddTaskRefInput): TaskDetail {
119
- const detail = addTaskRef(id, needsIssueRepo(input) ? withResolvedIssueRepo(input, getTaskDetail(id)) : input);
111
+ export async function addTaskEntityRef(id: number, input: AddTaskRefInput): Promise<TaskDetail> {
112
+ const detail = (await addTaskRefAsync(id, needsIssueRepo(input) ? withResolvedIssueRepo(input, getTaskDetail(id)) : input));
120
113
  emitTaskChanged(detail, "task.updated");
121
114
  return detail;
122
115
  }