@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,493 +0,0 @@
1
- import { lookup as lookupHost } from "node:dns/promises";
2
- import { request as httpRequest } from "node:http";
3
- import { request as httpsRequest } from "node:https";
4
- import { Readable } from "node:stream";
5
- import type { Clock, Disposable, Logger, Rng, Transport } from "./contract";
6
-
7
- function assertDelay(value: number, name: string, allowZero: boolean): void {
8
- if (!Number.isFinite(value) || value < 0 || (!allowZero && value === 0)) {
9
- const qualifier = allowZero ? "a non-negative" : "a positive";
10
- throw new RangeError(`${name} must be ${qualifier} finite number`);
11
- }
12
- }
13
-
14
- /** A logger that discards every record. Useful as the default ModuleCtx.log in tests. */
15
- export function createSilentLogger(): Logger {
16
- const noop = (): void => {};
17
- return { debug: noop, info: noop, warn: noop, error: noop };
18
- }
19
-
20
- /** A logger that forwards to the host console, tagging each record with its level. */
21
- export function createConsoleLogger(): Logger {
22
- const write = (level: "debug" | "info" | "warn" | "error") =>
23
- (message: string, fields?: Readonly<Record<string, unknown>>): void => {
24
- if (fields) console[level](message, fields);
25
- else console[level](message);
26
- };
27
- return { debug: write("debug"), info: write("info"), warn: write("warn"), error: write("error") };
28
- }
29
-
30
- /** Production wall-clock provider. Ambient time and timers stop at this kernel boundary. */
31
- export function createRealClock(): Clock {
32
- return {
33
- now: () => Date.now(),
34
- sleep(ms) {
35
- assertDelay(ms, "sleep delay", true);
36
- return new Promise((resolve) => setTimeout(resolve, ms));
37
- },
38
- every(ms, fn) {
39
- assertDelay(ms, "interval", false);
40
- const timer = setInterval(fn, ms);
41
- let disposed = false;
42
- return {
43
- dispose() {
44
- if (disposed) return;
45
- disposed = true;
46
- clearInterval(timer);
47
- },
48
- };
49
- },
50
- };
51
- }
52
-
53
- interface ScheduledAction {
54
- readonly id: number;
55
- due: number;
56
- readonly interval?: number;
57
- readonly run: () => void;
58
- }
59
-
60
- export interface ControllableClock extends Clock {
61
- /** Advance virtual time, firing due actions in stable registration order. */
62
- advanceBy(ms: number): void;
63
- /** Advance to an absolute virtual timestamp. Time cannot move backwards. */
64
- advanceTo(timestamp: number): void;
65
- }
66
-
67
- /**
68
- * A clock for deterministic tests and replay. It never consults or waits for wall time.
69
- * Scheduled work only runs when the caller advances the clock.
70
- */
71
- export function createControllableClock(initialNow = 0): ControllableClock {
72
- if (!Number.isFinite(initialNow)) throw new RangeError("initial time must be a finite number");
73
-
74
- let now = initialNow;
75
- let nextId = 1;
76
- const scheduled = new Map<number, ScheduledAction>();
77
-
78
- function schedule(delay: number, run: () => void, interval?: number): Disposable {
79
- const action: ScheduledAction = { id: nextId++, due: now + delay, interval, run };
80
- scheduled.set(action.id, action);
81
- return { dispose: () => scheduled.delete(action.id) };
82
- }
83
-
84
- function nextDueAtOrBefore(timestamp: number): ScheduledAction | undefined {
85
- let next: ScheduledAction | undefined;
86
- for (const action of scheduled.values()) {
87
- if (action.due > timestamp) continue;
88
- if (!next || action.due < next.due || (action.due === next.due && action.id < next.id)) next = action;
89
- }
90
- return next;
91
- }
92
-
93
- const clock: ControllableClock = {
94
- now: () => now,
95
- sleep(ms) {
96
- assertDelay(ms, "sleep delay", true);
97
- return new Promise((resolve) => {
98
- schedule(ms, resolve);
99
- });
100
- },
101
- every(ms, fn) {
102
- assertDelay(ms, "interval", false);
103
- return schedule(ms, fn, ms);
104
- },
105
- advanceBy(ms) {
106
- assertDelay(ms, "advance", true);
107
- clock.advanceTo(now + ms);
108
- },
109
- advanceTo(timestamp) {
110
- if (!Number.isFinite(timestamp)) throw new RangeError("target time must be a finite number");
111
- if (timestamp < now) throw new RangeError("controllable clock cannot move backwards");
112
-
113
- let action = nextDueAtOrBefore(timestamp);
114
- while (action) {
115
- now = action.due;
116
- if (action.interval === undefined) {
117
- scheduled.delete(action.id);
118
- } else {
119
- // Reschedule first so dispose() from inside the callback cancels the next firing.
120
- action.due += action.interval;
121
- }
122
- action.run();
123
- action = nextDueAtOrBefore(timestamp);
124
- }
125
- now = timestamp;
126
- },
127
- };
128
-
129
- return clock;
130
- }
131
-
132
- function assertJitterArgs(baseMs: number, spread: number): void {
133
- assertDelay(baseMs, "jitter base", true);
134
- assertDelay(spread, "jitter spread", true);
135
- }
136
-
137
- function jitter(random: () => number, baseMs: number, spread: number): number {
138
- assertJitterArgs(baseMs, spread);
139
- // spread is a ratio: 0.2 produces a value within baseMs +/- 20%.
140
- const factor = 1 + (random() * 2 - 1) * spread;
141
- return Math.max(0, Math.round(baseMs * factor));
142
- }
143
-
144
- /** Production cryptographic RNG provider. It never delegates to Math.random(). */
145
- export function createSystemRng(): Rng {
146
- const random = (): number => {
147
- const value = new Uint32Array(1);
148
- crypto.getRandomValues(value);
149
- return value[0]! / 0x1_0000_0000;
150
- };
151
-
152
- return {
153
- uuid: () => crypto.randomUUID(),
154
- random,
155
- jitter: (baseMs, spread) => jitter(random, baseMs, spread),
156
- };
157
- }
158
-
159
- function hashSeed(seed: string): number {
160
- // FNV-1a provides a small, stable conversion from string seeds to 32-bit state.
161
- let hash = 0x811c9dc5;
162
- for (let i = 0; i < seed.length; i++) {
163
- hash ^= seed.charCodeAt(i);
164
- hash = Math.imul(hash, 0x01000193);
165
- }
166
- return hash >>> 0;
167
- }
168
-
169
- /** Stable seeded RNG (Mulberry32) for deterministic tests and workflow replay. */
170
- export function createSeededRng(seed: number | string): Rng {
171
- if (typeof seed === "number" && !Number.isFinite(seed)) throw new RangeError("RNG seed must be finite");
172
- let state = typeof seed === "string" ? hashSeed(seed) : Math.trunc(seed) >>> 0;
173
-
174
- const nextUint32 = (): number => {
175
- state = (state + 0x6d2b79f5) >>> 0;
176
- let value = state;
177
- value = Math.imul(value ^ (value >>> 15), value | 1);
178
- value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
179
- return (value ^ (value >>> 14)) >>> 0;
180
- };
181
- const random = (): number => nextUint32() / 0x1_0000_0000;
182
-
183
- const uuid = (): string => {
184
- const bytes = new Uint8Array(16);
185
- for (let offset = 0; offset < bytes.length; offset += 4) {
186
- const value = nextUint32();
187
- bytes[offset] = value >>> 24;
188
- bytes[offset + 1] = value >>> 16;
189
- bytes[offset + 2] = value >>> 8;
190
- bytes[offset + 3] = value;
191
- }
192
- bytes[6] = (bytes[6]! & 0x0f) | 0x40;
193
- bytes[8] = (bytes[8]! & 0x3f) | 0x80;
194
- const hex = [...bytes].map((byte) => byte.toString(16).padStart(2, "0")).join("");
195
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
196
- };
197
-
198
- return {
199
- uuid,
200
- random,
201
- jitter: (baseMs, spread) => jitter(random, baseMs, spread),
202
- };
203
- }
204
-
205
- /**
206
- * Baseline protection for destinations modules should never need to reach directly.
207
- * Caller-provided rules extend this list by default.
208
- */
209
- export const DEFAULT_NET_DENY_LIST = Object.freeze([
210
- "localhost",
211
- "metadata.google.internal",
212
- "metadata.google",
213
- "0.0.0.0/8",
214
- "10.0.0.0/8",
215
- "100.64.0.0/10",
216
- "127.0.0.0/8",
217
- "169.254.0.0/16",
218
- "172.16.0.0/12",
219
- "192.0.0.0/24",
220
- "192.168.0.0/16",
221
- "198.18.0.0/15",
222
- "224.0.0.0/4",
223
- "240.0.0.0/4",
224
- "::/128",
225
- "::1/128",
226
- "::/96",
227
- "::ffff:0:0/96",
228
- "64:ff9b::/96",
229
- "64:ff9b:1::/48",
230
- "2001:db8::/32",
231
- "fc00::/7",
232
- "fe80::/10",
233
- "ff00::/8",
234
- ] as const);
235
-
236
- export interface NetResolvedAddress {
237
- readonly address: string;
238
- readonly family: 4 | 6;
239
- }
240
-
241
- export interface NetConnectionPin extends NetResolvedAddress {
242
- readonly hostname: string;
243
- }
244
-
245
- type ResolverCapability = (hostname: string) => Promise<readonly NetResolvedAddress[]>;
246
- type FetchCapability = (url: string, init: RequestInit | undefined, pin: NetConnectionPin) => Promise<Response>;
247
-
248
- export interface NetTransportOptions {
249
- /** Hostname or IPv4/IPv6 CIDR rules. Hostname rules include all subdomains. */
250
- denyList?: readonly string[];
251
- /** Defaults stay active unless this explicit escape hatch is disabled. */
252
- includeDefaultDenyList?: boolean;
253
- /** Trusted injected host capability; production uses a socket pinned to the vetted address. */
254
- fetch?: FetchCapability;
255
- /** Injected hostname resolver; production defaults to the operating-system resolver. */
256
- resolve?: ResolverCapability;
257
- }
258
-
259
- type ParsedRule =
260
- | { readonly source: string; readonly kind: "hostname"; readonly hostname: string }
261
- | { readonly source: string; readonly kind: "cidr"; readonly bits: 32 | 128; readonly network: bigint; readonly prefix: number };
262
-
263
- function parseIpv4(value: string): bigint | undefined {
264
- const parts = value.split(".");
265
- if (parts.length !== 4) return undefined;
266
- let result = 0n;
267
- for (const part of parts) {
268
- if (!/^\d+$/.test(part)) return undefined;
269
- if (part.length > 1 && part.startsWith("0")) return undefined;
270
- const octet = Number(part);
271
- if (octet > 255) return undefined;
272
- result = (result << 8n) | BigInt(octet);
273
- }
274
- return result;
275
- }
276
-
277
- function parseIpv6(value: string): bigint | undefined {
278
- let address = value.toLowerCase();
279
- if (address.startsWith("[") && address.endsWith("]")) address = address.slice(1, -1);
280
- if (address.includes("%")) return undefined;
281
-
282
- const doubleColon = address.indexOf("::");
283
- if (doubleColon !== -1 && doubleColon !== address.lastIndexOf("::")) return undefined;
284
- const left = (doubleColon === -1 ? address : address.slice(0, doubleColon)).split(":").filter(Boolean);
285
- const right = (doubleColon === -1 ? "" : address.slice(doubleColon + 2)).split(":").filter(Boolean);
286
-
287
- function expandIpv4Tail(parts: string[]): boolean {
288
- const tail = parts.at(-1);
289
- if (!tail?.includes(".")) return true;
290
- const ipv4 = parseIpv4(tail);
291
- if (ipv4 === undefined) return false;
292
- parts.splice(parts.length - 1, 1, ((ipv4 >> 16n) & 0xffffn).toString(16), (ipv4 & 0xffffn).toString(16));
293
- return true;
294
- }
295
-
296
- if (!expandIpv4Tail(left) || !expandIpv4Tail(right)) return undefined;
297
- const missing = 8 - left.length - right.length;
298
- if ((doubleColon === -1 && missing !== 0) || (doubleColon !== -1 && missing < 1)) return undefined;
299
- const groups = [...left, ...Array.from({ length: missing }, () => "0"), ...right];
300
- if (groups.length !== 8) return undefined;
301
-
302
- let result = 0n;
303
- for (const group of groups) {
304
- if (!/^[0-9a-f]{1,4}$/.test(group)) return undefined;
305
- result = (result << 16n) | BigInt(`0x${group}`);
306
- }
307
- return result;
308
- }
309
-
310
- function mask(bits: 32 | 128, prefix: number): bigint {
311
- if (prefix === 0) return 0n;
312
- return ((1n << BigInt(prefix)) - 1n) << BigInt(bits - prefix);
313
- }
314
-
315
- function parseRule(source: string): ParsedRule {
316
- const value = source.trim();
317
- if (!value) throw new TypeError("net deny-list rules must not be empty");
318
-
319
- const slash = value.lastIndexOf("/");
320
- if (slash !== -1) {
321
- const address = value.slice(0, slash);
322
- const parsedPrefix = Number(value.slice(slash + 1));
323
- const ipv4 = parseIpv4(address);
324
- const ipv6 = ipv4 === undefined ? parseIpv6(address) : undefined;
325
- const bits = ipv4 !== undefined ? 32 : ipv6 !== undefined ? 128 : undefined;
326
- if (!bits || !Number.isInteger(parsedPrefix) || parsedPrefix < 0 || parsedPrefix > bits) {
327
- throw new TypeError(`invalid net deny-list CIDR rule '${source}'`);
328
- }
329
- const addressValue = ipv4 ?? ipv6!;
330
- const prefixMask = mask(bits, parsedPrefix);
331
- return { source, kind: "cidr", bits, network: addressValue & prefixMask, prefix: parsedPrefix };
332
- }
333
-
334
- let hostname = value.startsWith(".") ? value.slice(1) : value;
335
- try {
336
- hostname = new URL(`http://${hostname}/`).hostname;
337
- } catch {
338
- throw new TypeError(`invalid net deny-list hostname rule '${source}'`);
339
- }
340
- hostname = hostname.toLowerCase().replace(/\.+$/, "");
341
- if (!hostname) throw new TypeError(`invalid net deny-list hostname rule '${source}'`);
342
- return { source, kind: "hostname", hostname };
343
- }
344
-
345
- function normalizeHostname(hostname: string): string {
346
- return hostname.toLowerCase().replace(/\.+$/, "");
347
- }
348
-
349
- function matchingRule(hostname: string, rules: readonly ParsedRule[]): ParsedRule | undefined {
350
- const normalized = normalizeHostname(hostname);
351
- const unbracketed = normalized.startsWith("[") && normalized.endsWith("]") ? normalized.slice(1, -1) : normalized;
352
- const ipv4 = parseIpv4(unbracketed);
353
- const ipv6 = ipv4 === undefined ? parseIpv6(unbracketed) : undefined;
354
-
355
- return rules.find((rule) => {
356
- if (rule.kind === "hostname") return normalized === rule.hostname || normalized.endsWith(`.${rule.hostname}`);
357
- const address = rule.bits === 32 ? ipv4 : ipv6;
358
- return address !== undefined && (address & mask(rule.bits, rule.prefix)) === rule.network;
359
- });
360
- }
361
-
362
- export class NetEgressDeniedError extends Error {
363
- constructor(
364
- readonly hostname: string,
365
- readonly rule: string,
366
- ) {
367
- super(`outbound HTTP to host '${hostname}' was refused by net deny-list rule '${rule}'`);
368
- this.name = "NetEgressDeniedError";
369
- }
370
- }
371
-
372
- export class NetRedirectRefusedError extends Error {
373
- constructor(readonly hostname: string) {
374
- super(`outbound HTTP redirect from host '${hostname}' was refused; follow it explicitly through ctx.net`);
375
- this.name = "NetRedirectRefusedError";
376
- }
377
- }
378
-
379
- export class NetEgressResolutionError extends Error {
380
- constructor(readonly hostname: string, options?: ErrorOptions) {
381
- super(`outbound HTTP to host '${hostname}' was refused because its address could not be resolved safely`, options);
382
- this.name = "NetEgressResolutionError";
383
- }
384
- }
385
-
386
- const REDIRECT_STATUSES = new Set([301, 302, 303, 307, 308]);
387
-
388
- async function defaultResolver(hostname: string): Promise<readonly NetResolvedAddress[]> {
389
- const addresses = await lookupHost(hostname, { all: true, verbatim: true });
390
- return addresses.map(({ address, family }) => {
391
- if (family !== 4 && family !== 6) throw new TypeError(`resolver returned an unsupported address family`);
392
- return { address, family };
393
- });
394
- }
395
-
396
- async function pinnedFetch(url: string, init: RequestInit | undefined, pin: NetConnectionPin): Promise<Response> {
397
- const request = new Request(url, init);
398
- const body = request.body ? Buffer.from(await request.arrayBuffer()) : undefined;
399
- const requestCapability = request.url.startsWith("https:") ? httpsRequest : httpRequest;
400
- const requestHeaders: Record<string, string> = {};
401
- request.headers.forEach((value, name) => {
402
- requestHeaders[name] = value;
403
- });
404
-
405
- return await new Promise<Response>((resolve, reject) => {
406
- const outgoing = requestCapability(request.url, {
407
- method: request.method,
408
- headers: requestHeaders,
409
- family: pin.family,
410
- signal: request.signal,
411
- // Supplying the exact vetted address here is the security boundary: the socket
412
- // cannot perform a second DNS lookup and therefore cannot be DNS-rebound.
413
- lookup: (_hostname, options, callback) => {
414
- if (options.all) callback(null, [{ address: pin.address, family: pin.family }]);
415
- else callback(null, pin.address, pin.family);
416
- },
417
- }, (incoming) => {
418
- const headers = new Headers();
419
- for (let index = 0; index < incoming.rawHeaders.length; index += 2) {
420
- headers.append(incoming.rawHeaders[index]!, incoming.rawHeaders[index + 1]!);
421
- }
422
- resolve(new Response(Readable.toWeb(incoming) as unknown as ReadableStream, {
423
- status: incoming.statusCode,
424
- statusText: incoming.statusMessage,
425
- headers,
426
- }));
427
- });
428
- outgoing.on("error", reject);
429
- outgoing.end(body);
430
- });
431
- }
432
-
433
- /** Create the outbound HTTP provider used as ModuleCtx.net. */
434
- export function createNetTransport(options: NetTransportOptions = {}): Transport {
435
- const sources = [
436
- ...(options.includeDefaultDenyList === false ? [] : DEFAULT_NET_DENY_LIST),
437
- ...(options.denyList ?? []),
438
- ];
439
- const rules = sources.map(parseRule);
440
- const fetchCapability = options.fetch ?? pinnedFetch;
441
- const resolver = options.resolve ?? defaultResolver;
442
-
443
- return {
444
- async fetch(input, init) {
445
- let url: URL;
446
- try {
447
- url = new URL(input);
448
- } catch {
449
- throw new TypeError(`ctx.net.fetch requires an absolute HTTP(S) URL`);
450
- }
451
- if (url.protocol !== "http:" && url.protocol !== "https:") {
452
- throw new TypeError(`ctx.net.fetch refuses non-HTTP protocol '${url.protocol}'`);
453
- }
454
-
455
- const hostname = normalizeHostname(url.hostname);
456
- url.hostname = hostname;
457
- const denied = matchingRule(hostname, rules);
458
- if (denied) throw new NetEgressDeniedError(url.hostname, denied.source);
459
-
460
- const unbracketed = hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
461
- const literalIpv4 = parseIpv4(unbracketed);
462
- const literalIpv6 = literalIpv4 === undefined ? parseIpv6(unbracketed) : undefined;
463
- let addresses: readonly NetResolvedAddress[];
464
- if (literalIpv4 !== undefined || literalIpv6 !== undefined) {
465
- addresses = [{ address: unbracketed, family: literalIpv4 !== undefined ? 4 : 6 }];
466
- } else {
467
- try {
468
- addresses = await resolver(hostname);
469
- } catch (cause) {
470
- throw new NetEgressResolutionError(hostname, { cause });
471
- }
472
- }
473
-
474
- if (addresses.length === 0) throw new NetEgressResolutionError(hostname);
475
- for (const address of addresses) {
476
- const valid = address.family === 4 ? parseIpv4(address.address) : address.family === 6 ? parseIpv6(address.address) : undefined;
477
- if (valid === undefined) throw new NetEgressResolutionError(hostname);
478
- const addressDenied = matchingRule(address.address, rules);
479
- if (addressDenied) throw new NetEgressDeniedError(hostname, addressDenied.source);
480
- }
481
- const selected = addresses[0]!;
482
- const pin: NetConnectionPin = { hostname, address: selected.address, family: selected.family };
483
-
484
- // Manual redirect handling is a security invariant: an allowed URL must not make
485
- // the host fetch a second, denied URL behind this gate.
486
- const response = await fetchCapability(url.href, { ...init, redirect: "manual" }, pin);
487
- if (REDIRECT_STATUSES.has(response.status) && init?.redirect !== "manual") {
488
- throw new NetRedirectRefusedError(url.hostname);
489
- }
490
- return response;
491
- },
492
- };
493
- }