@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,3 +1,5 @@
1
+ import { setConfigAsync } from "./config-store-write";
2
+ import { createCommandAsync } from "./commands-write";
1
3
  import { contextInjectUnsupported, launchContextSurvivesCompact, launchSystemPromptAppend } from "./context-injection-channel";
2
4
  // #1565 P4b — closing the auto-inject loop at the OTHER two boundaries (design §4.4).
3
5
  //
@@ -56,10 +58,10 @@ import { contextInjectUnsupported, launchContextSurvivesCompact, launchSystemPro
56
58
  import { createHash } from "node:crypto";
57
59
  import { stripRenderedAtLine } from "./context-block-rendered-at";
58
60
  import { errMessage, stringValue } from "@humwick/sdk";
59
- import { createCommand, findLaunchPromptCommandForAgent } from "./commands-db";
61
+ import { findLaunchPromptCommandForAgent } from "./commands-db";
60
62
  import { emitCommandEvent } from "./command-events";
61
63
  import { REAP_INTERVAL_MS } from "./config";
62
- import { getConfig, setConfig } from "./config-store";
64
+ import { getConfig } from "./config-store";
63
65
  import { findMessageByIdempotencyKey, getAgent, type MemoryIdentity } from "./db";
64
66
  import { composeMemoryPreamble, describeInstructionTruncation, describeMemoryDemotions, describeMemoryOmissions, describeUnresolvedInstructions, extractMemoryPreamble, memoryRetractionBlock, unresolvedInstructionSlugs, withMemorySupersedeNotice, type ComposedMemoryPreamble } from "./memory-preamble";
65
67
  import {
@@ -124,8 +126,8 @@ export function readMemoryInjectionState(agentId: string): MemoryInjectionState
124
126
  return getConfig<MemoryInjectionState>(MEMORY_INJECTION_NAMESPACE, agentId)?.value ?? null;
125
127
  }
126
128
 
127
- export function recordMemoryInjectionState(agentId: string, state: MemoryInjectionState): void {
128
- setConfig(MEMORY_INJECTION_NAMESPACE, agentId, state, "memory-injection");
129
+ export async function recordMemoryInjectionState(agentId: string, state: MemoryInjectionState): Promise<void> {
130
+ (await setConfigAsync(MEMORY_INJECTION_NAMESPACE, agentId, state, "memory-injection"));
129
131
  }
130
132
 
131
133
  /** #2591 — the journal gate's "what did this agent last receive" record. Same lifetime rules
@@ -144,8 +146,8 @@ export function readJournalInjectionState(agentId: string): JournalInjectionStat
144
146
  return getConfig<JournalInjectionState>(JOURNAL_INJECTION_NAMESPACE, agentId)?.value ?? null;
145
147
  }
146
148
 
147
- export function recordJournalInjectionState(agentId: string, state: JournalInjectionState): void {
148
- setConfig(JOURNAL_INJECTION_NAMESPACE, agentId, state, "journal-injection");
149
+ export async function recordJournalInjectionState(agentId: string, state: JournalInjectionState): Promise<void> {
150
+ (await setConfigAsync(JOURNAL_INJECTION_NAMESPACE, agentId, state, "journal-injection"));
149
151
  }
150
152
 
151
153
  /**
@@ -298,7 +300,7 @@ function hasEmptyBlockAccounting(seam: ResolvedMemorySeam, composed: ComposedMem
298
300
  * normal outcome (unchanged set, nothing resolvable, provider cannot inject) and is always
299
301
  * reported in the `relay-injection` event rather than being inferred from silence.
300
302
  */
301
- export function enqueueMemoryInjectionAfterContextCommand(command: Command, now: number = Date.now()): Command | null {
303
+ export async function enqueueMemoryInjectionAfterContextCommand(command: Command, now: number = Date.now()): Promise<Command | null> {
302
304
  // #2291 — the boundary's status answers "did the runner CONFIRM the destructive step", not "did a
303
305
  // boundary HAPPEN". This used to read `!== "succeeded"`, which silently dropped the whole memory
304
306
  // block on every unconfirmed clear and every timed-out compact: on the live coordinator that was
@@ -335,7 +337,7 @@ export function enqueueMemoryInjectionAfterContextCommand(command: Command, now:
335
337
  if (contextInjectUnsupported(agent)) {
336
338
  // Declared and logged, never a crash: this agent keeps whatever its spawn put in the system
337
339
  // prompt and simply does not get the boundary refresh.
338
- emitMemorySkip(agent, event, seam, composed, "inject-unsupported", command, now);
340
+ (await emitMemorySkip(agent, event, seam, composed, "inject-unsupported", command, now));
339
341
  return null;
340
342
  }
341
343
 
@@ -366,7 +368,7 @@ export function enqueueMemoryInjectionAfterContextCommand(command: Command, now:
366
368
  // empty block reached the agent when the spawn-time block is in fact still in its prompt.
367
369
  // Nothing needs the write either — the recorded hash is the block the agent LAST RECEIVED, and
368
370
  // if memory reappears the composed hash differs from it and the next boundary re-injects.
369
- if (hasEmptyBlockAccounting(seam, composed)) emitMemorySkip(agent, event, seam, composed, "nothing-to-inject", command, now);
371
+ if (hasEmptyBlockAccounting(seam, composed)) (await emitMemorySkip(agent, event, seam, composed, "nothing-to-inject", command, now));
370
372
  if (!journal.delivers) return null;
371
373
  } else if (event === "compact" && launchContextSurvivesCompact(agent) && launchBakedMemoryHash(agent) === hash) {
372
374
  // §4.3(4): a native compact preserves a real system prompt, so a block BAKED there and still
@@ -375,7 +377,7 @@ export function enqueueMemoryInjectionAfterContextCommand(command: Command, now:
375
377
  // of this delta skip (#3698). A clear destroys the context — nothing survives it to be unchanged. #2596 —
376
378
  // this reads `launchBakedMemoryHash`, NOT the "recorded last delivery" hash: a block that only
377
379
  // ever rode a transcript message has no such proof (see that function's doc).
378
- emitMemorySkip(agent, event, seam, composed, "unchanged", command, now);
380
+ (await emitMemorySkip(agent, event, seam, composed, "unchanged", command, now));
379
381
  if (!journal.delivers) return null;
380
382
  } else {
381
383
  memoryDelivers = true;
@@ -414,7 +416,7 @@ export function enqueueMemoryInjectionAfterContextCommand(command: Command, now:
414
416
  // keeping its own markers, notice and gate state).
415
417
  const content = [memoryContent, journal.content].filter(Boolean).join("\n\n");
416
418
  const boundaryKey = command.type === "agent.clearContext" ? { afterClearCommandId: command.id } : { afterCompactCommandId: command.id };
417
- const inject = createCommand({
419
+ const inject = (await createCommandAsync({
418
420
  type: "agent.injectContext",
419
421
  source: "system",
420
422
  target: command.target,
@@ -448,16 +450,16 @@ export function enqueueMemoryInjectionAfterContextCommand(command: Command, now:
448
450
  }
449
451
  : {}),
450
452
  },
451
- });
453
+ }));
452
454
  emitCommandEvent(inject, "command.requested");
453
- emitRelayInjectionEvent({
455
+ (await emitRelayInjectionEvent({
454
456
  agentId: agent.id,
455
457
  category: "memory",
456
458
  summary: deliverySummary(event, composed, memoryDelivers, journal),
457
459
  detail: injectionDetail(agent, event, seam, composed, { commandId: inject.id, content, seamVerified, ...journalEventDetail(journal) }),
458
460
  timestamp: now,
459
461
  idempotencyKey: memoryBoundaryEventKey("delivered", agent.id, command.id),
460
- });
462
+ }));
461
463
  return inject;
462
464
  }
463
465
 
@@ -552,8 +554,8 @@ function memoryBoundaryEventKey(outcome: "delivered" | "skipped" | "failed", age
552
554
  * swallowed silently: the operator sees the failure on the agent's timeline. The continuation
553
555
  * enqueue runs BEFORE this and is untouched by it, which is the ordering that matters.
554
556
  */
555
- export function settleMemoryInjectionAfterContextCommand(command: Command, now: number = Date.now()): Command | null {
556
- return containedMemoryInjection(command, now).inject;
557
+ export async function settleMemoryInjectionAfterContextCommand(command: Command, now: number = Date.now()): Promise<Command | null> {
558
+ return (await containedMemoryInjection(command, now)).inject;
557
559
  }
558
560
 
559
561
  /**
@@ -564,24 +566,24 @@ export function settleMemoryInjectionAfterContextCommand(command: Command, now:
564
566
  * both callers share one containment and one error report — a second try/catch in the sweep would
565
567
  * be a second place for the reporting to drift.
566
568
  */
567
- function containedMemoryInjection(command: Command, now: number, sweep = false): { inject: Command | null; composeFailed: boolean } {
569
+ async function containedMemoryInjection(command: Command, now: number, sweep = false): Promise<{ inject: Command | null; composeFailed: boolean }> {
568
570
  try {
569
- const inject = enqueueMemoryInjectionAfterContextCommand(command, now);
570
- settleMemoryInjectionCommand(command, now);
571
- settleAreaMemoryCommand(command, now);
571
+ const inject = (await enqueueMemoryInjectionAfterContextCommand(command, now));
572
+ (await settleMemoryInjectionCommand(command, now));
573
+ (await settleAreaMemoryCommand(command, now));
572
574
  return { inject, composeFailed: false };
573
575
  } catch (error) {
574
576
  // #2712 — the sweep runs on a fast-fail connection; a held write lock defers the boundary to the
575
577
  // next run rather than counting against its compose-failure cap.
576
578
  if (sweep && isSqliteBusyError(error)) throw error;
577
- emitRelayInjectionEvent({
579
+ (await emitRelayInjectionEvent({
578
580
  agentId: command.target,
579
581
  category: "memory",
580
582
  summary: `memory re-injection failed to compose after ${command.type === "agent.compact" ? "compact" : command.type === "agent.clearContext" ? "clear" : command.type}: ${errMessage(error)}`,
581
583
  detail: { source: "memory-preamble", agentId: command.target, commandId: command.id, failed: true },
582
584
  timestamp: now,
583
585
  idempotencyKey: memoryBoundaryEventKey("failed", command.target, command.id),
584
- });
586
+ }));
585
587
  return { inject: null, composeFailed: true };
586
588
  }
587
589
  }
@@ -635,12 +637,12 @@ function containedMemoryInjection(command: Command, now: number, sweep = false):
635
637
  * continuation sweep's existing policy (redundant beats wiped) applied to a larger payload, not a
636
638
  * new one; the runner's `ProviderInputQueue` serializes them rather than dropping any.
637
639
  */
638
- export function sweepMissedMemoryInjections(now: number = Date.now(), signal?: AbortSignal): { enqueuedCommandIds: string[]; aborted?: true } {
640
+ export async function sweepMissedMemoryInjections(now: number = Date.now(), signal?: AbortSignal): Promise<{ enqueuedCommandIds: string[]; aborted?: true }> {
639
641
  const enqueuedCommandIds: string[] = [];
640
642
  // #1819 — one candidate is the unit; bailing between candidates leaves the rest for the next tick.
641
643
  for (const command of newestBoundaryPerAgent(now, signal)) {
642
644
  if (signal?.aborted) break;
643
- sweepMemoryBoundary(command, now, enqueuedCommandIds);
645
+ (await sweepMemoryBoundary(command, now, enqueuedCommandIds));
644
646
  }
645
647
  return { enqueuedCommandIds, ...(signal?.aborted ? { aborted: true as const } : {}) };
646
648
  }
@@ -648,27 +650,27 @@ export function sweepMissedMemoryInjections(now: number = Date.now(), signal?: A
648
650
  /** #2712 — the job's form of {@link sweepMissedMemoryInjections}: the same units, one macrotask each. */
649
651
  async function sweepMissedMemoryInjectionsPaced(now: number, signal?: AbortSignal): Promise<{ enqueuedCommandIds: string[]; aborted?: true; moreWork?: true }> {
650
652
  const enqueuedCommandIds: string[] = [];
651
- const { moreWork } = await pacedInjectionSweep(() => newestBoundaryPerAgent(now, signal), (command) => sweepMemoryBoundary(command, now, enqueuedCommandIds), signal);
653
+ const { moreWork } = await pacedInjectionSweep(() => newestBoundaryPerAgent(now, signal), async (command) => (await sweepMemoryBoundary(command, now, enqueuedCommandIds)), signal);
652
654
  return { enqueuedCommandIds, ...(signal?.aborted ? { aborted: true as const } : {}), ...(moreWork ? { moreWork: true as const } : {}) };
653
655
  }
654
656
 
655
- function sweepMemoryBoundary(command: Command, now: number, enqueuedCommandIds: string[]): void {
657
+ async function sweepMemoryBoundary(command: Command, now: number, enqueuedCommandIds: string[]): Promise<void> {
656
658
  const { decision, attempts } = injectionAttemptDecision(command, MEMORY_INJECTION_REASON);
657
659
  if (decision === "in-flight") return;
658
660
  if (decision === "exhausted") {
659
- notifyMemoryInjectionExhausted(command, attempts, now);
661
+ (await notifyMemoryInjectionExhausted(command, attempts, now));
660
662
  return;
661
663
  }
662
664
  if (attempts === 0 && (sweepAlreadyDecided(command) || boundaryAlreadyDecided(command))) return;
663
665
  // Through the CONTAINED enqueue: composing reaches into the store, the ownership seam and
664
666
  // cwd→project resolution, and a throw on one agent must not abort the sweep for every agent
665
667
  // behind it (the #1565 F8 rationale, one level up).
666
- const { inject, composeFailed } = containedMemoryInjection(command, now, true);
668
+ const { inject, composeFailed } = (await containedMemoryInjection(command, now, true));
667
669
  if (inject) {
668
670
  enqueuedCommandIds.push(inject.id);
669
671
  return;
670
672
  }
671
- rememberSweepDecision(command, composeFailed, now);
673
+ (await rememberSweepDecision(command, composeFailed, now));
672
674
  }
673
675
 
674
676
  /**
@@ -752,13 +754,13 @@ function sweepAlreadyDecided(command: Command): boolean {
752
754
  return held?.commandId === command.id && held.done;
753
755
  }
754
756
 
755
- function rememberSweepDecision(command: Command, composeFailed: boolean, now: number): void {
757
+ async function rememberSweepDecision(command: Command, composeFailed: boolean, now: number): Promise<void> {
756
758
  const held = sweptBoundaryDecisions.get(command.target);
757
759
  const composeFailures = (held?.commandId === command.id ? held.composeFailures : 0) + (composeFailed ? 1 : 0);
758
760
  const done = !composeFailed || composeFailures >= MAX_INJECTION_ATTEMPTS;
759
761
  if (sweptBoundaryDecisions.size >= MAX_SWEPT_DECISIONS && !held) sweptBoundaryDecisions.clear();
760
762
  sweptBoundaryDecisions.set(command.target, { commandId: command.id, composeFailures, done });
761
- if (composeFailed && done) notifyMemoryInjectionExhausted(command, composeFailures, now, "compose");
763
+ if (composeFailed && done) (await notifyMemoryInjectionExhausted(command, composeFailures, now, "compose"));
762
764
  }
763
765
 
764
766
  export const MEMORY_INJECTION_SWEEP_JOB = {
@@ -785,22 +787,22 @@ function boundaryAlreadyDecided(command: Command): boolean {
785
787
  * exactly the state #2291 showed nobody can infer from silence. The two ways to spend it — the
786
788
  * DELIVERY failing and the COMPOSITION throwing — carry different keys, or the first one reported
787
789
  * would silence the other for the same boundary. */
788
- function notifyMemoryInjectionExhausted(command: Command, attempts: number, now: number, kind: "delivery" | "compose" = "delivery"): void {
790
+ async function notifyMemoryInjectionExhausted(command: Command, attempts: number, now: number, kind: "delivery" | "compose" = "delivery"): Promise<void> {
789
791
  const idempotencyKey = `memory-injection-exhausted${kind === "compose" ? "-compose" : ""}:${command.target}:${command.id}`;
790
792
  if (findMessageByIdempotencyKey(command.target, idempotencyKey)) return;
791
793
  const event = command.type === "agent.compact" ? "compact" : "clear";
792
794
  const what = kind === "compose" ? "failed to compose" : "could not be delivered";
793
- emitRelayInjectionEvent({
795
+ (await emitRelayInjectionEvent({
794
796
  agentId: command.target,
795
797
  category: "memory",
796
798
  summary: `memory re-injection gave up after ${attempts} attempt(s) at a ${event} boundary — it ${what}, so this agent is running without the current block`,
797
799
  detail: { source: "memory-preamble", agentId: command.target, commandId: command.id, event, attempts, exhausted: kind },
798
800
  timestamp: now,
799
801
  idempotencyKey,
800
- });
802
+ }));
801
803
  }
802
804
 
803
- function emitMemorySkip(
805
+ async function emitMemorySkip(
804
806
  agent: AgentCard,
805
807
  event: MemoryInjectionEvent,
806
808
  seam: ResolvedMemorySeam,
@@ -808,20 +810,20 @@ function emitMemorySkip(
808
810
  skipped: MemoryInjectionSkip,
809
811
  command: Command,
810
812
  now: number,
811
- ): void {
813
+ ): Promise<void> {
812
814
  const summaries: Record<MemoryInjectionSkip, string> = {
813
815
  unchanged: `memory unchanged after ${event} — re-injection skipped (${entriesLabel(renderedCount(composed))}, ${composed.tokens}t)`,
814
816
  "inject-unsupported": `memory NOT re-injected after ${event}: provider declares context.inject:false (spawn-time block only)`,
815
817
  "nothing-to-inject": `memory resolved nothing to inject after ${event}${omissionSuffix(composed)}`,
816
818
  };
817
- emitRelayInjectionEvent({
819
+ (await emitRelayInjectionEvent({
818
820
  agentId: agent.id,
819
821
  category: "memory",
820
822
  summary: summaries[skipped],
821
823
  detail: injectionDetail(agent, event, seam, composed, { skipped, commandId: command.id }),
822
824
  timestamp: now,
823
825
  idempotencyKey: memoryBoundaryEventKey("skipped", agent.id, command.id),
824
- });
826
+ }));
825
827
  }
826
828
 
827
829
  /**
@@ -836,7 +838,7 @@ function emitMemorySkip(
836
838
  * the same only-on-success rule. Each side records only when ITS payload rode the command, so a
837
839
  * journal-only delivery never stamps a phantom memory hash (and vice versa).
838
840
  */
839
- export function settleMemoryInjectionCommand(command: Command, now: number = Date.now()): void {
841
+ export async function settleMemoryInjectionCommand(command: Command, now: number = Date.now()): Promise<void> {
840
842
  if (command.type !== "agent.injectContext" || command.status !== "succeeded") return;
841
843
  if (command.params.reason !== MEMORY_INJECTION_REASON) return;
842
844
  const memory = command.params.memory;
@@ -844,13 +846,13 @@ export function settleMemoryInjectionCommand(command: Command, now: number = Dat
844
846
  const record = memory as Record<string, unknown>;
845
847
  const hash = typeof record.hash === "string" ? record.hash : undefined;
846
848
  if (hash !== undefined) {
847
- recordMemoryInjectionState(command.target, {
849
+ (await recordMemoryInjectionState(command.target, {
848
850
  hash,
849
851
  tokens: typeof record.tokens === "number" ? record.tokens : 0,
850
852
  entries: typeof record.entries === "number" ? record.entries : 0,
851
853
  event: record.event === "clear" ? "clear" : "compact",
852
854
  at: now,
853
- });
855
+ }));
854
856
  }
855
857
  }
856
858
  const journal = command.params.journal;
@@ -858,13 +860,13 @@ export function settleMemoryInjectionCommand(command: Command, now: number = Dat
858
860
  const record = journal as Record<string, unknown>;
859
861
  const hash = typeof record.hash === "string" ? record.hash : undefined;
860
862
  if (hash !== undefined) {
861
- recordJournalInjectionState(command.target, {
863
+ (await recordJournalInjectionState(command.target, {
862
864
  hash,
863
865
  tokens: typeof record.tokens === "number" ? record.tokens : 0,
864
866
  fields: typeof record.fields === "number" ? record.fields : 0,
865
867
  event: record.event === "clear" ? "clear" : "compact",
866
868
  at: now,
867
- });
869
+ }));
868
870
  }
869
871
  }
870
872
  }
@@ -1,5 +1,6 @@
1
+ import { releaseExpiredMergePausesAsync } from "./db/runtime-tail-async";
1
2
  import { REAP_INTERVAL_MS } from "./config";
2
- import { releaseExpiredMergePauses } from "./db";
3
+
3
4
 
4
5
  export const MERGE_PAUSE_MAINTENANCE_JOB = {
5
6
  id: "merge-pause-expiration",
@@ -8,12 +9,12 @@ export const MERGE_PAUSE_MAINTENANCE_JOB = {
8
9
  description: "Release expired repo/base auto-merge pauses.",
9
10
  intervalMs: REAP_INTERVAL_MS,
10
11
  runOnStart: true,
11
- // #1819 — SYNCHRONOUS, and ONE atomic statement: `releaseExpiredMergePauses` is a single UPDATE …
12
+ // #1819 — SYNCHRONOUS, and ONE atomic statement: `releaseExpiredMergePausesAsync` is a single UPDATE …
12
13
  // RETURNING. There is no interior checkpoint to add — splitting it would mean splitting a
13
14
  // transaction — so the pre-flight check is the whole of its cooperation. It cannot overrun a
14
15
  // deadline in any realistic fleet; if it ever does, the fix is #1809 offload, not more checks.
15
- handler(context: { signal?: AbortSignal }) {
16
+ async handler(context: { signal?: AbortSignal }) {
16
17
  if (context.signal?.aborted) return { releasedMergePauseIds: [], aborted: true };
17
- return { releasedMergePauseIds: releaseExpiredMergePauses() };
18
+ return { releasedMergePauseIds: (await releaseExpiredMergePausesAsync()) };
18
19
  },
19
20
  };
@@ -1,9 +1,13 @@
1
+ import { randomUUID } from "node:crypto";
1
2
  import { isRecord } from "@humwick/sdk";
2
- import { notifySystemMessageWithResult } from "./notify";
3
- import { createActivityEvent, getAgent, getMessage } from "./db";
3
+ import { getGateway } from "./db/gateway";
4
+ import { emitNewMessage } from "./sse";
5
+ import type { SendMessageResult } from "./db/messages";
6
+ import type { AgentNoticeSlot } from "./db/terminal-events";
7
+ import { createActivityEventAsync, getAgent, getMessage } from "./db";
4
8
  import { optedInNotificationRecipients, subscriptionDecisionFor } from "./db/notification-subscriptions";
5
9
  import { notificationEnabledFor } from "./notification-settings-store";
6
- import type { Message, MessageKind, NotificationRoutingExplanation, NotificationRoutingPreview, NotificationRoutingRecipientInput } from "./types";
10
+ import type { Message, SendMessageInput, MessageKind, NotificationRoutingExplanation, NotificationRoutingPreview, NotificationRoutingRecipientInput } from "./types";
7
11
  import { DEFAULT_TTL_MS } from "./notification-types";
8
12
  import type { NotificationScope, NotificationType } from "./notification-types";
9
13
  import { isNotificationSuppressedForRole, notificationTarget, resolveAudience } from "./notification-rules";
@@ -89,17 +93,33 @@ function effectiveTtlMs(type: NotificationType, ttlMs: number | null | undefined
89
93
  * Recipients are de-duplicated and emptied of falsy entries, so emitters can pass optional ids
90
94
  * without guarding. A notification with zero resolved recipients is a no-op.
91
95
  */
92
- export function routeNotification(input: RouteNotificationInput): Message[] {
96
+ export async function routeNotification(input: RouteNotificationInput): Promise<Message[]> {
97
+ const { inputs, preview, maxAgeSeconds } = prepareNotification(input);
98
+ if (!inputs.length) return [];
99
+ const results = await getGateway().write("notifications.route", { inputs }, { critical: true, idempotencyKey: randomUUID() }) as unknown as SendMessageResult[];
100
+ await emitNotificationResults(results, preview, maxAgeSeconds);
101
+ return results.map(result => result.message);
102
+ }
103
+
104
+ /** #1870 — the generation slot and every recipient message commit in one writer transaction. */
105
+ export async function routeAgentNotice(slot: AgentNoticeSlot, input?: RouteNotificationInput): Promise<boolean> {
106
+ const prepared = input ? prepareNotification(input) : undefined;
107
+ const result = await getGateway().write("notifications.agentNotice", { slot, inputs: prepared?.inputs ?? [] }, { critical: true, idempotencyKey: randomUUID() }) as unknown as { created: boolean; results: SendMessageResult[] };
108
+ if (prepared) await emitNotificationResults(result.results, prepared.preview, prepared.maxAgeSeconds);
109
+ return result.created;
110
+ }
111
+
112
+ function prepareNotification(input: RouteNotificationInput) {
93
113
  const ttl = effectiveTtlMs(input.type, input.ttlMs);
94
114
  const emittedAt = input.emittedAt ?? Date.now();
95
115
 
96
116
  // Staleness guard (#451): if the triggering event is already older than its TTL, drop before
97
117
  // sending. On the normal synchronous path emittedAt ≈ now so this rarely fires, but it makes the
98
118
  // router correct for any caller that routes a delayed/replayed event.
99
- if (ttl !== null && Date.now() - emittedAt > ttl) return [];
119
+ if (ttl !== null && Date.now() - emittedAt > ttl) return { inputs: [], preview: previewNotificationRouting({ ...input, recipients: [] }), maxAgeSeconds: null };
100
120
 
101
121
  const preview = previewNotificationRouting(input);
102
- if (preview.recipients.length === 0) return [];
122
+
103
123
 
104
124
  // Stamp the TTL on the message so the delivery/poll path (pollMessages) enforces it for offline
105
125
  // or late-joining recipients too. An explicit `null` (never-expire) is authoritative: it suppresses
@@ -107,7 +127,8 @@ export function routeNotification(input: RouteNotificationInput): Message[] {
107
127
  // never-expire intent instead of inheriting the moderate baseline.
108
128
  const maxAgeSeconds = ttl === null ? null : Math.max(1, Math.ceil(ttl / 1000));
109
129
 
110
- return preview.recipients.map((routing) => {
130
+ const inputs: SendMessageInput[] = [];
131
+ for (const routing of preview.recipients) {
111
132
  const meta = getAgent(routing.recipient)?.meta;
112
133
  const channel = meta?.kind === "channel" ? meta : undefined;
113
134
  const notificationPayload = {
@@ -115,7 +136,8 @@ export function routeNotification(input: RouteNotificationInput): Message[] {
115
136
  ...(input.message.wake === false ? { wake: false } : {}),
116
137
  routing: compactRoutingExplanation(routing),
117
138
  };
118
- const result = notifySystemMessageWithResult(routing.recipient, {
139
+ inputs.push({
140
+ to: routing.recipient,
119
141
  subject: input.message.subject,
120
142
  body: input.message.body,
121
143
  payload: channel ? {
@@ -124,16 +146,21 @@ export function routeNotification(input: RouteNotificationInput): Message[] {
124
146
  event: { title: input.message.subject, body: input.message.body, notification: notificationPayload },
125
147
  } : notificationPayload,
126
148
  idempotencyKey: recipientScopedIdempotencyKey(input.message.idempotencyKey, routing.recipient),
127
- kind: channel ? "channel.event" : input.message.kind,
128
- from: input.message.from,
149
+ kind: channel ? "channel.event" : input.message.kind ?? "system",
150
+ from: input.message.from ?? "system",
129
151
  replyExpected: channel ? false : input.message.replyExpected,
130
152
  maxAgeSeconds,
131
153
  });
132
- // The message idempotency key is the transition ledger. A retry that resolves to the existing
133
- // message must not manufacture another "Notification routed" activity row (#2365).
134
- if (result.created || result.updated) auditRoutingTrace(result.message, preview, maxAgeSeconds);
135
- return result.message;
136
- });
154
+ }
155
+ return { inputs, preview, maxAgeSeconds };
156
+ }
157
+
158
+ async function emitNotificationResults(results: SendMessageResult[], preview: NotificationRoutingPreview, maxAgeSeconds: number | null): Promise<void> {
159
+ for (const result of results) {
160
+ if (!result.created && !result.updated) continue;
161
+ emitNewMessage(result.message);
162
+ await auditRoutingTrace(result.message, preview, maxAgeSeconds);
163
+ }
137
164
  }
138
165
 
139
166
  function recipientScopedIdempotencyKey(key: string | undefined, recipient: string): string | undefined {
@@ -301,9 +328,9 @@ function routingExplanationFromPayload(value: unknown): NotificationRoutingExpla
301
328
  };
302
329
  }
303
330
 
304
- function auditRoutingTrace(message: Message, preview: NotificationRoutingPreview, maxAgeSeconds: number | null): void {
331
+ async function auditRoutingTrace(message: Message, preview: NotificationRoutingPreview, maxAgeSeconds: number | null): Promise<void> {
305
332
  try {
306
- createActivityEvent({
333
+ await createActivityEventAsync({
307
334
  clientId: `notification-route-${message.id}`,
308
335
  kind: "state",
309
336
  title: "Notification routed",
package/src/notify.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { sendMessageWithResult } from "./db";
1
+ import { sendMessageWithResultAsync } from "./db/message-send";
2
2
  import { emitNewMessage } from "./sse";
3
3
  import type { Message, MessageKind } from "./types";
4
4
 
@@ -33,13 +33,13 @@ interface SystemNotifyOptions {
33
33
  * "relay tells an agent something happened" — store-ahead delivers it on next poll if the
34
34
  * recipient is offline (#234). Used by the GC sweep (maintenance) and lifecycle events (#239).
35
35
  */
36
- export function notifySystemMessage(to: string, opts: SystemNotifyOptions): Message {
37
- return notifySystemMessageWithResult(to, opts).message;
36
+ export async function notifySystemMessage(to: string, opts: SystemNotifyOptions): Promise<Message> {
37
+ return (await notifySystemMessageWithResult(to, opts)).message;
38
38
  }
39
39
 
40
40
  /** Same send seam with creation provenance for callers that own one-shot side effects/audits. */
41
- export function notifySystemMessageWithResult(to: string, opts: SystemNotifyOptions) {
42
- const result = sendMessageWithResult({
41
+ export async function notifySystemMessageWithResult(to: string, opts: SystemNotifyOptions) {
42
+ const result = await sendMessageWithResultAsync({
43
43
  from: opts.from ?? "system",
44
44
  to,
45
45
  kind: opts.kind ?? "system",
@@ -8,14 +8,14 @@ import { settleStartupContextInjectionAfterContextCommand } from "./startup-cont
8
8
  /** #3698 — a `/clear` typed into the provider, or its auto-compaction, keeps the process and its
9
9
  * launch-baked system prompt. Refresh identity, memory + journal and startup context through the
10
10
  * SAME seams a commanded clear/compact settles; each is idempotent per boundary id. Never throws. */
11
- export function refreshContextAfterObservedReset(reset: ObservedContextReset, now: number = Date.now()): void {
11
+ export async function refreshContextAfterObservedReset(reset: ObservedContextReset, now: number = Date.now()): Promise<void> {
12
12
  const boundary = observedResetBoundary(reset);
13
13
  try {
14
- enqueueLifecycleIdentityInjectionAfterContextCommand(boundary);
14
+ (await enqueueLifecycleIdentityInjectionAfterContextCommand(boundary));
15
15
  } catch (error) {
16
16
  console.error(`#3698 identity refresh after observed ${reset.kind} ${reset.resetId} for ${reset.agentId} failed: ${errMessage(error)}`);
17
17
  }
18
18
  // Both contained: they report their own failures on the agent's timeline.
19
- settleMemoryInjectionAfterContextCommand(boundary, now);
20
- settleStartupContextInjectionAfterContextCommand(boundary, now);
19
+ (await settleMemoryInjectionAfterContextCommand(boundary, now));
20
+ (await settleStartupContextInjectionAfterContextCommand(boundary, now));
21
21
  }
@@ -40,11 +40,8 @@ function emitAlarm(input: OperatorAlarmInput): void {
40
40
  });
41
41
  }
42
42
 
43
- export function raiseOperatorAlarm(input: OperatorAlarmInput): boolean {
44
- const { created } = createActivityEventWithResult(alarmEvent(input));
45
- if (input.dedupeEvent && !created) return false;
46
- emitAlarm(input);
47
- return true;
43
+ export async function raiseOperatorAlarm(input: OperatorAlarmInput): Promise<boolean> {
44
+ return raiseOperatorAlarmAsync(input);
48
45
  }
49
46
 
50
47
  /** Same as `raiseOperatorAlarm`, with the activity row written on the writer thread. */
@@ -1,5 +1,5 @@
1
1
  import { join } from "node:path";
2
- import { listProjectEntries, rootsForProject, retractProjectEntry, writeProjectEntry } from "./db";
2
+ import { listProjectEntriesAsync, rootsForProjectAsync, retractProjectEntryAsync, writeProjectEntryAsync } from "./db";
3
3
  import { projectFileRoots, readProjectRootFile } from "./project-file-source";
4
4
  import type { ProjectEntry } from "./types";
5
5
 
@@ -117,7 +117,7 @@ export async function ingestClaudeMd(projectId: string, authorId: string): Promi
117
117
  // Index prior *ingested* entries by origin_ref (newest active wins). We only ever
118
118
  // read source:'ingested' here — manual/promoted are invisible to ingest by design.
119
119
  const byOrigin = new Map<string, ProjectEntry>();
120
- for (const entry of listProjectEntries(projectId)) {
120
+ for (const entry of await listProjectEntriesAsync(projectId)) {
121
121
  if (entry.source !== "ingested" || !entry.originRef) continue;
122
122
  if (!byOrigin.has(entry.originRef)) byOrigin.set(entry.originRef, entry);
123
123
  }
@@ -128,7 +128,7 @@ export async function ingestClaudeMd(projectId: string, authorId: string): Promi
128
128
  let updated = 0;
129
129
  let unchanged = 0;
130
130
 
131
- const registered = projectFileRoots(rootsForProject(projectId));
131
+ const registered = projectFileRoots(await rootsForProjectAsync(projectId));
132
132
  if (!registered.length && byOrigin.size) throw new Error(`no confirmed checkout host owns project ${projectId}`);
133
133
  for (const root of registered) {
134
134
  let filePath = join(root.rootPath, INGEST_FILENAME);
@@ -153,7 +153,7 @@ export async function ingestClaudeMd(projectId: string, authorId: string): Promi
153
153
  unchanged++;
154
154
  continue;
155
155
  }
156
- writeProjectEntry({
156
+ await writeProjectEntryAsync({
157
157
  projectId,
158
158
  authorId,
159
159
  kind: "rule",
@@ -166,7 +166,7 @@ export async function ingestClaudeMd(projectId: string, authorId: string): Promi
166
166
  });
167
167
  updated++;
168
168
  } else {
169
- writeProjectEntry({
169
+ await writeProjectEntryAsync({
170
170
  projectId,
171
171
  authorId,
172
172
  kind: "rule",
@@ -187,7 +187,7 @@ export async function ingestClaudeMd(projectId: string, authorId: string): Promi
187
187
  let retracted = 0;
188
188
  for (const [originRef, entry] of byOrigin) {
189
189
  if (seen.has(originRef)) continue;
190
- retractProjectEntry(entry.id);
190
+ await retractProjectEntryAsync(entry.id);
191
191
  retracted++;
192
192
  }
193
193
 
@@ -262,6 +262,13 @@ export function stripHumwickIdentitySection(value: string): string {
262
262
  .replace(/\n\n+$/, "");
263
263
  }
264
264
 
265
+ /** The relay-owned marked sections a prompt carries on top of the startup blocks: identity, memory
266
+ * and journal. The ONE strip every reader of a launched prompt uses, so a block added here (#3782:
267
+ * the journal) cannot be forgotten by one of them. */
268
+ export function stripRelayOwnedSections(value: string): string {
269
+ return stripJournalPreamble(stripMemoryPreamble(stripHumwickIdentitySection(value)));
270
+ }
271
+
265
272
  export function composeSpawnInstructionsWithEvents(input: {
266
273
  /** Resolved fact from the selected profile's Project Instructions cell. Absent fails closed. */
267
274
  projectInstructionsEnabled?: boolean;
@@ -526,7 +533,7 @@ export function composeSpawnInstructionsWithEvents(input: {
526
533
  // strict about what it removes, so a brief that merely mentions a marker survives intact — and
527
534
  // neutralizing what survives keeps it from being read as this prompt's memory/journal block later.
528
535
  const callerSystemPromptAppend = input.callerSystemPromptAppend
529
- ? neutralizeJournalMarkers(neutralizeMemoryMarkers(stripJournalPreamble(stripMemoryPreamble(stripHumwickIdentitySection(input.callerSystemPromptAppend)))))
536
+ ? neutralizeJournalMarkers(neutralizeMemoryMarkers(stripRelayOwnedSections(input.callerSystemPromptAppend)))
530
537
  : undefined;
531
538
  if (callerSystemPromptAppend?.trim()) {
532
539
  appendBlocks.push(callerSystemPromptAppend);