@atolis-hq/wake 0.2.96 → 0.3.0

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 (442) hide show
  1. package/dist/src/activities/agent/agent-activity-definition.js +26 -0
  2. package/dist/src/activities/agent/agent-activity.js +171 -0
  3. package/dist/src/activities/agent/agent-result.js +149 -0
  4. package/dist/src/activities/contracts/activity.js +10 -0
  5. package/dist/src/activities/contracts/config.js +2 -0
  6. package/dist/src/activities/contracts/event-schema.js +302 -0
  7. package/dist/src/activities/contracts/events.js +42 -0
  8. package/dist/src/activities/contracts/identifiers.js +29 -0
  9. package/dist/src/activities/contracts/registry.js +71 -0
  10. package/dist/src/activities/contracts/streams.js +17 -0
  11. package/dist/src/activities/contracts/vocabulary.js +58 -0
  12. package/dist/src/activities/index.js +21 -0
  13. package/dist/src/activities/pr/activity-support.js +111 -0
  14. package/dist/src/activities/pr/application.js +158 -0
  15. package/dist/src/activities/pr/approve.js +85 -0
  16. package/dist/src/activities/pr/capability.js +11 -0
  17. package/dist/src/activities/pr/decision-claim.js +76 -0
  18. package/dist/src/activities/pr/event-drafts.js +66 -0
  19. package/dist/src/activities/pr/intent.js +37 -0
  20. package/dist/src/activities/pr/merge-authority-gate.js +14 -0
  21. package/dist/src/activities/pr/merge.js +110 -0
  22. package/dist/src/activities/pr/policy.js +135 -0
  23. package/dist/src/activities/pr/projection.js +130 -0
  24. package/dist/src/activities/pr/vocabulary.js +30 -0
  25. package/dist/src/activities/review/authorization.js +22 -0
  26. package/dist/src/activities/review/contracts.js +22 -0
  27. package/dist/src/activities/review/signals.js +3 -0
  28. package/dist/src/bootstrap/analytics-projection.js +26 -0
  29. package/dist/src/bootstrap/board-projection.js +337 -0
  30. package/dist/src/bootstrap/composition-root.js +382 -0
  31. package/dist/src/bootstrap/config/load-config.js +51 -0
  32. package/dist/src/bootstrap/config/root-schema.js +134 -0
  33. package/dist/src/bootstrap/external-ref.js +12 -0
  34. package/dist/src/bootstrap/fake-provider-files.js +44 -0
  35. package/dist/src/bootstrap/fake-scenarios.js +22 -0
  36. package/dist/src/bootstrap/index.js +48 -0
  37. package/dist/src/bootstrap/initialise.js +434 -0
  38. package/dist/src/bootstrap/paths.js +15 -0
  39. package/dist/src/bootstrap/projection-runtime.js +27 -0
  40. package/dist/src/bootstrap/runner-quota-reporter.js +21 -0
  41. package/dist/src/bootstrap/runner-registry.js +30 -0
  42. package/dist/src/bootstrap/schedule-checkpoint-store.js +49 -0
  43. package/dist/src/bootstrap/self-update-application.js +195 -0
  44. package/dist/src/bootstrap/self-update-failure-log.js +33 -0
  45. package/dist/src/bootstrap/source-update-port.js +47 -0
  46. package/dist/src/bootstrap/status-publish-activity.js +42 -0
  47. package/dist/src/bootstrap/surface-api-applications.js +325 -0
  48. package/dist/src/bootstrap/surface-api-execution-applications.js +95 -0
  49. package/dist/src/bootstrap/surface-api-metadata.js +12 -0
  50. package/dist/src/bootstrap/surface-api-projection-pages.js +22 -0
  51. package/dist/src/bootstrap/surface-api-run-context.js +5 -0
  52. package/dist/src/bootstrap/surface-api-transcripts.js +57 -0
  53. package/dist/src/bootstrap/surface-api-work-applications.js +199 -0
  54. package/dist/src/bootstrap/surface-applications.js +7 -0
  55. package/dist/src/bootstrap/surface-cli-applications.js +701 -0
  56. package/dist/src/bootstrap/update-ledger.js +61 -0
  57. package/dist/src/bootstrap/update-maintenance-lease.js +176 -0
  58. package/dist/src/{version.js → bootstrap/version.js} +35 -51
  59. package/dist/src/control-plane/application/advance-once.js +184 -0
  60. package/dist/src/control-plane/application/control-plane-projection.js +42 -0
  61. package/dist/src/control-plane/application/control-plane-service.js +42 -0
  62. package/dist/src/control-plane/application/intake-pipeline.js +29 -0
  63. package/dist/src/control-plane/application/runner-control-service.js +66 -0
  64. package/dist/src/control-plane/application/runner-pipeline.js +57 -0
  65. package/dist/src/control-plane/application/schedule-service.js +47 -0
  66. package/dist/src/control-plane/application/work-cancellation-policy.js +31 -0
  67. package/dist/src/control-plane/contracts/commands.js +10 -0
  68. package/dist/src/control-plane/contracts/config.js +22 -0
  69. package/dist/src/control-plane/contracts/events.js +81 -0
  70. package/dist/src/control-plane/contracts/streams.js +5 -0
  71. package/dist/src/control-plane/domain/dispatch-policy.js +15 -0
  72. package/dist/src/control-plane/domain/quota-policy.js +26 -0
  73. package/dist/src/control-plane/domain/runner-quota.js +35 -0
  74. package/dist/src/control-plane/domain/schedule-policy.js +46 -0
  75. package/dist/src/control-plane/index.js +20 -0
  76. package/dist/src/control-plane/infrastructure/intake-host.js +24 -0
  77. package/dist/src/control-plane/infrastructure/resident-host.js +45 -0
  78. package/dist/src/control-plane/infrastructure/tick-host.js +35 -0
  79. package/dist/src/execution/application/activation-claim.js +50 -0
  80. package/dist/src/execution/application/active-run-cancellation.js +14 -0
  81. package/dist/src/execution/application/execution-activity.js +97 -0
  82. package/dist/src/execution/application/execution-projection.js +17 -0
  83. package/dist/src/execution/application/execution-service.js +372 -0
  84. package/dist/src/execution/application/execution-validation.js +26 -0
  85. package/dist/src/execution/application/recovery-service.js +212 -0
  86. package/dist/src/execution/application/run-lifecycle.js +115 -0
  87. package/dist/src/execution/application/run-liveness-service.js +80 -0
  88. package/dist/src/execution/application/run-repository.js +27 -0
  89. package/dist/src/execution/contracts/commands.js +1 -0
  90. package/dist/src/execution/contracts/config.js +35 -0
  91. package/dist/src/execution/contracts/control-plane.js +1 -0
  92. package/dist/src/execution/contracts/event-factory.js +53 -0
  93. package/dist/src/execution/contracts/events.js +274 -0
  94. package/dist/src/execution/contracts/identifiers.js +5 -0
  95. package/dist/src/execution/contracts/liveness.js +1 -0
  96. package/dist/src/execution/contracts/results.js +1 -0
  97. package/dist/src/execution/contracts/runner.js +15 -0
  98. package/dist/src/execution/contracts/streams.js +10 -0
  99. package/dist/src/execution/contracts/views.js +1 -0
  100. package/dist/src/execution/contracts/vocabulary.js +43 -0
  101. package/dist/src/execution/contracts/workspace.js +1 -0
  102. package/dist/src/execution/domain/run-result.js +34 -0
  103. package/dist/src/execution/domain/run.js +142 -0
  104. package/dist/src/execution/index.js +31 -0
  105. package/dist/src/execution/infrastructure/agent-runner-adapter.js +114 -0
  106. package/dist/src/execution/infrastructure/process-execution.js +29 -0
  107. package/dist/src/execution/infrastructure/prompt-templates.js +42 -0
  108. package/dist/src/execution/infrastructure/runners/claude.js +120 -0
  109. package/dist/src/execution/infrastructure/runners/codex.js +143 -0
  110. package/dist/src/execution/infrastructure/runners/command.js +4 -0
  111. package/dist/src/execution/infrastructure/runners/cursor.js +69 -0
  112. package/dist/src/execution/infrastructure/runners/fake-scenarios.js +99 -0
  113. package/dist/src/execution/infrastructure/runners/fake.js +65 -0
  114. package/dist/src/execution/infrastructure/runners/registry.js +26 -0
  115. package/dist/src/execution/infrastructure/transcript-store.js +223 -0
  116. package/dist/src/execution/infrastructure/transcripts.js +11 -0
  117. package/dist/src/execution/infrastructure/workspace/fake-workspace.js +19 -0
  118. package/dist/src/execution/infrastructure/workspace/git-workspace.js +241 -0
  119. package/dist/src/integrations/application/agent-run-publication-reactor.js +111 -0
  120. package/dist/src/integrations/application/artifact-registration-reactor.js +159 -0
  121. package/dist/src/integrations/application/poll-service.js +25 -0
  122. package/dist/src/integrations/application/terminal-agent-run-report.js +40 -0
  123. package/dist/src/integrations/application/work-admission.js +31 -0
  124. package/dist/src/integrations/application/work-conclusion.js +19 -0
  125. package/dist/src/integrations/contracts/artifact-events.js +60 -0
  126. package/dist/src/integrations/contracts/artifact-vocabulary.js +9 -0
  127. package/dist/src/integrations/contracts/config.js +14 -0
  128. package/dist/src/integrations/contracts/identifiers.js +5 -0
  129. package/dist/src/integrations/contracts/intake-rules.js +14 -0
  130. package/dist/src/integrations/contracts/intake.js +1 -0
  131. package/dist/src/integrations/contracts/outcome-vocabulary.js +7 -0
  132. package/dist/src/integrations/contracts/provider.js +37 -0
  133. package/dist/src/integrations/contracts/streams.js +10 -0
  134. package/dist/src/integrations/delivery/application/delivery-outcome-reactor.js +75 -0
  135. package/dist/src/integrations/delivery/application/delivery-projector.js +165 -0
  136. package/dist/src/integrations/delivery/application/delivery-service.js +173 -0
  137. package/dist/src/integrations/delivery/contracts/commands.js +1 -0
  138. package/dist/src/integrations/delivery/contracts/config.js +1 -0
  139. package/dist/src/integrations/delivery/contracts/event-factory.js +18 -0
  140. package/dist/src/integrations/delivery/contracts/events.js +86 -0
  141. package/dist/src/integrations/delivery/contracts/intents.js +89 -0
  142. package/dist/src/integrations/delivery/contracts/views.js +1 -0
  143. package/dist/src/integrations/delivery/contracts/vocabulary.js +22 -0
  144. package/dist/src/integrations/fake/durable-delivery-provider.js +48 -0
  145. package/dist/src/integrations/fake/external-sink.js +9 -0
  146. package/dist/src/integrations/fake/external-source.js +44 -0
  147. package/dist/src/integrations/fake/inbound-translator.js +130 -0
  148. package/dist/src/integrations/fake/provider.js +95 -0
  149. package/dist/src/integrations/github/application/agent-context-reader.js +54 -0
  150. package/dist/src/integrations/github/application/agent-run-comment.js +94 -0
  151. package/dist/src/integrations/github/application/comment-history-reader.js +43 -0
  152. package/dist/src/integrations/github/application/inbound-context.js +10 -0
  153. package/dist/src/integrations/github/application/inbound-review-signals.js +159 -0
  154. package/dist/src/integrations/github/application/inbound-translator.js +231 -0
  155. package/dist/src/integrations/github/application/inbound-watch-gate-signals.js +84 -0
  156. package/dist/src/integrations/github/application/intake-policy.js +23 -0
  157. package/dist/src/integrations/github/application/outbound-translator.js +47 -0
  158. package/dist/src/integrations/github/application/poll-service.js +29 -0
  159. package/dist/src/integrations/github/application/pull-request-translation.js +10 -0
  160. package/dist/src/integrations/github/application/resource-links.js +8 -0
  161. package/dist/src/integrations/github/application/review-command-translator.js +16 -0
  162. package/dist/src/integrations/github/application/wake-labels.js +95 -0
  163. package/dist/src/integrations/github/contracts/config.js +47 -0
  164. package/dist/src/integrations/github/contracts/events.js +127 -0
  165. package/dist/src/integrations/github/contracts/external-key.js +19 -0
  166. package/dist/src/integrations/github/contracts/payloads.js +9 -0
  167. package/dist/src/integrations/github/contracts/vocabulary.js +55 -0
  168. package/dist/src/integrations/github/index.js +31 -0
  169. package/dist/src/integrations/github/infrastructure/client-reads.js +214 -0
  170. package/dist/src/integrations/github/infrastructure/client.js +132 -0
  171. package/dist/src/integrations/github/infrastructure/content-fingerprint.js +10 -0
  172. package/dist/src/integrations/github/infrastructure/delivery.js +31 -0
  173. package/dist/src/integrations/github/infrastructure/etag-cache.js +56 -0
  174. package/dist/src/integrations/github/infrastructure/gh-auth.js +19 -0
  175. package/dist/src/integrations/github/infrastructure/issue-source.js +109 -0
  176. package/dist/src/integrations/github/infrastructure/pr-source.js +186 -0
  177. package/dist/src/integrations/github/infrastructure/review-source.js +70 -0
  178. package/dist/src/integrations/github/infrastructure/source.js +108 -0
  179. package/dist/src/integrations/github/provider.js +96 -0
  180. package/dist/src/integrations/index.js +30 -0
  181. package/dist/src/kernel/contracts/checkpoint-store.js +1 -0
  182. package/dist/src/kernel/contracts/clock.js +1 -0
  183. package/dist/src/kernel/contracts/commands.js +1 -0
  184. package/dist/src/kernel/contracts/event-journal.js +2 -0
  185. package/dist/src/kernel/contracts/event-schema.js +54 -0
  186. package/dist/src/kernel/contracts/events.js +11 -0
  187. package/dist/src/kernel/contracts/id-generator.js +1 -0
  188. package/dist/src/kernel/contracts/identifiers.js +8 -0
  189. package/dist/src/kernel/contracts/projection-store.js +1 -0
  190. package/dist/src/kernel/contracts/relations.js +1 -0
  191. package/dist/src/kernel/contracts/schema.js +17 -0
  192. package/dist/src/kernel/contracts/vocabulary.js +6 -0
  193. package/dist/src/kernel/domain/event-envelope.js +29 -0
  194. package/dist/src/kernel/domain/match-mode.js +11 -0
  195. package/dist/src/kernel/domain/relation.js +10 -0
  196. package/dist/src/kernel/index.js +17 -0
  197. package/dist/src/{lib/clock.js → kernel/infrastructure/system-clock.js} +3 -3
  198. package/dist/src/kernel/infrastructure/ulid-id-generator.js +9 -0
  199. package/dist/src/main.js +137 -1030
  200. package/dist/src/orchestration/application/accept-activity-outcome.js +25 -0
  201. package/dist/src/orchestration/application/accept-signal.js +35 -0
  202. package/dist/src/orchestration/application/advance-workflow.js +160 -0
  203. package/dist/src/orchestration/application/coordination-claims.js +107 -0
  204. package/dist/src/orchestration/application/group-budget-recorder.js +43 -0
  205. package/dist/src/orchestration/application/orchestration-projection.js +20 -0
  206. package/dist/src/orchestration/application/orchestration-repository.js +36 -0
  207. package/dist/src/orchestration/application/orchestration-service.js +82 -0
  208. package/dist/src/orchestration/application/request-child.js +118 -0
  209. package/dist/src/orchestration/application/signal-reactor.js +17 -0
  210. package/dist/src/orchestration/application/start-workflow.js +51 -0
  211. package/dist/src/orchestration/application/watch-reactor.js +82 -0
  212. package/dist/src/orchestration/contracts/activity-outcome.js +18 -0
  213. package/dist/src/orchestration/contracts/commands.js +1 -0
  214. package/dist/src/orchestration/contracts/config.js +128 -0
  215. package/dist/src/orchestration/contracts/event-decoder.js +263 -0
  216. package/dist/src/orchestration/contracts/events.js +41 -0
  217. package/dist/src/orchestration/contracts/identifiers.js +35 -0
  218. package/dist/src/orchestration/contracts/streams.js +38 -0
  219. package/dist/src/orchestration/contracts/views.js +1 -0
  220. package/dist/src/orchestration/contracts/vocabulary.js +30 -0
  221. package/dist/src/orchestration/domain/activation-policy.js +55 -0
  222. package/dist/src/orchestration/domain/approval-defaults.js +17 -0
  223. package/dist/src/orchestration/domain/child-policy.js +63 -0
  224. package/dist/src/orchestration/domain/compiler.js +162 -0
  225. package/dist/src/orchestration/domain/coordination-events.js +25 -0
  226. package/dist/src/orchestration/domain/decision-events.js +47 -0
  227. package/dist/src/orchestration/domain/interpreter.js +49 -0
  228. package/dist/src/orchestration/domain/operator-retry-policy.js +34 -0
  229. package/dist/src/orchestration/domain/retry-policy.js +26 -0
  230. package/dist/src/orchestration/domain/signal-policy.js +120 -0
  231. package/dist/src/orchestration/domain/supplemental-policy.js +61 -0
  232. package/dist/src/orchestration/domain/transition.js +55 -0
  233. package/dist/src/orchestration/domain/workflow-graph.js +41 -0
  234. package/dist/src/orchestration/domain/workflow-instance-events.js +236 -0
  235. package/dist/src/orchestration/domain/workflow-instance.js +41 -0
  236. package/dist/src/orchestration/domain/workflow-selector.js +21 -0
  237. package/dist/src/orchestration/index.js +19 -0
  238. package/dist/src/persistence/application/projection-runner.js +79 -0
  239. package/dist/src/persistence/filesystem/file-checkpoint-store.js +35 -0
  240. package/dist/src/persistence/filesystem/file-event-journal.js +143 -0
  241. package/dist/src/persistence/filesystem/file-lock.js +91 -0
  242. package/dist/src/persistence/filesystem/file-projection-store.js +64 -0
  243. package/dist/src/persistence/index.js +8 -0
  244. package/dist/src/persistence/memory/in-memory-checkpoint-store.js +14 -0
  245. package/dist/src/persistence/memory/in-memory-event-journal.js +88 -0
  246. package/dist/src/persistence/memory/in-memory-projection-store.js +17 -0
  247. package/dist/src/resources/application/lookup-projections.js +48 -0
  248. package/dist/src/resources/application/resource-lookup.js +16 -0
  249. package/dist/src/resources/application/resource-projections.js +81 -0
  250. package/dist/src/resources/application/resource-repository.js +18 -0
  251. package/dist/src/resources/application/resource-service.js +83 -0
  252. package/dist/src/resources/contracts/commands.js +1 -0
  253. package/dist/src/resources/contracts/config.js +2 -0
  254. package/dist/src/resources/contracts/events.js +83 -0
  255. package/dist/src/resources/contracts/identifiers.js +15 -0
  256. package/dist/src/resources/contracts/streams.js +6 -0
  257. package/dist/src/resources/contracts/views.js +1 -0
  258. package/dist/src/resources/contracts/vocabulary.js +67 -0
  259. package/dist/src/resources/domain/correlation.js +8 -0
  260. package/dist/src/resources/domain/resource.js +58 -0
  261. package/dist/src/resources/index.js +14 -0
  262. package/dist/src/surfaces/api/contracts/activities.js +1 -0
  263. package/dist/src/surfaces/api/contracts/board.js +2 -0
  264. package/dist/src/surfaces/api/contracts/common.js +46 -0
  265. package/dist/src/surfaces/api/contracts/control-plane.js +5 -0
  266. package/dist/src/surfaces/api/contracts/events.js +1 -0
  267. package/dist/src/surfaces/api/contracts/execution.js +1 -0
  268. package/dist/src/surfaces/api/contracts/index.js +13 -0
  269. package/dist/src/surfaces/api/contracts/observability.js +1 -0
  270. package/dist/src/surfaces/api/contracts/orchestration.js +1 -0
  271. package/dist/src/surfaces/api/contracts/resources.js +1 -0
  272. package/dist/src/surfaces/api/contracts/status.js +1 -0
  273. package/dist/src/surfaces/api/contracts/system.js +1 -0
  274. package/dist/src/surfaces/api/contracts/transport-values.js +39 -0
  275. package/dist/src/surfaces/api/contracts/work.js +17 -0
  276. package/dist/src/surfaces/api/http-server.js +121 -0
  277. package/dist/src/surfaces/api/presenters/activities.js +1 -0
  278. package/dist/src/surfaces/api/presenters/board.js +3 -0
  279. package/dist/src/surfaces/api/presenters/control-plane.js +1 -0
  280. package/dist/src/surfaces/api/presenters/events.js +1 -0
  281. package/dist/src/surfaces/api/presenters/execution.js +59 -0
  282. package/dist/src/surfaces/api/presenters/observability.js +1 -0
  283. package/dist/src/surfaces/api/presenters/orchestration.js +19 -0
  284. package/dist/src/surfaces/api/presenters/resources.js +15 -0
  285. package/dist/src/surfaces/api/presenters/status.js +3 -0
  286. package/dist/src/surfaces/api/presenters/system.js +14 -0
  287. package/dist/src/surfaces/api/presenters/work.js +16 -0
  288. package/dist/src/surfaces/api/problem-details.js +9 -0
  289. package/dist/src/surfaces/api/router.js +13 -0
  290. package/dist/src/surfaces/api/routes/activities.js +1 -0
  291. package/dist/src/surfaces/api/routes/applications.js +1 -0
  292. package/dist/src/surfaces/api/routes/commands.js +82 -0
  293. package/dist/src/surfaces/api/routes/control-plane.js +6 -0
  294. package/dist/src/surfaces/api/routes/events.js +1 -0
  295. package/dist/src/surfaces/api/routes/execution.js +8 -0
  296. package/dist/src/surfaces/api/routes/index.js +18 -0
  297. package/dist/src/surfaces/api/routes/observability.js +1 -0
  298. package/dist/src/surfaces/api/routes/orchestration.js +1 -0
  299. package/dist/src/surfaces/api/routes/pagination.js +78 -0
  300. package/dist/src/surfaces/api/routes/read.js +135 -0
  301. package/dist/src/surfaces/api/routes/resources.js +1 -0
  302. package/dist/src/surfaces/api/routes/responses.js +67 -0
  303. package/dist/src/surfaces/api/routes/system.js +1 -0
  304. package/dist/src/surfaces/api/routes/work.js +9 -0
  305. package/dist/src/surfaces/cli/commands/api.js +1 -0
  306. package/dist/src/surfaces/cli/commands/audit.js +10 -0
  307. package/dist/src/surfaces/cli/commands/correlate.js +2 -0
  308. package/dist/src/surfaces/cli/commands/doctor.js +6 -0
  309. package/dist/src/surfaces/cli/commands/init.js +39 -0
  310. package/dist/src/surfaces/cli/commands/sandbox-entrypoint.js +33 -0
  311. package/dist/src/surfaces/cli/commands/sandbox-setup.js +29 -0
  312. package/dist/src/surfaces/cli/commands/sandbox.js +105 -0
  313. package/dist/src/surfaces/cli/commands/self-update.js +38 -0
  314. package/dist/src/surfaces/cli/commands/smoke.js +16 -0
  315. package/dist/src/surfaces/cli/commands/start.js +1 -0
  316. package/dist/src/surfaces/cli/commands/stop.js +13 -0
  317. package/dist/src/surfaces/cli/commands/tick.js +1 -0
  318. package/dist/src/surfaces/cli/commands/ui.js +2 -0
  319. package/dist/src/surfaces/cli/commands/validate-state.js +5 -0
  320. package/dist/src/surfaces/cli/infrastructure/docker-cli.js +221 -0
  321. package/dist/src/surfaces/cli/infrastructure/process-log.js +86 -0
  322. package/dist/src/surfaces/cli/main.js +140 -0
  323. package/dist/src/surfaces/cli/usage.js +33 -0
  324. package/dist/src/surfaces/contracts/config.js +34 -0
  325. package/dist/src/surfaces/index.js +47 -0
  326. package/dist/src/surfaces/web-assets/assets/index-Bfn4FwZG.css +1 -0
  327. package/dist/src/surfaces/web-assets/assets/index-ipB6JPGU.js +1090 -0
  328. package/dist/src/surfaces/web-assets/index.html +13 -0
  329. package/dist/src/surfaces/web-host/asset-source.js +1 -0
  330. package/dist/src/surfaces/web-host/packaged-assets.js +44 -0
  331. package/dist/src/work/application/work-projection.js +59 -0
  332. package/dist/src/work/application/work-repository.js +18 -0
  333. package/dist/src/work/application/work-service.js +117 -0
  334. package/dist/src/work/contracts/commands.js +1 -0
  335. package/dist/src/work/contracts/config.js +2 -0
  336. package/dist/src/work/contracts/events.js +103 -0
  337. package/dist/src/work/contracts/identifiers.js +5 -0
  338. package/dist/src/work/contracts/streams.js +6 -0
  339. package/dist/src/work/contracts/views.js +1 -0
  340. package/dist/src/work/contracts/vocabulary.js +6 -0
  341. package/dist/src/work/domain/work-item.js +89 -0
  342. package/dist/src/work/index.js +11 -0
  343. package/docker/Dockerfile +10 -6
  344. package/docker/Dockerfile.packaged +3 -3
  345. package/package.json +29 -4
  346. package/prompts/implement.md +2 -2
  347. package/templates/SETUP.md +7 -7
  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 -2365
  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/dist/src/{core → activities/pr}/contracts.js +0 -0
  442. /package/dist/src/{domain/types.js → control-plane/contracts/views.js} +0 -0
