@humwick/server 0.130.1 → 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 (437) hide show
  1. package/README.md +5 -0
  2. package/docs/guides/tools-administration.md +4 -0
  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-B_rFEbnL.js → fleet-C7jQWbw2.js} +2 -2
  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 +8 -0
  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 +3 -3
  128. package/src/config-store-write.ts +13 -1
  129. package/src/config-store.ts +25 -14
  130. package/src/db/activity-async.ts +6 -1
  131. package/src/db/activity-write-ops.ts +12 -1
  132. package/src/db/activity.ts +1 -14
  133. package/src/db/agent-search.ts +1 -15
  134. package/src/db/agents-async.ts +52 -5
  135. package/src/db/agents-write-ops.ts +12 -3
  136. package/src/db/agents.ts +81 -54
  137. package/src/db/ci-incidents-async.ts +5 -5
  138. package/src/db/ci-incidents-write-ops.ts +2 -2
  139. package/src/db/command-row.ts +10 -2
  140. package/src/db/commands-list-query.ts +2 -0
  141. package/src/db/commands-spawn-read.ts +1 -1
  142. package/src/db/config-store-write-ops.ts +7 -2
  143. package/src/db/continuation-archives-async.ts +5 -0
  144. package/src/db/continuation-archives-write-ops.ts +7 -0
  145. package/src/db/continuations.ts +2 -2
  146. package/src/db/db-writer-worker.ts +8 -1
  147. package/src/db/deploy-events-async.ts +1 -0
  148. package/src/db/deploy-events-read-ops.ts +2 -1
  149. package/src/db/deploy-events.ts +35 -4
  150. package/src/db/hosts-registration.ts +10 -2
  151. package/src/db/hosts.ts +9 -6
  152. package/src/db/inbox.ts +0 -14
  153. package/src/db/index.ts +2 -0
  154. package/src/db/integrations-async.ts +8 -0
  155. package/src/db/integrations-ops.ts +15 -0
  156. package/src/db/integrations.ts +15 -21
  157. package/src/db/issue-lifecycle.ts +3 -4
  158. package/src/db/issue-refs-async.ts +20 -0
  159. package/src/db/issue-refs-write-ops.ts +29 -0
  160. package/src/db/issue-refs.ts +7 -8
  161. package/src/db/long-running-work.ts +2 -2
  162. package/src/db/main-connection-writes.ts +23 -2
  163. package/src/db/maintenance-job-reconcile.ts +61 -0
  164. package/src/db/maintenance-job-runs-async.ts +14 -0
  165. package/src/db/maintenance-job-write-ops.ts +9 -0
  166. package/src/db/mappers.ts +2 -14
  167. package/src/db/merge-lease.ts +1 -15
  168. package/src/db/migrations.ts +7 -15
  169. package/src/db/orchestrators.ts +4 -72
  170. package/src/db/pairs.ts +1 -13
  171. package/src/db/project-profile-instructions.ts +50 -0
  172. package/src/db/prompt-versions.ts +9 -2
  173. package/src/db/provider-config-history.ts +8 -3
  174. package/src/db/provider-model-seed.ts +34 -0
  175. package/src/db/read-op-marshaling-fixtures.ts +5 -0
  176. package/src/db/read-ops.ts +4 -0
  177. package/src/db/routing-policy.ts +2 -3
  178. package/src/db/schema.ts +9 -3
  179. package/src/db/spawn-delegation-state.ts +11 -4
  180. package/src/db/stats-async.ts +4 -3
  181. package/src/db/task-entity.ts +23 -2
  182. package/src/db/task-list.ts +3 -1
  183. package/src/db/tasks.ts +1 -17
  184. package/src/db/timer-ingress.ts +7 -1
  185. package/src/db/token-db-write-ops.ts +17 -0
  186. package/src/db/token-standing.ts +15 -11
  187. package/src/db/workflow-contact.ts +1 -1
  188. package/src/db/workflow-task-read-ops.ts +30 -0
  189. package/src/db/write-ops.ts +6 -0
  190. package/src/db/writer-gateway.ts +17 -11
  191. package/src/dispatch-availability.ts +10 -6
  192. package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
  193. package/src/host/disk-alert.ts +121 -0
  194. package/src/lifecycle-manager.ts +3 -2
  195. package/src/maintenance/cd-watcher.ts +3 -3
  196. package/src/maintenance/critical-job-watchdog.ts +16 -17
  197. package/src/maintenance/index.ts +1 -0
  198. package/src/maintenance/jobs.ts +3 -2
  199. package/src/maintenance/scheduler.ts +84 -128
  200. package/src/maintenance/stalled-delivery-pager.ts +6 -5
  201. package/src/maintenance/workspaces.ts +1 -1
  202. package/src/managed-policy.ts +31 -27
  203. package/src/mcp/index.ts +5 -2
  204. package/src/mcp/output-descriptions.ts +8 -8
  205. package/src/mcp/presentation.ts +4 -4
  206. package/src/mcp/project-profile-instructions.ts +32 -0
  207. package/src/mcp/tool-groups.ts +1 -1
  208. package/src/mcp/tools-spawn.ts +4 -3
  209. package/src/mcp-agent-action.ts +1 -2
  210. package/src/mcp-issue-ref-tools.ts +12 -11
  211. package/src/mcp-maintenance-tools.ts +2 -2
  212. package/src/mcp-profile-trust-tools.ts +4 -4
  213. package/src/mcp-provider-catalog.ts +2 -2
  214. package/src/mcp-task-tools.ts +11 -5
  215. package/src/mcp-team-template-tools.ts +3 -3
  216. package/src/mcp-workflow-tools.ts +10 -3
  217. package/src/notification-types.ts +2 -1
  218. package/src/operator-alarm.ts +26 -11
  219. package/src/project-instructions.ts +4 -0
  220. package/src/project-profile-instruction-text.ts +6 -0
  221. package/src/project-profile-instructions.ts +20 -0
  222. package/src/provider-catalog-store.ts +3 -49
  223. package/src/provider-config-store.ts +12 -11
  224. package/src/provider-model-seed.ts +1 -18
  225. package/src/provider-quota-config-store.ts +5 -4
  226. package/src/provider-secrets.test-fixture.ts +3 -3
  227. package/src/recipe-runner.ts +2 -2
  228. package/src/repo-config-source.ts +10 -4
  229. package/src/routes/agent-profiles.ts +6 -6
  230. package/src/routes/agents-spawn.ts +1 -1
  231. package/src/routes/agents.ts +6 -6
  232. package/src/routes/commands-listing.ts +4 -0
  233. package/src/routes/commands.ts +2 -2
  234. package/src/routes/continuation-archives.ts +2 -2
  235. package/src/routes/index.ts +10 -1
  236. package/src/routes/integrations.ts +24 -50
  237. package/src/routes/issue-refs.ts +7 -7
  238. package/src/routes/orchestrator-bootstrap.ts +1 -1
  239. package/src/routes/orchestrator-host-registration.ts +2 -2
  240. package/src/routes/orchestrator-host-utilization.ts +3 -1
  241. package/src/routes/orchestrator-proxy.ts +2 -2
  242. package/src/routes/orchestrator.ts +2 -2
  243. package/src/routes/project-profile-instructions.ts +27 -0
  244. package/src/routes/project-trust.ts +2 -2
  245. package/src/routes/provider-config.ts +6 -6
  246. package/src/routes/provider-quota-config.ts +2 -2
  247. package/src/routes/settings.ts +5 -5
  248. package/src/routes/stats.ts +6 -6
  249. package/src/routes/task-http.ts +15 -1
  250. package/src/routes/task-issues.ts +11 -26
  251. package/src/routes/tasks.ts +22 -53
  252. package/src/routes/team-templates.ts +5 -5
  253. package/src/routes/teams-config.ts +2 -2
  254. package/src/routes/tokens.ts +12 -5
  255. package/src/routes/workflows.ts +20 -5
  256. package/src/routing-policy-normalize.ts +1 -2
  257. package/src/routing-step-defaults.ts +0 -2
  258. package/src/runner-token-mint-limit.ts +63 -0
  259. package/src/runtime-grant.ts +4 -2
  260. package/src/runtime-tokens.ts +39 -7
  261. package/src/security.ts +13 -20
  262. package/src/server-background.ts +1 -1
  263. package/src/server.ts +5 -2
  264. package/src/services/host-utilization.ts +23 -0
  265. package/src/services/idle-epics.ts +5 -6
  266. package/src/services/issue-lifecycle.ts +57 -61
  267. package/src/services/issue-refs.ts +9 -13
  268. package/src/services/kernel-timers-cutover-chaos-worker.ts +10 -7
  269. package/src/services/kernel-timers-ingress.ts +1 -1
  270. package/src/services/landed-ancestry.ts +19 -3
  271. package/src/services/memory-areas.ts +15 -51
  272. package/src/services/plan-ci-notice.ts +57 -0
  273. package/src/services/plan-ci-recovery.ts +2 -55
  274. package/src/services/plan-wake-digest.ts +1 -0
  275. package/src/services/profile-trust.ts +4 -3
  276. package/src/services/project-config-read.ts +70 -0
  277. package/src/services/project-profile-instructions.ts +54 -0
  278. package/src/services/provisioning-harness/budget-baseline.json +4 -4
  279. package/src/services/restart-spawn.ts +61 -49
  280. package/src/services/self-care-state.ts +2 -1
  281. package/src/services/self-effort.ts +5 -5
  282. package/src/services/send-message.ts +5 -1
  283. package/src/services/spawn-agent.ts +13 -2
  284. package/src/services/spawn-chain-inspector.ts +6 -13
  285. package/src/services/spawn-policy.ts +68 -0
  286. package/src/services/spawn-tree-cleanup.ts +2 -2
  287. package/src/services/task-dispatch.ts +3 -0
  288. package/src/services/task-state-reconcile.ts +6 -14
  289. package/src/services/team-templates.ts +9 -8
  290. package/src/services/transient-agent-reaper.ts +3 -1
  291. package/src/services/workflow-auto-start.ts +25 -13
  292. package/src/services/workflow-ci-main.ts +1 -1
  293. package/src/services/workflow-deferred-cleanup.ts +4 -2
  294. package/src/services/workflow-effect-driver.ts +2 -0
  295. package/src/services/workflow-effects.ts +18 -11
  296. package/src/services/workflow-land-notice.ts +10 -0
  297. package/src/services/workflow-pause-text.ts +43 -0
  298. package/src/services/workflow-reconcile.ts +13 -11
  299. package/src/services/workflow-run-view.ts +2 -0
  300. package/src/services/workflow-runs.ts +29 -13
  301. package/src/services/workflow-supervisor-state.ts +5 -0
  302. package/src/services/workflow-supervisor.ts +7 -3
  303. package/src/settings/registry.ts +1 -2
  304. package/src/spawn-command.ts +4 -4
  305. package/src/spawn-models.ts +10 -12
  306. package/src/spawn-placement.ts +1 -1
  307. package/src/spawn-targets.ts +1 -1
  308. package/src/startup-context-injection.ts +1 -0
  309. package/src/state-adoption/cd-cutover.ts +53 -7
  310. package/src/state-adoption/fleet-cutover.ts +35 -0
  311. package/src/state-adoption/fleet-plan.ts +36 -0
  312. package/src/state-adoption/index.ts +2 -2
  313. package/src/state-adoption/linux-plan.ts +2 -2
  314. package/src/state-adoption/linux.ts +2 -2
  315. package/src/state-adoption/macos-plan.ts +2 -2
  316. package/src/state-adoption/macos.ts +1 -1
  317. package/src/steward.ts +7 -6
  318. package/src/task-dispatch-live.ts +1 -1
  319. package/src/task-dispatcher.ts +1 -1
  320. package/src/teams-config-store.ts +4 -3
  321. package/src/token-db-write.ts +10 -0
  322. package/src/workspace-command-settle.ts +2 -1
  323. package/src/workspace-steward-wake.ts +2 -2
  324. package/node_modules/@humwick/kernel/LICENSE +0 -167
  325. package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
  326. package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
  327. package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
  328. package/node_modules/@humwick/kernel/config.ts +0 -111
  329. package/node_modules/@humwick/kernel/contract.ts +0 -572
  330. package/node_modules/@humwick/kernel/control-authz.ts +0 -281
  331. package/node_modules/@humwick/kernel/control.ts +0 -645
  332. package/node_modules/@humwick/kernel/effects.ts +0 -493
  333. package/node_modules/@humwick/kernel/event-log.ts +0 -319
  334. package/node_modules/@humwick/kernel/http-transport.ts +0 -384
  335. package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
  336. package/node_modules/@humwick/kernel/identity.ts +0 -248
  337. package/node_modules/@humwick/kernel/index.ts +0 -28
  338. package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
  339. package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
  340. package/node_modules/@humwick/kernel/landing.ts +0 -953
  341. package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
  342. package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
  343. package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
  344. package/node_modules/@humwick/kernel/message-authority.ts +0 -281
  345. package/node_modules/@humwick/kernel/module-host.ts +0 -722
  346. package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
  347. package/node_modules/@humwick/kernel/package.json +0 -39
  348. package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
  349. package/node_modules/@humwick/kernel/persistence.ts +0 -510
  350. package/node_modules/@humwick/kernel/registry.ts +0 -60
  351. package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
  352. package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
  353. package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
  354. package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
  355. package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
  356. package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
  357. package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
  358. package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
  359. package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
  360. package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
  361. package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
  362. package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
  363. package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
  364. package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
  365. package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
  366. package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
  367. package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
  368. package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
  369. package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
  370. package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
  371. package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
  372. package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
  373. package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
  374. package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
  375. package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
  376. package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
  377. package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
  378. package/node_modules/@humwick/offload/LICENSE +0 -167
  379. package/node_modules/@humwick/offload/README.md +0 -57
  380. package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
  381. package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
  382. package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
  383. package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
  384. package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
  385. package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
  386. package/node_modules/@humwick/offload/dist/envelope.js +0 -80
  387. package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
  388. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
  389. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
  390. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
  391. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
  392. package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
  393. package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
  394. package/node_modules/@humwick/offload/dist/index.js +0 -5
  395. package/node_modules/@humwick/offload/dist/index.js.map +0 -1
  396. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
  397. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
  398. package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
  399. package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
  400. package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
  401. package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
  402. package/node_modules/@humwick/offload/dist/types.js +0 -176
  403. package/node_modules/@humwick/offload/dist/types.js.map +0 -1
  404. package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
  405. package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
  406. package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
  407. package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
  408. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
  409. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
  410. package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
  411. package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
  412. package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
  413. package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
  414. package/node_modules/@humwick/offload/dist/worker.js +0 -1
  415. package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
  416. package/node_modules/@humwick/offload/package.json +0 -42
  417. package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
  418. package/node_modules/@humwick/offload/src/envelope.ts +0 -92
  419. package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
  420. package/node_modules/@humwick/offload/src/index.ts +0 -4
  421. package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
  422. package/node_modules/@humwick/offload/src/types.ts +0 -235
  423. package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
  424. package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
  425. package/node_modules/@humwick/offload/src/worker.ts +0 -5
  426. package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
  427. package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
  428. package/public/assets/index-B7ZerHLY.css +0 -2
  429. package/public/assets/index-BU3uWo2t.js +0 -15
  430. package/public/assets/projects-B_lmcqfO.js +0 -2
  431. package/public/assets/provider-display-DbLWpP3j.js +0 -2
  432. package/public/assets/run-card-CO_bguQf.js +0 -2
  433. package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
  434. package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
  435. package/runner/src/gate-run-lease-probe.ts +0 -38
  436. package/src/db/claude-catalog-reconcile.ts +0 -27
  437. package/src/routing-model-aliases.ts +0 -21
