@humwick/server 0.130.0 → 0.130.2

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 (486) hide show
  1. package/README.md +5 -0
  2. package/docs/guides/tools-administration.md +6 -1
  3. package/docs/guides/tools-coordination.md +1 -0
  4. package/docs/guides/tools-tasks.md +8 -0
  5. package/docs/guides/workflows.md +58 -0
  6. package/docs/openapi.json +414 -1
  7. package/package.json +8 -17
  8. package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-BWLqMGKG.js} +2 -2
  9. package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-3TlIQpjk.js} +2 -2
  10. package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-Wimm0Czv.js} +2 -2
  11. package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-Bau_vNax.js} +2 -2
  12. package/public/assets/{activity-yLztXEBt.js → activity-CrSurn-r.js} +2 -2
  13. package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-CknAJKcb.js} +2 -2
  14. package/public/assets/agent-liveness-CaNwK0Zf.js +2 -0
  15. package/public/assets/{agent-name-CTZBrSD9.js → agent-name-DKbiIhBo.js} +2 -2
  16. package/public/assets/agent-profiles-DwF6EQ4R.js +2 -0
  17. package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-Diz4Sjjb.js} +2 -2
  18. package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-CRhpRQza.js} +2 -2
  19. package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-LrUEU3lB.js} +2 -2
  20. package/public/assets/{agents-BYDslkJc.js → agents-B-v66C-4.js} +2 -2
  21. package/public/assets/{analytics-B-XSbEMC.js → analytics-BqCb-LKi.js} +2 -2
  22. package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-kf4pGuAR.js} +2 -2
  23. package/public/assets/{artifacts-oBOqks-2.js → artifacts-D32zyw4Y.js} +2 -2
  24. package/public/assets/{artifacts-DPN1q4pA.js → artifacts-DJevXcvg.js} +2 -2
  25. package/public/assets/{automation-4KcRFXEu.js → automation-BpRajx_5.js} +2 -2
  26. package/public/assets/{backlog-Cw9xPTCF.js → backlog-D_UjTdzX.js} +2 -2
  27. package/public/assets/{busy-health-CTu32MZt.js → busy-health-N3VEh4ao.js} +2 -2
  28. package/public/assets/{channels-BiXzg1G9.js → channels-9jopungq.js} +2 -2
  29. package/public/assets/{chat-Ctk2qwvA.js → chat-CSXrTB3C.js} +2 -2
  30. package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-p1NnmqK0.js} +2 -2
  31. package/public/assets/{connectors-C36ax4Vw.js → connectors-CZdqlDNL.js} +2 -2
  32. package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BgdsE4dG.js} +2 -2
  33. package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-30aXTKva.js} +2 -2
  34. package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-B_jvw2GE.js} +2 -2
  35. package/public/assets/{deploys-Bwfq146q.js → deploys-DoN6bAb5.js} +2 -2
  36. package/public/assets/{display-CfO7rTuF.js → display-BrKWFGJz.js} +2 -2
  37. package/public/assets/{files-DhhZI2Ih.js → files-D6XEu8Ng.js} +2 -2
  38. package/public/assets/fleet-C7jQWbw2.js +2 -0
  39. package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BiDs3MLx.js} +2 -2
  40. package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-CQBwc1fb.js} +3 -3
  41. package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-DyG0WsQS.js} +2 -2
  42. package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-DKaW31dN.js} +2 -2
  43. package/public/assets/index-CRHep3M9.js +15 -0
  44. package/public/assets/index-MYAIwYTX.css +2 -0
  45. package/public/assets/{insights-fH1EL-qZ.js → insights-CzrtkpOE.js} +2 -2
  46. package/public/assets/{integrations-C5Oix6ng.js → integrations-aVsUmigt.js} +2 -2
  47. package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-BnSlM_95.js} +2 -2
  48. package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-qe7Ee47Z.js} +2 -2
  49. package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-NfjqFZAk.js} +2 -2
  50. package/public/assets/{managed-agents-egllbpij.js → managed-agents-BiH0HgaE.js} +2 -2
  51. package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-BixaT3Xr.js} +3 -3
  52. package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-DNGlWIS3.js} +2 -2
  53. package/public/assets/{memory-C8WmXsyr.js → memory-DNsCl6UX.js} +2 -2
  54. package/public/assets/{messages-BzQdqlO6.js → messages-DopU1L1X.js} +2 -2
  55. package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Cq7ckLQT.js} +2 -2
  56. package/public/assets/{overview-DCUnI4Z7.js → overview-C1DCTzzV.js} +2 -2
  57. package/public/assets/{pairs-ftCd2XcD.js → pairs-DE_m6rrE.js} +2 -2
  58. package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-B3rfh77F.js} +2 -2
  59. package/public/assets/project-profile-instructions-DQWZE0kA.js +2 -0
  60. package/public/assets/projects-Br2Bd2h1.js +2 -0
  61. package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-BKvFsvGD.js} +2 -2
  62. package/public/assets/provider-display-DsuWMvVL.js +2 -0
  63. package/public/assets/{registry-DWCU5c8q.js → registry-Cw38_6gW.js} +2 -2
  64. package/public/assets/run-card-CpKqRbhg.js +2 -0
  65. package/public/assets/scroll-text-BKXS1ahr.js +2 -0
  66. package/public/assets/{secrets-C7GIUATz.js → secrets-DxI-vzSq.js} +2 -2
  67. package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-D9s_VJbd.js} +2 -2
  68. package/public/assets/{settings-C6sZ9eBa.js → settings-CKZTVGIx.js} +2 -2
  69. package/public/assets/{shipping-Bu8p1gEw.js → shipping-B9YtnwtG.js} +2 -2
  70. package/public/assets/{stats-V9Z-GxUd.js → stats-DyUBKyWI.js} +2 -2
  71. package/public/assets/{status-dot-CVv0iGHL.js → status-dot-DYqlEUhJ.js} +2 -2
  72. package/public/assets/{store-BvtFdlGX.js → store-DcClXLH0.js} +3 -3
  73. package/public/assets/{tasks-CXU75HRF.js → tasks-Bh7Chr4-.js} +2 -2
  74. package/public/assets/{teams-BPf976zb.js → teams-bowI7qVY.js} +2 -2
  75. package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-BgVLHdsU.js} +3 -3
  76. package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-Dz22UPy6.js} +2 -2
  77. package/public/assets/token-estimate-Co-Jdphh.js +2 -0
  78. package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-DSQQ-iY7.js} +2 -2
  79. package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-samMQhQf.js} +2 -2
  80. package/public/assets/use-project-list-59LheVP7.js +2 -0
  81. package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BZa25xEB.js} +2 -2
  82. package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-DHxlvUvV.js} +2 -2
  83. package/public/assets/versioned-prompt-editor-BmED5DnJ.js +8 -0
  84. package/public/assets/{work-queue-TCjJxeT-.js → work-queue-CSvpuNLz.js} +2 -2
  85. package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-DAZcj5qt.js} +2 -2
  86. package/public/assets/{workflows-CXQX20Qj.js → workflows-DdmxRSyg.js} +2 -2
  87. package/public/assets/{workspaces-qSYzKYMA.js → workspaces-BxeKfVuF.js} +2 -2
  88. package/public/cosmos.html +4 -4
  89. package/public/index.html +31 -29
  90. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  91. package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
  92. package/runner/src/adapters/claude-effort.ts +2 -4
  93. package/runner/src/adapters/codex-launch-config.ts +4 -5
  94. package/runner/src/adapters/codex.ts +1 -1
  95. package/runner/src/adapters/opencode-provider.ts +7 -22
  96. package/runner/src/adapters/opencode.ts +4 -4
  97. package/runner/src/agent-runner/credentials.ts +42 -12
  98. package/runner/src/agent-runner/inbox.ts +27 -0
  99. package/runner/src/agent-runner/lifecycle-milestones.ts +0 -2
  100. package/runner/src/bin/claude.ts +4 -0
  101. package/runner/src/bin/codex.ts +4 -0
  102. package/runner/src/bin/opencode.ts +4 -0
  103. package/runner/src/index.ts +5 -2
  104. package/runner/src/provider-setup.ts +34 -0
  105. package/runner/src/providers.ts +2 -1
  106. package/runner/src/runner-core.ts +18 -23
  107. package/runner/src/spawn-input.ts +2 -1
  108. package/runner/src/test-run-dedup.ts +59 -56
  109. package/scripts/cd-config.ts +24 -3
  110. package/scripts/gate-run-lease.ts +10 -7
  111. package/scripts/gate.sh +5 -1
  112. package/src/branch-land-notice.ts +93 -0
  113. package/src/branch-landed.ts +7 -76
  114. package/src/bus.ts +19 -20
  115. package/src/cd-deploy-notify.ts +30 -2
  116. package/src/cd-host-lag-notify.ts +7 -6
  117. package/src/ci/incidents.ts +2 -2
  118. package/src/ci/monitor.ts +5 -8
  119. package/src/ci/root-missing.ts +2 -7
  120. package/src/ci/transition-notify.ts +7 -39
  121. package/src/cli/cd-pauses.ts +19 -0
  122. package/src/cli/orchestrator.ts +1 -1
  123. package/src/cli/state.ts +2 -19
  124. package/src/cli/task-edit.ts +22 -0
  125. package/src/cli/task.ts +3 -1
  126. package/src/cli/workflow.ts +8 -2
  127. package/src/commands-db.ts +10 -6
  128. package/src/commands-write.ts +8 -0
  129. package/src/config-store-write.ts +13 -1
  130. package/src/config-store.ts +25 -14
  131. package/src/db/activity-async.ts +6 -1
  132. package/src/db/activity-write-ops.ts +13 -1
  133. package/src/db/activity.ts +1 -14
  134. package/src/db/agent-lifecycle-write-ops.ts +1 -0
  135. package/src/db/agent-meta.ts +2 -2
  136. package/src/db/agent-ownership-write-ops.ts +4 -0
  137. package/src/db/agent-search.ts +1 -15
  138. package/src/db/agents-async.ts +58 -7
  139. package/src/db/agents-write-ops.ts +28 -5
  140. package/src/db/agents.ts +81 -54
  141. package/src/db/artifacts-write-ops.ts +8 -3
  142. package/src/db/bus-outbox-write-ops.ts +1 -0
  143. package/src/db/channels-write-ops.ts +4 -0
  144. package/src/db/ci-incidents-async.ts +5 -5
  145. package/src/db/ci-incidents-write-ops.ts +2 -2
  146. package/src/db/claude-api-budget-ops.ts +5 -5
  147. package/src/db/claude-app-oauth.ts +4 -4
  148. package/src/db/codex-reset-consumes-write-ops.ts +3 -0
  149. package/src/db/command-row.ts +10 -2
  150. package/src/db/commands-list-query.ts +2 -0
  151. package/src/db/commands-spawn-read.ts +1 -1
  152. package/src/db/commands-write-ops.ts +21 -0
  153. package/src/db/config-store-write-ops.ts +9 -2
  154. package/src/db/continuation-archives-async.ts +5 -0
  155. package/src/db/continuation-archives-write-ops.ts +9 -0
  156. package/src/db/continuations.ts +2 -2
  157. package/src/db/db-writer-worker.ts +8 -1
  158. package/src/db/delivery-write-ops.ts +5 -0
  159. package/src/db/deploy-events-async.ts +1 -0
  160. package/src/db/deploy-events-read-ops.ts +2 -1
  161. package/src/db/deploy-events.ts +35 -4
  162. package/src/db/hosts-registration.ts +10 -2
  163. package/src/db/hosts-write-ops.ts +14 -0
  164. package/src/db/hosts.ts +9 -6
  165. package/src/db/inbox-write-ops.ts +4 -0
  166. package/src/db/inbox.ts +0 -14
  167. package/src/db/index.ts +2 -0
  168. package/src/db/insights-write-ops.ts +1 -0
  169. package/src/db/integrations-async.ts +8 -0
  170. package/src/db/integrations-ops.ts +15 -0
  171. package/src/db/integrations.ts +15 -21
  172. package/src/db/issue-lifecycle.ts +3 -4
  173. package/src/db/issue-refs-async.ts +20 -0
  174. package/src/db/issue-refs-write-ops.ts +29 -0
  175. package/src/db/issue-refs.ts +7 -8
  176. package/src/db/long-running-work.ts +2 -2
  177. package/src/db/macos-privacy.ts +1 -1
  178. package/src/db/main-connection-writes.ts +23 -2
  179. package/src/db/maintenance-job-reconcile.ts +61 -0
  180. package/src/db/maintenance-job-runs-async.ts +14 -0
  181. package/src/db/maintenance-job-write-ops.ts +9 -0
  182. package/src/db/mappers.ts +2 -14
  183. package/src/db/merge-lease.ts +1 -15
  184. package/src/db/message-reads-write-ops.ts +3 -0
  185. package/src/db/message-write-ops.ts +4 -0
  186. package/src/db/migrations.ts +7 -15
  187. package/src/db/orchestrators-async.ts +7 -3
  188. package/src/db/orchestrators-write-ops.ts +7 -1
  189. package/src/db/orchestrators.ts +21 -77
  190. package/src/db/pairs.ts +1 -13
  191. package/src/db/project-profile-instructions.ts +50 -0
  192. package/src/db/prompt-versions-ops.ts +1 -0
  193. package/src/db/prompt-versions.ts +9 -2
  194. package/src/db/provider-catalog-write-ops.ts +4 -4
  195. package/src/db/provider-config-history.ts +8 -3
  196. package/src/db/provider-flap-messages-write-ops.ts +1 -0
  197. package/src/db/provider-model-seed.ts +34 -0
  198. package/src/db/provider-quota-lease-write-ops.ts +1 -0
  199. package/src/db/provider-quota-write-ops.ts +2 -0
  200. package/src/db/provisioning-write-ops.ts +9 -8
  201. package/src/db/read-op-marshaling-fixtures.ts +5 -0
  202. package/src/db/read-ops.ts +4 -0
  203. package/src/db/routing-policy.ts +3 -4
  204. package/src/db/schema.ts +9 -3
  205. package/src/db/secrets-broker-write-ops.ts +5 -5
  206. package/src/db/secrets-vault-write.ts +7 -7
  207. package/src/db/services-write-ops.ts +3 -0
  208. package/src/db/spawn-delegation-state.ts +11 -4
  209. package/src/db/spawn-tree-cleanup.ts +3 -0
  210. package/src/db/stats-async.ts +4 -3
  211. package/src/db/task-entity.ts +23 -2
  212. package/src/db/task-list.ts +3 -1
  213. package/src/db/tasks.ts +1 -17
  214. package/src/db/team-spawn-delegation.ts +1 -1
  215. package/src/db/teams-write-ops.ts +4 -4
  216. package/src/db/timer-cutover-write-ops.ts +7 -0
  217. package/src/db/timer-ingress-write-ops.ts +9 -0
  218. package/src/db/timer-ingress.ts +7 -1
  219. package/src/db/timer-operator-write-ops.ts +14 -0
  220. package/src/db/timer-transfer-write-ops.ts +4 -0
  221. package/src/db/timer-write-ops.ts +14 -0
  222. package/src/db/token-db-write-ops.ts +21 -0
  223. package/src/db/token-standing.ts +15 -11
  224. package/src/db/user-settings-write-ops.ts +1 -0
  225. package/src/db/vault-backup.ts +2 -2
  226. package/src/db/vault-expiry.ts +2 -2
  227. package/src/db/vault-health.ts +3 -3
  228. package/src/db/vault-token-ops.ts +8 -8
  229. package/src/db/web-tool-call-ops.ts +3 -3
  230. package/src/db/workflow-contact.ts +1 -1
  231. package/src/db/workflow-task-read-ops.ts +30 -0
  232. package/src/db/write-ops.ts +15 -1
  233. package/src/db/writer-fault-seam.ts +5 -2
  234. package/src/db/writer-gateway.ts +21 -12
  235. package/src/dispatch-availability.ts +10 -6
  236. package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
  237. package/src/host/disk-alert.ts +121 -0
  238. package/src/lifecycle-manager.ts +3 -2
  239. package/src/maintenance/cd-watcher.ts +3 -3
  240. package/src/maintenance/critical-job-watchdog.ts +16 -17
  241. package/src/maintenance/index.ts +1 -0
  242. package/src/maintenance/jobs.ts +3 -2
  243. package/src/maintenance/scheduler.ts +84 -128
  244. package/src/maintenance/stalled-delivery-pager.ts +6 -5
  245. package/src/maintenance/workspaces.ts +1 -1
  246. package/src/managed-policy.ts +31 -27
  247. package/src/mcp/index.ts +5 -2
  248. package/src/mcp/output-descriptions.ts +8 -8
  249. package/src/mcp/presentation.ts +4 -4
  250. package/src/mcp/project-profile-instructions.ts +32 -0
  251. package/src/mcp/tool-groups.ts +1 -1
  252. package/src/mcp/tools-spawn.ts +4 -3
  253. package/src/mcp-agent-action.ts +1 -2
  254. package/src/mcp-host-tools.ts +1 -1
  255. package/src/mcp-issue-ref-tools.ts +12 -11
  256. package/src/mcp-maintenance-tools.ts +2 -2
  257. package/src/mcp-profile-trust-tools.ts +4 -4
  258. package/src/mcp-provider-catalog.ts +2 -2
  259. package/src/mcp-task-tools.ts +11 -5
  260. package/src/mcp-team-template-tools.ts +3 -3
  261. package/src/mcp-workflow-tools.ts +10 -3
  262. package/src/notification-types.ts +2 -1
  263. package/src/operator-alarm.ts +26 -11
  264. package/src/package-pack.ts +42 -39
  265. package/src/project-instructions.ts +4 -0
  266. package/src/project-profile-instruction-text.ts +6 -0
  267. package/src/project-profile-instructions.ts +20 -0
  268. package/src/provider-catalog-store.ts +3 -49
  269. package/src/provider-config-store.ts +12 -11
  270. package/src/provider-model-seed.ts +1 -18
  271. package/src/provider-quota-config-store.ts +5 -4
  272. package/src/provider-secrets.test-fixture.ts +3 -3
  273. package/src/recipe-runner.ts +2 -2
  274. package/src/repo-config-source.ts +10 -4
  275. package/src/routes/agent-profiles.ts +6 -6
  276. package/src/routes/agents-spawn.ts +1 -1
  277. package/src/routes/agents.ts +6 -6
  278. package/src/routes/commands-listing.ts +4 -0
  279. package/src/routes/commands.ts +2 -2
  280. package/src/routes/continuation-archives.ts +2 -2
  281. package/src/routes/host-resource-control.ts +4 -1
  282. package/src/routes/index.ts +10 -1
  283. package/src/routes/integrations.ts +24 -50
  284. package/src/routes/issue-refs.ts +7 -7
  285. package/src/routes/orchestrator-bootstrap.ts +3 -3
  286. package/src/routes/orchestrator-host-registration.ts +2 -2
  287. package/src/routes/orchestrator-host-utilization.ts +3 -1
  288. package/src/routes/orchestrator-proxy.ts +2 -2
  289. package/src/routes/orchestrator.ts +4 -4
  290. package/src/routes/project-profile-instructions.ts +27 -0
  291. package/src/routes/project-trust.ts +2 -2
  292. package/src/routes/provider-config.ts +9 -8
  293. package/src/routes/provider-quota-config.ts +2 -2
  294. package/src/routes/settings.ts +5 -5
  295. package/src/routes/stats.ts +6 -6
  296. package/src/routes/task-http.ts +15 -1
  297. package/src/routes/task-issues.ts +11 -26
  298. package/src/routes/tasks.ts +22 -53
  299. package/src/routes/team-templates.ts +5 -5
  300. package/src/routes/teams-config.ts +2 -2
  301. package/src/routes/tokens.ts +12 -5
  302. package/src/routes/workflows.ts +20 -5
  303. package/src/routing-policy-normalize.ts +1 -2
  304. package/src/routing-step-defaults.ts +0 -2
  305. package/src/runner-token-mint-limit.ts +63 -0
  306. package/src/runtime-grant.ts +4 -2
  307. package/src/runtime-tokens.ts +50 -9
  308. package/src/security.ts +13 -20
  309. package/src/server-background.ts +1 -1
  310. package/src/server.ts +5 -2
  311. package/src/services/host-utilization.ts +23 -0
  312. package/src/services/idle-epics.ts +5 -6
  313. package/src/services/issue-lifecycle.ts +57 -61
  314. package/src/services/issue-refs.ts +9 -13
  315. package/src/services/kernel-timers-cutover-chaos-worker.ts +12 -7
  316. package/src/services/kernel-timers-ingress.ts +1 -1
  317. package/src/services/kernel-timers-request-key-migration-chaos-worker.ts +4 -1
  318. package/src/services/landed-ancestry.ts +19 -3
  319. package/src/services/memory-areas.ts +15 -51
  320. package/src/services/plan-ci-notice.ts +57 -0
  321. package/src/services/plan-ci-recovery.ts +2 -55
  322. package/src/services/plan-wake-digest.ts +1 -0
  323. package/src/services/profile-trust.ts +4 -3
  324. package/src/services/project-config-read.ts +70 -0
  325. package/src/services/project-profile-instructions.ts +54 -0
  326. package/src/services/provisioning-harness/budget-baseline.json +4 -4
  327. package/src/services/restart-spawn.ts +61 -49
  328. package/src/services/self-care-state.ts +2 -1
  329. package/src/services/self-effort.ts +5 -5
  330. package/src/services/send-message.ts +5 -1
  331. package/src/services/spawn-agent.ts +13 -2
  332. package/src/services/spawn-chain-inspector.ts +6 -13
  333. package/src/services/spawn-policy.ts +68 -0
  334. package/src/services/spawn-tree-cleanup.ts +2 -2
  335. package/src/services/task-dispatch.ts +3 -0
  336. package/src/services/task-state-reconcile.ts +6 -14
  337. package/src/services/team-templates.ts +9 -8
  338. package/src/services/transient-agent-reaper.ts +3 -1
  339. package/src/services/workflow-auto-start.ts +25 -13
  340. package/src/services/workflow-ci-main.ts +1 -1
  341. package/src/services/workflow-deferred-cleanup.ts +4 -2
  342. package/src/services/workflow-effect-driver.ts +2 -0
  343. package/src/services/workflow-effects.ts +18 -11
  344. package/src/services/workflow-land-notice.ts +10 -0
  345. package/src/services/workflow-pause-text.ts +43 -0
  346. package/src/services/workflow-reconcile.ts +13 -11
  347. package/src/services/workflow-run-view.ts +2 -0
  348. package/src/services/workflow-runs.ts +29 -13
  349. package/src/services/workflow-supervisor-state.ts +5 -0
  350. package/src/services/workflow-supervisor.ts +7 -3
  351. package/src/settings/registry.ts +1 -2
  352. package/src/spawn-command.ts +4 -4
  353. package/src/spawn-models.ts +10 -12
  354. package/src/spawn-placement.ts +1 -1
  355. package/src/spawn-targets.ts +1 -1
  356. package/src/startup-context-injection.ts +1 -0
  357. package/src/state-adoption/cd-cutover.ts +53 -7
  358. package/src/state-adoption/fleet-cutover.ts +35 -0
  359. package/src/state-adoption/fleet-plan.ts +36 -0
  360. package/src/state-adoption/index.ts +2 -2
  361. package/src/state-adoption/linux-plan.ts +2 -2
  362. package/src/state-adoption/linux.ts +2 -2
  363. package/src/state-adoption/macos-plan.ts +2 -2
  364. package/src/state-adoption/macos.ts +1 -1
  365. package/src/steward.ts +7 -6
  366. package/src/task-dispatch-live.ts +1 -1
  367. package/src/task-dispatcher.ts +1 -1
  368. package/src/teams-config-store.ts +4 -3
  369. package/src/token-db-write.ts +10 -0
  370. package/src/workspace-command-settle.ts +2 -1
  371. package/src/workspace-steward-wake.ts +2 -2
  372. package/node_modules/@humwick/kernel/LICENSE +0 -167
  373. package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
  374. package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
  375. package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
  376. package/node_modules/@humwick/kernel/config.ts +0 -111
  377. package/node_modules/@humwick/kernel/contract.ts +0 -572
  378. package/node_modules/@humwick/kernel/control-authz.ts +0 -281
  379. package/node_modules/@humwick/kernel/control.ts +0 -645
  380. package/node_modules/@humwick/kernel/effects.ts +0 -493
  381. package/node_modules/@humwick/kernel/event-log.ts +0 -319
  382. package/node_modules/@humwick/kernel/http-transport.ts +0 -384
  383. package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
  384. package/node_modules/@humwick/kernel/identity.ts +0 -248
  385. package/node_modules/@humwick/kernel/index.ts +0 -28
  386. package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
  387. package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
  388. package/node_modules/@humwick/kernel/landing.ts +0 -953
  389. package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
  390. package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
  391. package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
  392. package/node_modules/@humwick/kernel/message-authority.ts +0 -281
  393. package/node_modules/@humwick/kernel/module-host.ts +0 -722
  394. package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
  395. package/node_modules/@humwick/kernel/package.json +0 -47
  396. package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
  397. package/node_modules/@humwick/kernel/persistence.ts +0 -510
  398. package/node_modules/@humwick/kernel/registry.ts +0 -60
  399. package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
  400. package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
  401. package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
  402. package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
  403. package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
  404. package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
  405. package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
  406. package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
  407. package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
  408. package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
  409. package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
  410. package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
  411. package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
  412. package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
  413. package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
  414. package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
  415. package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
  416. package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
  417. package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
  418. package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
  419. package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
  420. package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
  421. package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
  422. package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
  423. package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
  424. package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
  425. package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
  426. package/node_modules/@humwick/offload/LICENSE +0 -167
  427. package/node_modules/@humwick/offload/README.md +0 -57
  428. package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
  429. package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
  430. package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
  431. package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
  432. package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
  433. package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
  434. package/node_modules/@humwick/offload/dist/envelope.js +0 -80
  435. package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
  436. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
  437. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
  438. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
  439. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
  440. package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
  441. package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
  442. package/node_modules/@humwick/offload/dist/index.js +0 -5
  443. package/node_modules/@humwick/offload/dist/index.js.map +0 -1
  444. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
  445. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
  446. package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
  447. package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
  448. package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
  449. package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
  450. package/node_modules/@humwick/offload/dist/types.js +0 -176
  451. package/node_modules/@humwick/offload/dist/types.js.map +0 -1
  452. package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
  453. package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
  454. package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
  455. package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
  456. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
  457. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
  458. package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
  459. package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
  460. package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
  461. package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
  462. package/node_modules/@humwick/offload/dist/worker.js +0 -1
  463. package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
  464. package/node_modules/@humwick/offload/package.json +0 -46
  465. package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
  466. package/node_modules/@humwick/offload/src/envelope.ts +0 -92
  467. package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
  468. package/node_modules/@humwick/offload/src/index.ts +0 -4
  469. package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
  470. package/node_modules/@humwick/offload/src/types.ts +0 -235
  471. package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
  472. package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
  473. package/node_modules/@humwick/offload/src/worker.ts +0 -5
  474. package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
  475. package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
  476. package/public/assets/fleet-BL4UXS_k.js +0 -2
  477. package/public/assets/index-B7ZerHLY.css +0 -2
  478. package/public/assets/index-BK0WV6hF.js +0 -15
  479. package/public/assets/projects-B_lmcqfO.js +0 -2
  480. package/public/assets/provider-display-DbLWpP3j.js +0 -2
  481. package/public/assets/run-card-CO_bguQf.js +0 -2
  482. package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
  483. package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
  484. package/runner/src/gate-run-lease-probe.ts +0 -38
  485. package/src/db/claude-catalog-reconcile.ts +0 -27
  486. package/src/routing-model-aliases.ts +0 -21