@@ -0,0 +1,143 @@
1
+ import { appendFile, mkdir, readdir, readFile, stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { isDeepStrictEqual } from 'node:util';
4
+ import { decodeEventEnvelope, WrongExpectedSequenceError } from '../../kernel/index.js';
5
+ import { withFileLock } from './file-lock.js';
6
+ export class FileEventJournal {
7
+ root;
8
+ clock;
9
+ constructor(root, clock) {
10
+ this.root = root;
11
+ this.clock = clock;
12
+ }
13
+ cached;
14
+ async append(stream, expectedSequence, drafts) {
15
+ return withFileLock(join(this.root, 'locks', 'event-journal.lock'), async () => {
16
+ const current = await this.scan();
17
+ const byId = new Map(current.map((event) => [event.eventId, event]));
18
+ const batchIds = new Set();
19
+ for (const draft of drafts) {
20
+ if (batchIds.has(draft.eventId))
21
+ throw new Error(`Event id ${draft.eventId} is repeated in one append`);
22
+ batchIds.add(draft.eventId);
23
+ }
24
+ const existing = drafts.map((draft) => byId.get(draft.eventId));
25
+ for (const [index, event] of existing.entries())
26
+ if (event !== undefined && !sameDraft(event, drafts[index]))
27
+ throw new Error(`Event id ${event.eventId} has already been used with different content`);
28
+ if (drafts.length > 0 && existing.every(isDefined))
29
+ return existing.filter(isDefined);
30
+ const streamEvents = current.filter((event) => key(event.stream) === key(stream));
31
+ if (streamEvents.length !== expectedSequence)
32
+ throw new WrongExpectedSequenceError(`Expected sequence ${expectedSequence} for ${key(stream)}, actual ${streamEvents.length}`);
33
+ for (const draft of drafts)
34
+ if (key(draft.stream) !== key(stream))
35
+ throw new Error('Event stream mismatch');
36
+ const recordedAt = this.clock.now().toISOString();
37
+ let newCount = 0;
38
+ const envelopes = drafts.map((draft, index) => {
39
+ const prior = existing[index];
40
+ if (prior !== undefined)
41
+ return prior;
42
+ newCount += 1;
43
+ return {
44
+ ...draft,
45
+ recordedAt,
46
+ sequence: streamEvents.length + newCount,
47
+ globalPosition: current.length + newCount,
48
+ };
49
+ });
50
+ const finalizedEnvelopes = envelopes.map((event) => decodeEventEnvelope(event));
51
+ const newEnvelopes = finalizedEnvelopes.filter((event) => !byId.has(event.eventId));
52
+ if (newEnvelopes.length > 0) {
53
+ const directory = join(this.root, 'events');
54
+ await mkdir(directory, { recursive: true });
55
+ const day = recordedAt.slice(0, 10);
56
+ await appendFile(join(directory, `${day}.jsonl`), newEnvelopes.map((event) => JSON.stringify(event)).join('\n') + '\n', 'utf8');
57
+ }
58
+ this.cached = undefined;
59
+ return finalizedEnvelopes;
60
+ });
61
+ }
62
+ async readStream(stream) {
63
+ return (await this.scan()).filter((event) => key(event.stream) === key(stream));
64
+ }
65
+ async readAll(after, limit = Number.POSITIVE_INFINITY) {
66
+ return (await this.scan()).filter((event) => event.globalPosition > after).slice(0, limit);
67
+ }
68
+ async readLatest(beforeGlobalPosition, limit = Number.POSITIVE_INFINITY) {
69
+ const events = await this.scan();
70
+ const before = beforeGlobalPosition ?? events.length + 1;
71
+ return events
72
+ .slice(0, before - 1)
73
+ .slice(-limit)
74
+ .reverse();
75
+ }
76
+ async scan() {
77
+ const directory = join(this.root, 'events');
78
+ let files;
79
+ try {
80
+ files = (await readdir(directory))
81
+ .filter((file) => /^\d{4}-\d{2}-\d{2}\.jsonl$/.test(file))
82
+ .sort();
83
+ }
84
+ catch (error) {
85
+ if (error.code === 'ENOENT')
86
+ return [];
87
+ throw error;
88
+ }
89
+ const fingerprint = (await Promise.all(files.map(async (file) => {
90
+ const info = await stat(join(directory, file));
91
+ return `${file}:${info.size}:${info.mtimeMs}`;
92
+ }))).join('|');
93
+ if (this.cached?.fingerprint === fingerprint)
94
+ return this.cached.events;
95
+ const events = [];
96
+ for (const file of files) {
97
+ const raw = await readFile(join(directory, file), 'utf8');
98
+ if (raw.length > 0 && !raw.endsWith('\n'))
99
+ throw new Error(`Incomplete trailing line in ${file}`);
100
+ for (const [index, line] of raw.split('\n').slice(0, -1).entries()) {
101
+ let input;
102
+ try {
103
+ input = JSON.parse(line);
104
+ const event = decodeEventEnvelope(input);
105
+ validateEnvelope(event, events.length + 1);
106
+ events.push(event);
107
+ }
108
+ catch (error) {
109
+ const context = eventContext(input);
110
+ throw new Error(`Corrupt event at ${file}:${index + 1}${context}: ${error.message}`, { cause: error });
111
+ }
112
+ }
113
+ }
114
+ this.cached = { fingerprint, events };
115
+ return events;
116
+ }
117
+ }
118
+ const key = (stream) => `${stream.kind}:${stream.id}`;
119
+ const sameDraft = (event, draft) => isDeepStrictEqual({
120
+ eventId: event.eventId,
121
+ eventType: event.eventType,
122
+ schemaVersion: event.schemaVersion,
123
+ occurredAt: event.occurredAt,
124
+ correlationId: event.correlationId,
125
+ causationId: event.causationId,
126
+ actor: event.actor,
127
+ source: event.source,
128
+ stream: event.stream,
129
+ payload: event.payload,
130
+ }, draft);
131
+ function validateEnvelope(event, expectedPosition) {
132
+ if (event.globalPosition !== expectedPosition)
133
+ throw new Error('Invalid event envelope position');
134
+ }
135
+ function eventContext(input) {
136
+ if (typeof input !== 'object' || input === null || !('eventId' in input))
137
+ return '';
138
+ const eventId = input.eventId;
139
+ return typeof eventId === 'string' && eventId.length > 0 ? ` event ${eventId}` : '';
140
+ }
141
+ function isDefined(value) {
142
+ return value !== undefined;
143
+ }
@@ -0,0 +1,91 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdir, open, readFile, rm } from 'node:fs/promises';
3
+ import { dirname } from 'node:path';
4
+ export async function acquireFileLock(path, options) {
5
+ await mkdir(dirname(path), { recursive: true });
6
+ const metadata = {
7
+ pid: process.pid,
8
+ acquiredAt: (options?.now ?? new Date()).toISOString(),
9
+ lockId: randomUUID(),
10
+ };
11
+ try {
12
+ return await createFileLock(path, metadata);
13
+ }
14
+ catch (error) {
15
+ if (error.code !== 'EEXIST')
16
+ throw error;
17
+ return reclaimStaleFileLock(path, metadata, options);
18
+ }
19
+ }
20
+ async function createFileLock(path, metadata) {
21
+ const handle = await open(path, 'wx');
22
+ try {
23
+ await handle.writeFile(`${JSON.stringify(metadata)}\n`, 'utf8');
24
+ await handle.sync();
25
+ }
26
+ finally {
27
+ await handle.close();
28
+ }
29
+ return { acquired: true, metadata, release: () => releaseFileLock(path, metadata) };
30
+ }
31
+ async function releaseFileLock(path, metadata) {
32
+ try {
33
+ const current = JSON.parse(await readFile(path, 'utf8'));
34
+ if (current.lockId === metadata.lockId)
35
+ await rm(path, { force: true });
36
+ }
37
+ catch {
38
+ /* already released */
39
+ }
40
+ }
41
+ async function reclaimStaleFileLock(path, metadata, options) {
42
+ if (options?.staleAfterMs === undefined)
43
+ return unavailableFileLock();
44
+ try {
45
+ const prior = JSON.parse(await readFile(path, 'utf8'));
46
+ if (!isStale(prior, options))
47
+ return unavailableFileLock();
48
+ if (options.staleRequiresDeadProcess && ownerMayBeAlive(options, prior.pid))
49
+ return unavailableFileLock();
50
+ }
51
+ catch {
52
+ // A corrupt or vanished lock has no trustworthy owner and can be reclaimed.
53
+ }
54
+ await rm(path, { force: true });
55
+ return createFileLock(path, metadata);
56
+ }
57
+ function isStale(prior, options) {
58
+ return ((options.now ?? new Date()).getTime() - Date.parse(prior.acquiredAt) >= options.staleAfterMs);
59
+ }
60
+ function unavailableFileLock() {
61
+ return { acquired: false, async release() { } };
62
+ }
63
+ function isProcessAlive(pid) {
64
+ try {
65
+ process.kill(pid, 0);
66
+ return true;
67
+ }
68
+ catch {
69
+ return false;
70
+ }
71
+ }
72
+ function ownerMayBeAlive(options, pid) {
73
+ try {
74
+ return (options.isProcessAlive ?? isProcessAlive)(pid);
75
+ }
76
+ catch {
77
+ // Permission and platform-probe failures are indeterminate: never steal a live owner's lock.
78
+ return true;
79
+ }
80
+ }
81
+ export async function withFileLock(path, operation) {
82
+ const lock = await acquireFileLock(path, { staleAfterMs: 60_000 });
83
+ if (!lock.acquired)
84
+ throw new Error(`File lock is already held: ${path}`);
85
+ try {
86
+ return await operation();
87
+ }
88
+ finally {
89
+ await lock.release();
90
+ }
91
+ }
@@ -0,0 +1,64 @@
1
+ import { mkdir, open, readFile, readdir, rename, rm } from 'node:fs/promises';
2
+ import { dirname, join } from 'node:path';
3
+ export class FileProjectionStore {
4
+ root;
5
+ constructor(root) {
6
+ this.root = root;
7
+ }
8
+ async read(namespace, key) {
9
+ try {
10
+ return JSON.parse(await readFile(this.path(namespace, key), 'utf8'));
11
+ }
12
+ catch (error) {
13
+ if (error.code === 'ENOENT')
14
+ return null;
15
+ throw error;
16
+ }
17
+ }
18
+ async write(projection) {
19
+ await atomicJson(this.path(projection.namespace, projection.key), projection);
20
+ }
21
+ async list(namespace) {
22
+ const directory = join(this.root, 'projections', encode(namespace));
23
+ try {
24
+ const files = (await readdir(directory)).filter((file) => file.endsWith('.json')).sort();
25
+ return Promise.all(files.map(async (file) => JSON.parse(await readFile(join(directory, file), 'utf8'))));
26
+ }
27
+ catch (error) {
28
+ if (error.code === 'ENOENT')
29
+ return [];
30
+ throw error;
31
+ }
32
+ }
33
+ async clear(namespace) {
34
+ await rm(namespace === undefined
35
+ ? join(this.root, 'projections')
36
+ : join(this.root, 'projections', encode(namespace)), { recursive: true, force: true });
37
+ }
38
+ path(namespace, key) {
39
+ return join(this.root, 'projections', encode(namespace), `${encode(key)}.json`);
40
+ }
41
+ }
42
+ export function encode(value) {
43
+ if (value.length === 0 || /[\\/]/.test(value))
44
+ throw new Error('Storage name must not contain path separators');
45
+ return encodeURIComponent(value).replace(/%/g, '~').replace(/\./g, '~2E');
46
+ }
47
+ export async function atomicJson(path, value) {
48
+ await mkdir(dirname(path), { recursive: true });
49
+ const temporary = `${path}.${process.pid}.${Date.now()}.tmp`;
50
+ try {
51
+ const handle = await open(temporary, 'wx');
52
+ try {
53
+ await handle.writeFile(`${JSON.stringify(value)}\n`, 'utf8');
54
+ await handle.sync();
55
+ }
56
+ finally {
57
+ await handle.close();
58
+ }
59
+ await rename(temporary, path);
60
+ }
61
+ finally {
62
+ await rm(temporary, { force: true });
63
+ }
64
+ }
@@ -0,0 +1,8 @@
1
+ export * from './application/projection-runner.js';
2
+ export * from './filesystem/file-checkpoint-store.js';
3
+ export * from './filesystem/file-event-journal.js';
4
+ export * from './filesystem/file-lock.js';
5
+ export * from './filesystem/file-projection-store.js';
6
+ export * from './memory/in-memory-checkpoint-store.js';
7
+ export * from './memory/in-memory-event-journal.js';
8
+ export * from './memory/in-memory-projection-store.js';
@@ -0,0 +1,14 @@
1
+ export class InMemoryCheckpointStore {
2
+ values = new Map();
3
+ async load(consumer) {
4
+ return this.values.get(consumer) ?? 0;
5
+ }
6
+ async save(consumer, position) {
7
+ if (position < (await this.load(consumer)))
8
+ throw new Error(`Checkpoint regression for ${consumer}`);
9
+ this.values.set(consumer, position);
10
+ }
11
+ async reset(consumer) {
12
+ this.values.delete(consumer);
13
+ }
14
+ }
@@ -0,0 +1,88 @@
1
+ import { isDeepStrictEqual } from 'node:util';
2
+ import { WrongExpectedSequenceError } from '../../kernel/index.js';
3
+ export class InMemoryEventJournal {
4
+ clock;
5
+ streams = new Map();
6
+ events = [];
7
+ eventIds = new Map();
8
+ constructor(clock) {
9
+ this.clock = clock;
10
+ }
11
+ async append(stream, expectedSequence, events) {
12
+ validateBatch(stream, events);
13
+ const existingEvents = events.map((draft) => this.eventIds.get(draft.eventId));
14
+ this.rejectChangedEventIds(events, existingEvents);
15
+ if (events.length > 0 && existingEvents.every((event) => event !== undefined)) {
16
+ return existingEvents.map((event) => event.envelope);
17
+ }
18
+ const streamEvents = this.streams.get(streamKey(stream)) ?? [];
19
+ if (streamEvents.length !== expectedSequence) {
20
+ throw new WrongExpectedSequenceError(`Expected sequence ${expectedSequence} for ${streamKey(stream)}, actual ${streamEvents.length}`);
21
+ }
22
+ const recordedAt = this.clock.now().toISOString();
23
+ const appended = [];
24
+ for (const [index, draft] of events.entries()) {
25
+ const prior = existingEvents[index];
26
+ if (prior !== undefined) {
27
+ appended.push(prior.envelope);
28
+ continue;
29
+ }
30
+ const envelope = {
31
+ ...draft,
32
+ recordedAt,
33
+ sequence: streamEvents.length + 1,
34
+ globalPosition: this.events.length + 1,
35
+ };
36
+ streamEvents.push(envelope);
37
+ this.events.push(envelope);
38
+ this.eventIds.set(draft.eventId, { draft, envelope });
39
+ appended.push(envelope);
40
+ }
41
+ this.streams.set(streamKey(stream), streamEvents);
42
+ return appended;
43
+ }
44
+ async readStream(stream) {
45
+ return [...(this.streams.get(streamKey(stream)) ?? [])];
46
+ }
47
+ async readAll(afterGlobalPosition, limit = Number.POSITIVE_INFINITY) {
48
+ return this.events
49
+ .filter((event) => event.globalPosition > afterGlobalPosition)
50
+ .slice(0, limit);
51
+ }
52
+ async readLatest(beforeGlobalPosition = this.events.length + 1, limit = Number.POSITIVE_INFINITY) {
53
+ return this.events
54
+ .slice(0, beforeGlobalPosition - 1)
55
+ .slice(-limit)
56
+ .reverse();
57
+ }
58
+ rejectChangedEventIds(drafts, existingEvents) {
59
+ for (const [index, draft] of drafts.entries()) {
60
+ const existing = existingEvents[index];
61
+ if (existing !== undefined && !isDeepStrictEqual(existing.draft, draft)) {
62
+ throw new Error(`Event id ${draft.eventId} has already been used with different content`);
63
+ }
64
+ }
65
+ }
66
+ }
67
+ function streamKey(stream) {
68
+ return `${stream.kind}:${stream.id}`;
69
+ }
70
+ function assertSameStream(expected, actual) {
71
+ if (streamKey(expected) !== streamKey(actual)) {
72
+ throw new Error(`Event stream ${streamKey(actual)} does not match append stream ${streamKey(expected)}`);
73
+ }
74
+ }
75
+ function validateBatch(stream, drafts) {
76
+ const eventIds = new Map();
77
+ for (const draft of drafts) {
78
+ assertSameStream(stream, draft.stream);
79
+ const prior = eventIds.get(draft.eventId);
80
+ if (prior !== undefined) {
81
+ if (!isDeepStrictEqual(prior, draft)) {
82
+ throw new Error(`Event id ${draft.eventId} is repeated with different content in one append`);
83
+ }
84
+ throw new Error(`Event id ${draft.eventId} is repeated in one append`);
85
+ }
86
+ eventIds.set(draft.eventId, draft);
87
+ }
88
+ }
@@ -0,0 +1,17 @@
1
+ export class InMemoryProjectionStore {
2
+ values = new Map();
3
+ async read(namespace, key) {
4
+ return this.values.get(`${namespace}\0${key}`) ?? null;
5
+ }
6
+ async write(projection) {
7
+ this.values.set(`${projection.namespace}\0${projection.key}`, structuredClone(projection));
8
+ }
9
+ async list(namespace) {
10
+ return [...this.values.values()].filter((value) => value.namespace === namespace);
11
+ }
12
+ async clear(namespace) {
13
+ for (const [key, value] of this.values)
14
+ if (namespace === undefined || value.namespace === namespace)
15
+ this.values.delete(key);
16
+ }
17
+ }
@@ -0,0 +1,48 @@
1
+ import { ResourceEventType, selectResourceEvent } from '../contracts/events.js';
2
+ export const externalKeyProjectionKey = (externalKey) => `${encodeURIComponent(externalKey.adapter)}:${encodeURIComponent(externalKey.key)}`;
3
+ export const resourcesByExternalKeyProjection = {
4
+ name: 'resources-by-external-key',
5
+ select(event) {
6
+ const owned = selectResourceEvent(event);
7
+ return owned?.eventType === ResourceEventType.ResourceDiscovered
8
+ ? { key: externalKeyProjectionKey(owned.payload.externalKey) }
9
+ : null;
10
+ },
11
+ initial: () => null,
12
+ project(previous, event) {
13
+ const owned = selectResourceEvent(event);
14
+ if (owned?.eventType !== ResourceEventType.ResourceDiscovered)
15
+ return previous;
16
+ return previous ?? owned.stream.id;
17
+ },
18
+ };
19
+ export const workCorrelationsProjection = {
20
+ name: 'work-correlations',
21
+ select(event) {
22
+ const owned = selectResourceEvent(event);
23
+ if (owned?.eventType === ResourceEventType.WorkCorrelationEstablished)
24
+ return { key: owned.payload.workItemId };
25
+ if (owned?.eventType === ResourceEventType.WorkCorrelationRetracted)
26
+ return { key: owned.payload.workItemId };
27
+ return null;
28
+ },
29
+ initial: () => [],
30
+ project(previous, event) {
31
+ const owned = selectResourceEvent(event);
32
+ if (owned?.eventType === ResourceEventType.WorkCorrelationEstablished) {
33
+ const correlation = {
34
+ resourceId: owned.stream.id,
35
+ workItemId: owned.payload.workItemId,
36
+ role: owned.payload.role,
37
+ provenance: owned.payload.provenance,
38
+ establishedByEventId: owned.eventId,
39
+ };
40
+ return previous.some((value) => value.resourceId === correlation.resourceId)
41
+ ? previous
42
+ : [...previous, correlation];
43
+ }
44
+ if (owned?.eventType === ResourceEventType.WorkCorrelationRetracted)
45
+ return previous.filter((value) => value.resourceId !== owned.stream.id);
46
+ return previous;
47
+ },
48
+ };
@@ -0,0 +1,16 @@
1
+ import { externalKeyProjectionKey, resourcesByExternalKeyProjection, workCorrelationsProjection, } from './lookup-projections.js';
2
+ export function createResourceLookup(dependencies) {
3
+ const seeded = async (definition, key) => {
4
+ const stored = await dependencies.projections.read(definition.name, key);
5
+ let value = stored?.value ?? definition.initial(key);
6
+ for (const event of await dependencies.journal.readAll(stored?.lastGlobalPosition ?? 0)) {
7
+ if (definition.select(event)?.key === key)
8
+ value = definition.project(value, event);
9
+ }
10
+ return value;
11
+ };
12
+ return {
13
+ resourceIdForExternalKey: (externalKey) => seeded(resourcesByExternalKeyProjection, externalKeyProjectionKey(externalKey)),
14
+ correlationsForWork: (workItemId) => seeded(workCorrelationsProjection, workItemId),
15
+ };
16
+ }
@@ -0,0 +1,81 @@
1
+ import { ResourceEventType, selectResourceEvent } from '../contracts/events.js';
2
+ export const resourceProjection = {
3
+ name: 'resources',
4
+ select(event) {
5
+ const owned = selectResourceEvent(event);
6
+ return owned === null ? null : { key: owned.stream.id };
7
+ },
8
+ initial: () => null,
9
+ project(previous, event) {
10
+ const owned = selectResourceEvent(event);
11
+ if (owned === null)
12
+ return previous;
13
+ switch (owned.eventType) {
14
+ case ResourceEventType.ResourceDiscovered:
15
+ return {
16
+ resourceId: owned.stream.id,
17
+ kind: owned.payload.kind,
18
+ externalKey: owned.payload.externalKey,
19
+ capabilities: owned.payload.capabilities,
20
+ ...(owned.payload.revision === undefined ? {} : { revision: owned.payload.revision }),
21
+ ...(owned.payload.title === undefined ? {} : { title: owned.payload.title }),
22
+ };
23
+ case ResourceEventType.ResourceRevisionObserved:
24
+ return previous === null ? previous : { ...previous, revision: owned.payload.revision };
25
+ case ResourceEventType.WorkCorrelationConflicted:
26
+ return previous === null
27
+ ? previous
28
+ : {
29
+ ...previous,
30
+ primaryCorrelationConflict: {
31
+ attemptedWorkItemId: owned.payload.workItemId,
32
+ existingWorkItemId: owned.payload.existingWorkItemId,
33
+ eventId: owned.eventId,
34
+ },
35
+ };
36
+ case ResourceEventType.WorkCorrelationEstablished:
37
+ case ResourceEventType.WorkCorrelationRetracted:
38
+ return previous;
39
+ default:
40
+ return assertNever(owned);
41
+ }
42
+ },
43
+ };
44
+ export const resourceCorrelationProjection = {
45
+ name: 'resource-correlations',
46
+ select(event) {
47
+ const owned = selectResourceEvent(event);
48
+ return owned === null ? null : { key: owned.stream.id };
49
+ },
50
+ initial: () => [],
51
+ project(previous, event) {
52
+ const owned = selectResourceEvent(event);
53
+ if (owned === null)
54
+ return previous;
55
+ switch (owned.eventType) {
56
+ case ResourceEventType.WorkCorrelationEstablished: {
57
+ const correlation = {
58
+ resourceId: owned.stream.id,
59
+ workItemId: owned.payload.workItemId,
60
+ role: owned.payload.role,
61
+ provenance: owned.payload.provenance,
62
+ establishedByEventId: owned.eventId,
63
+ };
64
+ return previous.some((value) => value.workItemId === correlation.workItemId)
65
+ ? previous
66
+ : [...previous, correlation];
67
+ }
68
+ case ResourceEventType.WorkCorrelationRetracted:
69
+ return previous.filter((value) => value.workItemId !== owned.payload.workItemId);
70
+ case ResourceEventType.ResourceDiscovered:
71
+ case ResourceEventType.ResourceRevisionObserved:
72
+ case ResourceEventType.WorkCorrelationConflicted:
73
+ return previous;
74
+ default:
75
+ return assertNever(owned);
76
+ }
77
+ },
78
+ };
79
+ function assertNever(value) {
80
+ throw new Error(`Unhandled Resource event: ${JSON.stringify(value)}`);
81
+ }
@@ -0,0 +1,18 @@
1
+ import { decodeResourceEvent, selectResourceEvent, } from '../contracts/events.js';
2
+ import { resourceStream } from '../contracts/streams.js';
3
+ import { foldResource } from '../domain/resource.js';
4
+ export class ResourceRepository {
5
+ journal;
6
+ constructor(journal) {
7
+ this.journal = journal;
8
+ }
9
+ async load(resourceId) {
10
+ const events = await this.journal.readStream(resourceStream(resourceId));
11
+ const owned = events.map(selectResourceEvent).filter((event) => event !== null);
12
+ return { sequence: events.length, resource: foldResource(owned) };
13
+ }
14
+ async append(resourceId, expectedSequence, drafts) {
15
+ const events = await this.journal.append(resourceStream(resourceId), expectedSequence, drafts);
16
+ return events.map(decodeResourceEvent);
17
+ }
18
+ }