@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,7 +1,9 @@
1
1
  import { createPlanRow, deletePlan, replacePlanIfVersion, setPlanArchived } from "./plans.ts";
2
+ import { PLAN_READY_NOTICE_WRITE_OPS } from "./plan-ready-notices.ts";
2
3
  import type { WriterOpContext, WriterOpSpec } from "./write-ops.ts";
3
4
 
4
5
  export const PLANS_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
6
+ ...PLAN_READY_NOTICE_WRITE_OPS,
5
7
  "plans.create": { offLoop: true, idempotent: false, fn: (args: { input: Parameters<typeof createPlanRow>[0] }, ctx: WriterOpContext) => createPlanRow(args.input, ctx.now) },
6
8
  "plans.replace": { offLoop: true, idempotent: false, fn: (args: { input: Parameters<typeof replacePlanIfVersion>[0]; changedBy?: string }, ctx: WriterOpContext) => replacePlanIfVersion(args.input, args.changedBy, ctx.now, false) },
7
9
  "plans.setArchived": { offLoop: true, idempotent: true, fn: (args: { id: string; archived: boolean }, ctx: WriterOpContext) => setPlanArchived(args.id, args.archived, ctx.now) },
@@ -104,6 +104,11 @@ export function snapshotBufferedPresence(): PresenceSnapshot {
104
104
  * current, and the caller's surrounding status/ready predicates constrain the match. */
105
105
  export function bufferedLiveAgentIds(cutoff: number): string[] {
106
106
  const ids: string[] = [];
107
+ const snapshot = writerPresenceSnapshot();
108
+ if (snapshot) {
109
+ for (const beat of snapshot) if (beat.lastSeen > cutoff) ids.push(beat.id);
110
+ return ids;
111
+ }
107
112
  for (const [id, pending] of pendingPresence) {
108
113
  if (pending.lastSeen > cutoff) ids.push(id);
109
114
  }
@@ -1,3 +1,4 @@
1
+ import { framed } from "../hub-metrics";
1
2
  import { assertMainThreadState } from "./main-thread-state";
2
3
  // Lifecycle glue for the coalesced presence buffer. Kept outside agents.ts so its writer-op body
3
4
  // never depends on the gateway-facing facade (ADR 0001 §3.1).
@@ -6,53 +7,47 @@ import { errMessage } from "@humwick/sdk";
6
7
  import { PRESENCE_FLUSH_MS } from "../config";
7
8
  import { drainPendingLandSettleSideEffects } from "../land-settle-dispatch";
8
9
  import { onShutdown } from "../shutdown";
9
- import { flushPresence } from "./agents.ts";
10
+ import { flushPresenceAsync } from "./presence-write.ts";
10
11
  import { pendingPresence } from "./presence-buffer.ts";
11
12
 
12
13
  let presenceFlushTimer: ReturnType<typeof setInterval> | undefined;
13
- let asyncPresenceFlusher: (() => Promise<{ flushed: number }>) | undefined;
14
14
  let removeShutdownHook: (() => void) | undefined;
15
15
 
16
- /** Attach the gateway-backed normal-tick flusher without importing the gateway into agents.ts. */
17
- export function setAsyncPresenceFlusher(flusher: () => Promise<{ flushed: number }>): void {
18
- assertMainThreadState("presence-loop.ts");
19
- asyncPresenceFlusher = flusher;
20
- }
21
-
22
16
  /** Start the periodic presence-buffer flush loop (server boot). */
23
17
  export function startPresenceFlushLoop(intervalMs: number = PRESENCE_FLUSH_MS): void {
24
18
  assertMainThreadState("presence-loop.ts");
25
19
  if (presenceFlushTimer) return;
26
- presenceFlushTimer = setInterval(() => {
27
- const flush = asyncPresenceFlusher;
28
- if (!flush) return flushPresenceQuietly(); // Bootstrap/isolated compatibility fallback.
29
- void flush().catch((err) => console.warn(`[presence] flush failed: ${errMessage(err)}`));
30
- }, intervalMs);
20
+ presenceFlushTimer = setInterval(framed("timer presence-flush", () =>
21
+ flushPresenceAsync().catch((err) => console.warn(`[presence] flush failed: ${errMessage(err)}`))), intervalMs);
31
22
  presenceFlushTimer.unref?.();
32
- process.once("beforeExit", flushPresenceQuietly);
33
- removeShutdownHook = onShutdown("presence", () => {
34
- drainPendingLandSettleSideEffects();
35
- stopPresenceFlushLoop();
23
+ process.once("beforeExit", flushPresenceBeforeExit);
24
+ removeShutdownHook = onShutdown("presence", async () => {
25
+ await drainPendingLandSettleSideEffects();
26
+ await stopPresenceFlushLoop();
36
27
  });
37
28
  }
38
29
 
39
30
  /** Stop the loop and persist whatever is buffered (graceful shutdown / test teardown). */
40
- export function stopPresenceFlushLoop(): void {
31
+ function detachPresenceLoop(): void {
41
32
  assertMainThreadState("presence-loop.ts");
42
33
  removeShutdownHook?.();
43
34
  removeShutdownHook = undefined;
44
- process.removeListener("beforeExit", flushPresenceQuietly);
35
+ process.removeListener("beforeExit", flushPresenceBeforeExit);
45
36
  if (presenceFlushTimer) clearInterval(presenceFlushTimer);
46
37
  presenceFlushTimer = undefined;
47
- flushPresenceQuietly();
48
38
  }
49
39
 
50
- function flushPresenceQuietly(): void {
51
- try { flushPresence(); } catch (err) { console.warn(`[presence] flush failed: ${errMessage(err)}`); }
40
+ export async function stopPresenceFlushLoop(): Promise<void> {
41
+ detachPresenceLoop();
42
+ await flushPresenceAsync();
43
+ }
44
+
45
+ function flushPresenceBeforeExit(): void {
46
+ void flushPresenceAsync().catch(err => console.warn(`[presence] flush failed: ${errMessage(err)}`));
52
47
  }
53
48
 
54
49
  /** Test-only: drop the buffered presence and stop the flush loop. */
55
50
  export function resetPresenceBufferForTests(): void {
56
51
  pendingPresence.clear();
57
- stopPresenceFlushLoop();
52
+ detachPresenceLoop();
58
53
  }
@@ -3,7 +3,6 @@ import { assertMainThreadState } from "./main-thread-state";
3
3
  // Kept outside agents.ts because the writer registry imports the op body from that module; importing
4
4
  // the gateway there would make the writer-stack cycle gateway → write-ops → agents → gateway.
5
5
 
6
- import { setAsyncPresenceFlusher } from "./presence-loop.ts";
7
6
  import { settlePendingPresenceFlush, snapshotPendingPresenceFlush, type PresenceFlushPayload } from "./presence-buffer.ts";
8
7
  import { getGateway } from "./gateway.ts";
9
8
 
@@ -31,8 +30,3 @@ export function flushPresenceAsync(now: number = Date.now()): Promise<{ flushed:
31
30
  .finally(() => { activeFlush = undefined; });
32
31
  return activeFlush;
33
32
  }
34
-
35
- // The timer remains owned by presence-loop.ts for its synchronous shutdown guarantee, while normal ticks
36
- // arrive here through an injected callback. This direction deliberately avoids a writer-op → gateway
37
- // dependency cycle; the callback carries no DB closure across the worker seam.
38
- setAsyncPresenceFlusher(flushPresenceAsync);
@@ -1,3 +1,5 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import type { writeProjectEntry, promoteBlackboardEntry } from "./project-entries";
1
3
  // Async project-entries facades (T4060 hub on-loop). Kept outside
2
4
  // project-entries.ts to avoid a gateway cycle.
3
5
  import { getGateway } from "./gateway.ts";
@@ -16,3 +18,15 @@ export const searchProjectEntriesAsync = (
16
18
  query: string,
17
19
  opts: ProjectEntrySearchOptions = {},
18
20
  ): Promise<ProjectEntrySearchResult[]> => read("projectEntries.search", { projectId, query, ...opts });
21
+
22
+ export const getProjectEntryAsync = (id: string): Promise<ProjectEntry | null> => read("projectEntries.get", { id });
23
+ export const getProjectEntryChainAsync = (id: string): Promise<ProjectEntry[]> => read("projectEntries.chain", { id });
24
+ export const listActiveEntriesInAreaAsync = (projectId: string, area: string): Promise<ProjectEntry[]> => read("projectEntries.inArea", { projectId, area });
25
+ export const countActivePinnedEntriesInAreaAsync = (projectId: string, area: string): Promise<number> => read("projectEntries.countPinnedInArea", { projectId, area });
26
+
27
+ export const writeProjectEntryAsync = (input: Parameters<typeof writeProjectEntry>[0], requestId: string = randomUUID()): Promise<ProjectEntry> =>
28
+ getGateway().write("projectEntries.write", input, { idempotencyKey: requestId }) as unknown as Promise<ProjectEntry>;
29
+ export const retractProjectEntryAsync = (id: string): Promise<ProjectEntry | null> =>
30
+ getGateway().write("projectEntries.retract", { id }) as unknown as Promise<ProjectEntry | null>;
31
+ export const promoteBlackboardEntryAsync = (input: Parameters<typeof promoteBlackboardEntry>[0], requestId: string = randomUUID()): Promise<ProjectEntry> =>
32
+ getGateway().write("projectEntries.promoteBlackboard", input, { idempotencyKey: requestId }) as unknown as Promise<ProjectEntry>;
@@ -1,10 +1,14 @@
1
1
  // Project-entries reader operations (T4060 hub on-loop). The MCP memory/project
2
2
  // read tools ran these scans synchronously on the event loop — including the
3
3
  // temp-B-TREE display ORDER BY over cells whose rows are ~95% retracted.
4
- import { listProjectEntries, searchProjectEntries } from "./project-entries.ts";
4
+ import { countActivePinnedEntriesInArea, getProjectEntry, getProjectEntryChain, listActiveEntriesInArea, listProjectEntries, searchProjectEntries } from "./project-entries.ts";
5
5
  import type { ProjectEntryKind, ProjectEntryStatus, ProjectEntrySearchOptions } from "../types";
6
6
 
7
7
  export const PROJECT_ENTRIES_READ_OPS = {
8
+ "projectEntries.get": (args: { id: string }) => getProjectEntry(args.id),
9
+ "projectEntries.chain": (args: { id: string }) => getProjectEntryChain(args.id),
10
+ "projectEntries.inArea": (args: { projectId: string; area: string }) => listActiveEntriesInArea(args.projectId, args.area),
11
+ "projectEntries.countPinnedInArea": (args: { projectId: string; area: string }) => countActivePinnedEntriesInArea(args.projectId, args.area),
8
12
  "projectEntries.list": (args: {
9
13
  projectId: string;
10
14
  kind?: ProjectEntryKind;
@@ -0,0 +1,8 @@
1
+ import { promoteBlackboardEntry, retractProjectEntry, writeProjectEntry } from "./project-entries";
2
+ import type { WriterOpSpec } from "./write-ops";
3
+
4
+ export const PROJECT_ENTRIES_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = {
5
+ "projectEntries.write": { offLoop: true, idempotent: false, fn: (args: Parameters<typeof writeProjectEntry>[0], ctx) => writeProjectEntry(args, ctx.now) },
6
+ "projectEntries.retract": { offLoop: true, idempotent: true, fn: (args: { id: string }, ctx) => retractProjectEntry(args.id, ctx.now) },
7
+ "projectEntries.promoteBlackboard": { offLoop: true, idempotent: false, fn: (args: Parameters<typeof promoteBlackboardEntry>[0], ctx) => promoteBlackboardEntry(args, ctx.now) },
8
+ };
@@ -1,7 +1,7 @@
1
1
  import { isolateMemoryEntry } from "../memory-entry-safety";
2
2
  import { validateProjectEntryText } from "../validation";
3
3
  import { randomUUID } from "node:crypto";
4
- import { getDb, writeTransaction, ValidationError } from "./connection.ts";
4
+ import { getDb, inWriteTransaction, ValidationError } from "./connection.ts";
5
5
  import { getEntry as getBlackboardEntry, listEntries as listBlackboardEntries } from "./blackboard.ts";
6
6
  import { parseJson } from "../utils";
7
7
  import {
@@ -211,7 +211,7 @@ function assertProjectKnowledge(projectId: string): void {
211
211
  }
212
212
  }
213
213
 
214
- export function writeProjectEntry(input: WriteProjectEntryInput): ProjectEntry {
214
+ export function writeProjectEntry(input: WriteProjectEntryInput, now: number = Date.now()): ProjectEntry {
215
215
  validateProjectEntryText(input);
216
216
  assertProjectKnowledge(input.projectId);
217
217
  assertKind(input.kind);
@@ -234,8 +234,7 @@ export function writeProjectEntry(input: WriteProjectEntryInput): ProjectEntry {
234
234
  supersedes = latestEntryByTitle(input.projectId, input.kind, input.title)?.id;
235
235
  }
236
236
  const id = projectEntryId();
237
- const now = Date.now();
238
- writeTransaction(() => {
237
+ inWriteTransaction(() => {
239
238
  let inheritedAreas: string[] | null = null;
240
239
  if (supersedes) {
241
240
  const previous = getProjectEntry(supersedes);
@@ -404,21 +403,25 @@ export function countActivePinnedEntriesInArea(projectId: string, area: string):
404
403
  }
405
404
 
406
405
  /** #3410 — active entries of one cell that name `area`, newest first. Same index as the count above. */
407
- export function listActiveEntriesInArea(projectId: string, area: string): ProjectEntry[] {
408
- const rows = getDb().query(`
406
+ export function buildActiveEntriesInAreaQuery(projectId: string, area: string): { sql: string; params: string[] } {
407
+ return { sql: `
409
408
  SELECT * FROM project_entries
410
409
  WHERE project_id = ? AND status = 'active' AND areas LIKE ? ESCAPE '\\'
411
410
  ORDER BY updated_at DESC, created_at DESC, id DESC
412
- `).all(projectId, `%${escapeLike(JSON.stringify(area))}%`) as ProjectEntryRow[];
413
- return rows.map(rowToEntry);
411
+ `, params: [projectId, `%${escapeLike(JSON.stringify(area))}%`] };
414
412
  }
415
413
 
416
- export function retractProjectEntry(id: string): ProjectEntry | null {
414
+ export function listActiveEntriesInArea(projectId: string, area: string): ProjectEntry[] {
415
+ const { sql, params } = buildActiveEntriesInAreaQuery(projectId, area);
416
+ return (getDb().query(sql).all(...params) as ProjectEntryRow[]).map(rowToEntry);
417
+ }
418
+
419
+ export function retractProjectEntry(id: string, now: number = Date.now()): ProjectEntry | null {
417
420
  const existing = getProjectEntry(id);
418
421
  if (!existing) return null;
419
422
  assertStatus("retracted");
420
423
  getDb().query("UPDATE project_entries SET status = 'retracted', updated_at = ? WHERE id = ?")
421
- .run(Date.now(), id);
424
+ .run(now, id);
422
425
  return getProjectEntry(id);
423
426
  }
424
427
 
@@ -472,7 +475,7 @@ function activePromotedEntry(projectId: string, originRef: string): ProjectEntry
472
475
  * project supersedes the prior promoted copy rather than duplicating it, so the durable
473
476
  * ledger holds at most one active entry per promoted finding while keeping the full
474
477
  * supersede chain for audit. */
475
- export function promoteBlackboardEntry(input: PromoteBlackboardEntryInput): ProjectEntry {
478
+ export function promoteBlackboardEntry(input: PromoteBlackboardEntryInput, now: number = Date.now()): ProjectEntry {
476
479
  const source = getBlackboardEntry(input.blackboardEntryId);
477
480
  if (!source) throw new ValidationError(`blackboard entry ${input.blackboardEntryId} not found`);
478
481
  if (source.status !== "active") {
@@ -489,7 +492,7 @@ export function promoteBlackboardEntry(input: PromoteBlackboardEntryInput): Proj
489
492
  source: "promoted",
490
493
  originRef: source.id,
491
494
  ...(existing ? { supersedes: existing.id } : {}),
492
- });
495
+ }, now);
493
496
  }
494
497
 
495
498
  export interface UnpromotedBlackboardSummary {
@@ -203,7 +203,7 @@ export function setProjectJournalFields(input: {
203
203
  fields: Record<string, string | null>;
204
204
  changedBy: string;
205
205
  now?: number;
206
- }): ProjectJournalFieldChange[] {
206
+ }, submittedAt: number = Date.now()): ProjectJournalFieldChange[] {
207
207
  const entries = Object.entries(input.fields);
208
208
  if (!entries.length) throw new ValidationError("fields must name at least one journal field");
209
209
  const plan: Array<{ field: ProjectJournalField; value: string | null; previous: string | null }> = [];
@@ -222,7 +222,7 @@ export function setProjectJournalFields(input: {
222
222
  plan.push({ field, value: value === "" ? null : value, previous });
223
223
  }
224
224
 
225
- const now = input.now ?? Date.now();
225
+ const now = input.now ?? submittedAt;
226
226
  const changes: ProjectJournalFieldChange[] = [];
227
227
  writeTransaction(() => {
228
228
  for (const { field, value, previous } of plan) {
@@ -68,9 +68,9 @@ export interface UpsertProjectTrustApprovalInput {
68
68
  /** Records `approvedValue` as the trusted content for this (profile, repo, capability), replacing
69
69
  * any prior approval — used both by the operator-triggered dashboard approve action and by the
70
70
  * gate's own grandfather-on-first-encounter path (decision #4). */
71
- export function upsertProjectTrustApproval(input: UpsertProjectTrustApprovalInput): ProjectTrustApproval {
71
+ export function upsertProjectTrustApproval(input: UpsertProjectTrustApprovalInput, submittedAt: number = Date.now()): ProjectTrustApproval {
72
72
  return writeTransaction(() => {
73
- const now = Date.now();
73
+ const now = submittedAt;
74
74
  const existing = getDb().query(`
75
75
  SELECT id FROM project_trust_approvals WHERE profile_name = ? AND repo_key = ? AND capability = ?
76
76
  `).get(input.profileName, input.repoKey, input.capability) as { id: string } | null;
@@ -74,8 +74,8 @@ export function listTemplates(category?: string): PromptTemplateRecord[] {
74
74
  return templates;
75
75
  }
76
76
 
77
- export function upsertTemplate(slug: string, template: string): void {
78
- const now = Date.now();
77
+ export function upsertTemplate(slug: string, template: string, submittedAt: number = Date.now()): void {
78
+ const now = submittedAt;
79
79
  if (versionedPromptSlot(slug)) {
80
80
  throw new ValidationError("Use the versioned prompt writer with expectedVersion and actor");
81
81
  }
@@ -83,11 +83,11 @@ export function upsertTemplate(slug: string, template: string): void {
83
83
  if ((result.changes ?? 0) === 0) throw new ValidationError(`prompt template ${slug} not found`);
84
84
  }
85
85
 
86
- export function resetTemplate(slug: string): void {
86
+ export function resetTemplate(slug: string, submittedAt: number = Date.now()): void {
87
87
  if (versionedPromptSlot(slug)) {
88
88
  throw new ValidationError("Use the versioned prompt writer with expectedVersion and actor");
89
89
  }
90
- const now = Date.now();
90
+ const now = submittedAt;
91
91
  const result = getDb().query("UPDATE prompt_templates SET template = default_template, updated_at = ? WHERE slug = ?").run(now, slug);
92
92
  if ((result.changes ?? 0) === 0) throw new ValidationError(`prompt template ${slug} not found`);
93
93
  }
@@ -191,6 +191,16 @@ export const READ_OP_MARSHALING_FIXTURES: ReadOpFixtures = {
191
191
  "projects.resolveEntries": { args: { projectId: SEED.projectId } },
192
192
  "projects.readMemoryEntriesByIds": { args: { identity: { projectId: SEED.projectId }, ids: ["pe_t9_alpha"] } },
193
193
  "projects.memoryPreamble": { args: { identity: { projectId: SEED.projectId }, options: {} } },
194
+ "issueRefs.list": { args: { limit: 10 } },
195
+ "automations.listRuns": { args: { limit: 10 } },
196
+ "automations.pendingPrecheckRuns": { args: undefined },
197
+ "automations.reconcilableRuns": { args: undefined },
198
+ "automations.dispatchableQueuedRuns": { args: undefined },
199
+ "automations.dueAutomations": { args: { now: 1_700_000_000_000 } },
200
+ "projectEntries.get": { args: { id: "pe_t9_alpha" } },
201
+ "projectEntries.chain": { args: { id: "pe_t9_alpha" } },
202
+ "projectEntries.inArea": { args: { projectId: SEED.projectId, area: "db" } },
203
+ "projectEntries.countPinnedInArea": { args: { projectId: SEED.projectId, area: "db" } },
194
204
  "projectEntries.list": { args: { projectId: SEED.projectId } },
195
205
  "projectEntries.search": { args: { projectId: SEED.projectId, query: "t9" } },
196
206
  "teams.spawnDelegation.get": { args: { teamId: SEED.teamId } },
@@ -242,6 +252,7 @@ export const READ_OP_MARSHALING_FIXTURES: ReadOpFixtures = {
242
252
  // --- commands / codex reset / inbox / insights --------------------------------------------------
243
253
  "commands.spawnOutcome": { args: { spawnRequestId: "spawn-t9" } },
244
254
  "commands.get": { args: { id: SEED.commandId } },
255
+ "commands.latestAttempt": { args: { baseId: SEED.commandId } },
245
256
  "commands.listLegacyLandingBackfillCandidates": { args: { afterId: "", limit: 10 } },
246
257
  // `observedAt` is the dispatcher's own `ctx.now`, so the in-process and worker runs legitimately
247
258
  // stamp different clock readings for the same DB state — normalize it out or the #1960 worker-seam
@@ -714,6 +725,12 @@ export function seedReadOpMarshalingData(): void {
714
725
  VALUES ('t9', 't9 claimed task', 't9', 'info', 'in_progress', 't9', 'claim', ?, ?, ?, ?, ?)`,
715
726
  ).run(SEED.agentId, t - 1, t, t, t);
716
727
 
728
+ // An open task-bound run so the automation scan ops marshal a NON-trivial run (meta/result JSON parsed worker-side).
729
+ db.query(
730
+ `INSERT INTO automation_runs (id, automation_id, status, scheduled_for, orchestrator_id, task_id, meta, created_at, updated_at)
731
+ VALUES ('run-t9', 'automation-t9', 'running', ?, 'orch-t9', 1, '{"k":"v"}', ?, ?)`,
732
+ ).run(t, t, t);
733
+
717
734
  // Project-entries rows so `projectEntries.list`/`search` marshal NON-trivial results:
718
735
  // two active rows the query term hits, plus a retracted row proving mixed-status parity.
719
736
  for (const [id, title, body, status, updatedAt] of [
@@ -725,5 +742,6 @@ export function seedReadOpMarshalingData(): void {
725
742
  `INSERT INTO project_entries (id, project_id, kind, title, body, status, tags, author_id, source, audience, inject, sensitivity, created_at, updated_at)
726
743
  VALUES (?, ?, 'rule', ?, ?, ?, '["t9"]', ?, 'manual', 'all', 'indexed', 'normal', ?, ?)`,
727
744
  ).run(id, SEED.projectId, title, body, status, SEED.agentId, updatedAt, updatedAt);
745
+ db.query("UPDATE project_entries SET areas = ?, inject = ? WHERE id = ?").run('["db"]', "pinned", id);
728
746
  }
729
747
  }
@@ -63,6 +63,8 @@ import { ARTIFACTS_READ_OPS } from "./artifacts-read-ops.ts";
63
63
  import { PLANS_READ_OPS } from "./plans-read-ops.ts";
64
64
  import { CONTINUATION_ARCHIVES_READ_OPS } from "./continuation-archives-read-ops.ts";
65
65
  import { WORKFLOW_JOURNAL_READ_OPS } from "./workflow-journal-read-ops.ts";
66
+ import { AUTOMATION_READ_OPS } from "./automation-read-ops.ts";
67
+ import { ISSUE_REFS_READ_OPS } from "./issue-refs-read-ops.ts";
66
68
  import { PROJECTS_READ_OPS } from "./projects-read-ops.ts";
67
69
  import { PROJECT_ENTRIES_READ_OPS } from "./project-entries-read-ops.ts";
68
70
  import { CHANNELS_READ_OPS } from "./channels-read-ops.ts";
@@ -256,6 +258,8 @@ export const readOps = {
256
258
  ...WORKFLOW_JOURNAL_READ_OPS,
257
259
  ...PROJECTS_READ_OPS,
258
260
  ...PROJECT_ENTRIES_READ_OPS,
261
+ ...AUTOMATION_READ_OPS,
262
+ ...ISSUE_REFS_READ_OPS,
259
263
  ...CHANNELS_READ_OPS,
260
264
  ...INTEGRATIONS_READ_OPS,
261
265
  } satisfies Record<string, ReadOpFn>;
@@ -1,5 +1,6 @@
1
1
  import { getDb, getDbPath, runDbMaintenanceWorker } from "./connection.ts";
2
2
  import { spawnProcessGoneSql } from "./spawn-process-evidence";
3
+ import { slimSpawnProfileChunk } from "./command-agent-profile-backfill";
3
4
 
4
5
  export interface RetentionPruneInput {
5
6
  messageCutoff: number;
@@ -13,6 +14,8 @@ export interface RetentionPruneResult {
13
14
  prunedMessages: number;
14
15
  prunedActivityEvents: number;
15
16
  prunedSpawnCommands: number;
17
+ /** #3610 — legacy spawn rows whose inline agentProfile moved to the content-hash store. */
18
+ slimmedSpawnProfiles: number;
16
19
  // #1758 — true when this run stopped on its batch-size cap or its wall-time budget with candidate
17
20
  // rows still available in at least one table, i.e. it made bounded progress but did NOT drain the
18
21
  // backlog. The scheduler uses it to record the run `succeeded` (not `failed`) and to reschedule the
@@ -325,11 +328,13 @@ export function pruneRetentionBatchOnDb(db: RetentionDb, input: RetentionPruneIn
325
328
  const messages = pruneChunks(batchSize, deadlineAt, (limit) => messageChunk(db, input.messageCutoff, limit));
326
329
  const activity = pruneChunks(batchSize, deadlineAt, (limit) => activityChunk(db, input.activityCutoff, activityHotSetBoundary, limit));
327
330
  const spawnCommands = pruneChunks(batchSize, deadlineAt, (limit) => spawnCommandChunk(db, input.spawnCommandCutoff, limit));
331
+ const profiles = pruneChunks(batchSize, deadlineAt, (limit) => slimSpawnProfileChunk(db, limit));
328
332
  return {
329
333
  prunedMessages: messages.pruned,
330
334
  prunedActivityEvents: activity.pruned,
331
335
  prunedSpawnCommands: spawnCommands.pruned,
332
- moreWork: messages.moreWork || activity.moreWork || spawnCommands.moreWork,
336
+ slimmedSpawnProfiles: profiles.pruned,
337
+ moreWork: messages.moreWork || activity.moreWork || spawnCommands.moreWork || profiles.moreWork,
333
338
  };
334
339
  }
335
340
 
@@ -362,10 +367,13 @@ export async function pruneRetentionBatchOnDbAsync(
362
367
  const runMessages = (deadlineAt: number) => pruneChunksAsync(batchCap, deadlineAt, (limit) => messageChunk(db, input.messageCutoff, limit));
363
368
  const runActivity = (deadlineAt: number) => pruneChunksAsync(batchCap, deadlineAt, (limit) => activityChunk(db, input.activityCutoff, activityHotSetBoundary, limit));
364
369
  const runSpawn = (deadlineAt: number) => pruneChunksAsync(batchCap, deadlineAt, (limit) => spawnCommandChunk(db, input.spawnCommandCutoff, limit));
370
+ // After the deletes, so rows about to age out are never rewritten first.
371
+ const runProfiles = (deadlineAt: number) => pruneChunksAsync(batchCap, deadlineAt, (limit) => slimSpawnProfileChunk(db, limit));
365
372
 
366
373
  let messages: { pruned: number; moreWork: boolean };
367
374
  let activity: { pruned: number; moreWork: boolean };
368
375
  let spawnCommands: { pruned: number; moreWork: boolean };
376
+ let profiles: { pruned: number; moreWork: boolean };
369
377
  if (options.catchUp) {
370
378
  // Cumulative per-table deadline checkpoints against one shared clock. With the batch cap unreachable,
371
379
  // a single shared deadline would let a large `messages` backlog consume the whole budget before
@@ -377,6 +385,7 @@ export async function pruneRetentionBatchOnDbAsync(
377
385
  const third = totalBudget / 3;
378
386
  activity = await runActivity(start + third);
379
387
  spawnCommands = await runSpawn(start + 2 * third);
388
+ profiles = await runProfiles(start + 2 * third);
380
389
  messages = await runMessages(start + totalBudget);
381
390
  } else {
382
391
  // Inline-async fallback (:memory:): one shared deadline + the operator batch cap, unchanged.
@@ -384,12 +393,14 @@ export async function pruneRetentionBatchOnDbAsync(
384
393
  messages = await runMessages(deadlineAt);
385
394
  activity = await runActivity(deadlineAt);
386
395
  spawnCommands = await runSpawn(deadlineAt);
396
+ profiles = await runProfiles(deadlineAt);
387
397
  }
388
398
  return {
389
399
  prunedMessages: messages.pruned,
390
400
  prunedActivityEvents: activity.pruned,
391
401
  prunedSpawnCommands: spawnCommands.pruned,
392
- moreWork: messages.moreWork || activity.moreWork || spawnCommands.moreWork,
402
+ slimmedSpawnProfiles: profiles.pruned,
403
+ moreWork: messages.moreWork || activity.moreWork || spawnCommands.moreWork || profiles.moreWork,
393
404
  };
394
405
  }
395
406
 
@@ -0,0 +1,8 @@
1
+ import { createCommandInternal, type CreateCommandWriteArgs } from "../commands-db";
2
+ import { upsertReviewRefCleanup } from "./review-ref-cleanups";
3
+ export type ReviewCleanupInput = Omit<Parameters<typeof upsertReviewRefCleanup>[0], "id">;
4
+ export function createReviewPublishBody(args: { command: CreateCommandWriteArgs; cleanup: ReviewCleanupInput }, now: number) {
5
+ const command = createCommandInternal(args.command, now);
6
+ upsertReviewRefCleanup({ ...args.cleanup, id: command.id });
7
+ return command;
8
+ }
@@ -0,0 +1,19 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { getGateway } from "./gateway";
3
+ import { emitWorkspaceChange, emitWorkspaceCreate, type RecoveredWorkspaceInput } from "./workspaces";
4
+ import type { upsertWorkspaceRow } from "./workspaces";
5
+ import type { recoverWorkspaceBody, expireRuntimeCommands } from "./runtime-admin-write-ops";
6
+
7
+ export async function upsertWorkspaceAsync(input: Parameters<typeof upsertWorkspaceRow>[0]) {
8
+ const result = await getGateway().write("workspaces.upsertRow", input, { idempotencyKey: randomUUID() }) as unknown as ReturnType<typeof upsertWorkspaceRow>;
9
+ if (result.changed) emitWorkspaceChange(result.workspace);
10
+ return result.workspace;
11
+ }
12
+ export async function insertRecoveredWorkspaceAsync(input: RecoveredWorkspaceInput): Promise<ReturnType<typeof recoverWorkspaceBody>> {
13
+ const result = await getGateway().write("workspaces.recover", input, { idempotencyKey: randomUUID() }) as unknown as ReturnType<typeof recoverWorkspaceBody>;
14
+ if (result.created) { emitWorkspaceChange(result.workspace); emitWorkspaceCreate(result.workspace); }
15
+ return result;
16
+ }
17
+ export function expireCommandsAsync(now = Date.now()): Promise<ReturnType<typeof expireRuntimeCommands>> {
18
+ return getGateway().write("commands.expireRuntime", { now }, { idempotencyKey: randomUUID(), critical: true }) as unknown as Promise<ReturnType<typeof expireRuntimeCommands>>;
19
+ }
@@ -0,0 +1,36 @@
1
+ import { createUserInvite, acceptUserInvite } from "./user-invites";
2
+ import { getAgent } from "./agents";
3
+ import { getWorkspace, upsertWorkspaceRow, type RecoveredWorkspaceInput } from "./workspaces";
4
+ import { expireCommands, updateCommandInternal, applyCommandUpdatePostCommit } from "../commands-db";
5
+ import { redactCommandSecrets } from "../command-secrets";
6
+ import type { Command } from "../types";
7
+ import type { WriterOpSpec } from "./write-ops";
8
+
9
+ export function recoverWorkspaceBody(input: RecoveredWorkspaceInput, now: number) {
10
+ const existing = getWorkspace(input.id);
11
+ if (existing) return { workspace: existing, created: false };
12
+ const result = upsertWorkspaceRow({ id: input.id, repoRoot: input.repoRoot, sourceCwd: input.sourceCwd, worktreePath: input.worktreePath,
13
+ branch: input.branch, baseRef: input.baseRef, baseSha: input.baseSha, mode: "isolated", status: "active", orchestratorId: input.orchestratorId,
14
+ ownerAgentId: input.ownerAgentId, metadata: { reregistered: true, ...input.landMetadata } }, now);
15
+ return { workspace: result.workspace, created: result.created };
16
+ }
17
+ export function expireRuntimeCommands(now: number) {
18
+ return expireCommands(now, {
19
+ isTargetGone: command => Boolean(command.target && command.target !== "system" && (!getAgent(command.target) || getAgent(command.target)!.status === "offline")),
20
+ update: (id, input, options) => {
21
+ const result = updateCommandInternal(id, input, options, now);
22
+ return applyCommandUpdatePostCommit(result.previousStatus, result.command);
23
+ },
24
+ });
25
+ }
26
+ export const RUNTIME_ADMIN_WRITE_OPS: Readonly<Record<string, WriterOpSpec>> = Object.freeze({
27
+ "userInvites.create": { offLoop: true, idempotent: false,
28
+ fn: (input: Parameters<typeof createUserInvite>[0], ctx) => createUserInvite({ ...input, now: input.now ?? ctx.now }),
29
+ // The invite code is a bearer credential returned once, like a token mint (#1870).
30
+ serializeIdempotencyResult: value => ({ invite: (value as ReturnType<typeof createUserInvite>).invite }) },
31
+ "userInvites.accept": { offLoop: true, idempotent: false, fn: (input: Parameters<typeof acceptUserInvite>[0], ctx) => acceptUserInvite({ ...input, now: input.now ?? ctx.now }) },
32
+ "workspaces.upsertRow": { offLoop: true, idempotent: false, fn: (input: Parameters<typeof upsertWorkspaceRow>[0], ctx) => upsertWorkspaceRow(input, ctx.now) },
33
+ "workspaces.recover": { offLoop: true, idempotent: false, fn: (input: RecoveredWorkspaceInput, ctx) => recoverWorkspaceBody(input, ctx.now) },
34
+ "commands.expireRuntime": { offLoop: true, idempotent: false, fn: (args: { now?: number }, ctx) => expireRuntimeCommands(args.now ?? ctx.now),
35
+ serializeIdempotencyResult: value => (value as Command[]).map(command => redactCommandSecrets(command)) },
36
+ });