@@ -5,7 +5,7 @@ import { McpAuthError } from "./mcp-errors";
5
5
  import { ValidationError } from "./db";
6
6
  import { authContextFromMcp } from "./services/auth-context";
7
7
  import { ServiceAuthError } from "./services/errors";
8
- import { cancelWorkflowRun, getWorkflowRun, resumeWorkflowRun, startWorkflowRun } from "./services/workflow-runs";
8
+ import { cancelWorkflowRun, getWorkflowRun, pauseWorkflowRun, resumeWorkflowRun, startWorkflowRun } from "./services/workflow-runs";
9
9
  import { parseWorkflowPins } from "./services/workflow-pins";
10
10
  import { cleanString, taskIdField } from "./validation";
11
11
 
@@ -48,7 +48,7 @@ export const WORKFLOW_TOOLS = [
48
48
  {
49
49
  name: "relay_workflow_resume",
50
50
  description:
51
- "Resume or answer/escalate a decision.",
51
+ "Resume, pause/unpause, or answer/escalate a decision.",
52
52
  requiredScopes: ["task:write"],
53
53
  inputSchema: {
54
54
  type: "object",
@@ -66,6 +66,7 @@ export const WORKFLOW_TOOLS = [
66
66
  activationId: { type: "string" },
67
67
  step: { type: "string" },
68
68
  note: { type: "string" },
69
+ pause: { type: "boolean" },
69
70
  pins: PINS_PROP,
70
71
  },
71
72
  required: ["runId"],
@@ -112,7 +113,7 @@ type McpAuthLike = Parameters<typeof authContextFromMcp>[0];
112
113
 
113
114
  function mutationReceipt(full: Record<string, unknown>, verbose: unknown): Record<string, unknown> {
114
115
  if (verbose === true) return full;
115
- const fields = ["runId", "taskId", "workflow", "status", "step", "round", "callerAgentId", "budget", "existing", "resumed", "cancelled", "reason", "warnings"];
116
+ const fields = ["runId", "taskId", "workflow", "status", "step", "round", "callerAgentId", "budget", "existing", "resumed", "cancelled", "paused", "reason", "warnings"];
116
117
  return Object.fromEntries(fields.filter(key => full[key] !== undefined).map(key => [key, full[key]]));
117
118
  }
118
119
 
@@ -132,6 +133,12 @@ export async function relayWorkflowTool(auth: McpAuthLike, name: string, args: R
132
133
  if (!runId) throw new ValidationError("runId is required");
133
134
  const step = cleanString(args.step, "step", { max: 64 });
134
135
  const note = cleanString(args.note, "note", { max: 8000 });
136
+ if (args.pause !== undefined) {
137
+ // #3757 — pause (note is the required reason) or unpause; nothing else rides along.
138
+ if (typeof args.pause !== "boolean") throw new ValidationError("pause must be a boolean");
139
+ if (step || args.pins !== undefined || args.decision !== undefined || args.activationId !== undefined) throw new ValidationError("pause takes only runId and, to pause, note as the reason");
140
+ return mutationReceipt(await pauseWorkflowRun({ runId, pause: args.pause, ...(note ? { reason: note } : {}) }, ctx), args.verbose);
141
+ }
135
142
  const pins = parseWorkflowPins(args.pins);
136
143
  return mutationReceipt(await resumeWorkflowRun({ runId, decision: parseWorkflowDecisionResponse(args.decision), activationId: cleanString(args.activationId, "activationId", { max: 2000 }), ...(step ? { step } : {}), ...(note ? { note } : {}), ...(pins ? { pins } : {}) }, ctx), args.verbose);
137
144
  }
@@ -97,7 +97,8 @@ export type NotificationType =
97
97
  | "ci.config_mismatch"
98
98
  | "ci.root_missing"
99
99
  // #1645 — a critical maintenance job is not running (disabled, held indefinitely, a lapsed pause
100
- // nobody resumed, or simply silent past several of its own intervals).
100
+ // nobody resumed, or simply silent past several of its own intervals). Also carries host disk
101
+ // alerts (#3762) — a new type would grow three MCP tool schemas past their pinned budgets.
101
102
  | "maintenance.degraded";
102
103
 
103
104
  /**
@@ -1,4 +1,5 @@
1
1
  import { createActivityEventWithResult } from "./db";
2
+ import { createActivityEventByClientIdAsync } from "./db/activity-async";
2
3
  import { emitRelayEvent } from "./events";
3
4
 
4
5
  export interface OperatorAlarmInput {
@@ -20,22 +21,36 @@ export interface OperatorAlarmInput {
20
21
  // done. This raises a distinct `operator.alarm` relay event (dashboard banner) plus a
21
22
  // persisted `operator`-kind activity event, so a relay with no reachable escalation target
22
23
  // is observable instead of looping forever in the dark.
23
- export function raiseOperatorAlarm(input: OperatorAlarmInput): boolean {
24
- const { created } = createActivityEventWithResult({
25
- clientId: input.clientId,
26
- kind: "operator",
27
- title: input.subject,
28
- body: input.detail,
29
- icon: "ti-alert-octagon",
30
- view: input.view ?? "orchestrators",
31
- metadata: { source: input.source, operatorAlarm: true, ...(input.metadata ?? {}) },
32
- });
33
- if (input.dedupeEvent && !created) return false;
24
+ const alarmEvent = (input: OperatorAlarmInput) => ({
25
+ clientId: input.clientId,
26
+ kind: "operator" as const,
27
+ title: input.subject,
28
+ body: input.detail,
29
+ icon: "ti-alert-octagon",
30
+ view: input.view ?? "orchestrators",
31
+ metadata: { source: input.source, operatorAlarm: true, ...(input.metadata ?? {}) },
32
+ });
33
+
34
+ function emitAlarm(input: OperatorAlarmInput): void {
34
35
  emitRelayEvent({
35
36
  type: "operator.alarm",
36
37
  source: input.source,
37
38
  subject: input.subject,
38
39
  data: { subject: input.subject, detail: input.detail, ...(input.metadata ?? {}) },
39
40
  });
41
+ }
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;
48
+ }
49
+
50
+ /** Same as `raiseOperatorAlarm`, with the activity row written on the writer thread. */
51
+ export async function raiseOperatorAlarmAsync(input: OperatorAlarmInput): Promise<boolean> {
52
+ const { created } = await createActivityEventByClientIdAsync(alarmEvent(input));
53
+ if (input.dedupeEvent && !created) return false;
54
+ emitAlarm(input);
40
55
  return true;
41
56
  }
@@ -131,6 +131,42 @@ export function privateWorkspaceDependencies(packageDir: string): string[] {
131
131
  return privateDeps;
132
132
  }
133
133
 
134
+ type DependencyMap = Record<string, string>;
135
+ export type ConsumerManifest = {
136
+ dependencies?: DependencyMap;
137
+ optionalDependencies?: DependencyMap;
138
+ bundleDependencies?: string[];
139
+ };
140
+ export type VendoredManifest = {
141
+ version?: string;
142
+ dependencies?: DependencyMap;
143
+ optionalDependencies?: DependencyMap;
144
+ peerDependencies?: DependencyMap;
145
+ };
146
+
147
+ // Pin and bundle a vendored private dep on its consumer (bundleDependencies keeps the nested copy
148
+ // across reinstall/prune, #1772), and move the dep's own dependencies onto the consumer. npm counts
149
+ // every dependency a bundled package declares as bundled too and never extracts it, so a global
150
+ // install left @humwick/sdk, hono, zod … as empty folders (#3301). The vendored code still resolves
151
+ // them by walking up node_modules.
152
+ export function bundleVendoredDependency(consumer: ConsumerManifest, depName: string, vendored: VendoredManifest): void {
153
+ delete consumer.optionalDependencies?.[depName];
154
+ consumer.dependencies ??= {};
155
+ consumer.dependencies[depName] = vendored.version ?? "0.0.0";
156
+ consumer.bundleDependencies ??= [];
157
+ if (!consumer.bundleDependencies.includes(depName)) consumer.bundleDependencies.push(depName);
158
+ for (const field of ["dependencies", "optionalDependencies", "peerDependencies"] as const) {
159
+ for (const [name, spec] of Object.entries(vendored[field] ?? {})) {
160
+ const declared = consumer.dependencies[name] ?? consumer.optionalDependencies?.[name];
161
+ if (declared !== undefined && declared !== spec) {
162
+ fail(`package-pack: bundled ${depName} needs ${name}@${spec} but its consumer declares ${name}@${declared}; align the two specs`);
163
+ }
164
+ if (declared === undefined) consumer.dependencies[name] = spec;
165
+ }
166
+ delete vendored[field];
167
+ }
168
+ }
169
+
134
170
  // Vendor a PRIVATE (unpublished, `workspace:*`) workspace dependency into the packed
135
171
  // tarball as a nested `node_modules/<dep>` package, pin its bundled version in
136
172
  // the packed manifest, and merge its own runtime dependencies up into the consumer so
@@ -148,31 +184,19 @@ async function bundlePrivateWorkspaceDeps(cwd: string, packageDir: string, tarba
148
184
  try {
149
185
  tar(["-xzf", tarball, "-C", stage]);
150
186
  const pkgRoot = join(stage, "package");
151
- const packed = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8")) as {
152
- dependencies?: Record<string, string>;
153
- optionalDependencies?: Record<string, string>;
154
- bundleDependencies?: string[];
155
- };
187
+ const packed = JSON.parse(readFileSync(join(pkgRoot, "package.json"), "utf8")) as ConsumerManifest;
156
188
 
157
189
  for (const depName of privateDeps) {
158
190
  const depDir = dirByName.get(depName);
159
191
  if (!depDir) fail(`package-pack: private workspace dep ${depName} not found in root workspaces`);
160
192
  const depSrc = resolve(cwd, depDir);
161
- const depManifest = JSON.parse(readFileSync(join(depSrc, "package.json"), "utf8")) as {
162
- version?: string;
163
- dependencies?: Record<string, string>;
164
- };
165
193
 
166
194
  // Vendor the private package's REAL published file set by packing it exactly as it would be
167
195
  // published — `npm pack` honors the dep's own `files`/`exports` and runs its `prepack` build —
168
196
  // then extract the packed `package/` into node_modules/<dep>. Copying only flat root *.ts (the
169
197
  // pre-#1838 behavior) silently shipped a package.json-ONLY stub for any dep whose entrypoint is
170
- // a BUILT dist or lives in a nested dir: @humwick/offload's `main` is ./dist/index.js with
171
- // source under src/, so the vendored copy carried no dist and the installed consumer crashed at
172
- // import with "Cannot find package '@humwick/offload'". Packing is the canonical publish
173
- // representation and works for BOTH a raw-.ts dep (@humwick/kernel, exports ./index.ts) and a
174
- // built-dist dep (@humwick/offload) — and for any future published-package offload adopter
175
- // (orchestrator #1807, later waves) with no per-dep special-casing here.
198
+ // a BUILT dist or lives in a nested dir (@humwick/offload's `main` is ./dist/index.js). Packing
199
+ // works for BOTH a raw-.ts dep (@humwick/kernel) and a built-dist dep with no special-casing.
176
200
  const vendorDir = join(pkgRoot, "node_modules", depName);
177
201
  const depStage = mkdtempSync(join(packDir, "dep-pack-"));
178
202
  try {
@@ -186,30 +210,9 @@ async function bundlePrivateWorkspaceDeps(cwd: string, packageDir: string, tarba
186
210
  } finally {
187
211
  rmSync(depStage, { recursive: true, force: true });
188
212
  }
189
-
190
- // Replace the unresolvable workspace:* spec with the vendored version AND declare the
191
- // dep as a bundleDependency. This is the canonical npm/bun representation of a bundled
192
- // package: the nested node_modules/<dep> is treated as an intentional, protected part of
193
- // the tarball — preserved on install, never fetched from the registry (bundled wins over
194
- // the pinned version), and — critically — never pruned as "extraneous" on a second
195
- // `npm install` / `npm ci` / dedupe / prune pass. Merely DROPPING the workspace:* spec
196
- // (the pre-#1772 behavior) let the FIRST install keep the vendored copy but any later
197
- // tree reconciliation deleted node_modules/<dep> entirely, breaking every
198
- // `<dep>/<subpath>` import at runtime (e.g. @humwick/kernel/workflow-journal-codec
199
- // → CLI crash at startup). See #1772.
200
- for (const field of ["dependencies", "optionalDependencies"] as const) {
201
- if (packed[field]) delete packed[field][depName];
202
- }
203
- packed.dependencies ??= {};
204
- packed.dependencies[depName] = depManifest.version ?? "0.0.0";
205
- packed.bundleDependencies ??= [];
206
- if (!packed.bundleDependencies.includes(depName)) packed.bundleDependencies.push(depName);
207
-
208
- // Hoist the private dep's own runtime deps so the clean-env install resolves them from
209
- // the registry (kernel imports zod/hono/…).
210
- for (const [name, spec] of Object.entries(depManifest.dependencies ?? {})) {
211
- packed.dependencies[name] ??= spec;
212
- }
213
+ const vendored = JSON.parse(readFileSync(join(vendorDir, "package.json"), "utf8")) as VendoredManifest;
214
+ bundleVendoredDependency(packed, depName, vendored);
215
+ writeFileSync(join(vendorDir, "package.json"), JSON.stringify(vendored, null, 2) + "\n");
213
216
  }
214
217
 
215
218
  writeFileSync(join(pkgRoot, "package.json"), JSON.stringify(packed, null, 2) + "\n");
@@ -2,6 +2,7 @@ import { composeMemoryPreambleAsync } from "./memory-preamble-async";
2
2
  import { composeHostAwareness } from "./host-awareness";
3
3
  import { composeGuideIndex } from "./guides";
4
4
  import { profileInstructionBlocks } from "./profile-instruction-blocks";
5
+ import { projectProfileInstructionBlock } from "./project-profile-instructions";
5
6
  // Spawn-time instruction sources (#557) — the relay-owned composer that assembles what a spawned
6
7
  // agent's systemPromptAppend says, from declared sources only, never from host CLAUDE.md.
7
8
  //
@@ -283,6 +284,7 @@ export function composeSpawnInstructionsWithEvents(input: {
283
284
  * host → project`, audience-filtered by `profile`). Absent → no memory block at all, so a
284
285
  * caller that does not know the identity produces a byte-identical pre-#1565 spawn. */
285
286
  memoryIdentity?: MemoryIdentity;
287
+ projectId?: string;
286
288
  profile?: Pick<AgentProfile, "instructions" | "maxSpawnedAgents" | "hostAwareness" | "roleAssets"> & { name?: string; relay?: AgentProfile["relay"] };
287
289
  spawnedBy?: string;
288
290
  /** #3045 — a workflow step agent: its step reporting block replaces the spawned-child report-up. */
@@ -475,6 +477,8 @@ export function composeSpawnInstructionsWithEvents(input: {
475
477
  const { system: profileSystem, append: profileAppend } = profileInstructionBlocks(input.profile, input.memoryIdentity?.provider);
476
478
  if (profileSystem) appendBlocks.push(profileSystem);
477
479
  appendBlocks.push(...profileAppend);
480
+ const projectProfile = projectProfileInstructionBlock(input.projectId ?? input.memoryIdentity?.projectId, input.profile?.name ?? input.memoryIdentity?.profile);
481
+ if (projectProfile) { appendBlocks.push(projectProfile.content); relayInjectionEvents.push(projectProfile.event); }
478
482
  // After the profile, so the step rule is the last word over a charter's report-to-spawner text.
479
483
  if (input.workflowRunId) {
480
484
  const instruction = renderTemplate("spawn.reportup.workflow-step", { runId: input.workflowRunId });
@@ -0,0 +1,6 @@
1
+ import { assertNoControlBytes, ValidationError } from "@humwick/sdk";
2
+
3
+ export function validateProjectProfileInstructionText(value: unknown, source: string): asserts value is string {
4
+ if (typeof value !== "string" || value.length > 16_000) throw new ValidationError(`${source} must be a string up to 16000 characters`);
5
+ assertNoControlBytes(value, source);
6
+ }
@@ -0,0 +1,20 @@
1
+ import { errMessage } from "@humwick/sdk";
2
+ import { getProjectProfileInstructions } from "./db/project-profile-instructions";
3
+ import { validateProjectProfileInstructionText } from "./project-profile-instruction-text";
4
+
5
+ /** #3515 — one optional block at the charter seam, independent of project memory's switch. */
6
+ export function projectProfileInstructionBlock(projectId: string | undefined, profile: string | undefined) {
7
+ if (!projectId || !profile) return;
8
+ const source = `project ${projectId} profile ${profile} instructions`;
9
+ try {
10
+ const entry = getProjectProfileInstructions({ projectId, profile });
11
+ validateProjectProfileInstructionText(entry.template, source);
12
+ const content = entry.template.trim();
13
+ if (!content) return;
14
+ return { content, event: { category: "instructions" as const,
15
+ summary: `injected ${source} v${entry.version}`,
16
+ detail: { source: "project-profile-instructions", projectId, profile, version: entry.version, content } } };
17
+ } catch (error) {
18
+ console.warn(`[launch] skipped ${source}: ${errMessage(error)}`);
19
+ }
20
+ }
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  deriveProviderDisabledState,
3
3
  disabledProviderSet,
4
- providerCatalogList,
4
+ providerMetadataList,
5
5
  type ProviderCatalogEntry,
6
6
  type ProviderContextThreshold,
7
7
  type ProviderEnablementSetting,
@@ -44,7 +44,7 @@ export interface ProviderModelOverrideInput {
44
44
 
45
45
  function listProviderModelOverrides(): ProviderModelOverride[] {
46
46
  const rows = getDb()
47
- .query("SELECT * FROM provider_model_overrides ORDER BY provider ASC, alias ASC")
47
+ .query("SELECT * FROM provider_model_overrides ORDER BY provider ASC, rowid ASC")
48
48
  .all() as ProviderModelOverrideRow[];
49
49
  return rows.map(rowToOverride).filter((entry): entry is ProviderModelOverride => Boolean(entry));
50
50
  }
@@ -120,7 +120,7 @@ export function setProviderDefaultModel(provider: SpawnProvider, alias: string,
120
120
  }
121
121
 
122
122
  export function effectiveProviderCatalogList(now = Date.now()): ProviderCatalogEntry[] {
123
- const catalog = mergeProviderCatalog(providerCatalogList(), listProviderModelOverrides());
123
+ const catalog = mergeProviderCatalog(providerMetadataList(), listProviderModelOverrides());
124
124
  const defaults = getDb().query("SELECT provider, alias FROM provider_model_defaults").all() as Array<{ provider: string; alias: string }>;
125
125
  for (const { provider, alias } of defaults) {
126
126
  const entry = catalog.find((item) => item.provider === provider);
@@ -215,9 +215,6 @@ function normalizeOverrideInput(input: ProviderModelOverrideInput): ProviderMode
215
215
  if (limits) entry.limits = limits;
216
216
  else delete entry.limits;
217
217
  delete entry.disabled;
218
- // #368 — unavailable is a static catalog fact (provider-side suspension), not an operator toggle;
219
- // strip it from DB overrides so an admin can't accidentally clear a catalog-level suspension.
220
- delete entry.unavailable;
221
218
  // #2598 — `deleted` is a row-level tombstone column, never part of a stored entry blob.
222
219
  delete (entry as unknown as Record<string, unknown>).deleted;
223
220
  return {
@@ -288,49 +285,6 @@ function allowlistedLimitConfidence(value: unknown): ProviderModelLimitWindow["c
288
285
  : "declared";
289
286
  }
290
287
 
291
- /**
292
- * #2598 — additive, idempotent backfill of every static-catalog model into `provider_model_overrides`,
293
- * so the whole catalogue is uniformly DB-backed and operator-editable. Rules:
294
- * - INSERT-ONLY-IF-ABSENT (`ON CONFLICT DO NOTHING`): an existing row — a prior seed OR an operator
295
- * edit OR an operator delete-tombstone — is never touched, so operator edits ALWAYS win and a
296
- * deleted static model is never resurrected. Re-runnable; a re-run inserts only genuinely NEW
297
- * static models (e.g. added by a later release).
298
- * - SKIP disabled/unavailable static models: materializing them would strip those flags at the
299
- * write chokepoint (#368/#643) and resurrect a suspended model as spawnable. They stay
300
- * static-only until an operator explicitly adds them.
301
- * Stamped `updated_by = <stamp>` (e.g. `seed:<version>`) purely for provenance; precedence is decided
302
- * by row EXISTENCE, not by parsing the stamp.
303
- */
304
- export function seedProviderModelOverrides(stamp: string, now = Date.now()): { inserted: number } {
305
- const db = getDb();
306
- const existing = new Map<string, Set<string>>();
307
- for (const row of db.query("SELECT provider, alias FROM provider_model_overrides").all() as Array<{ provider: string; alias: string }>) {
308
- let aliases = existing.get(row.provider);
309
- if (!aliases) existing.set(row.provider, (aliases = new Set()));
310
- aliases.add(row.alias);
311
- }
312
- let inserted = 0;
313
- const insert = db.query(`
314
- INSERT INTO provider_model_overrides (provider, alias, entry, deleted, disabled, updated_at, updated_by)
315
- VALUES (?, ?, ?, 0, 0, ?, ?)
316
- ON CONFLICT(provider, alias) DO NOTHING
317
- `);
318
- const seed = db.transaction(() => {
319
- for (const providerEntry of providerCatalogList()) {
320
- const seen = existing.get(providerEntry.provider);
321
- for (const model of providerEntry.models) {
322
- if (model.disabled || model.unavailable) continue;
323
- if (seen?.has(model.alias)) continue;
324
- const normalized = normalizeOverrideInput({ provider: providerEntry.provider, alias: model.alias, entry: model, updatedBy: stamp });
325
- const result = insert.run(normalized.provider, normalized.alias, JSON.stringify(normalized.entry), now, normalized.updatedBy ?? null);
326
- if (result.changes > 0) inserted++;
327
- }
328
- }
329
- });
330
- seed();
331
- return { inserted };
332
- }
333
-
334
288
  function rowToOverride(row: ProviderModelOverrideRow): ProviderModelOverride | undefined {
335
289
  const parsed = parseJson<ProviderModelCatalogEntry | undefined>(row.entry, undefined);
336
290
  if (!parsed || typeof parsed.alias !== "string") return undefined;
@@ -4,7 +4,8 @@ import { hostname } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { ValidationError, listOrchestrators } from "./db";
6
6
  import { isSecretEnvKey } from "./db/provider-config-secrets";
7
- import { getConfig, listConfig, setConfig } from "./config-store";
7
+ import { getConfig, listConfig } from "./config-store";
8
+ import { setConfigAsync } from "./config-store-write";
8
9
  import { localOrchestratorIdFromEnv, providerConfigHomeFromEnv } from "./config";
9
10
  import { cleanString, cleanStringArray, optionalEnum } from "./validation";
10
11
  import { emitConfigChanged } from "./sse";
@@ -90,11 +91,11 @@ export function listProviderConfigEntries(host = defaultProviderConfigHost()): R
90
91
  ) as Record<SpawnProvider, ProviderConfigEntry>;
91
92
  }
92
93
 
93
- export function setProviderConfig(
94
+ export async function setProviderConfigAsync(
94
95
  provider: string,
95
96
  value: unknown,
96
97
  opts: { host?: string; updatedBy?: string } = {},
97
- ): ProviderConfigEntry {
98
+ ): Promise<ProviderConfigEntry> {
98
99
  const cleanProvider = normalizeProviderConfigProvider(provider);
99
100
  const host = normalizeProviderConfigHost(opts.host ?? defaultProviderConfigHost());
100
101
  const normalized = cleanProviderConfig(cleanProvider, resolveMaskedEnvSentinels(value, host, cleanProvider));
@@ -102,7 +103,7 @@ export function setProviderConfig(
102
103
  ensureProviderConfigDescriptors([key]);
103
104
  const validation = validateSettingValue(PROVIDER_CONFIG_NAMESPACE, key, normalized);
104
105
  if (!validation.valid) throw new ValidationError(validation.errors.join("; "));
105
- return setConfig(PROVIDER_CONFIG_NAMESPACE, key, normalized, opts.updatedBy) as ProviderConfigEntry;
106
+ return await setConfigAsync(PROVIDER_CONFIG_NAMESPACE, key, normalized, opts.updatedBy) as ProviderConfigEntry;
106
107
  }
107
108
 
108
109
  export function providerConfigPublic(entry: ProviderConfigEntry, opts: { maskEnv?: boolean } = {}): Record<string, unknown> {
@@ -138,11 +139,11 @@ export function providerConfigPublic(entry: ProviderConfigEntry, opts: { maskEnv
138
139
  * This is the server-authority write path: callers are in-process (local migration
139
140
  * or the orchestrator command-bus result handler), so no HTTP scope is required.
140
141
  */
141
- export function seedProviderConfigs(
142
+ export async function seedProviderConfigsAsync(
142
143
  host: string,
143
144
  rawByProvider: Record<string, unknown>,
144
145
  opts: { legacyHost?: string } = {},
145
- ): ProviderConfigEntry[] {
146
+ ): Promise<ProviderConfigEntry[]> {
146
147
  const seeded: ProviderConfigEntry[] = [];
147
148
  const cleanHost = normalizeProviderConfigHost(host);
148
149
  const legacyHost = opts.legacyHost ? normalizeProviderConfigHost(opts.legacyHost) : undefined;
@@ -159,7 +160,7 @@ export function seedProviderConfigs(
159
160
  // still validates; the relay owns the schema, the reporter stays dumb.
160
161
  const value = legacy?.value ?? { ...providerConfigDefaults(provider), ...(isRecord(raw) ? raw : {}) };
161
162
  try {
162
- const entry = setProviderConfig(provider, value, { host: cleanHost, updatedBy: `migration:${cleanHost}` });
163
+ const entry = await setProviderConfigAsync(provider, value, { host: cleanHost, updatedBy: `migration:${cleanHost}` });
163
164
  emitConfigChanged(entry.namespace, entry.key, entry.version);
164
165
  seeded.push(entry);
165
166
  } catch {
@@ -174,16 +175,16 @@ export function seedProviderConfigs(
174
175
  * owns the stable-id/legacy-hostname resolution together so command routes do
175
176
  * not re-parse or accidentally bypass the migration authority rules.
176
177
  */
177
- export function seedMigratedProviderConfigs(result: unknown): { host: string; seeded: ProviderConfigEntry[] } | null {
178
+ export async function seedMigratedProviderConfigsAsync(result: unknown): Promise<{ host: string; seeded: ProviderConfigEntry[] } | null> {
178
179
  if (!isRecord(result)) return null;
179
180
  const host = cleanString(result.host, "result.host", { max: 120 });
180
181
  const hostname = cleanString(result.hostname, "result.hostname", { max: 120 });
181
182
  const configs = isRecord(result.configs) ? result.configs : undefined;
182
183
  if (!host || !configs) return null;
183
- return { host, seeded: seedProviderConfigs(host, configs, { legacyHost: hostname }) };
184
+ return { host, seeded: await seedProviderConfigsAsync(host, configs, { legacyHost: hostname }) };
184
185
  }
185
186
 
186
- export function migrateLocalProviderConfigs(home = humwickHome(), host = defaultProviderConfigHost()): ProviderConfigEntry[] {
187
+ export async function migrateLocalProviderConfigsAsync(home = humwickHome(), host = defaultProviderConfigHost()): Promise<ProviderConfigEntry[]> {
187
188
  const dir = join(home, "providers");
188
189
  if (!existsSync(dir)) return [];
189
190
  const raw: Record<string, unknown> = {};
@@ -192,7 +193,7 @@ export function migrateLocalProviderConfigs(home = humwickHome(), host = default
192
193
  if (!VALID_PROVIDER_CONFIGS.includes(provider as SpawnProvider)) continue;
193
194
  raw[provider] = loadLocalProviderConfig(provider, home);
194
195
  }
195
- return seedProviderConfigs(host, raw);
196
+ return seedProviderConfigsAsync(host, raw);
196
197
  }
197
198
 
198
199
  function normalizeProviderConfigHost(host: string): string {
@@ -1,18 +1 @@
1
- import { getConfig, setConfig } from "./config-store";
2
- import { seedProviderModelOverrides } from "./provider-catalog-store";
3
- import { reconcileClaudeCatalogSeeds } from "./db/claude-catalog-reconcile";
4
- import { VERSION } from "./config";
5
- import { errMessage } from "@humwick/sdk";
6
-
7
- // Stamp only after the transactional seed succeeds so a failure retries next boot.
8
- export function reconcileProviderModelSeed(): void {
9
- try {
10
- reconcileClaudeCatalogSeeds();
11
- const stamp = `seed:${VERSION}`;
12
- if (getConfig<string>("system", "provider-model-seed-version")?.value === stamp) return;
13
- seedProviderModelOverrides(stamp);
14
- setConfig("system", "provider-model-seed-version", stamp, "server-startup");
15
- } catch (err) {
16
- console.warn(`[provider-model-seed] skipped: ${errMessage(err)}`);
17
- }
18
- }
1
+ export { reconcileProviderModelSeed, seedProviderModelOverrides } from "./db/provider-model-seed";
@@ -9,7 +9,8 @@
9
9
  // provider *spawn* config (provider-config-store.ts) by design — different scope,
10
10
  // different cardinality.
11
11
  import { ValidationError } from "./db";
12
- import { getConfig, listConfig, setConfig } from "./config-store";
12
+ import { getConfig, listConfig } from "./config-store";
13
+ import { setConfigAsync } from "./config-store-write";
13
14
  import { emitConfigChanged } from "./sse";
14
15
  import {
15
16
  DEFAULT_PROVIDER_QUOTA_CONFIG,
@@ -47,14 +48,14 @@ export function listProviderQuotaConfigs(): ProviderQuotaConfigMap {
47
48
  * clamped to 5m–15m, unset fields defaulted), so a partial body still validates.
48
49
  * Emits `config.changed` so the orchestrator + dashboard pick it up live.
49
50
  */
50
- export function setProviderQuotaConfig(
51
+ export async function setProviderQuotaConfigAsync(
51
52
  provider: string,
52
53
  value: unknown,
53
54
  opts: { updatedBy?: string } = {},
54
- ): ProviderQuotaConfig {
55
+ ): Promise<ProviderQuotaConfig> {
55
56
  const clean = assertValidProvider(provider);
56
57
  const normalized = normalizeProviderQuotaConfig(value);
57
- const entry = setConfig(PROVIDER_QUOTA_CONFIG_NAMESPACE, clean, normalized, opts.updatedBy);
58
+ const entry = await setConfigAsync(PROVIDER_QUOTA_CONFIG_NAMESPACE, clean, normalized, opts.updatedBy);
58
59
  emitConfigChanged(entry.namespace, entry.key, entry.version);
59
60
  return normalized;
60
61
  }
@@ -1,5 +1,5 @@
1
1
  import { getDb } from "./db";
2
- import { setProviderConfig } from "./provider-config-store";
2
+ import { setProviderConfigAsync } from "./provider-config-store";
3
3
 
4
4
  // #3402 — fake values under every key name the hub's central provider config holds, plus one no masking
5
5
  // list knows, so a test proves masking follows the configured values rather than key names.
@@ -25,9 +25,9 @@ export function leakedProviderSecrets(text: string): string[] {
25
25
  }
26
26
 
27
27
  /** Seeds the central provider config of `host` and returns its rows the way `sqlite3 ... select` prints them. */
28
- export function seedProviderSecrets(host: string): string {
28
+ export async function seedProviderSecrets(host: string): Promise<string> {
29
29
  for (const [provider, env] of Object.entries(PROVIDER_SECRET_ENV)) {
30
- setProviderConfig(provider, { command: provider, env: { ...env, OPENCODE_CONFIG: "/srv/opencode.json" } }, { host });
30
+ await setProviderConfigAsync(provider, { command: provider, env: { ...env, OPENCODE_CONFIG: "/srv/opencode.json" } }, { host });
31
31
  }
32
32
  return (getDb().query("SELECT namespace, key, value FROM config WHERE namespace = 'provider-config'").all() as Array<Record<string, string>>)
33
33
  .map((row) => `${row.namespace}|${row.key}|${row.value}`).join("\n");
@@ -15,7 +15,7 @@ import {
15
15
  validateRecipeArtifactRefsAsync,
16
16
  } from "./recipe-async";
17
17
  import type { AttachmentRef, Command, RecipeInstance } from "./types";
18
- import { SYSTEM_LAUNCH, runnerRuntimeTokenEnv } from "./runtime-tokens";
18
+ import { SYSTEM_LAUNCH, runnerRuntimeTokenEnvAsync } from "./runtime-tokens";
19
19
  import { generateSpawnAgentId } from "./services/spawn-identity";
20
20
 
21
21
  interface StartRecipeInput {
@@ -114,7 +114,7 @@ export async function startRecipe(input: StartRecipeInput): Promise<StartRecipeR
114
114
  env: {
115
115
  ...(agent.env ?? {}),
116
116
  ...(attachments.length ? writeChildEnv({}, { AGENT_RELAY_RECIPE_ARTIFACTS: JSON.stringify(attachments) }) : {}),
117
- ...runnerRuntimeTokenEnv({ authority: SYSTEM_LAUNCH,
117
+ ...await runnerRuntimeTokenEnvAsync({ authority: SYSTEM_LAUNCH,
118
118
  agentId,
119
119
  orchestratorId: orchestrator.id,
120
120
  cwd,
@@ -6,7 +6,8 @@
6
6
  import { dirname, resolve } from "node:path";
7
7
  import { isRecord, stringValue } from "@humwick/sdk";
8
8
  import { isTrustedOrchestratorApiUrl, relayAuthHeaders } from "./config";
9
- import { getConfig, setConfig } from "./config-store";
9
+ import { getConfig } from "./config-store";
10
+ import { setConfigAsync } from "./config-store-write";
10
11
  import { listOrchestrators, reportedRepoRootForCwd } from "./db";
11
12
  import { hostIsRelayHost } from "./relay-host-locality";
12
13
  import { normalizeHostToken, parseJson, sameHostIdentity } from "./utils";
@@ -70,11 +71,16 @@ export function hostRepoConfigSource<T>(spec: HostRepoConfigSpec<T>): HostRepoCo
70
71
  return null;
71
72
  }
72
73
 
73
- function writeCached(host: string, keys: readonly string[], found: RepoConfigSource<T> | null): void {
74
+ /** #1870 S7: writes on the writer thread, and only when the answer changed. `at` is evidence, not a
75
+ * TTL, so re-stamping an identical answer on every read only bumped the version and history. */
76
+ async function writeCached(host: string, keys: readonly string[], found: RepoConfigSource<T> | null): Promise<void> {
74
77
  const at = Date.now();
78
+ const answer = JSON.stringify(found);
75
79
  for (const key of keys) {
76
80
  try {
77
- setConfig<CachedRepoConfigSource<T>>(spec.cacheNamespace, cacheKey(host, key), { found, at }, spec.cacheNamespace);
81
+ const current = getConfig<CachedRepoConfigSource<T>>(spec.cacheNamespace, cacheKey(host, key))?.value;
82
+ if (current?.at && JSON.stringify(current.found) === answer) continue;
83
+ await setConfigAsync<CachedRepoConfigSource<T>>(spec.cacheNamespace, cacheKey(host, key), { found, at }, spec.cacheNamespace);
78
84
  } catch {
79
85
  // The cache is an optimization for the sync paths; failing to record it must never fail a caller.
80
86
  }
@@ -149,7 +155,7 @@ export function hostRepoConfigSource<T>(spec: HostRepoConfigSpec<T>): HostRepoCo
149
155
  if (hostIsRelayHost(host)) return { known: true, found: await spec.findLocalAsync(cwd) };
150
156
  const read = await readFromHost(cwd, host!);
151
157
  if (read.known) {
152
- writeCached(host!, cacheWriteKeys(cwd, read.found, opts.alsoCacheFor), read.found);
158
+ await writeCached(host!, cacheWriteKeys(cwd, read.found, opts.alsoCacheFor), read.found);
153
159
  return read;
154
160
  }
155
161
  return cachedLookup(host!, cwd);
@@ -1,12 +1,12 @@
1
1
  import { PromptVersionConflictError } from "../prompt-version-errors";
2
2
  import { versionedPromptsEnabled } from "../versioned-prompts";
3
3
  import { promptActor } from "../services/prompt-version-writer";
4
- import { setConfigAsync } from "../config-store-write";
4
+ import { deleteAgentProfileAsync, setAgentProfileAsync, setConfigAsync } from "../config-store-write";
5
5
  import { memoryRetirementMessage } from "../memory-retirement";
6
6
  // Auto-split from routes.ts (#299). Domain: agent-profiles.
7
7
  import { ValidationError, withResolvedProvisioningAsync } from "../db";
8
8
  import { cleanString, optionalEnum } from "../validation";
9
- import { deleteAgentProfile, getAgentProfile, listAgentProfiles, resolveAgentProfileKey, setAgentProfile, validateAgentProfile } from "../config-store";
9
+ import { getAgentProfile, listAgentProfiles, resolveAgentProfileKey, validateAgentProfile } from "../config-store";
10
10
  import { RELAY_TOOL_GROUPS } from "../mcp";
11
11
  import { emitConfigChanged } from "../sse";
12
12
  import { error, isAdminRequest, json, normalizeConfigPathParam, parseBody, type Handler } from "./_shared";
@@ -140,8 +140,8 @@ export const putAgentProfileRoute: Handler = async (req, params) => {
140
140
  return json(saved);
141
141
  }
142
142
  const profile = existing?.value.builtIn && isAdminRequest(req)
143
- ? setAgentProfile({ ...parsed.body, name } as AgentProfile, updatedBy, { overrideBuiltIn: true })
144
- : setAgentProfile({ ...parsed.body, name } as AgentProfile, updatedBy);
143
+ ? await setAgentProfileAsync({ ...parsed.body, name } as AgentProfile, updatedBy, { overrideBuiltIn: true })
144
+ : await setAgentProfileAsync({ ...parsed.body, name } as AgentProfile, updatedBy);
145
145
  emitConfigChanged(profile.namespace, profile.key, profile.version);
146
146
  return json(profile, existing ? 200 : profile.version === 1 ? 201 : 200);
147
147
  } catch (e) {
@@ -151,14 +151,14 @@ export const putAgentProfileRoute: Handler = async (req, params) => {
151
151
  }
152
152
  };
153
153
 
154
- export const deleteAgentProfileRoute: Handler = (req, params) => {
154
+ export const deleteAgentProfileRoute: Handler = async (req, params) => {
155
155
  try {
156
156
  const name = normalizeConfigPathParam(params.name, "name");
157
157
  const existing = getAgentProfile(name);
158
158
  if (!existing) return error(memoryRetirementMessage(name) ?? "agent profile not found", 404);
159
159
  const updatedBy = versionedPromptsEnabled() ? promptActor(req) : cleanString(new URL(req.url).searchParams.get("updatedBy") ?? undefined, "updatedBy", { max: 200 });
160
160
  if (existing.value.builtIn && !isAdminRequest(req)) return error("built-in agent profiles are managed by Relay", 400);
161
- deleteAgentProfile(name, updatedBy, { resetBuiltInOverride: existing.value.builtIn });
161
+ await deleteAgentProfileAsync(name, updatedBy, { resetBuiltInOverride: existing.value.builtIn });
162
162
  emitConfigChanged(existing.namespace, existing.key, existing.version + 1);
163
163
  return json({ ok: true });
164
164
  } catch (e) {
@@ -208,7 +208,7 @@ export const postAgentSpawn: Handler = async (req) => {
208
208
  // strip the heavy inlined provisioning file contents from the echoed-back summary.
209
209
  return json({
210
210
  ok: true, spawnRequestId: result.spawnRequestId, harnessSubagents: result.harnessSubagents, orchestratorId: result.orchestratorId, placementReason: result.placementReason, provider: result.provider, command: summarizeSpawnCommandForCaller(result.command),
211
- ...(result.task ? { task: result.task } : {}), ...(result.warnings ? { warnings: result.warnings } : {}), ...(result.dispatchDecision ? { dispatchDecision: result.dispatchDecision } : {}), ...(workflow.reason ? { workflow: { started: false, reason: workflow.reason } } : {}),
211
+ ...(result.task ? { task: result.task } : {}), ...(result.warnings ? { warnings: result.warnings } : {}), ...(result.spawnPolicy ? { spawnPolicy: result.spawnPolicy } : {}), ...(result.dispatchDecision ? { dispatchDecision: result.dispatchDecision } : {}), ...(workflow.reason ? { workflow: { started: false, reason: workflow.reason } } : {}),
212
212
  }, 202);
213
213
  } catch (e) {
214
214
  if (e instanceof McpAuthError) return error(e.message, 403);