@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
@@ -1,460 +0,0 @@
1
- import { z } from "zod";
2
- import type {
3
- ConfigLayer,
4
- EntityDecl,
5
- EventName,
6
- HostCommandDecl,
7
- ModuleManifest,
8
- OpDecl,
9
- RawRouteDecl,
10
- RetryPolicy,
11
- WorkflowDecl,
12
- } from "./contract";
13
- import { matchesGrant, matchesModuleId } from "./identity-grammar";
14
-
15
- export interface ManifestValidationIssue {
16
- path: string;
17
- message: string;
18
- }
19
-
20
- export class ManifestValidationError extends Error {
21
- constructor(readonly issues: readonly ManifestValidationIssue[]) {
22
- super(`invalid module manifest:\n${issues.map((issue) => `- ${issue.path}: ${issue.message}`).join("\n")}`);
23
- this.name = "ManifestValidationError";
24
- }
25
- }
26
-
27
- const RESERVED_ENTITY_FIELDS = new Set(["scope", "version", "created_at", "updated_at"]);
28
- const CONFIG_LAYERS = new Set<ConfigLayer>(["defaults", "instance", "host", "tenant", "user"]);
29
- /** The only keys an op's `expose` block may carry — one per transport (K6b HTTP/MCP/CLI). */
30
- const EXPOSE_TARGETS = new Set(["http", "mcp", "cli"]);
31
-
32
- class Validator {
33
- readonly issues: ManifestValidationIssue[] = [];
34
-
35
- issue(path: string, message: string): void {
36
- this.issues.push({ path, message });
37
- }
38
-
39
- nonEmptyString(value: unknown, path: string): value is string {
40
- if (typeof value !== "string" || value.trim().length === 0) {
41
- this.issue(path, "must be a non-empty string");
42
- return false;
43
- }
44
- return true;
45
- }
46
-
47
- positiveInteger(value: unknown, path: string): boolean {
48
- if (!Number.isSafeInteger(value) || (value as number) <= 0) {
49
- this.issue(path, "must be a positive integer");
50
- return false;
51
- }
52
- return true;
53
- }
54
-
55
- record(value: unknown, path: string): value is Record<string, unknown> {
56
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
57
- this.issue(path, "must be an object");
58
- return false;
59
- }
60
- return true;
61
- }
62
-
63
- fn(value: unknown, path: string): boolean {
64
- if (typeof value !== "function") {
65
- this.issue(path, "must be a function");
66
- return false;
67
- }
68
- return true;
69
- }
70
-
71
- schema(value: unknown, path: string): boolean {
72
- if (!(value instanceof z.ZodType)) {
73
- this.issue(path, "must be a Zod schema");
74
- return false;
75
- }
76
- return true;
77
- }
78
-
79
- objectSchema(value: unknown, path: string): value is z.ZodObject {
80
- if (!(value instanceof z.ZodObject)) {
81
- this.issue(path, "must be a Zod object schema");
82
- return false;
83
- }
84
- return true;
85
- }
86
-
87
- grant(value: unknown, path: string): void {
88
- if (!this.nonEmptyString(value, path)) return;
89
- if (!matchesGrant(value)) this.issue(path, "must use '<module>:read|write|admin' or 'command:<name>'");
90
- }
91
-
92
- finish(): void {
93
- if (this.issues.length > 0) throw new ManifestValidationError(this.issues);
94
- }
95
- }
96
-
97
- /** Runtime structural and cross-field validation for a module declaration. */
98
- export function assertValidManifest(value: unknown): asserts value is ModuleManifest {
99
- const v = new Validator();
100
- if (!v.record(value, "manifest")) return v.finish();
101
-
102
- const idValid = v.nonEmptyString(value.id, "id");
103
- if (idValid && !matchesModuleId(value.id)) {
104
- v.issue("id", value.id === "command" ? "is reserved" : "must be kebab-case");
105
- }
106
- v.nonEmptyString(value.title, "title");
107
- v.nonEmptyString(value.description, "description");
108
-
109
- if (value.config !== undefined) validateConfig(value.config, "config", v);
110
- if (value.entities !== undefined) validateRecordEntries(value.entities, "entities", v, validateEntity);
111
- if (value.events !== undefined) validateEvents(value.events, idValid ? value.id as string : "", v);
112
- if (value.ops !== undefined) validateRecordEntries(value.ops, "ops", v, validateOp);
113
- if (value.ops !== undefined) validateHttpRouteCollisions(value.ops, v);
114
- if (value.routes !== undefined) validateRoutes(value.routes, v);
115
- if (value.workflows !== undefined) validateRecordEntries(value.workflows, "workflows", v, validateWorkflow);
116
- if (value.commands !== undefined) validateRecordEntries(value.commands, "commands", v, validateCommand);
117
- if (value.health !== undefined) validateHealth(value.health, "health", v);
118
- if (value.secrets !== undefined) validateSecrets(value.secrets, v);
119
- if (value.ui !== undefined) validateUi(value.ui, "ui", v);
120
- if (value.agentContext !== undefined) validateAgentContext(value.agentContext, v);
121
- if (value.data !== undefined) validateMigrations(value.data, v);
122
-
123
- validateEmittedEvents(value, v);
124
- v.finish();
125
- }
126
-
127
- function validateRecordEntries<T>(
128
- value: unknown,
129
- path: string,
130
- v: Validator,
131
- validate: (entry: T, path: string, v: Validator) => void,
132
- ): void {
133
- if (!v.record(value, path)) return;
134
- for (const [name, entry] of Object.entries(value)) {
135
- if (!v.nonEmptyString(name, `${path} key`)) continue;
136
- validate(entry as T, `${path}.${name}`, v);
137
- }
138
- }
139
-
140
- function validateConfig(value: unknown, path: string, v: Validator): void {
141
- if (!v.record(value, path)) return;
142
- const schema = value.schema;
143
- const schemaValid = v.objectSchema(schema, `${path}.schema`);
144
- const keys = schemaValid ? new Set(Object.keys(schema.shape)) : new Set<string>();
145
-
146
- if (value.env !== undefined && v.record(value.env, `${path}.env`)) {
147
- for (const [key, envName] of Object.entries(value.env)) {
148
- if (schemaValid && !keys.has(key)) v.issue(`${path}.env.${key}`, "must name a config schema key");
149
- v.nonEmptyString(envName, `${path}.env.${key}`);
150
- }
151
- }
152
-
153
- if (value.overridableAt !== undefined && v.record(value.overridableAt, `${path}.overridableAt`)) {
154
- for (const [key, layers] of Object.entries(value.overridableAt)) {
155
- const layerPath = `${path}.overridableAt.${key}`;
156
- if (schemaValid && !keys.has(key)) v.issue(layerPath, "must name a config schema key");
157
- if (!Array.isArray(layers) || layers.length === 0) {
158
- v.issue(layerPath, "must be a non-empty array of config layers");
159
- continue;
160
- }
161
- for (const layer of layers) {
162
- if (!CONFIG_LAYERS.has(layer as ConfigLayer)) v.issue(layerPath, `contains unknown layer '${String(layer)}'`);
163
- }
164
- }
165
- }
166
- }
167
-
168
- function validateEntity(value: EntityDecl, path: string, v: Validator): void {
169
- if (!v.record(value, path)) return;
170
- const schemaValid = v.objectSchema(value.schema, `${path}.schema`);
171
- const fields = schemaValid ? new Set(Object.keys(value.schema.shape)) : new Set<string>();
172
- if (schemaValid) {
173
- for (const field of fields) {
174
- if (RESERVED_ENTITY_FIELDS.has(field)) v.issue(`${path}.schema.${field}`, "is kernel-owned and may not be declared");
175
- }
176
- }
177
-
178
- if (value.key !== undefined && (!v.nonEmptyString(value.key, `${path}.key`) || (schemaValid && !fields.has(value.key)))) {
179
- if (typeof value.key === "string" && value.key.length > 0) v.issue(`${path}.key`, "must name a schema field");
180
- }
181
- if (value.key === undefined && schemaValid && !fields.has("id")) v.issue(`${path}.schema`, "must contain the default 'id' key or declare key");
182
-
183
- if (value.indexes !== undefined) {
184
- if (!Array.isArray(value.indexes)) v.issue(`${path}.indexes`, "must be an array");
185
- else for (const [index, fieldsOrField] of value.indexes.entries()) {
186
- const indexFields = Array.isArray(fieldsOrField) ? fieldsOrField : [fieldsOrField];
187
- if (indexFields.length === 0) v.issue(`${path}.indexes.${index}`, "must not be empty");
188
- for (const field of indexFields) {
189
- if (typeof field !== "string" || (schemaValid && !fields.has(field))) {
190
- v.issue(`${path}.indexes.${index}`, `'${String(field)}' must name a schema field`);
191
- }
192
- }
193
- }
194
- }
195
-
196
- if (value.references !== undefined && v.record(value.references, `${path}.references`)) {
197
- for (const [field, reference] of Object.entries(value.references)) {
198
- if (schemaValid && !fields.has(field)) v.issue(`${path}.references.${field}`, "must name a schema field");
199
- if (!v.record(reference, `${path}.references.${field}`)) continue;
200
- v.nonEmptyString(reference.module, `${path}.references.${field}.module`);
201
- v.nonEmptyString(reference.entity, `${path}.references.${field}.entity`);
202
- }
203
- }
204
-
205
- if (value.retention !== undefined && v.record(value.retention, `${path}.retention`)) {
206
- if (value.retention.ttlDays !== undefined) v.positiveInteger(value.retention.ttlDays, `${path}.retention.ttlDays`);
207
- if (value.retention.ttlField !== undefined
208
- && (!v.nonEmptyString(value.retention.ttlField, `${path}.retention.ttlField`)
209
- || (schemaValid && !fields.has(value.retention.ttlField)))) {
210
- if (typeof value.retention.ttlField === "string" && value.retention.ttlField.length > 0) {
211
- v.issue(`${path}.retention.ttlField`, "must name a schema field");
212
- }
213
- }
214
- }
215
- }
216
-
217
- function validateEvents(value: unknown, moduleId: string, v: Validator): void {
218
- if (!v.record(value, "events")) return;
219
- for (const [name, schema] of Object.entries(value)) {
220
- if (!name.startsWith(`${moduleId}.`) || name.length === moduleId.length + 1) {
221
- v.issue(`events.${name}`, `must begin with '${moduleId}.' and include an event name`);
222
- }
223
- v.schema(schema, `events.${name}`);
224
- }
225
- }
226
-
227
- function validateOp(value: OpDecl, path: string, v: Validator): void {
228
- if (!v.record(value, path)) return;
229
- if (value.kind !== "query" && value.kind !== "mutation") v.issue(`${path}.kind`, "must be 'query' or 'mutation'");
230
- v.schema(value.input, `${path}.input`);
231
- v.schema(value.output, `${path}.output`);
232
- v.grant(value.grant, `${path}.grant`);
233
- if (value.advertiseScopes !== undefined) {
234
- if (!Array.isArray(value.advertiseScopes) || value.advertiseScopes.length === 0) {
235
- v.issue(`${path}.advertiseScopes`, "must be a non-empty array of grants when declared");
236
- } else {
237
- value.advertiseScopes.forEach((scope, index) => v.grant(scope, `${path}.advertiseScopes[${index}]`));
238
- }
239
- }
240
- if (value.expose !== undefined) validateExpose(value.expose, `${path}.expose`, v);
241
- v.nonEmptyString(value.summary, `${path}.summary`);
242
- v.fn(value.handler, `${path}.handler`);
243
- if (value.kind === "mutation" && typeof value.idempotent !== "boolean") {
244
- v.issue(`${path}.idempotent`, "must be declared for mutations");
245
- }
246
- if (value.emits !== undefined && (!Array.isArray(value.emits) || value.emits.some((name) => typeof name !== "string"))) {
247
- v.issue(`${path}.emits`, "must be an array of event names");
248
- }
249
- if (value.http !== undefined) {
250
- if (!v.record(value.http, `${path}.http`)) return;
251
- if (!["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"].includes(value.http.method)) {
252
- v.issue(`${path}.http.method`, "is not a supported HTTP method");
253
- }
254
- if (v.nonEmptyString(value.http.path, `${path}.http.path`) && !value.http.path.startsWith("/")) {
255
- v.issue(`${path}.http.path`, "must begin with '/'");
256
- }
257
- }
258
- }
259
-
260
- /**
261
- * Strictly validate an op's `expose` block. Each transport flag (`http`/`mcp`/`cli`) is OPTIONAL, but
262
- * when present MUST be a real boolean, and NO unknown key is tolerated. This is a fail-closed guard:
263
- * the transport-exclusion gates read `expose.mcp !== false` / `expose.http === false` (see
264
- * {@link import("./mcp-transport").isMcpExposed} / {@link import("./http-transport").deriveHttpRoutes}),
265
- * so a truthy-but-non-boolean flag (`expose: { mcp: "false" }`) or a typo'd key (`expose: { mpc: false }`)
266
- * would silently leave a "hidden" op — e.g. a `*System` reconciler twin — EXPOSED on that transport.
267
- * Rejecting the malformed manifest at `defineModule` time makes that class of mistake unrepresentable.
268
- */
269
- function validateExpose(value: unknown, path: string, v: Validator): void {
270
- if (!v.record(value, path)) return;
271
- for (const [key, flag] of Object.entries(value)) {
272
- if (!EXPOSE_TARGETS.has(key)) {
273
- v.issue(`${path}.${key}`, "is not a known expose target (must be one of 'http', 'mcp', 'cli')");
274
- continue;
275
- }
276
- if (typeof flag !== "boolean") v.issue(`${path}.${key}`, "must be a boolean");
277
- }
278
- }
279
-
280
- /**
281
- * A path param token — `{name}` (OpenAPI) or `:name` (Hono) — carries no routing significance
282
- * beyond "a param goes here": Hono matches `/timers/{id}` and `/timers/{timerId}` as the exact same
283
- * structural route, binding whichever param name each op declared. Collapsing every param token to
284
- * a constant placeholder before comparing routes makes the collision key match Hono's own notion of
285
- * "same route", while literal (non-param) segments are preserved exactly.
286
- */
287
- const PARAM_TOKEN_PATTERN = /\{[^}]+\}/g;
288
- const HONO_PARAM_TOKEN_PATTERN = /:[A-Za-z_][A-Za-z0-9_]*/g;
289
-
290
- /** Normalize an OpenAPI- or Hono-style path to its structural shape, so two paths that Hono would
291
- * route identically (differing only in path-param names) normalize to the same string. */
292
- export function normalizeRoutePath(path: string): string {
293
- return path.replace(PARAM_TOKEN_PATTERN, "{}").replace(HONO_PARAM_TOKEN_PATTERN, "{}");
294
- }
295
-
296
- /** The key two ops collide under: same method + same structural route. Shared with
297
- * {@link deriveHttpRoutes}'s defense-in-depth guard so both stay consistent — a manifest must never
298
- * pass validation here and then throw at derive, or vice versa. */
299
- export function httpRouteCollisionKey(method: string, path: string): string {
300
- return `${method} ${normalizeRoutePath(path)}`;
301
- }
302
-
303
- /**
304
- * Two ops declaring the same `http` method+structural-route silently collide once derived: the
305
- * Hono router keeps the first-registered handler while the OpenAPI doc keeps the last, so the
306
- * route serves one op while the doc advertises the other. Catch that authoring error here so every
307
- * consumer of the manifest (not just the HTTP transport) is protected.
308
- */
309
- function validateHttpRouteCollisions(value: unknown, v: Validator): void {
310
- if (typeof value !== "object" || value === null || Array.isArray(value)) return;
311
- const seenBy = new Map<string, string>();
312
- for (const [opName, rawOp] of Object.entries(value as Record<string, unknown>)) {
313
- if (typeof rawOp !== "object" || rawOp === null) continue;
314
- const http = (rawOp as { http?: unknown }).http;
315
- if (typeof http !== "object" || http === null) continue;
316
- const { method, path } = http as { method?: unknown; path?: unknown };
317
- if (typeof method !== "string" || typeof path !== "string") continue;
318
- const key = httpRouteCollisionKey(method, path);
319
- const collidesWith = seenBy.get(key);
320
- if (collidesWith !== undefined) {
321
- v.issue(`ops.${opName}.http`, `'${method} ${path}' collides with ops.${collidesWith}.http — two ops may not declare the same method+route (path params are matched by position, not name)`);
322
- } else {
323
- seenBy.set(key, opName);
324
- }
325
- }
326
- }
327
-
328
- function validateRoutes(value: unknown, v: Validator): void {
329
- if (!Array.isArray(value)) return v.issue("routes", "must be an array");
330
- for (const [index, route] of value.entries()) validateRoute(route as RawRouteDecl, `routes.${index}`, v);
331
- }
332
-
333
- function validateRoute(value: RawRouteDecl, path: string, v: Validator): void {
334
- if (!v.record(value, path)) return;
335
- v.nonEmptyString(value.path, `${path}.path`);
336
- v.grant(value.grant, `${path}.grant`);
337
- if ("streaming" in value) {
338
- if (value.streaming === "sse") v.fn(value.subscribe, `${path}.subscribe`);
339
- else if (value.streaming === "websocket") v.fn(value.accept, `${path}.accept`);
340
- else v.issue(`${path}.streaming`, "must be 'sse' or 'websocket'");
341
- } else {
342
- if (v.nonEmptyString(value.method, `${path}.method`)
343
- && !["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "HEAD"].includes(value.method)) {
344
- v.issue(`${path}.method`, "is not a supported HTTP method");
345
- }
346
- v.fn(value.handler, `${path}.handler`);
347
- }
348
- }
349
-
350
- function validateWorkflow(value: WorkflowDecl, path: string, v: Validator): void {
351
- if (!v.record(value, path)) return;
352
- v.schema(value.input, `${path}.input`);
353
- v.schema(value.state, `${path}.state`);
354
- v.fn(value.init, `${path}.init`);
355
- const startValid = v.nonEmptyString(value.start, `${path}.start`);
356
- if (!v.record(value.steps, `${path}.steps`)) return;
357
- if (Object.keys(value.steps).length === 0) v.issue(`${path}.steps`, "must declare at least one step");
358
- if (startValid && !(value.start in value.steps)) v.issue(`${path}.start`, "must name a declared step");
359
- for (const [name, step] of Object.entries(value.steps)) {
360
- const stepPath = `${path}.steps.${name}`;
361
- if (!v.record(step, stepPath)) continue;
362
- v.fn(step.run, `${stepPath}.run`);
363
- if (step.timeoutMs !== undefined) v.positiveInteger(step.timeoutMs, `${stepPath}.timeoutMs`);
364
- if (step.retry !== undefined) validateRetry(step.retry, `${stepPath}.retry`, v);
365
- }
366
- }
367
-
368
- function validateCommand(value: HostCommandDecl, path: string, v: Validator): void {
369
- if (!v.record(value, path)) return;
370
- v.schema(value.input, `${path}.input`);
371
- v.schema(value.result, `${path}.result`);
372
- if (value.target !== "host-agent" && value.target !== "runner") v.issue(`${path}.target`, "must be 'host-agent' or 'runner'");
373
- v.grant(value.grant, `${path}.grant`);
374
- v.fn(value.idempotencyKey, `${path}.idempotencyKey`);
375
- v.positiveInteger(value.timeoutMs, `${path}.timeoutMs`);
376
- if (value.retry !== undefined) validateRetry(value.retry, `${path}.retry`, v);
377
- if (value.whenDegraded !== undefined && value.whenDegraded !== "queue" && value.whenDegraded !== "reject") {
378
- v.issue(`${path}.whenDegraded`, "must be 'queue' or 'reject'");
379
- }
380
- }
381
-
382
- function validateRetry(value: RetryPolicy, path: string, v: Validator): void {
383
- if (!v.record(value, path)) return;
384
- v.positiveInteger(value.maxAttempts, `${path}.maxAttempts`);
385
- if (!v.record(value.backoff, `${path}.backoff`)) return;
386
- if (value.backoff.kind === "fixed") v.positiveInteger(value.backoff.delayMs, `${path}.backoff.delayMs`);
387
- else if (value.backoff.kind === "exponential") {
388
- v.positiveInteger(value.backoff.initialMs, `${path}.backoff.initialMs`);
389
- v.positiveInteger(value.backoff.maxMs, `${path}.backoff.maxMs`);
390
- } else v.issue(`${path}.backoff.kind`, "must be 'fixed' or 'exponential'");
391
- }
392
-
393
- function validateHealth(value: unknown, path: string, v: Validator): void {
394
- if (!v.record(value, path)) return;
395
- if (!v.record(value.probes, `${path}.probes`)) return;
396
- for (const [name, probe] of Object.entries(value.probes)) {
397
- const probePath = `${path}.probes.${name}`;
398
- if (!v.record(probe, probePath)) continue;
399
- if (probe.intervalMs !== undefined) v.positiveInteger(probe.intervalMs, `${probePath}.intervalMs`);
400
- if (probe.check !== undefined) v.fn(probe.check, `${probePath}.check`);
401
- if (!Array.isArray(probe.degrades) || probe.degrades.length === 0) v.issue(`${probePath}.degrades`, "must name at least one capability");
402
- else for (const capability of probe.degrades) v.nonEmptyString(capability, `${probePath}.degrades`);
403
- if (probe.intervalMs === undefined && probe.check !== undefined) v.issue(probePath, "a pull check must declare intervalMs");
404
- if (probe.intervalMs !== undefined && probe.check === undefined) v.issue(probePath, "intervalMs requires a check callback");
405
- }
406
- }
407
-
408
- function validateSecrets(value: unknown, v: Validator): void {
409
- if (!Array.isArray(value)) return v.issue("secrets", "must be an array");
410
- const seen = new Set<string>();
411
- for (const [index, secret] of value.entries()) {
412
- if (!v.nonEmptyString(secret, `secrets.${index}`)) continue;
413
- if (seen.has(secret)) v.issue(`secrets.${index}`, `duplicates '${secret}'`);
414
- seen.add(secret);
415
- }
416
- }
417
-
418
- function validateUi(value: unknown, path: string, v: Validator): void {
419
- if (!v.record(value, path)) return;
420
- if (value.nav !== undefined && v.record(value.nav, `${path}.nav`)) {
421
- v.nonEmptyString(value.nav.section, `${path}.nav.section`);
422
- v.nonEmptyString(value.nav.icon, `${path}.nav.icon`);
423
- }
424
- if (value.surfaces !== undefined && !Array.isArray(value.surfaces)) v.issue(`${path}.surfaces`, "must be an array");
425
- if (value.custom !== undefined) v.fn(value.custom, `${path}.custom`);
426
- }
427
-
428
- function validateAgentContext(value: unknown, v: Validator): void {
429
- if (!v.record(value, "agentContext")) return;
430
- v.nonEmptyString(value.summary, "agentContext.summary");
431
- if (value.examples !== undefined && !Array.isArray(value.examples)) v.issue("agentContext.examples", "must be an array");
432
- if (value.caveats !== undefined && !Array.isArray(value.caveats)) v.issue("agentContext.caveats", "must be an array");
433
- }
434
-
435
- function validateMigrations(value: unknown, v: Validator): void {
436
- if (!Array.isArray(value)) return v.issue("data", "must be an array");
437
- const ids = new Set<string>();
438
- for (const [index, migration] of value.entries()) {
439
- const path = `data.${index}`;
440
- if (!v.record(migration, path)) continue;
441
- if (v.nonEmptyString(migration.id, `${path}.id`)) {
442
- if (ids.has(migration.id)) v.issue(`${path}.id`, `duplicates '${migration.id}'`);
443
- ids.add(migration.id);
444
- }
445
- v.fn(migration.run, `${path}.run`);
446
- }
447
- }
448
-
449
- function validateEmittedEvents(value: Record<string, unknown>, v: Validator): void {
450
- const ops = value.ops ?? {};
451
- const events = value.events ?? {};
452
- if (!v.record(ops, "ops") || !v.record(events, "events")) return;
453
- const declared = new Set(Object.keys(events));
454
- for (const [opName, rawOp] of Object.entries(ops)) {
455
- if (!v.record(rawOp, `ops.${opName}`) || !Array.isArray(rawOp.emits)) continue;
456
- for (const event of rawOp.emits as EventName[]) {
457
- if (!declared.has(event)) v.issue(`ops.${opName}.emits`, `'${event}' is not declared in events`);
458
- }
459
- }
460
- }
@@ -1,109 +0,0 @@
1
- import { z } from "zod";
2
- import type { Grant, ModuleDefinition, OpDecl } from "./contract";
3
-
4
- /**
5
- * K1-6 — the MCP tool surface, *derived* from a `defineModule` manifest (the sibling of
6
- * {@link import("./http-transport").deriveHttpRoutes}).
7
- *
8
- * There is no hand-written per-op tool table. {@link deriveMcpTools} reads each op's manifest and
9
- * produces one {@link DerivedMcpTool} per op that is MCP-exposed; a live MCP dispatcher spreads the
10
- * result into its tool list and routes each tool through {@link import("./module-host").ModuleHost.invoke},
11
- * which owns authorization (default-deny), I/O validation, and the atomic commit. The derivation
12
- * itself makes NO authorization decision — it decides only what is VISIBLE / advertised.
13
- *
14
- * ── The `*System`-twin structural exclusion (K-C2 / O1) ─────────────────────────────────────────────
15
- * A non-exposed op is excluded here **structurally**, by reading its `expose.mcp` flag — NOT by
16
- * re-filtering a hand-maintained name list that could drift from the manifest. Any op declaring
17
- * `expose.mcp === false` (the `*System` reconciler twins) is absent from the derived set, so no MCP
18
- * tool is ever authored for it and there is no transport path to invoke it. This is the ONLY place the
19
- * exclusion lives: the invoker deliberately does NOT gate on `expose` (a reconciler still reaches the
20
- * twins through a direct `host.invoke`), so removing them from every transport derivation is what makes
21
- * them unreachable over MCP/HTTP/CLI while leaving the internal seam intact.
22
- */
23
-
24
- /** One MCP tool derived from an op — everything a dispatcher needs to advertise it in `tools/list`
25
- * and route a call, and nothing more. The tool name and I/O schema come straight from the manifest;
26
- * `requiredScopes` is the ADVERTISED requirement (see below), and `grant` is what the invoker
27
- * actually gates on (the two differ only for an op that is stricter in-handler than its entry grant). */
28
- export interface DerivedMcpTool {
29
- readonly opName: string;
30
- readonly op: OpDecl;
31
- /** The MCP tool name a dispatcher registers (default `<prefix>_<opName>`, prefix = the module id). */
32
- readonly name: string;
33
- /** The tool description shown in `tools/list` — the op's `summary`. */
34
- readonly description: string;
35
- /** The op's raw input schema; a dispatcher converts it to the JSON Schema `tools/list` expects. */
36
- readonly input: z.ZodType;
37
- /** The grant the INVOKER gates on (`ModuleHost.invoke`'s default-deny check). */
38
- readonly grant: Grant;
39
- /** The scopes ADVERTISED as this tool's requirement (`tools/list.requiredScopes`). Equals the op's
40
- * `advertiseScopes` when declared, else `[grant]`. Advertising the op's true requirement (rather
41
- * than a bare entry `grant` an admin-only handler would still 403) keeps the surface honest (O3);
42
- * it is defense-in-depth over the invoker's default-deny, never the sole gate. */
43
- readonly requiredScopes: readonly Grant[];
44
- readonly kind: "query" | "mutation";
45
- }
46
-
47
- /** Whether an op is exposed over MCP. Default-expose (mirrors the HTTP surface): an op is MCP-exposed
48
- * unless it explicitly opts out with `expose.mcp === false`. This is the single discriminator the
49
- * `*System`-twin exclusion (O1) turns on — assert against THIS, not a hand-kept name list. */
50
- export function isMcpExposed(op: OpDecl): boolean {
51
- return op.expose?.mcp !== false;
52
- }
53
-
54
- /** The advertised requiredScopes for an op: its explicit `advertiseScopes`, else `[grant]` (O3). */
55
- export function advertisedScopesOf(op: OpDecl): readonly Grant[] {
56
- return op.advertiseScopes ?? [op.grant];
57
- }
58
-
59
- /**
60
- * Project a derived tool's Zod input to the JSON Schema an MCP `tools/list` advertises. Lives in the
61
- * kernel (which owns the `zod` dependency) so a src-side MCP dispatcher can consume a plain
62
- * `Record<string, unknown>` without taking a direct `zod` dependency — the sibling of the way
63
- * `deriveHttpRoutes`/`createHttpApp` keep the OpenAPI generation kernel-internal. Purely a projection:
64
- * it makes no authorization decision and reads only the op's declared input shape.
65
- */
66
- export function toMcpInputJsonSchema(tool: DerivedMcpTool): Record<string, unknown> {
67
- return z.toJSONSchema(tool.input) as Record<string, unknown>;
68
- }
69
-
70
- export interface McpDerivationOptions {
71
- /** Overrides the tool-name derivation. Receives the op name; defaults to `<prefix>_<opName>`. */
72
- readonly toolName?: (opName: string) => string;
73
- /** The prefix the default tool-name derivation uses. Defaults to the module id. */
74
- readonly prefix?: string;
75
- }
76
-
77
- /**
78
- * Derive the MCP tool list from a manifest: one {@link DerivedMcpTool} per op that is MCP-exposed
79
- * ({@link isMcpExposed}). Ops declaring `expose.mcp === false` (the `*System` twins) are excluded
80
- * structurally, so the derived set can never author a tool for a non-exposed op (O1 / K-C2). Guards
81
- * against two ops deriving the same tool name so a collision can never silently shadow a tool.
82
- */
83
- export function deriveMcpTools(module: ModuleDefinition, options: McpDerivationOptions = {}): DerivedMcpTool[] {
84
- const prefix = options.prefix ?? module.id;
85
- const nameOf = options.toolName ?? ((opName: string) => `${prefix}_${opName}`);
86
- const tools: DerivedMcpTool[] = [];
87
- const seen = new Map<string, string>();
88
- for (const [opName, op] of Object.entries(module.ops ?? {})) {
89
- // O1: a non-exposed op is unreachable over MCP because no tool is authored for it.
90
- if (!isMcpExposed(op)) continue;
91
- const name = nameOf(opName);
92
- const collidesWith = seen.get(name);
93
- if (collidesWith !== undefined) {
94
- throw new Error(`duplicate MCP tool name '${name}': derived from both '${collidesWith}' and '${opName}'`);
95
- }
96
- seen.set(name, opName);
97
- tools.push({
98
- opName,
99
- op,
100
- name,
101
- description: op.summary,
102
- input: op.input as z.ZodType,
103
- grant: op.grant,
104
- requiredScopes: advertisedScopesOf(op),
105
- kind: op.kind,
106
- });
107
- }
108
- return tools;
109
- }