@atolis-hq/wake 0.2.97 → 0.3.1

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 (443) hide show
  1. package/README.md +5 -5
  2. package/dist/src/activities/agent/agent-activity-definition.js +26 -0
  3. package/dist/src/activities/agent/agent-activity.js +171 -0
  4. package/dist/src/activities/agent/agent-result.js +149 -0
  5. package/dist/src/activities/contracts/activity.js +10 -0
  6. package/dist/src/activities/contracts/config.js +2 -0
  7. package/dist/src/activities/contracts/event-schema.js +302 -0
  8. package/dist/src/activities/contracts/events.js +42 -0
  9. package/dist/src/activities/contracts/identifiers.js +29 -0
  10. package/dist/src/activities/contracts/registry.js +71 -0
  11. package/dist/src/activities/contracts/streams.js +17 -0
  12. package/dist/src/activities/contracts/vocabulary.js +58 -0
  13. package/dist/src/activities/index.js +21 -0
  14. package/dist/src/activities/pr/activity-support.js +111 -0
  15. package/dist/src/activities/pr/application.js +158 -0
  16. package/dist/src/activities/pr/approve.js +85 -0
  17. package/dist/src/activities/pr/capability.js +11 -0
  18. package/dist/src/activities/pr/decision-claim.js +76 -0
  19. package/dist/src/activities/pr/event-drafts.js +66 -0
  20. package/dist/src/activities/pr/intent.js +37 -0
  21. package/dist/src/activities/pr/merge-authority-gate.js +14 -0
  22. package/dist/src/activities/pr/merge.js +110 -0
  23. package/dist/src/activities/pr/policy.js +135 -0
  24. package/dist/src/activities/pr/projection.js +130 -0
  25. package/dist/src/activities/pr/vocabulary.js +30 -0
  26. package/dist/src/activities/review/authorization.js +22 -0
  27. package/dist/src/activities/review/contracts.js +22 -0
  28. package/dist/src/activities/review/signals.js +3 -0
  29. package/dist/src/bootstrap/analytics-projection.js +26 -0
  30. package/dist/src/bootstrap/board-projection.js +337 -0
  31. package/dist/src/bootstrap/composition-root.js +382 -0
  32. package/dist/src/bootstrap/config/load-config.js +51 -0
  33. package/dist/src/bootstrap/config/root-schema.js +134 -0
  34. package/dist/src/bootstrap/external-ref.js +12 -0
  35. package/dist/src/bootstrap/fake-provider-files.js +44 -0
  36. package/dist/src/bootstrap/fake-scenarios.js +22 -0
  37. package/dist/src/bootstrap/index.js +48 -0
  38. package/dist/src/bootstrap/initialise.js +436 -0
  39. package/dist/src/bootstrap/paths.js +15 -0
  40. package/dist/src/bootstrap/projection-runtime.js +27 -0
  41. package/dist/src/bootstrap/runner-quota-reporter.js +21 -0
  42. package/dist/src/bootstrap/runner-registry.js +30 -0
  43. package/dist/src/bootstrap/schedule-checkpoint-store.js +49 -0
  44. package/dist/src/bootstrap/self-update-application.js +195 -0
  45. package/dist/src/bootstrap/self-update-failure-log.js +33 -0
  46. package/dist/src/bootstrap/source-update-port.js +47 -0
  47. package/dist/src/bootstrap/status-publish-activity.js +42 -0
  48. package/dist/src/bootstrap/surface-api-applications.js +325 -0
  49. package/dist/src/bootstrap/surface-api-execution-applications.js +95 -0
  50. package/dist/src/bootstrap/surface-api-metadata.js +12 -0
  51. package/dist/src/bootstrap/surface-api-projection-pages.js +22 -0
  52. package/dist/src/bootstrap/surface-api-run-context.js +5 -0
  53. package/dist/src/bootstrap/surface-api-transcripts.js +57 -0
  54. package/dist/src/bootstrap/surface-api-work-applications.js +199 -0
  55. package/dist/src/bootstrap/surface-applications.js +7 -0
  56. package/dist/src/bootstrap/surface-cli-applications.js +701 -0
  57. package/dist/src/bootstrap/update-ledger.js +61 -0
  58. package/dist/src/bootstrap/update-maintenance-lease.js +176 -0
  59. package/dist/src/{version.js → bootstrap/version.js} +35 -51
  60. package/dist/src/control-plane/application/advance-once.js +184 -0
  61. package/dist/src/control-plane/application/control-plane-projection.js +42 -0
  62. package/dist/src/control-plane/application/control-plane-service.js +42 -0
  63. package/dist/src/control-plane/application/intake-pipeline.js +29 -0
  64. package/dist/src/control-plane/application/runner-control-service.js +66 -0
  65. package/dist/src/control-plane/application/runner-pipeline.js +57 -0
  66. package/dist/src/control-plane/application/schedule-service.js +47 -0
  67. package/dist/src/control-plane/application/work-cancellation-policy.js +31 -0
  68. package/dist/src/control-plane/contracts/commands.js +10 -0
  69. package/dist/src/control-plane/contracts/config.js +22 -0
  70. package/dist/src/control-plane/contracts/events.js +81 -0
  71. package/dist/src/control-plane/contracts/streams.js +5 -0
  72. package/dist/src/control-plane/domain/dispatch-policy.js +15 -0
  73. package/dist/src/control-plane/domain/quota-policy.js +26 -0
  74. package/dist/src/control-plane/domain/runner-quota.js +35 -0
  75. package/dist/src/control-plane/domain/schedule-policy.js +46 -0
  76. package/dist/src/control-plane/index.js +20 -0
  77. package/dist/src/control-plane/infrastructure/intake-host.js +24 -0
  78. package/dist/src/control-plane/infrastructure/resident-host.js +45 -0
  79. package/dist/src/control-plane/infrastructure/tick-host.js +35 -0
  80. package/dist/src/execution/application/activation-claim.js +50 -0
  81. package/dist/src/execution/application/active-run-cancellation.js +14 -0
  82. package/dist/src/execution/application/execution-activity.js +97 -0
  83. package/dist/src/execution/application/execution-projection.js +17 -0
  84. package/dist/src/execution/application/execution-service.js +372 -0
  85. package/dist/src/execution/application/execution-validation.js +26 -0
  86. package/dist/src/execution/application/recovery-service.js +212 -0
  87. package/dist/src/execution/application/run-lifecycle.js +115 -0
  88. package/dist/src/execution/application/run-liveness-service.js +80 -0
  89. package/dist/src/execution/application/run-repository.js +27 -0
  90. package/dist/src/execution/contracts/commands.js +1 -0
  91. package/dist/src/execution/contracts/config.js +35 -0
  92. package/dist/src/execution/contracts/control-plane.js +1 -0
  93. package/dist/src/execution/contracts/event-factory.js +53 -0
  94. package/dist/src/execution/contracts/events.js +274 -0
  95. package/dist/src/execution/contracts/identifiers.js +5 -0
  96. package/dist/src/execution/contracts/liveness.js +1 -0
  97. package/dist/src/execution/contracts/results.js +1 -0
  98. package/dist/src/execution/contracts/runner.js +15 -0
  99. package/dist/src/execution/contracts/streams.js +10 -0
  100. package/dist/src/execution/contracts/views.js +1 -0
  101. package/dist/src/execution/contracts/vocabulary.js +43 -0
  102. package/dist/src/execution/contracts/workspace.js +1 -0
  103. package/dist/src/execution/domain/run-result.js +34 -0
  104. package/dist/src/execution/domain/run.js +142 -0
  105. package/dist/src/execution/index.js +31 -0
  106. package/dist/src/execution/infrastructure/agent-runner-adapter.js +114 -0
  107. package/dist/src/execution/infrastructure/process-execution.js +29 -0
  108. package/dist/src/execution/infrastructure/prompt-templates.js +42 -0
  109. package/dist/src/execution/infrastructure/runners/claude.js +120 -0
  110. package/dist/src/execution/infrastructure/runners/codex.js +143 -0
  111. package/dist/src/execution/infrastructure/runners/command.js +4 -0
  112. package/dist/src/execution/infrastructure/runners/cursor.js +69 -0
  113. package/dist/src/execution/infrastructure/runners/fake-scenarios.js +99 -0
  114. package/dist/src/execution/infrastructure/runners/fake.js +65 -0
  115. package/dist/src/execution/infrastructure/runners/registry.js +26 -0
  116. package/dist/src/execution/infrastructure/transcript-store.js +223 -0
  117. package/dist/src/execution/infrastructure/transcripts.js +11 -0
  118. package/dist/src/execution/infrastructure/workspace/fake-workspace.js +19 -0
  119. package/dist/src/execution/infrastructure/workspace/git-workspace.js +241 -0
  120. package/dist/src/integrations/application/agent-run-publication-reactor.js +111 -0
  121. package/dist/src/integrations/application/artifact-registration-reactor.js +159 -0
  122. package/dist/src/integrations/application/poll-service.js +25 -0
  123. package/dist/src/integrations/application/terminal-agent-run-report.js +40 -0
  124. package/dist/src/integrations/application/work-admission.js +31 -0
  125. package/dist/src/integrations/application/work-conclusion.js +19 -0
  126. package/dist/src/integrations/contracts/artifact-events.js +60 -0
  127. package/dist/src/integrations/contracts/artifact-vocabulary.js +9 -0
  128. package/dist/src/integrations/contracts/config.js +14 -0
  129. package/dist/src/integrations/contracts/identifiers.js +5 -0
  130. package/dist/src/integrations/contracts/intake-rules.js +14 -0
  131. package/dist/src/integrations/contracts/intake.js +1 -0
  132. package/dist/src/integrations/contracts/outcome-vocabulary.js +7 -0
  133. package/dist/src/integrations/contracts/provider.js +37 -0
  134. package/dist/src/integrations/contracts/streams.js +10 -0
  135. package/dist/src/integrations/delivery/application/delivery-outcome-reactor.js +75 -0
  136. package/dist/src/integrations/delivery/application/delivery-projector.js +165 -0
  137. package/dist/src/integrations/delivery/application/delivery-service.js +173 -0
  138. package/dist/src/integrations/delivery/contracts/commands.js +1 -0
  139. package/dist/src/integrations/delivery/contracts/config.js +1 -0
  140. package/dist/src/integrations/delivery/contracts/event-factory.js +18 -0
  141. package/dist/src/integrations/delivery/contracts/events.js +86 -0
  142. package/dist/src/integrations/delivery/contracts/intents.js +89 -0
  143. package/dist/src/integrations/delivery/contracts/views.js +1 -0
  144. package/dist/src/integrations/delivery/contracts/vocabulary.js +22 -0
  145. package/dist/src/integrations/fake/durable-delivery-provider.js +48 -0
  146. package/dist/src/integrations/fake/external-sink.js +9 -0
  147. package/dist/src/integrations/fake/external-source.js +44 -0
  148. package/dist/src/integrations/fake/inbound-translator.js +130 -0
  149. package/dist/src/integrations/fake/provider.js +95 -0
  150. package/dist/src/integrations/github/application/agent-context-reader.js +54 -0
  151. package/dist/src/integrations/github/application/agent-run-comment.js +94 -0
  152. package/dist/src/integrations/github/application/comment-history-reader.js +43 -0
  153. package/dist/src/integrations/github/application/inbound-context.js +10 -0
  154. package/dist/src/integrations/github/application/inbound-review-signals.js +159 -0
  155. package/dist/src/integrations/github/application/inbound-translator.js +231 -0
  156. package/dist/src/integrations/github/application/inbound-watch-gate-signals.js +84 -0
  157. package/dist/src/integrations/github/application/intake-policy.js +23 -0
  158. package/dist/src/integrations/github/application/outbound-translator.js +47 -0
  159. package/dist/src/integrations/github/application/poll-service.js +29 -0
  160. package/dist/src/integrations/github/application/pull-request-translation.js +10 -0
  161. package/dist/src/integrations/github/application/resource-links.js +8 -0
  162. package/dist/src/integrations/github/application/review-command-translator.js +16 -0
  163. package/dist/src/integrations/github/application/wake-labels.js +95 -0
  164. package/dist/src/integrations/github/contracts/config.js +47 -0
  165. package/dist/src/integrations/github/contracts/events.js +127 -0
  166. package/dist/src/integrations/github/contracts/external-key.js +19 -0
  167. package/dist/src/integrations/github/contracts/payloads.js +9 -0
  168. package/dist/src/integrations/github/contracts/vocabulary.js +55 -0
  169. package/dist/src/integrations/github/index.js +31 -0
  170. package/dist/src/integrations/github/infrastructure/client-reads.js +214 -0
  171. package/dist/src/integrations/github/infrastructure/client.js +132 -0
  172. package/dist/src/integrations/github/infrastructure/content-fingerprint.js +10 -0
  173. package/dist/src/integrations/github/infrastructure/delivery.js +31 -0
  174. package/dist/src/integrations/github/infrastructure/etag-cache.js +56 -0
  175. package/dist/src/integrations/github/infrastructure/gh-auth.js +19 -0
  176. package/dist/src/integrations/github/infrastructure/issue-source.js +109 -0
  177. package/dist/src/integrations/github/infrastructure/pr-source.js +186 -0
  178. package/dist/src/integrations/github/infrastructure/review-source.js +70 -0
  179. package/dist/src/integrations/github/infrastructure/source.js +108 -0
  180. package/dist/src/integrations/github/provider.js +96 -0
  181. package/dist/src/integrations/index.js +30 -0
  182. package/dist/src/kernel/contracts/checkpoint-store.js +1 -0
  183. package/dist/src/kernel/contracts/clock.js +1 -0
  184. package/dist/src/kernel/contracts/commands.js +1 -0
  185. package/dist/src/kernel/contracts/event-journal.js +2 -0
  186. package/dist/src/kernel/contracts/event-schema.js +54 -0
  187. package/dist/src/kernel/contracts/events.js +11 -0
  188. package/dist/src/kernel/contracts/id-generator.js +1 -0
  189. package/dist/src/kernel/contracts/identifiers.js +8 -0
  190. package/dist/src/kernel/contracts/projection-store.js +1 -0
  191. package/dist/src/kernel/contracts/relations.js +1 -0
  192. package/dist/src/kernel/contracts/schema.js +17 -0
  193. package/dist/src/kernel/contracts/vocabulary.js +6 -0
  194. package/dist/src/kernel/domain/event-envelope.js +29 -0
  195. package/dist/src/kernel/domain/match-mode.js +11 -0
  196. package/dist/src/kernel/domain/relation.js +10 -0
  197. package/dist/src/kernel/index.js +17 -0
  198. package/dist/src/{lib/clock.js → kernel/infrastructure/system-clock.js} +3 -3
  199. package/dist/src/kernel/infrastructure/ulid-id-generator.js +9 -0
  200. package/dist/src/main.js +137 -1030
  201. package/dist/src/orchestration/application/accept-activity-outcome.js +25 -0
  202. package/dist/src/orchestration/application/accept-signal.js +35 -0
  203. package/dist/src/orchestration/application/advance-workflow.js +160 -0
  204. package/dist/src/orchestration/application/coordination-claims.js +107 -0
  205. package/dist/src/orchestration/application/group-budget-recorder.js +43 -0
  206. package/dist/src/orchestration/application/orchestration-projection.js +20 -0
  207. package/dist/src/orchestration/application/orchestration-repository.js +36 -0
  208. package/dist/src/orchestration/application/orchestration-service.js +82 -0
  209. package/dist/src/orchestration/application/request-child.js +118 -0
  210. package/dist/src/orchestration/application/signal-reactor.js +17 -0
  211. package/dist/src/orchestration/application/start-workflow.js +51 -0
  212. package/dist/src/orchestration/application/watch-reactor.js +82 -0
  213. package/dist/src/orchestration/contracts/activity-outcome.js +18 -0
  214. package/dist/src/orchestration/contracts/commands.js +1 -0
  215. package/dist/src/orchestration/contracts/config.js +128 -0
  216. package/dist/src/orchestration/contracts/event-decoder.js +263 -0
  217. package/dist/src/orchestration/contracts/events.js +41 -0
  218. package/dist/src/orchestration/contracts/identifiers.js +35 -0
  219. package/dist/src/orchestration/contracts/streams.js +38 -0
  220. package/dist/src/orchestration/contracts/views.js +1 -0
  221. package/dist/src/orchestration/contracts/vocabulary.js +30 -0
  222. package/dist/src/orchestration/domain/activation-policy.js +55 -0
  223. package/dist/src/orchestration/domain/approval-defaults.js +17 -0
  224. package/dist/src/orchestration/domain/child-policy.js +63 -0
  225. package/dist/src/orchestration/domain/compiler.js +162 -0
  226. package/dist/src/orchestration/domain/coordination-events.js +25 -0
  227. package/dist/src/orchestration/domain/decision-events.js +47 -0
  228. package/dist/src/orchestration/domain/interpreter.js +49 -0
  229. package/dist/src/orchestration/domain/operator-retry-policy.js +34 -0
  230. package/dist/src/orchestration/domain/retry-policy.js +26 -0
  231. package/dist/src/orchestration/domain/signal-policy.js +120 -0
  232. package/dist/src/orchestration/domain/supplemental-policy.js +61 -0
  233. package/dist/src/orchestration/domain/transition.js +55 -0
  234. package/dist/src/orchestration/domain/workflow-graph.js +41 -0
  235. package/dist/src/orchestration/domain/workflow-instance-events.js +236 -0
  236. package/dist/src/orchestration/domain/workflow-instance.js +41 -0
  237. package/dist/src/orchestration/domain/workflow-selector.js +21 -0
  238. package/dist/src/orchestration/index.js +19 -0
  239. package/dist/src/persistence/application/projection-runner.js +79 -0
  240. package/dist/src/persistence/filesystem/file-checkpoint-store.js +35 -0
  241. package/dist/src/persistence/filesystem/file-event-journal.js +143 -0
  242. package/dist/src/persistence/filesystem/file-lock.js +91 -0
  243. package/dist/src/persistence/filesystem/file-projection-store.js +64 -0
  244. package/dist/src/persistence/index.js +8 -0
  245. package/dist/src/persistence/memory/in-memory-checkpoint-store.js +14 -0
  246. package/dist/src/persistence/memory/in-memory-event-journal.js +88 -0
  247. package/dist/src/persistence/memory/in-memory-projection-store.js +17 -0
  248. package/dist/src/resources/application/lookup-projections.js +48 -0
  249. package/dist/src/resources/application/resource-lookup.js +16 -0
  250. package/dist/src/resources/application/resource-projections.js +81 -0
  251. package/dist/src/resources/application/resource-repository.js +18 -0
  252. package/dist/src/resources/application/resource-service.js +83 -0
  253. package/dist/src/resources/contracts/commands.js +1 -0
  254. package/dist/src/resources/contracts/config.js +2 -0
  255. package/dist/src/resources/contracts/events.js +83 -0
  256. package/dist/src/resources/contracts/identifiers.js +15 -0
  257. package/dist/src/resources/contracts/streams.js +6 -0
  258. package/dist/src/resources/contracts/views.js +1 -0
  259. package/dist/src/resources/contracts/vocabulary.js +67 -0
  260. package/dist/src/resources/domain/correlation.js +8 -0
  261. package/dist/src/resources/domain/resource.js +58 -0
  262. package/dist/src/resources/index.js +14 -0
  263. package/dist/src/surfaces/api/contracts/activities.js +1 -0
  264. package/dist/src/surfaces/api/contracts/board.js +2 -0
  265. package/dist/src/surfaces/api/contracts/common.js +46 -0
  266. package/dist/src/surfaces/api/contracts/control-plane.js +5 -0
  267. package/dist/src/surfaces/api/contracts/events.js +1 -0
  268. package/dist/src/surfaces/api/contracts/execution.js +1 -0
  269. package/dist/src/surfaces/api/contracts/index.js +13 -0
  270. package/dist/src/surfaces/api/contracts/observability.js +1 -0
  271. package/dist/src/surfaces/api/contracts/orchestration.js +1 -0
  272. package/dist/src/surfaces/api/contracts/resources.js +1 -0
  273. package/dist/src/surfaces/api/contracts/status.js +1 -0
  274. package/dist/src/surfaces/api/contracts/system.js +1 -0
  275. package/dist/src/surfaces/api/contracts/transport-values.js +39 -0
  276. package/dist/src/surfaces/api/contracts/work.js +17 -0
  277. package/dist/src/surfaces/api/http-server.js +121 -0
  278. package/dist/src/surfaces/api/presenters/activities.js +1 -0
  279. package/dist/src/surfaces/api/presenters/board.js +3 -0
  280. package/dist/src/surfaces/api/presenters/control-plane.js +1 -0
  281. package/dist/src/surfaces/api/presenters/events.js +1 -0
  282. package/dist/src/surfaces/api/presenters/execution.js +59 -0
  283. package/dist/src/surfaces/api/presenters/observability.js +1 -0
  284. package/dist/src/surfaces/api/presenters/orchestration.js +19 -0
  285. package/dist/src/surfaces/api/presenters/resources.js +15 -0
  286. package/dist/src/surfaces/api/presenters/status.js +3 -0
  287. package/dist/src/surfaces/api/presenters/system.js +14 -0
  288. package/dist/src/surfaces/api/presenters/work.js +16 -0
  289. package/dist/src/surfaces/api/problem-details.js +9 -0
  290. package/dist/src/surfaces/api/router.js +13 -0
  291. package/dist/src/surfaces/api/routes/activities.js +1 -0
  292. package/dist/src/surfaces/api/routes/applications.js +1 -0
  293. package/dist/src/surfaces/api/routes/commands.js +82 -0
  294. package/dist/src/surfaces/api/routes/control-plane.js +6 -0
  295. package/dist/src/surfaces/api/routes/events.js +1 -0
  296. package/dist/src/surfaces/api/routes/execution.js +8 -0
  297. package/dist/src/surfaces/api/routes/index.js +18 -0
  298. package/dist/src/surfaces/api/routes/observability.js +1 -0
  299. package/dist/src/surfaces/api/routes/orchestration.js +1 -0
  300. package/dist/src/surfaces/api/routes/pagination.js +78 -0
  301. package/dist/src/surfaces/api/routes/read.js +135 -0
  302. package/dist/src/surfaces/api/routes/resources.js +1 -0
  303. package/dist/src/surfaces/api/routes/responses.js +67 -0
  304. package/dist/src/surfaces/api/routes/system.js +1 -0
  305. package/dist/src/surfaces/api/routes/work.js +9 -0
  306. package/dist/src/surfaces/cli/commands/api.js +1 -0
  307. package/dist/src/surfaces/cli/commands/audit.js +10 -0
  308. package/dist/src/surfaces/cli/commands/correlate.js +2 -0
  309. package/dist/src/surfaces/cli/commands/doctor.js +6 -0
  310. package/dist/src/surfaces/cli/commands/init.js +39 -0
  311. package/dist/src/surfaces/cli/commands/sandbox-entrypoint.js +33 -0
  312. package/dist/src/surfaces/cli/commands/sandbox-setup.js +29 -0
  313. package/dist/src/surfaces/cli/commands/sandbox.js +105 -0
  314. package/dist/src/surfaces/cli/commands/self-update.js +38 -0
  315. package/dist/src/surfaces/cli/commands/smoke.js +16 -0
  316. package/dist/src/surfaces/cli/commands/start.js +1 -0
  317. package/dist/src/surfaces/cli/commands/stop.js +13 -0
  318. package/dist/src/surfaces/cli/commands/tick.js +1 -0
  319. package/dist/src/surfaces/cli/commands/ui.js +2 -0
  320. package/dist/src/surfaces/cli/commands/validate-state.js +5 -0
  321. package/dist/src/surfaces/cli/infrastructure/docker-cli.js +221 -0
  322. package/dist/src/surfaces/cli/infrastructure/process-log.js +86 -0
  323. package/dist/src/surfaces/cli/main.js +140 -0
  324. package/dist/src/surfaces/cli/usage.js +33 -0
  325. package/dist/src/surfaces/contracts/config.js +34 -0
  326. package/dist/src/surfaces/index.js +47 -0
  327. package/dist/src/surfaces/web-assets/assets/index-Bfn4FwZG.css +1 -0
  328. package/dist/src/surfaces/web-assets/assets/index-ipB6JPGU.js +1090 -0
  329. package/dist/src/surfaces/web-assets/index.html +13 -0
  330. package/dist/src/surfaces/web-host/asset-source.js +1 -0
  331. package/dist/src/surfaces/web-host/packaged-assets.js +44 -0
  332. package/dist/src/work/application/work-projection.js +59 -0
  333. package/dist/src/work/application/work-repository.js +18 -0
  334. package/dist/src/work/application/work-service.js +117 -0
  335. package/dist/src/work/contracts/commands.js +1 -0
  336. package/dist/src/work/contracts/config.js +2 -0
  337. package/dist/src/work/contracts/events.js +103 -0
  338. package/dist/src/work/contracts/identifiers.js +5 -0
  339. package/dist/src/work/contracts/streams.js +6 -0
  340. package/dist/src/work/contracts/views.js +1 -0
  341. package/dist/src/work/contracts/vocabulary.js +6 -0
  342. package/dist/src/work/domain/work-item.js +89 -0
  343. package/dist/src/work/index.js +11 -0
  344. package/docker/Dockerfile +10 -6
  345. package/docker/Dockerfile.packaged +3 -3
  346. package/package.json +29 -4
  347. package/prompts/implement.md +2 -2
  348. package/dist/src/adapters/claude/claude-runner.js +0 -529
  349. package/dist/src/adapters/codex/codex-runner.js +0 -503
  350. package/dist/src/adapters/cursor/cursor-runner.js +0 -418
  351. package/dist/src/adapters/docker/docker-cli.js +0 -150
  352. package/dist/src/adapters/fake/fake-artifact-verifier.js +0 -14
  353. package/dist/src/adapters/fake/fake-github-pull-request-activity-source.js +0 -77
  354. package/dist/src/adapters/fake/fake-resource-index.js +0 -21
  355. package/dist/src/adapters/fake/fake-runner.js +0 -77
  356. package/dist/src/adapters/fake/fake-ticketing-system.js +0 -185
  357. package/dist/src/adapters/fake/fake-workspace-manager.js +0 -81
  358. package/dist/src/adapters/fs/resource-index.js +0 -126
  359. package/dist/src/adapters/fs/self-update-ledger.js +0 -17
  360. package/dist/src/adapters/fs/state-store.js +0 -775
  361. package/dist/src/adapters/git/git-workspace-manager.js +0 -289
  362. package/dist/src/adapters/github/github-artifact-verifier.js +0 -38
  363. package/dist/src/adapters/github/github-auth.js +0 -16
  364. package/dist/src/adapters/github/github-client.js +0 -249
  365. package/dist/src/adapters/github/github-etag-cache.js +0 -57
  366. package/dist/src/adapters/github/github-issues-work-source.js +0 -692
  367. package/dist/src/adapters/github/github-pull-request-activity-source.js +0 -584
  368. package/dist/src/adapters/github/github-pull-request-merge-actor.js +0 -45
  369. package/dist/src/adapters/http/ui-assets.js +0 -1188
  370. package/dist/src/adapters/http/ui-data.js +0 -1107
  371. package/dist/src/adapters/http/ui-server.js +0 -458
  372. package/dist/src/adapters/runner/cli-command.js +0 -73
  373. package/dist/src/adapters/runner/prompt-templates.js +0 -76
  374. package/dist/src/adapters/runner/runner-cli-adapter.js +0 -112
  375. package/dist/src/adapters/runner/runner-registry.js +0 -139
  376. package/dist/src/adapters/runner/runtime-events.js +0 -32
  377. package/dist/src/adapters/runner/stage-prompt.js +0 -268
  378. package/dist/src/adapters/runner/transcripts.js +0 -25
  379. package/dist/src/cli/audit-command.js +0 -36
  380. package/dist/src/cli/correlate-command.js +0 -62
  381. package/dist/src/cli/doctor-command.js +0 -48
  382. package/dist/src/cli/init-command.js +0 -18
  383. package/dist/src/cli/sandbox-command.js +0 -258
  384. package/dist/src/cli/sandbox-entrypoint-command.js +0 -88
  385. package/dist/src/cli/sandbox-exec-logging.js +0 -7
  386. package/dist/src/cli/sandbox-resume.js +0 -79
  387. package/dist/src/cli/sandbox-setup-command.js +0 -31
  388. package/dist/src/cli/scaffold-assets.js +0 -100
  389. package/dist/src/cli/self-update-command.js +0 -198
  390. package/dist/src/cli/startup-preflight.js +0 -134
  391. package/dist/src/cli/stop-command.js +0 -46
  392. package/dist/src/cli/ui-command.js +0 -27
  393. package/dist/src/config/defaults.js +0 -10
  394. package/dist/src/config/discover-config-files.js +0 -11
  395. package/dist/src/config/load-config.js +0 -69
  396. package/dist/src/config/split-config.js +0 -14
  397. package/dist/src/core/active-run-recovery.js +0 -44
  398. package/dist/src/core/approval-intents.js +0 -16
  399. package/dist/src/core/audit-events.js +0 -82
  400. package/dist/src/core/control-plane.js +0 -192
  401. package/dist/src/core/event-builders.js +0 -153
  402. package/dist/src/core/event-resolver.js +0 -249
  403. package/dist/src/core/lifecycle-service.js +0 -8
  404. package/dist/src/core/live-execution.js +0 -81
  405. package/dist/src/core/outbox.js +0 -198
  406. package/dist/src/core/policy-engine.js +0 -389
  407. package/dist/src/core/projection-updater.js +0 -693
  408. package/dist/src/core/quota-backoff.js +0 -69
  409. package/dist/src/core/run-lease.js +0 -38
  410. package/dist/src/core/scheduled-workflow-source.js +0 -199
  411. package/dist/src/core/sink-router.js +0 -107
  412. package/dist/src/core/stale-run-reconciler.js +0 -352
  413. package/dist/src/core/tick-runner.js +0 -2442
  414. package/dist/src/core/workspace-cleanup.js +0 -117
  415. package/dist/src/domain/branch-naming.js +0 -14
  416. package/dist/src/domain/custom-commands.js +0 -58
  417. package/dist/src/domain/event-types.js +0 -158
  418. package/dist/src/domain/manual-labels.js +0 -1
  419. package/dist/src/domain/resource-uri.js +0 -38
  420. package/dist/src/domain/runner-routing.js +0 -127
  421. package/dist/src/domain/runtime-events.js +0 -36
  422. package/dist/src/domain/schema.js +0 -1233
  423. package/dist/src/domain/sources.js +0 -16
  424. package/dist/src/domain/stages.js +0 -36
  425. package/dist/src/domain/work-item-labels.js +0 -48
  426. package/dist/src/domain/work-item-lifecycle.js +0 -10
  427. package/dist/src/domain/work-item-status.js +0 -33
  428. package/dist/src/domain/workflows.js +0 -159
  429. package/dist/src/lib/deep-merge.js +0 -14
  430. package/dist/src/lib/detached-process-logging.js +0 -46
  431. package/dist/src/lib/event-log.js +0 -21
  432. package/dist/src/lib/format.js +0 -41
  433. package/dist/src/lib/json-file.js +0 -23
  434. package/dist/src/lib/lock.js +0 -181
  435. package/dist/src/lib/log-rotation.js +0 -42
  436. package/dist/src/lib/paths.js +0 -52
  437. package/dist/src/lib/process-identity.js +0 -54
  438. package/dist/src/lib/state-health.js +0 -30
  439. package/dist/src/lib/work-id.js +0 -19
  440. package/dist/src/lib/yaml-file.js +0 -20
  441. package/templates/SETUP.md +0 -115
  442. /package/dist/src/{core → activities/pr}/contracts.js +0 -0
  443. /package/dist/src/{domain/types.js → control-plane/contracts/views.js} +0 -0