@@ -1,167 +0,0 @@
1
- import { z } from "zod";
2
- import { OpError, type ModuleCtx } from "./contract";
3
- import { actionKind } from "./workflow-lane";
4
- import { parkDecision, rootRun, valueContext } from "./workflow-composition";
5
- import { itemResult, settleDependents } from "./workflow-container";
6
- import { waitTimeoutMs } from "./workflow-definition";
7
- import { workflowActivationSchema, type WorkflowActivation } from "./workflow-activation";
8
- import { ADMIN_GRANT, SIGNAL_TOPIC, stores, requireRun, usedEffects, type WorkflowRunRecord } from "./workflow-state";
9
-
10
- async function continueAncestors(ctx: ModuleCtx, run: WorkflowRunRecord | undefined, generation: number): Promise<void> {
11
- while (run) {
12
- await stores(ctx).run.update(run.id, { status: "running", reason: undefined, escalation: undefined, decisionChildRunId: undefined, generation });
13
- if (run.activationId) await stores(ctx).activation.update(run.activationId, { state: "waiting", error: undefined, generation });
14
- run = run.parentRunId ? await requireRun(ctx, run.parentRunId) : undefined;
15
- }
16
- }
17
-
18
- export async function resumeContainer(ctx: ModuleCtx, run: WorkflowRunRecord): Promise<boolean> {
19
- if (run.status !== "escalated" || run.awaiting?.kind !== "for-each") return false;
20
- const root = await rootRun(ctx, run);
21
- const deadline = ctx.clock.now() + waitTimeoutMs(run.definition, run.step);
22
- await stores(ctx).run.update(run.id, { awaiting: { ...run.awaiting, deadline } });
23
- await stores(ctx).activation.update(run.activationId!, { deadline });
24
- await continueAncestors(ctx, run, (root.generation ?? 0) + 1);
25
- return true;
26
- }
27
-
28
- export async function retryItem(ctx: ModuleCtx, run: WorkflowRunRecord, activationId: string | undefined): Promise<void> {
29
- const slot = await stores(ctx).activation.get(run.id);
30
- if (!slot?.parentId || activationId !== slot.id) throw new OpError("invalid_input", 400, "select the failed activationId to explicitly retry its work");
31
- const container = (await stores(ctx).activation.get(slot.parentId))!;
32
- const counts = container.container!;
33
- const root = await rootRun(ctx, run);
34
- if (root.budget!.activations >= (root.limits?.activations ?? 4096)) throw new OpError("conflict", 409, "ACTIVATION_LIMIT: retry budget exhausted");
35
- const used = await usedEffects(ctx, run);
36
- await stores(ctx).activation.update(slot.id, { state: "ready", active: true, attempt: slot.attempt + 1, outcome: undefined, outputs: undefined, error: undefined, childRunId: undefined,
37
- lane: { status: "running", waitSeq: used.seq, round: slot.attempt + 1 }, generation: (root.generation ?? 0) + 1 });
38
- await stores(ctx).activation.update(container.id, { state: "waiting", scheduling: true, container: { ...counts, stopped: counts.failed > 1, decision: false, live: counts.live + 1, settled: counts.settled - 1, failed: counts.failed - 1 } });
39
- await stores(ctx).run.update(root.id, { budget: { ...root.budget!, activations: root.budget!.activations + 1 } });
40
- await continueAncestors(ctx, run.parentRunId ? await requireRun(ctx, run.parentRunId) : undefined, (root.generation ?? 0) + 1);
41
- await ctx.workflows.start("run", { runId: slot.id }, { idempotencyKey: `${slot.id}:retry:${slot.attempt + 1}`, enlist: "op-commit" });
42
- }
43
-
44
- async function slots(ctx: ModuleCtx, id: string, where: Partial<WorkflowActivation> = {}): Promise<WorkflowActivation[]> {
45
- const rows: WorkflowActivation[] = [];
46
- let cursor: string | undefined;
47
- do {
48
- const page = await stores(ctx).activation.list({ where: { parentId: id, ...where }, limit: 200, ...(cursor ? { cursor } : {}) });
49
- rows.push(...page.items); cursor = page.cursor;
50
- } while (cursor);
51
- return rows;
52
- }
53
-
54
- async function tickContainer(ctx: ModuleCtx, container: WorkflowActivation, admit: boolean): Promise<{ admitted: boolean; cancel: string[] }> {
55
- const run = await requireRun(ctx, container.parentId ? container.id : container.runId);
56
- const root = await rootRun(ctx, run);
57
- const loop = run.definition.steps[run.step]?.forEach;
58
- if (!loop || run.activationId !== container.id || !container.container) {
59
- await stores(ctx).activation.update(container.id, { scheduling: false });
60
- return { admitted: false, cancel: [] };
61
- }
62
- const counts = { ...container.container };
63
- if (!run.cancel && !root.cancel && root.status === "running" && run.status === "running" && container.deadline !== undefined && ctx.clock.now() >= container.deadline) {
64
- await parkDecision(ctx, run, run, `CONTAINER_TIMEOUT: ${container.path} exceeded ${container.deadline}`);
65
- return { admitted: false, cancel: [] };
66
- }
67
- const items = await slots(ctx, container.id, { active: true });
68
- const cancel: string[] = [];
69
- for (const slot of items) {
70
- if (!slot.lane || slot.lane.counted === true) continue;
71
- const status = slot.lane.status;
72
- if (status !== "done" && status !== "failed" && status !== "cancelled") continue;
73
- if (status === "cancelled" && (slot.lane.cleanup as { status?: string } | undefined)?.status !== "complete") continue;
74
- const failed = status === "failed";
75
- if (status === "done" && loop.join === "any" && !counts.winner && slot.outcome !== "skipped") counts.winner = slot.key ?? String(slot.index);
76
- slot.state = status === "done" ? slot.outcome === "skipped" ? "skipped" : "succeeded" : status;
77
- slot.outcome = status === "done" ? slot.state === "skipped" ? "skipped" : "complete" : status;
78
- if (failed) slot.error ??= { code: "ITEM_FAILED", message: slot.lane.reason };
79
- slot.lane = { ...slot.lane, counted: true };
80
- await stores(ctx).activation.update(slot.id, { active: false, state: slot.state, outcome: slot.outcome, error: slot.error, lane: slot.lane });
81
- counts.live--; counts.settled++; if (failed) counts.failed++;
82
- if (status === "done" && slot.state !== "skipped") await settleDependents(ctx, slot, false);
83
- else if (slot.state === "skipped" || loop.onFailure === "continue") counts.settled += await settleDependents(ctx, slot, true);
84
- if (failed && loop.onFailure !== "continue") counts.stopped = true;
85
- if (failed && loop.onFailure === "escalate" && !counts.decision) {
86
- await parkDecision(ctx, await requireRun(ctx, slot.id), run, `ITEM_FAILED: ${slot.path}; explicitly retry this slot or cancel the group`);
87
- counts.decision = true;
88
- }
89
- }
90
- if (counts.failed && loop.onFailure === "escalate" && !counts.decision && !items.some(slot => slot.attempt > 1 && slot.lane?.counted !== true)) {
91
- const unresolved = (await slots(ctx, container.id, { state: "failed" }))[0];
92
- if (unresolved) {
93
- await parkDecision(ctx, await requireRun(ctx, unresolved.id), run, `ITEM_FAILED: ${unresolved.path}; explicitly retry this slot or cancel the group`);
94
- counts.stopped = true; counts.decision = true;
95
- }
96
- }
97
- const stopping = Boolean(counts.winner || root.cancel || run.cancel || (counts.stopped && loop.onFailure === "fail-fast"));
98
- if (stopping) {
99
- counts.stopped = true;
100
- for (const slot of [...await slots(ctx, container.id, { state: "pending" }), ...await slots(ctx, container.id, { state: "ready" })].filter(slot => !slot.active)) { await stores(ctx).activation.update(slot.id, { state: "skipped", outcome: "skipped", ...(counts.winner ? { error: { code: "JOIN_LOST", winner: counts.winner } } : {}) }); counts.settled++; }
101
- for (const slot of items) if (slot.lane?.counted !== true && slot.lane) {
102
- if (counts.winner) await stores(ctx).activation.update(slot.id, { error: { code: "JOIN_LOST", winner: counts.winner } });
103
- cancel.push(slot.id);
104
- }
105
- counts.next = counts.total;
106
- }
107
- let admitted = false;
108
- if (admit && !counts.stopped && !root.cancel && root.status === "running" && run.status === "running" && counts.live < loop.concurrency && counts.next < counts.total) {
109
- const slot = (await stores(ctx).activation.list({ where: { parentId: container.id, state: "ready", active: false }, limit: 1 })).items[0]
110
- ?? (await stores(ctx).activation.list({ where: { parentId: container.id, state: "pending" }, limit: 1 })).items.find(slot => slot.remaining === undefined);
111
- if (slot) {
112
- await stores(ctx).activation.update(slot.id, { state: "running", active: true, lane: { status: "running" } });
113
- await ctx.workflows.start("run", { runId: slot.id }, { idempotencyKey: slot.id, enlist: "op-commit" });
114
- counts.next++; counts.live++; admitted = true;
115
- }
116
- }
117
- await stores(ctx).activation.update(container.id, { container: counts });
118
- if (stopping && counts.live === 0) await stores(ctx).activation.update(container.id, { scheduling: false });
119
- // A parked decision retains its original wait even when every item has settled.
120
- if (!counts.decision && counts.settled === counts.total && run.status === "running" && !run.cancel && run.awaiting?.kind === "for-each" && !await stores(ctx).signal.get(run.awaiting.key)) {
121
- const results = (await slots(ctx, container.id)).map(itemResult);
122
- const ok = loop.join === "any" ? counts.winner !== undefined : counts.failed === 0;
123
- const base = { ok, ...(counts.winner ? { winner: counts.winner } : {}), resultsRef: container.id };
124
- const complete = { ...base, results: loop.branches ? Object.fromEntries(results.map(result => [result.key, result])) : results };
125
- const outputs = new TextEncoder().encode(JSON.stringify(complete)).length <= 65536 ? complete : base;
126
- const outcome = loop.join === "any" ? ok ? "complete" : "failed" : counts.failed && loop.onFailure !== "continue" ? "failed" : "complete";
127
- await stores(ctx).signal.create({ id: run.awaiting.key, runId: run.id, kind: "for-each", payload: { outcome, outputs }, createdAt: ctx.clock.now() });
128
- await stores(ctx).activation.update(container.id, { scheduling: false });
129
- await ctx.events.emit(SIGNAL_TOPIC, { runId: run.id, correlationId: run.awaiting.key });
130
- }
131
- return { admitted, cancel };
132
- }
133
-
134
- export const foreachOps = {
135
- tickItems: {
136
- kind: "mutation", idempotent: true, grant: ADMIN_GRANT, summary: "Settle item slots and fairly admit a bounded batch across containers.", expose: { http: false, mcp: false, cli: false },
137
- input: z.object({}), output: z.object({ admitted: z.number(), cancel: z.array(z.string()) }),
138
- handler: async (ctx: ModuleCtx) => {
139
- const cursor = await stores(ctx).admission.get("foreach");
140
- const page = await stores(ctx).activation.list({ where: { scheduling: true }, limit: 50, ...(cursor?.cursor ? { cursor: cursor.cursor } : {}) });
141
- let admitted = 0;
142
- const cancel: string[] = [];
143
- for (const container of page.items) {
144
- const tick = await tickContainer(ctx, container, true);
145
- admitted += Number(tick.admitted); cancel.push(...tick.cancel);
146
- }
147
- if (cursor) await stores(ctx).admission.update(cursor.id, { cursor: page.cursor });
148
- else await stores(ctx).admission.create({ id: "foreach", cursor: page.cursor });
149
- return { admitted, cancel };
150
- },
151
- },
152
- itemLanes: {
153
- kind: "query", grant: ADMIN_GRANT, summary: "Page active item lanes for ordinary wait reconciliation.", expose: { http: false, mcp: false, cli: false },
154
- input: z.object({ runId: z.string().optional(), containerId: z.string().optional(), cursor: z.string().optional() }), output: z.object({ items: z.array(workflowActivationSchema), cursor: z.string().optional() }),
155
- handler: async (ctx: ModuleCtx, input: { runId?: string; containerId?: string; cursor?: string }) => stores(ctx).activation.list({ where: { active: true, ...(input.runId ? { runId: input.runId } : {}), ...(input.containerId ? { parentId: input.containerId } : {}) }, limit: 100, ...(input.cursor ? { cursor: input.cursor } : {}) }),
156
- },
157
- itemResults: {
158
- kind: "query", grant: ADMIN_GRANT, summary: "Page input-ordered item results from a container reference.", expose: { http: false, mcp: false, cli: false },
159
- input: z.object({ runId: z.string(), resultsRef: z.string(), cursor: z.string().optional() }), output: z.object({ items: z.array(z.record(z.string(), z.unknown())), cursor: z.string().optional() }),
160
- handler: async (ctx: ModuleCtx, input: { runId: string; resultsRef: string; cursor?: string }) => {
161
- const container = await stores(ctx).activation.get(input.resultsRef);
162
- if (!container || container.runId !== input.runId || !container.container) throw new OpError("not_found", 404, "item collection not found");
163
- const page = await stores(ctx).activation.list({ where: { parentId: container.id }, limit: 100, ...(input.cursor ? { cursor: input.cursor } : {}) });
164
- return { items: page.items.map(itemResult), ...(page.cursor ? { cursor: page.cursor } : {}) };
165
- },
166
- },
167
- } as const;
@@ -1,339 +0,0 @@
1
- import { isDeepStrictEqual } from "node:util";
2
- import type { WorkflowInstanceRow, WorkflowStepJournalRow } from "./workflow-journal";
3
-
4
- /**
5
- * Strict durable-journal codecs + the step-journal fold, re-homed into the kernel from
6
- * `src/db/workflow-journal.ts` (epic #1408 / M1). These are the pure functions that validate and
7
- * serialize journal rows and reconstruct an instance's resume state from its immutable journal;
8
- * the DB-bound helpers that used the `src/` connection singleton stay in `src/` and now delegate
9
- * here through the strangler re-export. The kernel never imports `src/`, so the two small SDK
10
- * helpers this logic relied on (`isRecord`, `errMessage`) are inlined below.
11
- */
12
-
13
- /** True for a non-null, non-array object (inlined from `@humwick/sdk`). */
14
- function isRecord(value: unknown): value is Record<string, unknown> {
15
- return typeof value === "object" && value !== null && !Array.isArray(value);
16
- }
17
-
18
- /** Human-readable message from any thrown value (inlined from `@humwick/sdk`). */
19
- function errMessage(error: unknown): string {
20
- return error instanceof Error ? error.message : String(error);
21
- }
22
-
23
- export const WORKFLOW_INSTANCE_STATUSES = [
24
- "pending", "running", "sleeping", "waiting", "done", "failed", "canceled",
25
- ] as const;
26
- export type WorkflowInstanceStatus = typeof WORKFLOW_INSTANCE_STATUSES[number];
27
- export type WorkflowAttemptOutcome = "completed" | "failed";
28
- export type WorkflowWaitCondition = Record<string, unknown>;
29
-
30
- /** The camelCase, decoded view of a `workflow_instances` row. */
31
- export interface WorkflowInstance {
32
- id: string;
33
- moduleName: string;
34
- workflowName: string;
35
- idempotencyKey: string;
36
- input: unknown;
37
- initialState: unknown;
38
- startStep: string;
39
- status: WorkflowInstanceStatus;
40
- sleepUntil?: number;
41
- waitFor?: WorkflowWaitCondition;
42
- output?: unknown;
43
- failure?: unknown;
44
- journalCursor: number;
45
- journalPrunedThrough: number;
46
- executorLeaseOwner?: string;
47
- executorLeaseToken?: string;
48
- executorLeaseVersion: number;
49
- executorLeaseAcquiredAt?: number;
50
- executorLeaseExpiresAt?: number;
51
- createdAt: number;
52
- updatedAt: number;
53
- closedAt?: number;
54
- retentionUntil?: number;
55
- }
56
-
57
- /** The decoded shape of a memoized step result stored in `workflow_step_journal.result`. */
58
- export interface WorkflowStepResult {
59
- state: unknown;
60
- next: string;
61
- output?: unknown;
62
- sleepUntil?: number;
63
- waitFor?: WorkflowWaitCondition;
64
- }
65
-
66
- /** The camelCase, decoded view of an immutable `workflow_step_journal` attempt row. */
67
- export interface WorkflowJournalRecord {
68
- instanceId: string;
69
- seq: number;
70
- stepIndex: number;
71
- stepName: string;
72
- attempt: number;
73
- outcome: WorkflowAttemptOutcome;
74
- stateSnapshot: unknown;
75
- result: unknown;
76
- sleepUntil?: number;
77
- waitFor?: WorkflowWaitCondition;
78
- startedAt: number;
79
- completedAt: number;
80
- }
81
-
82
- export type WorkflowResumeStatus = "ready" | "sleeping" | "waiting" | "done" | "failed" | "canceled";
83
-
84
- /** Where a folded journal says execution resumes, and the state it resumes with. */
85
- export interface WorkflowResumePoint {
86
- instanceId: string;
87
- status: WorkflowResumeStatus;
88
- state: unknown;
89
- stepIndex: number;
90
- stepName?: string;
91
- nextAttempt: number;
92
- completedSteps: number;
93
- cursor: number;
94
- sleepUntil?: number;
95
- waitFor?: WorkflowWaitCondition;
96
- output?: unknown;
97
- failure?: unknown;
98
- }
99
-
100
- /** Raised when durable journal state is malformed; replay must fail loudly, never invent state. */
101
- export class WorkflowJournalCorruptionError extends Error {
102
- constructor(message: string) {
103
- super(`workflow journal corruption: ${message}`);
104
- this.name = "WorkflowJournalCorruptionError";
105
- }
106
- }
107
-
108
- /** Serialize with a lossless round-trip guard; throws for non-JSON-safe values. */
109
- export function encodeJson(value: unknown, label: string): string {
110
- try {
111
- const encoded = JSON.stringify(value);
112
- if (encoded === undefined) throw new TypeError("value is not JSON-serializable");
113
- if (!isDeepStrictEqual(JSON.parse(encoded), value)) throw new TypeError("value changes during JSON encoding");
114
- return encoded;
115
- } catch (error) {
116
- throw new TypeError(`${label} must be JSON-serializable: ${errMessage(error)}`);
117
- }
118
- }
119
-
120
- /** Parse durable JSON, converting a parse failure into a loud corruption error. */
121
- export function decodeJson(raw: string, label: string): unknown {
122
- try {
123
- return JSON.parse(raw);
124
- } catch {
125
- throw new WorkflowJournalCorruptionError(`${label} is not valid JSON`);
126
- }
127
- }
128
-
129
- function decodeWaitCondition(value: unknown, label: string): WorkflowWaitCondition {
130
- if (!isRecord(value)) throw new WorkflowJournalCorruptionError(`${label} must be a JSON object`);
131
- return value;
132
- }
133
-
134
- /** Strict decode of a memoized step result: a JSON object with state + a non-empty `next`. */
135
- export function decodeStepResult(value: unknown, label: string): WorkflowStepResult {
136
- if (!isRecord(value) || !("state" in value) || typeof value.next !== "string" || value.next.length === 0) {
137
- throw new WorkflowJournalCorruptionError(`${label} must contain a state and non-empty next step`);
138
- }
139
- if (value.sleepUntil !== undefined && (typeof value.sleepUntil !== "number" || !Number.isFinite(value.sleepUntil))) {
140
- throw new WorkflowJournalCorruptionError(`${label}.sleepUntil must be a finite number`);
141
- }
142
- const waitFor = value.waitFor === undefined ? undefined : decodeWaitCondition(value.waitFor, `${label}.waitFor`);
143
- if (value.sleepUntil !== undefined && waitFor !== undefined) {
144
- throw new WorkflowJournalCorruptionError(`${label} cannot contain both sleepUntil and waitFor`);
145
- }
146
- if (value.next === "done" && (value.sleepUntil !== undefined || waitFor !== undefined)) {
147
- throw new WorkflowJournalCorruptionError(`${label} cannot schedule work after next=done`);
148
- }
149
- return {
150
- state: value.state,
151
- next: value.next,
152
- ...(Object.hasOwn(value, "output") ? { output: value.output } : {}),
153
- ...(value.sleepUntil !== undefined ? { sleepUntil: value.sleepUntil } : {}),
154
- ...(waitFor !== undefined ? { waitFor } : {}),
155
- };
156
- }
157
-
158
- /** Strict row codec: durable replay must fail loudly rather than invent state from malformed JSON. */
159
- export function workflowInstanceFromRow(row: WorkflowInstanceRow): WorkflowInstance {
160
- if (!WORKFLOW_INSTANCE_STATUSES.includes(row.status as WorkflowInstanceStatus)) {
161
- throw new WorkflowJournalCorruptionError(`instance ${row.id} has unknown status ${row.status}`);
162
- }
163
- if (![row.journal_cursor, row.journal_pruned_through, row.executor_lease_version].every(Number.isSafeInteger)
164
- || row.journal_cursor < 0 || row.journal_pruned_through < 0 || row.journal_pruned_through > row.journal_cursor
165
- || row.executor_lease_version < 0) {
166
- throw new WorkflowJournalCorruptionError(`instance ${row.id} has invalid journal/lease cursors`);
167
- }
168
- const waitForValue = row.wait_for === null ? undefined : decodeWaitCondition(decodeJson(row.wait_for, `instance ${row.id} wait_for`), `instance ${row.id} wait_for`);
169
- return {
170
- id: row.id,
171
- moduleName: row.module_name,
172
- workflowName: row.workflow_name,
173
- idempotencyKey: row.idempotency_key,
174
- input: decodeJson(row.input, `instance ${row.id} input`),
175
- initialState: decodeJson(row.initial_state, `instance ${row.id} initial_state`),
176
- startStep: row.start_step,
177
- status: row.status as WorkflowInstanceStatus,
178
- ...(row.sleep_until !== null ? { sleepUntil: row.sleep_until } : {}),
179
- ...(waitForValue !== undefined ? { waitFor: waitForValue } : {}),
180
- ...(row.output !== null ? { output: decodeJson(row.output, `instance ${row.id} output`) } : {}),
181
- ...(row.failure !== null ? { failure: decodeJson(row.failure, `instance ${row.id} failure`) } : {}),
182
- journalCursor: row.journal_cursor,
183
- journalPrunedThrough: row.journal_pruned_through,
184
- ...(row.executor_lease_owner !== null ? { executorLeaseOwner: row.executor_lease_owner } : {}),
185
- ...(row.executor_lease_token !== null ? { executorLeaseToken: row.executor_lease_token } : {}),
186
- executorLeaseVersion: row.executor_lease_version,
187
- ...(row.executor_lease_acquired_at !== null ? { executorLeaseAcquiredAt: row.executor_lease_acquired_at } : {}),
188
- ...(row.executor_lease_expires_at !== null ? { executorLeaseExpiresAt: row.executor_lease_expires_at } : {}),
189
- createdAt: row.created_at,
190
- updatedAt: row.updated_at,
191
- ...(row.closed_at !== null ? { closedAt: row.closed_at } : {}),
192
- ...(row.retention_until !== null ? { retentionUntil: row.retention_until } : {}),
193
- };
194
- }
195
-
196
- /** Strict codec for the immutable per-attempt journal row. */
197
- export function workflowJournalRecordFromRow(row: WorkflowStepJournalRow): WorkflowJournalRecord {
198
- if (row.outcome !== "completed" && row.outcome !== "failed") {
199
- throw new WorkflowJournalCorruptionError(`instance ${row.instance_id} seq ${row.seq} has unknown outcome ${row.outcome}`);
200
- }
201
- if (![row.seq, row.step_index, row.attempt, row.started_at, row.completed_at].every(Number.isSafeInteger)
202
- || row.seq < 1 || row.step_index < 0 || row.attempt < 1 || row.completed_at < row.started_at) {
203
- throw new WorkflowJournalCorruptionError(`instance ${row.instance_id} has invalid journal coordinates`);
204
- }
205
- const label = `instance ${row.instance_id} seq ${row.seq}`;
206
- const stateSnapshot = decodeJson(row.state_snapshot, `${label} state_snapshot`);
207
- const result = decodeJson(row.result, `${label} result`);
208
- const waitFor = row.wait_for === null ? undefined : decodeWaitCondition(decodeJson(row.wait_for, `${label} wait_for`), `${label} wait_for`);
209
- if (row.outcome === "completed") {
210
- const completed = decodeStepResult(result, `${label} result`);
211
- if (!isDeepStrictEqual(completed.state, stateSnapshot)) {
212
- throw new WorkflowJournalCorruptionError(`${label} state_snapshot does not match result.state`);
213
- }
214
- if ((completed.sleepUntil ?? null) !== row.sleep_until || !isDeepStrictEqual(completed.waitFor, waitFor)) {
215
- throw new WorkflowJournalCorruptionError(`${label} timer/wait columns do not match result`);
216
- }
217
- } else if (row.sleep_until !== null || waitFor !== undefined) {
218
- throw new WorkflowJournalCorruptionError(`${label} failed attempt cannot schedule a timer or wait`);
219
- }
220
- return {
221
- instanceId: row.instance_id,
222
- seq: row.seq,
223
- stepIndex: row.step_index,
224
- stepName: row.step_name,
225
- attempt: row.attempt,
226
- outcome: row.outcome,
227
- stateSnapshot,
228
- result,
229
- ...(row.sleep_until !== null ? { sleepUntil: row.sleep_until } : {}),
230
- ...(waitFor !== undefined ? { waitFor } : {}),
231
- startedAt: row.started_at,
232
- completedAt: row.completed_at,
233
- };
234
- }
235
-
236
- /** Fold a complete immutable journal into the exact step/attempt at which execution resumes. */
237
- export function foldWorkflowJournal(instance: WorkflowInstance, records: WorkflowJournalRecord[]): WorkflowResumePoint {
238
- if (instance.journalPrunedThrough > 0) {
239
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} was pruned through seq ${instance.journalPrunedThrough}`);
240
- }
241
- let state = instance.initialState;
242
- let stepName = instance.startStep;
243
- let stepIndex = 0;
244
- let nextAttempt = 1;
245
- let status: WorkflowResumeStatus = "ready";
246
- let sleepUntil: number | undefined;
247
- let waitFor: WorkflowWaitCondition | undefined;
248
- let output: unknown;
249
- let hasOutput = false;
250
-
251
- for (let index = 0; index < records.length; index += 1) {
252
- const record = records[index]!;
253
- const expectedSeq = index + 1;
254
- if (record.instanceId !== instance.id || record.seq !== expectedSeq) {
255
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} expected seq ${expectedSeq}`);
256
- }
257
- if (record.stepIndex !== stepIndex || record.stepName !== stepName || record.attempt !== nextAttempt) {
258
- throw new WorkflowJournalCorruptionError(
259
- `instance ${instance.id} seq ${record.seq} expected step ${stepIndex}:${stepName} attempt ${nextAttempt}`,
260
- );
261
- }
262
- // Seeing an attempt proves any timer/wait before this step was satisfied.
263
- status = "ready";
264
- sleepUntil = undefined;
265
- waitFor = undefined;
266
- if (record.outcome === "failed") {
267
- if (!isDeepStrictEqual(record.stateSnapshot, state)) {
268
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} seq ${record.seq} failed attempt changed state`);
269
- }
270
- nextAttempt += 1;
271
- continue;
272
- }
273
- const result = decodeStepResult(record.result, `instance ${instance.id} seq ${record.seq} result`);
274
- if (!isDeepStrictEqual(result.state, record.stateSnapshot)) {
275
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} seq ${record.seq} state snapshot mismatch`);
276
- }
277
- state = record.stateSnapshot;
278
- stepIndex += 1;
279
- nextAttempt = 1;
280
- if (result.next === "done") {
281
- status = "done";
282
- stepName = "";
283
- output = result.output;
284
- hasOutput = Object.hasOwn(result, "output");
285
- if (index !== records.length - 1) throw new WorkflowJournalCorruptionError(`instance ${instance.id} has records after done`);
286
- continue;
287
- }
288
- stepName = result.next;
289
- if (result.sleepUntil !== undefined) {
290
- status = "sleeping";
291
- sleepUntil = result.sleepUntil;
292
- } else if (result.waitFor !== undefined) {
293
- status = "waiting";
294
- waitFor = result.waitFor;
295
- }
296
- }
297
- if (records.length !== instance.journalCursor) {
298
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} cursor ${instance.journalCursor} has ${records.length} records`);
299
- }
300
- if (instance.status === "done" && status !== "done") {
301
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} is done without a terminal checkpoint`);
302
- }
303
- if (instance.status === "failed" || instance.status === "canceled") {
304
- status = instance.status;
305
- } else if (instance.status === "sleeping") {
306
- // The instance row is authoritative for a parked schedule. Two sources land here: a completed
307
- // step whose result carried `sleepUntil` (also reconstructable from the record), AND a retry
308
- // backoff parked after a FAILED attempt — which the immutable journal record cannot itself
309
- // carry (a failed record's timer/wait columns must be null), so its due-time lives only on the
310
- // row. Trusting the row unifies both and keeps the fold's resume schedule correct for retries.
311
- if (instance.sleepUntil === undefined) {
312
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} is sleeping without a sleep_until`);
313
- }
314
- status = "sleeping";
315
- sleepUntil = instance.sleepUntil;
316
- waitFor = undefined;
317
- } else if (instance.status === "waiting") {
318
- if (instance.waitFor === undefined) {
319
- throw new WorkflowJournalCorruptionError(`instance ${instance.id} is waiting without a wait_for`);
320
- }
321
- status = "waiting";
322
- waitFor = instance.waitFor;
323
- sleepUntil = undefined;
324
- }
325
- return {
326
- instanceId: instance.id,
327
- status,
328
- state,
329
- stepIndex,
330
- ...(stepName ? { stepName } : {}),
331
- nextAttempt,
332
- completedSteps: stepIndex,
333
- cursor: instance.journalCursor,
334
- ...(sleepUntil !== undefined ? { sleepUntil } : {}),
335
- ...(waitFor !== undefined ? { waitFor } : {}),
336
- ...(status === "done" && hasOutput ? { output } : {}),
337
- ...(instance.failure !== undefined ? { failure: instance.failure } : {}),
338
- };
339
- }