@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,317 +0,0 @@
1
- import { enterActivation, settleActivation, valueContext } from "./workflow-composition";
2
- import { expandItems } from "./workflow-container";
3
- import { validateWorkflowValue, workflowValue, workflowCondition, WorkflowValueError } from "./workflow-values";
4
- import { z } from "zod";
5
- import { type ModuleCtx, type StepResult } from "./contract";
6
- import { workflowBackstop, workflowStepChange } from "./workflow-backstop";
7
- import { workflowScriptResultSchema } from "./workflow-script";
8
- import { CI_MAIN_STEP, isLoopBack, routeOutcome, stepOutcome, stepReap, waitTimeoutMs, WORKFLOW_EXITED_OUTCOME, workflowStepPin, type RouteDecision } from "./workflow-definition";
9
- import { stores, requireRun, writeEffect, SIGNAL_TOPIC, ciVerdictSchema, type WorkflowRunRecord, type Awaiting } from "./workflow-state";
10
- export type RunState = { runId: string };
11
- type RunStep = StepResult<RunState>;
12
-
13
- function routeChange(run: WorkflowRunRecord, decision: RouteDecision, now: number) {
14
- return { ...workflowStepChange(run, decision.target, now), counters: decision.counters, round: isLoopBack(run.definition, run.step, decision.target) ? run.round + 1 : run.round };
15
- }
16
-
17
- export function landIntent(run: WorkflowRunRecord, override = run.resuming !== undefined): Record<string, unknown> {
18
- const resume = run.resumes?.at(-1);
19
- const entry = run.rounds.at(-1)?.steps.at(-1);
20
- const source = override ? { at: resume?.at, by: resume?.by, step: resume?.step, escalation: resume?.escalation }
21
- : { at: entry?.at, taskId: entry?.taskId, step: entry?.step, outcome: entry?.outcome };
22
- return { taskId: run.taskId, eventId: run.cursor, workspaceId: run.deliveryWorkspaceId, head: run.head,
23
- approval: { kind: override ? "override" : "go", source } };
24
- }
25
-
26
- /** Enter `run.step`: write its effect and park until the src supervisor signals the wait. */
27
- export async function enter(ctx: ModuleCtx, state: RunState): Promise<RunStep> {
28
- const run = await requireRun(ctx, state.runId);
29
- if (run.cancel) return finish(ctx, run, {}, { status: "cancelled", reason: run.cancel.reason });
30
- const seq = run.waitSeq + 1;
31
- const key = `${run.id}:${seq}`;
32
- const now = ctx.clock.now();
33
- const resume = run.resuming ? { resume: run.resuming } : {};
34
- // The dispatch carries the pin it applies, so a retried effect spawns what this entry decided.
35
- const applied = workflowStepPin(run.definition, run.pins, run.step, run.routingDefaults);
36
- const pin = applied ? { pin: applied } : {};
37
- const declared = run.definition.steps[run.step];
38
- try {
39
- if (declared?.condition !== undefined && !workflowCondition(declared.condition, valueContext(run))) {
40
- await enterActivation(ctx, run, key, now, true);
41
- const current = await requireRun(ctx, run.id);
42
- const patch = await settleActivation(ctx, current, "skipped", {});
43
- const decision = routeOutcome(run.definition, run.step, "skipped", run.counters, valueContext({ ...current, ...patch }));
44
- const update = { ...patch, waitSeq: seq, counters: decision.counters };
45
- if (decision.target === "done") return finish(ctx, current, update, { status: "done" });
46
- if (decision.target === "fail" || decision.target === "escalate") return finish(ctx, current, update, { status: decision.target === "fail" ? "failed" : "escalated", reason: "skipped step route" });
47
- await stores(ctx).run.update(run.id, { ...update, ...routeChange(run, decision, now) });
48
- return { state, next: "enter" };
49
- }
50
- } catch (error) { return finish(ctx, await requireRun(ctx, run.id), {}, { status: "failed", reason: String(error) }); }
51
- const decisionWait = run.definition.steps[run.step]?.decision;
52
- const activationDeadline = decisionWait ? (decisionWait.deadlineMs === undefined ? undefined : now + decisionWait.deadlineMs) : now + waitTimeoutMs(run.definition, run.step);
53
- let data: Record<string, unknown> = {};
54
- try { data = await enterActivation(ctx, run, key, activationDeadline); }
55
- catch (error) { return finish(ctx, run, {}, { status: "escalated", reason: String(error) }); }
56
- let awaiting: Awaiting;
57
- let landOperationId: string | undefined;
58
- if (run.step === "close") {
59
- const id = await writeEffect(ctx, run, seq, "close", {}, key);
60
- awaiting = { key, kind: "closed", effectId: id, afterEventId: run.cursor, since: now };
61
- } else if (run.step === "land") {
62
- landOperationId = await writeEffect(ctx, run, seq, "clear-hold", landIntent(run), key);
63
- awaiting = { key, kind: "landed", taskId: run.taskId, afterEventId: run.cursor, since: now };
64
- } else if (run.step === CI_MAIN_STEP) {
65
- // The work landed: no step agent has anything left to do while CI runs.
66
- await writeEffect(ctx, run, seq, "reap", { scope: "run" });
67
- awaiting = { key, kind: "ci", taskId: run.taskId, sha: run.landed!.sha, afterEventId: run.cursor, since: now };
68
- } else {
69
- const step = run.definition.steps[run.step]!;
70
- if (step.forEach) {
71
- try { await expandItems(ctx, await requireRun(ctx, run.id)); }
72
- catch (error) { return finish(ctx, await requireRun(ctx, run.id), {}, { status: "escalated", reason: String(error) }); }
73
- awaiting = { key, kind: "for-each", afterEventId: 0, since: now };
74
- } else if (step.decision) {
75
- const id = await writeEffect(ctx, run, seq, "decision", { step: run.step, ...data }, key);
76
- awaiting = { key, kind: "decision", effectId: id, afterEventId: 0, since: now, ...(step.decision.deadlineMs !== undefined ? { deadline: now + step.decision.deadlineMs } : {}) };
77
- } else if (step.workflow) {
78
- const id = await writeEffect(ctx, run, seq, "child", { step: run.step, ...data }, key);
79
- awaiting = { key, kind: "child", effectId: id, afterEventId: 0, since: now };
80
- } else if (step.script) {
81
- const poll = run.scriptPoll ?? { step: run.step, attempt: 1, deadline: now + step.script.timeoutMs, nextAt: now };
82
- const id = await writeEffect(ctx, run, seq, "script", { ...poll, ...data }, key);
83
- awaiting = { key, kind: "script", effectId: id, afterEventId: run.cursor, since: now, deadline: poll.deadline };
84
- await stores(ctx).run.update(run.id, { scriptPoll: poll });
85
- } else if (step.task === "input") {
86
- // #3660 — a gated input step (a single-agent audit) links its Task with the gate, so its delivery is a verdict.
87
- const inputGate = step.gate ? { gate: step.gate } : {};
88
- if (run.resuming) {
89
- // The src effect hands the note to the warm builder, or dispatches a fresh one when it is gone.
90
- await writeEffect(ctx, run, seq, "dispatch", { step: run.step, role: step.role, taskId: run.taskId, round: run.round, hold: true, ...inputGate, ...resume, ...pin, ...data }, key);
91
- } else if (run.entered.includes(run.step)) {
92
- await writeEffect(ctx, run, seq, "findings", { taskId: run.taskId, round: run.round, ...run.feedback }, key);
93
- } else {
94
- await writeEffect(ctx, run, seq, "dispatch", { step: run.step, role: step.role, taskId: run.taskId, hold: true, ...inputGate, ...pin, ...data }, key);
95
- }
96
- awaiting = { key, kind: "delivery", taskId: run.taskId, afterEventId: run.cursor, since: now };
97
- } else {
98
- const id = await writeEffect(ctx, run, seq, "dispatch", {
99
- step: run.step, role: step.role, round: run.round, parentTaskId: run.taskId,
100
- ...(run.head ? { head: run.head } : {}), ...(step.gate ? { gate: step.gate } : {}), ...resume, ...pin, ...data,
101
- }, key);
102
- awaiting = { key, kind: "delivery", effectId: id, afterEventId: 0, since: now };
103
- }
104
- }
105
- if (awaiting.kind !== "decision") awaiting.deadline ??= now + waitTimeoutMs(run.definition, run.step);
106
- const entered = run.step === "land" || run.entered.includes(run.step) ? run.entered : [...run.entered, run.step];
107
- const backstop = run.scriptPoll && run.overdueAt !== undefined ? {} : workflowBackstop(run, now, awaiting.deadline);
108
- await stores(ctx).run.update(run.id, { ...backstop, waitSeq: seq, awaiting, entered, resuming: undefined, ...(landOperationId ? { landOperationId } : {}), updatedAt: now });
109
- return { state, next: "route", waitFor: { kind: "event", topic: SIGNAL_TOPIC, correlationId: key } };
110
- }
111
-
112
- type RunEnd = { status: "escalated" | "cancelled" | "failed"; reason: string } | { status: "done"; landedSha?: string; nothingToLand?: boolean; ci?: z.output<typeof ciVerdictSchema> };
113
-
114
- async function finish(ctx: ModuleCtx, run: WorkflowRunRecord, patch: Partial<WorkflowRunRecord>, end: RunEnd, cleanupSettled = false): Promise<RunStep> {
115
- const now = ctx.clock.now();
116
- const final = { ...run, ...patch, status: end.status, ...(end.status === "done" && end.landedSha ? { landed: { ...run.landed, sha: end.landedSha, at: run.landed?.at ?? now } } : {}) };
117
- let returned: Record<string, unknown> | undefined;
118
- if (end.status === "done" && run.definition.version === 2) {
119
- try {
120
- returned = (cleanupSettled ? run.finalizing : workflowValue(run.definition.returns ?? {}, valueContext(final))) as Record<string, unknown>;
121
- validateWorkflowValue(run.definition.outputs, returned, "OUTPUT_INVALID");
122
- } catch (error) { return finish(ctx, run, patch, { status: "failed", reason: String(error) }); }
123
- }
124
- // The end consumes its seq, so a resumed run's next step and end never reuse these effect ids.
125
- const seq = run.waitSeq + 1;
126
- if (run.awaiting?.kind === "decision") await writeEffect(ctx, run, seq, "withdraw-decision", { effectId: run.awaiting.effectId });
127
- if (run.activationId) {
128
- const activation = await stores(ctx).activation.get(run.activationId);
129
- if (activation && activation.state === "waiting") await stores(ctx).activation.update(activation.id, { state: end.status === "done" ? "succeeded" : end.status === "cancelled" ? "cancelled" : "paused", outcome: end.status, updatedAt: now });
130
- }
131
- if (end.status === "done" && !cleanupSettled) {
132
- const ci = end.ci ?? final.landed?.ci;
133
- const output = (cleanupSettled ? run.finalizing : undefined) ?? returned ?? { landedSha: end.landedSha, rounds: final.round, ...(end.nothingToLand ? { nothingToLand: true } : {}), ...(ci ? { ci } : {}) };
134
- const key = `${run.id}:${seq}`;
135
- const id = await writeEffect(ctx, final, seq, "reap", { scope: "run" }, key);
136
- await stores(ctx).run.update(run.id, { ...patch, waitSeq: seq, ...(final.landed ? { landed: final.landed } : {}), finalizing: output, cleanup: { status: "pending", deadline: now + 300000 }, awaiting: { kind: "cleanup", key, effectId: id, afterEventId: run.cursor, since: now, deadline: now + 300000 }, updatedAt: now });
137
- return { state: { runId: run.id }, next: "route", waitFor: { kind: "event", topic: SIGNAL_TOPIC, correlationId: key } };
138
- }
139
- if (!cleanupSettled) await writeEffect(ctx, final, seq, "reap", { scope: "run" });
140
- if (end.status !== "done") {
141
- // A cancel is the coordinator's own act (cancel, abandon): nothing to tell it.
142
- const escalation = end.status === "escalated" || end.status === "failed" ? { escalation: { id: await writeEffect(ctx, final, seq, "escalate", { reason: end.reason }), at: now } } : {};
143
- await stores(ctx).run.update(run.id, { ...patch, ...escalation, ...(end.status === "cancelled" ? { cleanup: run.cleanup ?? { status: "pending" as const, deadline: now + 300000 } } : {}), waitSeq: seq, status: end.status, reason: end.reason, awaiting: null, resuming: undefined, updatedAt: now });
144
- } else {
145
- const ci = end.ci ?? final.landed?.ci;
146
- const output = (cleanupSettled ? run.finalizing : undefined) ?? returned ?? { landedSha: end.landedSha, rounds: final.round, ...(end.nothingToLand || final.landed?.nothingToLand ? { nothingToLand: true } : {}), ...(ci ? { ci } : {}) };
147
- await writeEffect(ctx, final, seq, "result", output);
148
- await stores(ctx).run.update(run.id, { ...patch, waitSeq: seq, status: "done", finalizing: undefined, cleanup: { status: "complete", deadline: run.cleanup?.deadline ?? now }, output, ...(run.rootRunId ? { outputs: output } : {}), awaiting: null, resuming: undefined, updatedAt: now });
149
- }
150
- await ctx.events.emit("workflow.finished", { runId: run.id, status: end.status });
151
- return { state: { runId: run.id }, next: "done", output: end };
152
- }
153
-
154
- function textField(value: unknown): string | undefined {
155
- return typeof value === "string" && value.trim() ? value : undefined;
156
- }
157
-
158
- /** Consume the signal of the current wait and decide the next step. */
159
- export async function route(ctx: ModuleCtx, state: RunState): Promise<RunStep> {
160
- try { return await routeSignal(ctx, state); }
161
- catch (error) {
162
- if (!(error instanceof WorkflowValueError)) throw error;
163
- return finish(ctx, await requireRun(ctx, state.runId), {}, { status: "failed", reason: error.message });
164
- }
165
- }
166
-
167
- async function routeSignal(ctx: ModuleCtx, state: RunState): Promise<RunStep> {
168
- const run = await requireRun(ctx, state.runId);
169
- // A cancel wins over whatever woke the wait, including a result that arrived first.
170
- if (run.cancel) return finish(ctx, run, {}, { status: "cancelled", reason: run.cancel.reason });
171
- const key = run.awaiting?.key;
172
- const signal = key ? await stores(ctx).signal.get(key) : undefined;
173
- if (!signal) throw new Error(`workflow run '${run.id}' woke without the signal for its wait`);
174
- // The resume op already set the run up; a run leaving its land wait takes its step now the Task is held.
175
- if (signal.kind === "resume") {
176
- const to = run.resuming?.to;
177
- if (to) await stores(ctx).run.update(run.id, { ...workflowStepChange(run, to, ctx.clock.now()), resuming: run.resuming?.note ? { note: run.resuming.note } : {} });
178
- return { state, next: "enter" };
179
- }
180
- const payload = signal.payload;
181
- if (run.awaiting?.kind === "cleanup" && signal.kind === "cleanup") return finish(ctx, run, {}, { status: "done" }, true);
182
- if (signal.kind === "effect-failed") {
183
- const message = `${String(payload.effect)} failed: ${String(payload.error)}`;
184
- const patch = await settleActivation(ctx, run, "blocked", {}, { code: String(payload.error).split(":")[0], message, effectId: run.awaiting?.effectId });
185
- return finish(ctx, run, patch, { status: "escalated", reason: message });
186
- }
187
- if (signal.kind === "land-withdrawn") {
188
- // #3603 — a withdrawn land parks the run at the step that delivered it: same run, builder and worktree.
189
- const delivering = run.rounds.flatMap((round) => round.steps).reverse().find((entry) => entry.taskId === run.taskId && run.definition.steps[entry.step]?.task === "input")?.step;
190
- if (!delivering) return finish(ctx, run, {}, { status: "cancelled", reason: String(payload.reason) });
191
- const note = `The armed land of ${run.head ?? "your delivered head"} was withdrawn: ${String(payload.reason)}. The run is parked here; your worktree and commits are kept.`;
192
- await stores(ctx).run.update(run.id, { ...workflowStepChange(run, delivering, ctx.clock.now()), round: run.round + 1, feedback: null, resuming: { note } });
193
- return { state, next: "enter" };
194
- }
195
- if (signal.kind === "land-cancelled" || signal.kind === "start-refused") return finish(ctx, run, {}, { status: "cancelled", reason: String(payload.reason) });
196
- if (run.step === "close") return finish(ctx, run, {}, { status: "done", landedSha: String(payload.landedSha ?? run.landed?.sha) });
197
- if (run.step === CI_MAIN_STEP) {
198
- const ci = ciVerdictSchema.parse(payload);
199
- if (run.definition.land?.then) {
200
- if (ci.status !== "pass") return finish(ctx, run, {}, { status: "escalated", reason: `CI on main: ${ci.status}; verification did not run` });
201
- await stores(ctx).run.update(run.id, { ...workflowStepChange(run, run.definition.land.then, ctx.clock.now()), landed: { ...run.landed!, ci } });
202
- return { state, next: "enter" };
203
- }
204
- return finish(ctx, run, {}, { status: "done", landedSha: run.landed!.sha, ci });
205
- }
206
- if (run.step === "land") {
207
- if (run.definition.land?.then) {
208
- const landed = { sha: String(payload.sha), at: ctx.clock.now(), ...(payload.nothingToLand === true ? { nothingToLand: true } : {}) };
209
- const next = run.definition.ciMain && !landed.nothingToLand ? CI_MAIN_STEP : run.definition.land.then;
210
- await stores(ctx).run.update(run.id, { ...workflowStepChange(run, next, ctx.clock.now()), landed });
211
- return { state, next: "enter" };
212
- }
213
- // Nothing landed, so CI on main has no land of this run's to judge.
214
- if (payload.nothingToLand === true) return finish(ctx, run, {}, { status: "done", landedSha: String(payload.sha), nothingToLand: true });
215
- if (!run.definition.ciMain) return finish(ctx, run, {}, { status: "done", landedSha: String(payload.sha) });
216
- await stores(ctx).run.update(run.id, { ...workflowStepChange(run, CI_MAIN_STEP, ctx.clock.now()), landed: { sha: String(payload.sha), at: ctx.clock.now() } });
217
- return { state, next: "enter" };
218
- }
219
-
220
- const step = run.definition.steps[run.step]!;
221
- if (step.decision || step.workflow || step.forEach) {
222
- const outputs = (payload.outputs ?? {}) as Record<string, unknown>;
223
- const outcome = String(payload.outcome);
224
- let patch: Partial<WorkflowRunRecord>;
225
- try {
226
- if (outcome === "complete" && step.outputSchema) validateWorkflowValue(step.outputSchema, outputs, "OUTPUT_INVALID");
227
- patch = await settleActivation(ctx, run, outcome, outputs, payload.error as Record<string, unknown> | undefined);
228
- } catch (error) {
229
- patch = await settleActivation(ctx, run, "failed", {}, { code: "OUTPUT_INVALID", message: String(error), childRunId: payload.childRunId });
230
- return finish(ctx, run, patch, { status: "failed", reason: String(error) });
231
- }
232
- const decision = routeOutcome(run.definition, run.step, outcome, run.counters, valueContext({ ...run, ...patch }));
233
- patch.counters = decision.counters;
234
- if (decision.target === "done") return finish(ctx, run, patch, { status: "done" });
235
- if (decision.target === "fail" || decision.target === "escalate") return finish(ctx, run, patch, { status: decision.target === "fail" ? "failed" : "escalated", reason: String(payload.error ?? decision.reason ?? `child ${outcome}`) });
236
- await stores(ctx).run.update(run.id, { ...patch, ...routeChange(run, decision, ctx.clock.now()) });
237
- return { state, next: "enter" };
238
- }
239
- if (step.script) {
240
- const result = workflowScriptResultSchema.parse(payload);
241
- const outcome = result.timedOut ? "timeout" : String(result.exitCode ?? "unknown");
242
- const decision = routeOutcome(run.definition, run.step, outcome, run.counters, valueContext({ ...run, results: { ...run.results, [run.step]: { status: result.exitCode === 0 ? "succeeded" : "failed", outputs: result.output ?? {} } } }));
243
- await stores(ctx).scriptAttempt.create({ id: signal.id, runId: run.id, ...result });
244
- const scriptOutputs = { ...run.scriptOutputs, ...(result.output ? { [run.step]: result.output } : {}) };
245
- if (decision.target === "wait") {
246
- await stores(ctx).run.update(run.id, { scriptOutputs, scriptPoll: { ...run.scriptPoll!, attempt: result.attempt + 1, nextAt: ctx.clock.now() + step.script.everyMs! }, updatedAt: ctx.clock.now() });
247
- return { state, next: "enter" };
248
- }
249
- const entry = { step: run.step, taskId: run.taskId, outcome, startedAt: run.awaiting!.since, at: ctx.clock.now() };
250
- const rounds = run.rounds.some((r) => r.round === run.round)
251
- ? run.rounds.map((r) => r.round === run.round ? { ...r, steps: [...r.steps, entry] } : r)
252
- : [...run.rounds, { round: run.round, steps: [entry] }];
253
- let activationPatch: Partial<WorkflowRunRecord> = {};
254
- if (run.rootRunId) {
255
- try {
256
- if (result.error) throw new Error(String(result.error.message));
257
- if (step.outputSchema) validateWorkflowValue(step.outputSchema, result.output ?? {}, "OUTPUT_INVALID");
258
- activationPatch = await settleActivation(ctx, run, decision.outcome ?? (decision.target === "escalate" ? "blocked" : decision.target === "fail" ? "failed" : "complete"), result.output ?? {});
259
- } catch (error) {
260
- activationPatch = await settleActivation(ctx, run, "failed", {}, { code: "OUTPUT_INVALID", message: String(error), artifactId: result.logArtifactId });
261
- return finish(ctx, run, { ...activationPatch, scriptPoll: undefined, rounds }, { status: "failed", reason: `OUTPUT_INVALID: ${String(error)}` });
262
- }
263
- }
264
- const patch = { scriptOutputs, scriptPoll: undefined, rounds, ...activationPatch, counters: decision.counters };
265
- if (decision.target === "escalate" || decision.target === "fail") return finish(ctx, run, patch, { status: decision.target === "fail" ? "failed" : "escalated", reason: decision.reason! });
266
- if (decision.target === "done") return finish(ctx, run, patch, { status: "done", landedSha: run.landed?.sha ?? "" });
267
- await stores(ctx).run.update(run.id, { ...patch, ...routeChange(run, decision, ctx.clock.now()) });
268
- return { state, next: "enter" };
269
- }
270
- const exited = signal.kind === "agent-exited";
271
- const outcome = exited ? WORKFLOW_EXITED_OUTCOME : stepOutcome(step, { disposition: String(payload.disposition), gateStatus: textField(payload.gateStatus) });
272
- const input = step.task === "input";
273
- const head = input ? textField(payload.head) ?? run.head : run.head;
274
- const entry = {
275
- step: run.step,
276
- taskId: Number(payload.taskId),
277
- outcome,
278
- ...(head ? { head } : {}),
279
- ...(textField(payload.summary) ? { summary: textField(payload.summary) } : {}),
280
- ...(textField(payload.findings) ? { findings: textField(payload.findings) } : {}),
281
- ...(run.awaiting ? { startedAt: run.awaiting.since } : {}),
282
- at: ctx.clock.now(),
283
- };
284
- const rounds = run.rounds.some((r) => r.round === run.round)
285
- ? run.rounds.map((r) => (r.round === run.round ? { ...r, steps: [...r.steps, entry] } : r))
286
- : [...run.rounds, { round: run.round, steps: [entry] }];
287
- if (stepReap(step) === "on-step-done") await writeEffect(ctx, run, run.waitSeq, "reap", { scope: "step", step: run.step });
288
- const decision = routeOutcome(run.definition, run.step, outcome, run.counters, valueContext({ ...run, results: { ...run.results, [run.step]: { status: outcome === "complete" || outcome === "pass" ? "succeeded" : "failed", outcome, outputs: payload.outputs ?? {} } } }));
289
- // An exit consumed no delivery, so the next wait still counts from the last one.
290
- let activationPatch: Partial<WorkflowRunRecord> = {};
291
- if (run.rootRunId) {
292
- const outputs = payload.outputs as Record<string, unknown> | undefined ?? {};
293
- try {
294
- if (step.outputSchema) validateWorkflowValue(step.outputSchema, outputs, "OUTPUT_INVALID");
295
- activationPatch = await settleActivation(ctx, run, outcome, outputs);
296
- } catch (error) {
297
- activationPatch = await settleActivation(ctx, run, "failed", {}, { code: "OUTPUT_INVALID", message: String(error), deliveryEventId: payload.eventId });
298
- return finish(ctx, run, activationPatch, { status: "failed", reason: String(error) });
299
- }
300
- }
301
- const patch: Partial<WorkflowRunRecord> = { ...activationPatch, rounds, counters: decision.counters, scriptOutputs: { ...run.scriptOutputs, [run.step]: payload }, ...(input && !exited ? { cursor: Number(payload.eventId), deliveryWorkspaceId: textField(payload.workspaceId) } : {}), ...(head ? { head } : {}) };
302
- await ctx.events.emit("workflow.routed", { runId: run.id, step: run.step, outcome, target: decision.target });
303
- if (decision.target === "done") return finish(ctx, run, patch, { status: "done" });
304
- if (decision.target === "fail") return finish(ctx, run, patch, { status: "failed", reason: `step ${run.step} returned ${outcome}` });
305
- if (decision.target === "escalate") {
306
- // An exit the workflow does not route escalates with its own account.
307
- const reason = exited && !run.definition.routes[run.step]?.[outcome] ? String(payload.summary) : decision.reason ?? `step ${run.step} returned ${outcome}`;
308
- return finish(ctx, run, patch, { status: "escalated", reason });
309
- }
310
-
311
- const loop = isLoopBack(run.definition, run.step, decision.target);
312
- const feedback = loop && run.definition.steps[decision.target]?.task === "input"
313
- ? { ...(head ? { head } : {}), findings: entry.findings ?? entry.summary ?? outcome, taskId: entry.taskId, step: run.step }
314
- : null;
315
- await stores(ctx).run.update(run.id, { ...patch, ...routeChange(run, decision, ctx.clock.now()), feedback });
316
- return { state, next: "enter" };
317
- }
@@ -1,153 +0,0 @@
1
- import jsep from "jsep";
2
- import Ajv, { type ValidateFunction } from "ajv";
3
- import { z } from "zod";
4
-
5
- export const workflowObject = z.record(z.string(), z.unknown());
6
- export const emptyBoundary = { type: "object", additionalProperties: false, properties: {} };
7
- const ajv = new Ajv({ strict: true, allErrors: true, coerceTypes: false, useDefaults: false, removeAdditional: false });
8
- const compiled = new Map<string, ValidateFunction>();
9
- function schemaKey(schema: Record<string, unknown>): string { return JSON.stringify(schema); }
10
- const keywords = new Set(["type", "properties", "required", "additionalProperties", "items", "enum", "const", "nullable", "minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf", "minLength", "maxLength", "minItems", "maxItems", "uniqueItems", "minProperties", "maxProperties", "$defs", "$ref", "description", "title"]);
11
-
12
- export class WorkflowValueError extends Error {
13
- constructor(readonly code: string, message: string) { super(`${code}: ${message}`); }
14
- }
15
-
16
- export function validateWorkflowSchema(schema: Record<string, unknown>, boundary = false): void {
17
- if (boundary && (schema.type !== "object" || schema.additionalProperties !== false)) throw new WorkflowValueError("SCHEMA_INVALID", "boundary must declare type: object and additionalProperties: false");
18
- let nodes = 0;
19
- function visit(value: unknown, depth: number): void {
20
- if (++nodes > 1000 || depth > 32) throw new WorkflowValueError("SCHEMA_INVALID", "schema exceeds depth/node limit");
21
- if (!value || typeof value !== "object" || Array.isArray(value)) throw new WorkflowValueError("SCHEMA_INVALID", "schema must be an object");
22
- for (const [key, child] of Object.entries(value)) {
23
- if (!keywords.has(key)) throw new WorkflowValueError("SCHEMA_INVALID", `unsupported keyword ${key}`);
24
- if (key === "$ref" && (typeof child !== "string" || !child.startsWith("#/$defs/"))) throw new WorkflowValueError("SCHEMA_INVALID", "only local $defs references are supported");
25
- if (key === "properties" || key === "$defs") {
26
- if (!child || typeof child !== "object" || Array.isArray(child)) throw new WorkflowValueError("SCHEMA_INVALID", `${key} must be an object`);
27
- for (const nested of Object.values(child)) visit(nested, depth + 1);
28
- } else if (key === "items" || (key === "additionalProperties" && typeof child === "object")) visit(child, depth + 1);
29
- }
30
- }
31
- visit(schema, 0);
32
- const key = schemaKey(schema);
33
- if (!compiled.has(key)) {
34
- if (compiled.size >= 512) compiled.delete(compiled.keys().next().value!);
35
- compiled.set(key, ajv.compile(schema));
36
- }
37
- }
38
-
39
- export function validateWorkflowValue(schema: Record<string, unknown> | undefined, data: Record<string, unknown>, code: string): void {
40
- if (new TextEncoder().encode(JSON.stringify(data)).length > 65536) throw new WorkflowValueError(code, "object exceeds 64 KiB");
41
- const definition = schema ?? emptyBoundary;
42
- if (!compiled.has(schemaKey(definition))) validateWorkflowSchema(definition);
43
- const check = compiled.get(schemaKey(definition))!;
44
- if (!check(data)) throw new WorkflowValueError(code, ajv.errorsText(check.errors));
45
- }
46
-
47
- const expressions = new Map<string, jsep.Expression>();
48
- const binary = ["&&", "||", "==", "!=", "<", "<=", ">", ">="];
49
- class MissingPath extends WorkflowValueError {}
50
- function children(node: jsep.Expression): jsep.Expression[] {
51
- if (node.type === "MemberExpression") return [(node as jsep.MemberExpression).object];
52
- if (node.type === "UnaryExpression") return [(node as jsep.UnaryExpression).argument];
53
- if (node.type === "BinaryExpression") return [(node as jsep.BinaryExpression).left, (node as jsep.BinaryExpression).right];
54
- if (node.type === "CallExpression") return (node as jsep.CallExpression).arguments;
55
- return [];
56
- }
57
- function expression(text: string): jsep.Expression {
58
- const source = /^\$\{\{([\s\S]*)\}\}$/.exec(text)?.[1];
59
- if (source === undefined || source.length > 4096) throw new WorkflowValueError("EXPRESSION_INVALID", "expected a whole expression");
60
- const cached = expressions.get(source);
61
- if (cached) return cached;
62
- let parsed: jsep.Expression;
63
- try { parsed = jsep(source); } catch (error) { throw new WorkflowValueError("EXPRESSION_INVALID", String(error)); }
64
- let nodes = 0;
65
- function check(node: jsep.Expression, depth: number): void {
66
- if (++nodes > 256 || depth > 32) throw new WorkflowValueError("EXPRESSION_INVALID", "expression exceeds depth/node limit");
67
- let valid = false;
68
- if (node.type === "Identifier") valid = ["inputs", "steps", "run", "item", "index"].includes((node as jsep.Identifier).name);
69
- if (node.type === "Literal") valid = (node as jsep.Literal).value === null || ["string", "boolean", "number"].includes(typeof (node as jsep.Literal).value);
70
- if (node.type === "MemberExpression") {
71
- const member = node as jsep.MemberExpression;
72
- const property = member.computed ? (member.property as jsep.Literal).value : (member.property as jsep.Identifier).name;
73
- valid = (!member.computed || member.property.type === "Literal") && (typeof property === "string" || typeof property === "number" && Number.isSafeInteger(property) && property >= 0) && !["__proto__", "prototype", "constructor"].includes(String(property));
74
- }
75
- if (node.type === "UnaryExpression") valid = (node as jsep.UnaryExpression).operator === "!" || (node as jsep.UnaryExpression).operator === "-" && (node as jsep.UnaryExpression).argument.type === "Literal" && typeof ((node as jsep.UnaryExpression).argument as jsep.Literal).value === "number";
76
- if (node.type === "BinaryExpression") valid = binary.includes((node as jsep.BinaryExpression).operator);
77
- if (node.type === "CallExpression") {
78
- const call = node as jsep.CallExpression;
79
- valid = call.callee.type === "Identifier" && (call.callee as jsep.Identifier).name === "has" && call.arguments.length === 1 && ["MemberExpression", "Identifier"].includes(call.arguments[0]!.type);
80
- }
81
- if (!valid) throw new WorkflowValueError("EXPRESSION_INVALID", `unsupported ${node.type}`);
82
- for (const child of children(node)) check(child, depth + 1);
83
- }
84
- check(parsed, 0);
85
- if (expressions.size >= 1024) expressions.delete(expressions.keys().next().value!);
86
- expressions.set(source, parsed);
87
- return parsed;
88
- }
89
-
90
- export function validateWorkflowExpressions(value: unknown, steps: readonly string[]): void {
91
- if (typeof value === "string" && value.startsWith("${{")) {
92
- function names(part: jsep.Expression): void {
93
- if (part.type === "MemberExpression") {
94
- const member = part as jsep.MemberExpression;
95
- if (member.object.type === "Identifier" && (member.object as jsep.Identifier).name === "steps") {
96
- const name = member.computed ? (member.property as jsep.Literal).value : (member.property as jsep.Identifier).name;
97
- if (!steps.includes(String(name))) throw new WorkflowValueError("EXPRESSION_INVALID", `unknown step ${String(name)}`);
98
- }
99
- }
100
- for (const child of children(part)) names(child);
101
- }
102
- names(expression(value));
103
- } else if (value && typeof value === "object") for (const item of Object.values(value)) validateWorkflowExpressions(item, steps);
104
- }
105
-
106
- function boolean(value: unknown): boolean {
107
- if (typeof value !== "boolean") throw new WorkflowValueError("EXPRESSION_INVALID", "condition requires a boolean");
108
- return value;
109
- }
110
- export function workflowCondition(value: unknown, context: Record<string, unknown>): boolean { return boolean(workflowValue(value, context)); }
111
-
112
- export function workflowValue(value: unknown, context: Record<string, unknown>): unknown {
113
- if (typeof value === "string" && value.startsWith("${{")) {
114
- function evaluate(node: jsep.Expression): unknown {
115
- if (node.type === "Literal") return (node as jsep.Literal).value;
116
- if (node.type === "Identifier") {
117
- const name = (node as jsep.Identifier).name;
118
- if (!Object.hasOwn(context, name)) throw new MissingPath("EXPRESSION_INVALID", `missing context ${name}`);
119
- return context[name];
120
- }
121
- if (node.type === "CallExpression") {
122
- try { evaluate((node as jsep.CallExpression).arguments[0]!); return true; }
123
- catch (error) { if (error instanceof MissingPath) return false; throw error; }
124
- }
125
- if (node.type === "UnaryExpression") {
126
- const unary = node as jsep.UnaryExpression;
127
- return unary.operator === "!" ? !boolean(evaluate(unary.argument)) : -Number((unary.argument as jsep.Literal).value);
128
- }
129
- if (node.type === "BinaryExpression") {
130
- const { operator, left, right } = node as jsep.BinaryExpression;
131
- const a = evaluate(left);
132
- if (operator === "&&") return boolean(a) && boolean(evaluate(right));
133
- if (operator === "||") return boolean(a) || boolean(evaluate(right));
134
- const b = evaluate(right);
135
- if ((a !== null && typeof a === "object") || (b !== null && typeof b === "object") || typeof a !== typeof b) throw new WorkflowValueError("EXPRESSION_INVALID", "comparison requires matching scalar types");
136
- if (operator === "==") return a === b;
137
- if (operator === "!=") return a !== b;
138
- if (typeof a === "number" && typeof b === "number") return operator === "<" ? a < b : operator === "<=" ? a <= b : operator === ">" ? a > b : a >= b;
139
- if (typeof a === "string" && typeof b === "string") return operator === "<" ? a < b : operator === "<=" ? a <= b : operator === ">" ? a > b : a >= b;
140
- throw new WorkflowValueError("EXPRESSION_INVALID", "ordering requires numbers or strings");
141
- }
142
- const member = node as jsep.MemberExpression;
143
- const target = evaluate(member.object);
144
- const key = member.computed ? (member.property as jsep.Literal).value : (member.property as jsep.Identifier).name;
145
- if (!target || typeof target !== "object" || !Object.hasOwn(target, String(key))) throw new MissingPath("EXPRESSION_INVALID", `missing property ${String(key)}`);
146
- return (target as Record<string, unknown>)[String(key)];
147
- }
148
- return evaluate(expression(value));
149
- }
150
- if (Array.isArray(value)) return value.map(item => workflowValue(item, context));
151
- if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, workflowValue(item, context)]));
152
- return value;
153
- }