@@ -0,0 +1,61 @@
1
+ import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ export function createUpdateLedger(wakeRoot) {
4
+ const path = join(wakeRoot, '.wake', 'update-ledger.json');
5
+ return {
6
+ async read() {
7
+ return (await readState(path)).lastHealthyTag ?? null;
8
+ },
9
+ async begin(tag) {
10
+ const state = await readState(path);
11
+ await writeState(path, { ...state, pendingTag: tag });
12
+ },
13
+ async write(tag) {
14
+ const state = await readState(path);
15
+ await writeState(path, {
16
+ lastHealthyTag: tag,
17
+ ...(state.badTags === undefined ? {} : { badTags: state.badTags }),
18
+ });
19
+ },
20
+ async isBad(tag) {
21
+ return (await readState(path)).badTags?.includes(tag) ?? false;
22
+ },
23
+ async recordBad(tag) {
24
+ const state = await readState(path);
25
+ await writeState(path, { ...state, badTags: [...new Set([...(state.badTags ?? []), tag])] });
26
+ },
27
+ async recover() {
28
+ const state = await readState(path);
29
+ if (state.pendingTag === undefined)
30
+ return null;
31
+ await writeState(path, {
32
+ ...(state.lastHealthyTag === undefined ? {} : { lastHealthyTag: state.lastHealthyTag }),
33
+ ...(state.badTags === undefined ? {} : { badTags: state.badTags }),
34
+ });
35
+ return state.lastHealthyTag ?? null;
36
+ },
37
+ };
38
+ }
39
+ async function readState(path) {
40
+ try {
41
+ const value = JSON.parse(await readFile(path, 'utf8'));
42
+ return {
43
+ ...(typeof value.lastHealthyTag === 'string' ? { lastHealthyTag: value.lastHealthyTag } : {}),
44
+ ...(typeof value.pendingTag === 'string' ? { pendingTag: value.pendingTag } : {}),
45
+ ...(Array.isArray(value.badTags) && value.badTags.every((tag) => typeof tag === 'string')
46
+ ? { badTags: value.badTags }
47
+ : {}),
48
+ };
49
+ }
50
+ catch (error) {
51
+ if (error.code === 'ENOENT')
52
+ return {};
53
+ throw error;
54
+ }
55
+ }
56
+ async function writeState(path, state) {
57
+ await mkdir(dirname(path), { recursive: true });
58
+ const temporary = `${path}.${process.pid}.tmp`;
59
+ await writeFile(temporary, `${JSON.stringify(state)}\n`, 'utf8');
60
+ await rename(temporary, path);
61
+ }
@@ -0,0 +1,176 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
+ import { dirname, join } from 'node:path';
4
+ import { defineClosedVocabulary } from '../kernel/index.js';
5
+ import { acquireFileLock } from '../persistence/index.js';
6
+ export const UpdateMaintenancePhase = defineClosedVocabulary({
7
+ Quiescing: 'quiescing',
8
+ Updating: 'updating',
9
+ RollingBack: 'rolling-back',
10
+ Failed: 'failed',
11
+ });
12
+ export function createUpdateMaintenanceLease(wakeRoot, now = () => new Date().toISOString(), createAttemptId = randomUUID, isProcessAlive) {
13
+ const path = join(wakeRoot, '.wake', 'update-maintenance.json');
14
+ const acquire = async (tag, retryFailed = false) => withLeaseLock(path, async () => {
15
+ const existing = await readState(path);
16
+ if (existing !== null &&
17
+ !(existing.phase === UpdateMaintenancePhase.Failed && (existing.tag !== tag || retryFailed)))
18
+ return existing;
19
+ const initial = {
20
+ attemptId: createAttemptId(),
21
+ tag,
22
+ phase: UpdateMaintenancePhase.Quiescing,
23
+ startedAt: now(),
24
+ };
25
+ await writeState(path, initial);
26
+ return initial;
27
+ });
28
+ return {
29
+ async read() {
30
+ return readState(path);
31
+ },
32
+ acquire,
33
+ async runExclusive(tag, retryFailed, operation) {
34
+ return withAttemptLock(path, isProcessAlive, async () => operation(await acquire(tag, retryFailed)));
35
+ },
36
+ async transition(phase, attemptId) {
37
+ return withLeaseLock(path, async () => {
38
+ const current = await requireState(path);
39
+ requireOwnership(current, attemptId);
40
+ if (!canTransition(current.phase, phase)) {
41
+ throw new Error(`Invalid maintenance lease transition from ${current.phase} to ${phase}`);
42
+ }
43
+ const next = { ...current, phase };
44
+ await writeState(path, next);
45
+ return next;
46
+ });
47
+ },
48
+ async fail(error, attemptId) {
49
+ return withLeaseLock(path, async () => {
50
+ const current = await requireState(path);
51
+ requireOwnership(current, attemptId);
52
+ if (current.phase === UpdateMaintenancePhase.Failed)
53
+ return current;
54
+ const next = {
55
+ ...current,
56
+ phase: UpdateMaintenancePhase.Failed,
57
+ failure: error instanceof Error ? error.message : String(error),
58
+ };
59
+ await writeState(path, next);
60
+ return next;
61
+ });
62
+ },
63
+ async clear(attemptId) {
64
+ await withLeaseLock(path, async () => {
65
+ const current = await readState(path);
66
+ if (current === null) {
67
+ if (attemptId !== undefined)
68
+ throw new Error('No maintenance lease is active');
69
+ return;
70
+ }
71
+ requireOwnership(current, attemptId);
72
+ await rm(path, { force: true });
73
+ });
74
+ },
75
+ };
76
+ }
77
+ function requireOwnership(state, attemptId) {
78
+ if (attemptId !== undefined && state.attemptId !== attemptId)
79
+ throw new Error(`Maintenance attempt ${attemptId} no longer owns the lease`);
80
+ }
81
+ function canTransition(from, to) {
82
+ return ((from === UpdateMaintenancePhase.Quiescing && to === UpdateMaintenancePhase.Updating) ||
83
+ (from === UpdateMaintenancePhase.Updating && to === UpdateMaintenancePhase.RollingBack));
84
+ }
85
+ async function requireState(path) {
86
+ const state = await readState(path);
87
+ if (state === null)
88
+ throw new Error('No maintenance lease is active');
89
+ return state;
90
+ }
91
+ async function readState(path) {
92
+ try {
93
+ return parseState(JSON.parse(await readFile(path, 'utf8')));
94
+ }
95
+ catch (error) {
96
+ if (error.code === 'ENOENT')
97
+ return null;
98
+ throw error;
99
+ }
100
+ }
101
+ function parseState(value) {
102
+ if (typeof value !== 'object' ||
103
+ value === null ||
104
+ typeof value.attemptId !== 'string' ||
105
+ typeof value.tag !== 'string' ||
106
+ !isPhase(value.phase) ||
107
+ typeof value.startedAt !== 'string' ||
108
+ ('failure' in value && typeof value.failure !== 'string')) {
109
+ throw new Error('Invalid maintenance lease state');
110
+ }
111
+ return value;
112
+ }
113
+ function isPhase(value) {
114
+ return (value === UpdateMaintenancePhase.Quiescing ||
115
+ value === UpdateMaintenancePhase.Updating ||
116
+ value === UpdateMaintenancePhase.RollingBack ||
117
+ value === UpdateMaintenancePhase.Failed);
118
+ }
119
+ async function writeState(path, state) {
120
+ await mkdir(dirname(path), { recursive: true });
121
+ const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
122
+ await writeFile(temporary, `${JSON.stringify(state)}\n`, 'utf8');
123
+ await rename(temporary, path);
124
+ }
125
+ async function withLeaseLock(path, operation) {
126
+ const lockPath = `${path}.lock`;
127
+ while (true) {
128
+ let lock;
129
+ try {
130
+ lock = await acquireFileLock(lockPath, { staleAfterMs: 60_000 });
131
+ }
132
+ catch (error) {
133
+ if (error.code !== 'EPERM')
134
+ throw error;
135
+ await new Promise((resolve) => setTimeout(resolve, 1));
136
+ continue;
137
+ }
138
+ if (lock.acquired) {
139
+ try {
140
+ return await operation();
141
+ }
142
+ finally {
143
+ await lock.release();
144
+ }
145
+ }
146
+ await new Promise((resolve) => setTimeout(resolve, 1));
147
+ }
148
+ }
149
+ async function withAttemptLock(path, isProcessAlive, operation) {
150
+ const lockPath = `${path}.attempt.lock`;
151
+ while (true) {
152
+ let lock;
153
+ try {
154
+ lock = await acquireFileLock(lockPath, {
155
+ staleAfterMs: 60_000,
156
+ staleRequiresDeadProcess: true,
157
+ ...(isProcessAlive === undefined ? {} : { isProcessAlive }),
158
+ });
159
+ }
160
+ catch (error) {
161
+ if (error.code !== 'EPERM')
162
+ throw error;
163
+ await new Promise((resolve) => setTimeout(resolve, 1));
164
+ continue;
165
+ }
166
+ if (lock.acquired) {
167
+ try {
168
+ return await operation();
169
+ }
170
+ finally {
171
+ await lock.release();
172
+ }
173
+ }
174
+ await new Promise((resolve) => setTimeout(resolve, 1));
175
+ }
176
+ }
@@ -2,7 +2,7 @@ import { execFileSync } from 'node:child_process';
2
2
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
3
3
  import { dirname, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- const defaultRepoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
5
+ const defaultRepoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
6
6
  function gitOutputFromRoot(repoRoot, args) {
7
7
  try {
8
8
  return execFileSync('git', args, {
@@ -24,104 +24,88 @@ function defaultReadTextFile(path) {
24
24
  }
25
25
  }
26
26
  function defaultListTextFiles(path) {
27
- if (!existsSync(path)) {
27
+ if (!existsSync(path))
28
28
  return [];
29
- }
30
29
  const files = [];
31
30
  for (const entry of readdirSync(path, { withFileTypes: true })) {
32
31
  const entryPath = resolve(path, entry.name);
33
- if (entry.isDirectory()) {
32
+ if (entry.isDirectory())
34
33
  files.push(...defaultListTextFiles(entryPath));
35
- }
36
34
  else if (entry.isFile()) {
37
35
  const content = defaultReadTextFile(entryPath);
38
- if (content !== undefined) {
36
+ if (content !== undefined)
39
37
  files.push({ path: entryPath, content });
40
- }
41
38
  }
42
39
  }
43
40
  return files;
44
41
  }
45
42
  function currentHeadHash(repoRoot, readTextFile) {
46
43
  const head = readTextFile(resolve(repoRoot, '.git', 'HEAD'))?.trim();
47
- if (head === undefined || head.length === 0) {
44
+ if (head === undefined || head.length === 0)
48
45
  return '';
49
- }
50
- if (!head.startsWith('ref: ')) {
46
+ if (!head.startsWith('ref: '))
51
47
  return head;
52
- }
53
- const refPath = head.slice('ref: '.length).trim();
54
- return readTextFile(resolve(repoRoot, '.git', ...refPath.split('/')))?.trim() ?? '';
48
+ return (readTextFile(resolve(repoRoot, '.git', ...head.slice('ref: '.length).trim().split('/')))?.trim() ?? '');
55
49
  }
56
- function looseTagRefs(repoRoot, listTextFiles) {
50
+ function exactTagFromGitFiles(repoRoot, readTextFile, listTextFiles) {
51
+ const headHash = currentHeadHash(repoRoot, readTextFile);
52
+ if (headHash.length === 0)
53
+ return '';
57
54
  const tagsRoot = resolve(repoRoot, '.git', 'refs', 'tags');
58
- return listTextFiles(tagsRoot).map((file) => ({
59
- name: file.path.replaceAll('\\', '/').slice(tagsRoot.replaceAll('\\', '/').length + 1),
55
+ const root = tagsRoot.replaceAll('\\', '/');
56
+ const looseTags = listTextFiles(tagsRoot).map((file) => ({
57
+ name: file.path.replaceAll('\\', '/').slice(root.length + 1),
60
58
  hash: file.content.trim(),
61
59
  }));
60
+ return ([...looseTags, ...packedTagRefs(repoRoot, readTextFile)].find((tag) => tag.hash === headHash)
61
+ ?.name ?? '');
62
62
  }
63
63
  function packedTagRefs(repoRoot, readTextFile) {
64
64
  const packedRefs = readTextFile(resolve(repoRoot, '.git', 'packed-refs'));
65
- if (packedRefs === undefined) {
65
+ if (packedRefs === undefined)
66
66
  return [];
67
- }
68
- const refs = [];
69
- let previousTag;
67
+ const tags = [];
68
+ let precedingTag;
70
69
  for (const line of packedRefs.split(/\r?\n/)) {
71
- if (line.length === 0 || line.startsWith('#')) {
70
+ if (line.length === 0 || line.startsWith('#'))
72
71
  continue;
73
- }
74
72
  if (line.startsWith('^')) {
75
- if (previousTag !== undefined) {
76
- previousTag.hash = line.slice(1).trim();
77
- }
73
+ if (precedingTag !== undefined)
74
+ precedingTag.hash = line.slice(1).trim();
78
75
  continue;
79
76
  }
80
- previousTag = undefined;
77
+ precedingTag = undefined;
81
78
  const [hash, ref] = line.split(' ');
82
79
  if (hash !== undefined && ref?.startsWith('refs/tags/') === true) {
83
- previousTag = { name: ref.slice('refs/tags/'.length), hash };
84
- refs.push(previousTag);
80
+ precedingTag = { name: ref.slice('refs/tags/'.length), hash };
81
+ tags.push(precedingTag);
85
82
  }
86
83
  }
87
- return refs;
88
- }
89
- function exactTagFromGitFiles(repoRoot, readTextFile, listTextFiles) {
90
- const headHash = currentHeadHash(repoRoot, readTextFile);
91
- if (headHash.length === 0) {
92
- return '';
93
- }
94
- const matchingTag = [
95
- ...looseTagRefs(repoRoot, listTextFiles),
96
- ...packedTagRefs(repoRoot, readTextFile),
97
- ].find((tag) => tag.hash === headHash);
98
- return matchingTag?.name ?? '';
84
+ return tags;
99
85
  }
86
+ // Mirrors legacy src/version.ts: exact tag at HEAD, else latest tag + short hash, else
87
+ // short hash, else a dev placeholder. Packaged installs get a literal value baked in at
88
+ // build time by scripts/embed-version.mjs, so the git plumbing here only runs from source.
100
89
  export function resolveWakeVersion(options = {}) {
101
90
  const repoRoot = options.repoRoot ?? defaultRepoRoot;
102
91
  const gitOutput = options.gitOutput ?? ((args) => gitOutputFromRoot(repoRoot, args));
103
92
  const readTextFile = options.readTextFile ?? defaultReadTextFile;
104
93
  const listTextFiles = options.listTextFiles ?? defaultListTextFiles;
105
94
  const exactTag = gitOutput(['describe', '--tags', '--exact-match', 'HEAD']);
106
- if (exactTag.length > 0) {
95
+ if (exactTag.length > 0)
107
96
  return exactTag;
108
- }
109
97
  const exactFileTag = exactTagFromGitFiles(repoRoot, readTextFile, listTextFiles);
110
- if (exactFileTag.length > 0) {
98
+ if (exactFileTag.length > 0)
111
99
  return exactFileTag;
112
- }
113
100
  const latestTag = gitOutput(['describe', '--tags', '--abbrev=0']);
114
101
  const shortHash = gitOutput(['rev-parse', '--short', 'HEAD']);
115
- if (latestTag.length > 0 && shortHash.length > 0) {
102
+ if (latestTag.length > 0 && shortHash.length > 0)
116
103
  return `${latestTag}+g${shortHash}`;
117
- }
118
- if (shortHash.length > 0) {
104
+ if (shortHash.length > 0)
119
105
  return `g${shortHash}`;
120
- }
121
106
  const headHash = currentHeadHash(repoRoot, readTextFile);
122
- if (headHash.length > 0) {
107
+ if (headHash.length > 0)
123
108
  return `g${headHash.slice(0, 7)}`;
124
- }
125
109
  return '0.1.0-dev';
126
110
  }
127
- export const wakeVersion = "g17e7db1";
111
+ export const wakeVersion = "g9e7311e";
@@ -0,0 +1,184 @@
1
+ import { RunStatus, WorkspaceMode } from '../../execution/index.js';
2
+ import { correlationId, EventActorKind, } from '../../kernel/index.js';
3
+ import { WorkflowStatus } from '../../orchestration/index.js';
4
+ import { WorkStatus } from '../../work/index.js';
5
+ import { ControlStreamKind } from '../contracts/streams.js';
6
+ import { DispatchPolicy } from '../domain/dispatch-policy.js';
7
+ export function createAdvanceOnce(orchestration, execution, resources, clock, dependencies) {
8
+ const runnerIneligibility = dependencies.runnerIneligibility ?? (async () => new Set());
9
+ const isDispatchPaused = dependencies.isDispatchPaused ?? (async () => false);
10
+ const workspaceRecovery = dependencies.workspaceRecovery;
11
+ const transcriptRetention = dependencies.transcriptRetention;
12
+ const dispatchPolicy = dependencies.dispatchPolicy ?? new DispatchPolicy({ maxDispatches: 1 });
13
+ const context = (cause) => ({
14
+ commandId: dependencies.ids.next('command'),
15
+ correlationId: correlationId(cause),
16
+ occurredAt: clock.now().toISOString(),
17
+ actor: { kind: EventActorKind.System, id: ControlStreamKind.Global },
18
+ });
19
+ return async (options) => {
20
+ if (options.maxProgress < 1)
21
+ return { kind: 'exhausted', progressCount: 0 };
22
+ if (await isDispatchPaused())
23
+ return { kind: 'paused' };
24
+ if (workspaceRecovery !== undefined) {
25
+ await workspaceRecovery.recover(await execution.list(), {
26
+ isPaused: isDispatchPaused,
27
+ retainWorkItem: async (workItemId) => {
28
+ const work = await dependencies.work?.get(workItemId);
29
+ return work?.state === WorkStatus.Open && work.deleted !== true;
30
+ },
31
+ onWorkspaceReclaimed: async (workItemId) => {
32
+ if (await isDispatchPaused())
33
+ return false;
34
+ const work = await dependencies.work?.get(workItemId);
35
+ if (work?.state !== WorkStatus.Closed)
36
+ return true;
37
+ try {
38
+ return (await transcriptRetention?.markClosedWorkItem(workItemId)) ?? true;
39
+ }
40
+ catch {
41
+ return false;
42
+ }
43
+ },
44
+ });
45
+ }
46
+ if (await isDispatchPaused())
47
+ return { kind: 'paused' };
48
+ await execution.recoverActive?.(ControlStreamKind.Global);
49
+ if (await isDispatchPaused())
50
+ return { kind: 'paused' };
51
+ if (transcriptRetention !== undefined) {
52
+ for (const workItemId of (await dependencies.closedWorkItemIds?.()) ?? []) {
53
+ if (await isDispatchPaused())
54
+ return { kind: 'paused' };
55
+ try {
56
+ await transcriptRetention.markClosedWorkItem(workItemId);
57
+ }
58
+ catch {
59
+ // Retention is operational filesystem maintenance, not Run lifecycle state.
60
+ }
61
+ }
62
+ }
63
+ if (await isDispatchPaused())
64
+ return { kind: 'paused' };
65
+ try {
66
+ await transcriptRetention?.sweep();
67
+ }
68
+ catch {
69
+ // Retention is operational filesystem maintenance, not Run lifecycle state.
70
+ }
71
+ if (await isDispatchPaused())
72
+ return { kind: 'paused' };
73
+ await orchestration.reconcileChildCompletions(context('child-completion-reconciliation'));
74
+ if (await isDispatchPaused())
75
+ return { kind: 'paused' };
76
+ const rawPending = await orchestration.listPendingActivations(options.workItemId);
77
+ const pending = (await Promise.all(rawPending.map(async (candidate) => {
78
+ const work = await dependencies.work?.get(candidate.workflow.workItemId);
79
+ return work?.frozen || work?.deleted ? null : candidate;
80
+ }))).filter((candidate) => candidate !== null);
81
+ const blocked = ((await orchestration.listAll?.()) ?? []).flatMap((workflow) => workflow.status === WorkflowStatus.Blocked &&
82
+ workflow.pendingActivation !== undefined &&
83
+ (options.workItemId === undefined || workflow.workItemId === options.workItemId)
84
+ ? [{ workflow, activation: workflow.pendingActivation }]
85
+ : []);
86
+ const recovery = await findUnresolvedTerminal([...pending, ...blocked], execution);
87
+ if (recovery !== undefined) {
88
+ if (await isDispatchPaused())
89
+ return { kind: 'paused' };
90
+ if (recovery.run.status === RunStatus.Succeeded) {
91
+ await orchestration.acceptOutcome({
92
+ workflowInstanceId: recovery.item.workflow.workflowInstanceId,
93
+ activationId: recovery.item.activation.activationId,
94
+ outcome: recovery.run.outcome,
95
+ }, context(recovery.run.runId));
96
+ return {
97
+ kind: 'progressed',
98
+ activationId: recovery.item.activation.activationId,
99
+ runId: recovery.run.runId,
100
+ };
101
+ }
102
+ await orchestration.resolveExecutionFailure?.(recovery.item.workflow.workflowInstanceId, {
103
+ activationId: recovery.item.activation.activationId,
104
+ runId: recovery.run.runId,
105
+ reason: recovery.run.failure?.message ?? 'execution failed',
106
+ }, context(recovery.run.runId));
107
+ return {
108
+ kind: WorkflowStatus.Blocked,
109
+ workflowInstanceId: recovery.item.workflow.workflowInstanceId,
110
+ reason: recovery.run.failure?.message ?? 'execution failed',
111
+ };
112
+ }
113
+ const allRuns = await execution.list();
114
+ const selectedCandidate = dispatchPolicy.select(await Promise.all(pending.map(async (item, requestedPosition) => ({
115
+ workItemId: item.workflow.workItemId,
116
+ activationId: item.activation.activationId,
117
+ requestedPosition,
118
+ hasActiveRun: (await execution.list(item.activation.activationId)).some((run) => run.status === RunStatus.Started) ||
119
+ allRuns.some((run) => run.status === RunStatus.Started &&
120
+ run.workflowInstanceId === item.workflow.workflowInstanceId &&
121
+ run.workspace?.mode === WorkspaceMode.Branch),
122
+ cancelled: false,
123
+ }))))[0];
124
+ const selected = selectedCandidate === undefined
125
+ ? undefined
126
+ : pending.find((item) => item.activation.activationId === selectedCandidate.activationId);
127
+ if (selected === undefined) {
128
+ const waiting = (await orchestration.listWaiting()).find((view) => view !== null);
129
+ return waiting === undefined
130
+ ? { kind: 'no-work' }
131
+ : { kind: WorkflowStatus.Waiting, workflowInstanceId: waiting.workflowInstanceId };
132
+ }
133
+ // Recheck at the dispatch boundary so maintenance cannot race a selected activation.
134
+ if (await isDispatchPaused())
135
+ return { kind: 'paused' };
136
+ await orchestration.markActivationStarted(selected.workflow.workflowInstanceId, selected.activation.activationId, context(selected.activation.activationId));
137
+ const correlated = await resources.correlationsForWork(selected.workflow.workItemId);
138
+ const resourceViews = (await Promise.all(correlated.map((entry) => resources.get(entry.resourceId)))).filter((resource) => resource !== null);
139
+ const ineligible = await runnerIneligibility();
140
+ const run = await execution.attempt(selected.activation, {
141
+ workItemId: selected.workflow.workItemId,
142
+ workflowInstanceId: selected.workflow.workflowInstanceId,
143
+ orchestrationGroupId: selected.workflow.orchestrationGroupId,
144
+ resources: resourceViews,
145
+ sessionPolicy: selected.workflow.parentWorkflowInstanceId === undefined ? 'resume-stage' : 'fresh',
146
+ awaitImmediateCompletion: true,
147
+ ...(ineligible.size === 0 ? {} : { ineligibleRunners: ineligible }),
148
+ });
149
+ if (run.status === RunStatus.Succeeded && run.outcome !== undefined) {
150
+ if (await isDispatchPaused())
151
+ return { kind: 'paused' };
152
+ await orchestration.acceptOutcome({
153
+ workflowInstanceId: selected.workflow.workflowInstanceId,
154
+ activationId: selected.activation.activationId,
155
+ outcome: run.outcome,
156
+ }, context(run.runId));
157
+ }
158
+ if (isExecutionFailureTerminal(run.status))
159
+ await orchestration.resolveExecutionFailure?.(selected.workflow.workflowInstanceId, {
160
+ activationId: selected.activation.activationId,
161
+ runId: run.runId,
162
+ reason: run.failure?.message ?? 'execution failed',
163
+ }, context(run.runId));
164
+ return run.status === RunStatus.Succeeded || run.status === RunStatus.Started
165
+ ? { kind: 'progressed', activationId: selected.activation.activationId, runId: run.runId }
166
+ : {
167
+ kind: WorkflowStatus.Blocked,
168
+ workflowInstanceId: selected.workflow.workflowInstanceId,
169
+ reason: run.failure?.message ?? 'execution failed',
170
+ };
171
+ };
172
+ }
173
+ async function findUnresolvedTerminal(pending, execution) {
174
+ for (const item of pending) {
175
+ const run = (await execution.list(item.activation.activationId)).find((candidate) => (candidate.status === RunStatus.Succeeded && candidate.outcome !== undefined) ||
176
+ isExecutionFailureTerminal(candidate.status));
177
+ if (run !== undefined && !item.workflow.acceptedOutcomes.includes(item.activation.activationId))
178
+ return { item, run };
179
+ }
180
+ return undefined;
181
+ }
182
+ function isExecutionFailureTerminal(status) {
183
+ return (status === RunStatus.Failed || status === RunStatus.Cancelled || status === RunStatus.Ambiguous);
184
+ }
@@ -0,0 +1,42 @@
1
+ import { ControlEventType, selectControlEvent } from '../contracts/events.js';
2
+ import { ControlStreamKind } from '../contracts/streams.js';
3
+ export function ineligibleRunners(view, now) {
4
+ const current = Date.parse(now);
5
+ return new Set(Object.entries(view.runnerPauses)
6
+ .filter(([, pause]) => pause.resumeAt === undefined || Date.parse(pause.resumeAt) > current)
7
+ .map(([runnerName]) => runnerName));
8
+ }
9
+ export const controlPlaneProjection = {
10
+ name: ControlStreamKind.Global,
11
+ select(event) {
12
+ return selectControlEvent(event) === null ? null : { key: 'global' };
13
+ },
14
+ initial: () => ({ pausedUntil: null, runnerPauses: {} }),
15
+ project(previous, envelope) {
16
+ const event = selectControlEvent(envelope);
17
+ if (event === null)
18
+ return previous;
19
+ switch (event.eventType) {
20
+ case ControlEventType.DispatchPaused:
21
+ return { ...previous, pausedUntil: event.payload.resumeAt, reason: event.payload.reason };
22
+ case ControlEventType.DispatchResumed:
23
+ return withoutDispatchPause(previous);
24
+ case ControlEventType.RunnerPaused:
25
+ return {
26
+ ...previous,
27
+ runnerPauses: { ...previous.runnerPauses, [event.payload.runnerName]: event.payload },
28
+ };
29
+ case ControlEventType.RunnerResumed: {
30
+ const { [event.payload.runnerName]: _, ...runnerPauses } = previous.runnerPauses;
31
+ return { ...previous, runnerPauses };
32
+ }
33
+ }
34
+ },
35
+ };
36
+ function withoutDispatchPause(previous) {
37
+ const { reason: _, ...rest } = previous;
38
+ return { ...rest, pausedUntil: null };
39
+ }
40
+ export const controlPlaneProjectionDefinitions = [
41
+ controlPlaneProjection,
42
+ ];
@@ -0,0 +1,42 @@
1
+ import { EventActorKind, correlationId, } from '../../kernel/index.js';
2
+ import { ControlEventType, createControlEventDraft, selectControlEvent, } from '../contracts/events.js';
3
+ import { controlPlaneStream } from '../contracts/streams.js';
4
+ export function createControlPlaneService(input) {
5
+ return {
6
+ pause: (key) => change(input, key, 'pause'),
7
+ resume: (key) => change(input, key, 'resume'),
8
+ async isPaused() {
9
+ let paused = false;
10
+ for (const envelope of await input.journal.readStream(controlPlaneStream())) {
11
+ const event = selectControlEvent(envelope);
12
+ if (event?.eventType === ControlEventType.DispatchPaused)
13
+ paused = true;
14
+ if (event?.eventType === ControlEventType.DispatchResumed)
15
+ paused = false;
16
+ }
17
+ return paused;
18
+ },
19
+ };
20
+ }
21
+ async function change(input, idempotencyKey, operation) {
22
+ const stream = controlPlaneStream();
23
+ const events = await input.journal.readStream(stream);
24
+ const eventType = operation === 'pause' ? ControlEventType.DispatchPaused : ControlEventType.DispatchResumed;
25
+ const correlation = correlationId(`control:${operation}:${idempotencyKey}`);
26
+ if (events.some((event) => event.eventType === eventType && event.correlationId === correlation))
27
+ return;
28
+ const currentlyPaused = await createControlPlaneService(input).isPaused();
29
+ if ((operation === 'pause' && currentlyPaused) || (operation === 'resume' && !currentlyPaused))
30
+ return;
31
+ const occurredAt = input.clock.now().toISOString();
32
+ const context = {
33
+ commandId: input.ids.next('command'),
34
+ correlationId: correlation,
35
+ occurredAt,
36
+ actor: { kind: EventActorKind.Operator, id: 'web' },
37
+ };
38
+ const event = operation === 'pause'
39
+ ? createControlEventDraft(ControlEventType.DispatchPaused, { resumeAt: '9999-12-31T23:59:59.999Z', reason: 'paused by operator' }, context)
40
+ : createControlEventDraft(ControlEventType.DispatchResumed, { resumedAt: occurredAt }, context);
41
+ await input.journal.append(stream, events.length, [event]);
42
+ }