@atolis-hq/wake 0.2.97 → 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 -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/dist/src/{core → activities/pr}/contracts.js +0 -0
  442. /package/dist/src/{domain/types.js → control-plane/contracts/views.js} +0 -0
@@ -1,192 +0,0 @@
1
- export function createControlPlane(deps) {
2
- let running = true;
3
- let lastStatus;
4
- let lastIntakeStatus;
5
- let lastRunnerStatus;
6
- let consecutiveIdleTicks = 0;
7
- let consecutiveIntakeIdleTicks = 0;
8
- let consecutiveRunnerIdleTicks = 0;
9
- let lastSingleTickRequest;
10
- let lastIntakeTickRequest;
11
- let lastRunnerTickRequest;
12
- const maxIntervalMs = deps.maxIntervalMs ?? deps.intervalMs * 16;
13
- function nextSleepMs(consecutiveTicks) {
14
- const backoffMs = deps.intervalMs * 2 ** Math.min(consecutiveTicks, 20);
15
- return Math.min(backoffMs, maxIntervalMs);
16
- }
17
- async function tickRequestPending(input) {
18
- const request = (await deps.readTickRequest?.()) ?? null;
19
- if (request === null || request === input.getLastRequest()) {
20
- return false;
21
- }
22
- input.setLastRequest(request);
23
- return true;
24
- }
25
- async function sleepUntilNextTick(ms, requestState) {
26
- if (deps.readTickRequest === undefined || ms <= 0) {
27
- await deps.sleep(ms);
28
- return { forced: false };
29
- }
30
- if (await tickRequestPending(requestState)) {
31
- return { forced: true };
32
- }
33
- const deadline = Date.now() + ms;
34
- while (running) {
35
- const remainingMs = deadline - Date.now();
36
- if (remainingMs <= 0) {
37
- return { forced: false };
38
- }
39
- await deps.sleep(Math.min(remainingMs, 250));
40
- if (await tickRequestPending(requestState)) {
41
- return { forced: true };
42
- }
43
- }
44
- return { forced: false };
45
- }
46
- async function isPaused() {
47
- return Boolean(await deps.isPaused());
48
- }
49
- function logStatus(message, status, last) {
50
- if (status !== last) {
51
- deps.logger.info(message);
52
- }
53
- return status;
54
- }
55
- async function runLoopOnce(input) {
56
- if (await isPaused()) {
57
- const status = 'paused';
58
- if (input.label === 'intake') {
59
- lastIntakeStatus = logStatus('[wake] intake status=paused', status, lastIntakeStatus);
60
- }
61
- else {
62
- lastRunnerStatus = logStatus('[wake] runner status=paused', status, lastRunnerStatus);
63
- }
64
- return { status: 'paused' };
65
- }
66
- const result = await input.run();
67
- const status = result?.status ?? 'unknown';
68
- if (input.label === 'intake') {
69
- lastIntakeStatus = logStatus(`[wake] intake status=${status}`, status, lastIntakeStatus);
70
- }
71
- else {
72
- lastRunnerStatus = logStatus(`[wake] runner status=${status}`, status, lastRunnerStatus);
73
- }
74
- return result;
75
- }
76
- async function startLoop(input) {
77
- while (running) {
78
- let result;
79
- try {
80
- result = await runLoopOnce({ run: input.run, label: input.label });
81
- }
82
- catch (error) {
83
- deps.logger.error(error instanceof Error ? error.message : String(error));
84
- }
85
- if (!running) {
86
- break;
87
- }
88
- const status = result?.status;
89
- if (status === 'processed') {
90
- input.setIdleTicks(0);
91
- if (input.label === 'intake') {
92
- await sleepUntilNextTick(deps.intervalMs, {
93
- getLastRequest: input.getLastRequest,
94
- setLastRequest: input.setLastRequest,
95
- });
96
- }
97
- }
98
- else {
99
- const waitMs = input.idleBackoff ? nextSleepMs(input.getIdleTicks()) : deps.intervalMs;
100
- const wait = await sleepUntilNextTick(waitMs, {
101
- getLastRequest: input.getLastRequest,
102
- setLastRequest: input.setLastRequest,
103
- });
104
- if (!wait.forced && input.idleBackoff) {
105
- input.setIdleTicks(input.getIdleTicks() + 1);
106
- }
107
- }
108
- }
109
- }
110
- return {
111
- stop() {
112
- running = false;
113
- },
114
- async runOnce() {
115
- if (await isPaused()) {
116
- if (lastStatus !== 'paused') {
117
- deps.logger.info('[wake] status=paused');
118
- lastStatus = 'paused';
119
- }
120
- return { status: 'paused' };
121
- }
122
- const result = await deps.tickRunner.runTick();
123
- const status = result?.status ?? 'unknown';
124
- if (status !== lastStatus) {
125
- deps.logger.info(`[wake] status=${status}`);
126
- lastStatus = status;
127
- }
128
- return result;
129
- },
130
- async start() {
131
- if (deps.tickRunner.runIntakeTick !== undefined &&
132
- deps.tickRunner.runRunnerTick !== undefined) {
133
- await Promise.all([
134
- startLoop({
135
- run: deps.tickRunner.runIntakeTick,
136
- label: 'intake',
137
- getIdleTicks: () => consecutiveIntakeIdleTicks,
138
- setIdleTicks: (value) => {
139
- consecutiveIntakeIdleTicks = value;
140
- },
141
- getLastRequest: () => lastIntakeTickRequest,
142
- setLastRequest: (value) => {
143
- lastIntakeTickRequest = value;
144
- },
145
- idleBackoff: true,
146
- }),
147
- startLoop({
148
- run: deps.tickRunner.runRunnerTick,
149
- label: 'runner',
150
- getIdleTicks: () => consecutiveRunnerIdleTicks,
151
- setIdleTicks: (value) => {
152
- consecutiveRunnerIdleTicks = value;
153
- },
154
- getLastRequest: () => lastRunnerTickRequest,
155
- setLastRequest: (value) => {
156
- lastRunnerTickRequest = value;
157
- },
158
- idleBackoff: false,
159
- }),
160
- ]);
161
- return;
162
- }
163
- while (running) {
164
- let result;
165
- try {
166
- result = await this.runOnce();
167
- }
168
- catch (error) {
169
- deps.logger.error(error instanceof Error ? error.message : String(error));
170
- }
171
- if (!running) {
172
- break;
173
- }
174
- const status = result?.status;
175
- if (status === 'processed') {
176
- consecutiveIdleTicks = 0;
177
- }
178
- else {
179
- const wait = await sleepUntilNextTick(nextSleepMs(consecutiveIdleTicks), {
180
- getLastRequest: () => lastSingleTickRequest,
181
- setLastRequest: (value) => {
182
- lastSingleTickRequest = value;
183
- },
184
- });
185
- if (!wait.forced) {
186
- consecutiveIdleTicks += 1;
187
- }
188
- }
189
- }
190
- },
191
- };
192
- }
@@ -1,153 +0,0 @@
1
- import { LABELS_REQUESTED_EVENT, PUBLISH_INTENT_REQUESTED_EVENT } from '../domain/event-types.js';
2
- import { createEventEnvelope } from '../lib/event-log.js';
3
- import { extractTokenCount, formatCostUsd, formatDuration, formatTokenCount, } from '../lib/format.js';
4
- function isReviewThreadResourceUri(resourceUri) {
5
- return resourceUri.split(':')[1] === 'pr-review-thread';
6
- }
7
- // `latestComment` is a sticky, per-work-item field: projection-updater.ts's
8
- // comment fold overwrites it unconditionally on every inbound comment
9
- // (any surface) and nothing ever resets it. So it means "the last comment
10
- // this work item has ever received," not "the comment that triggered the
11
- // currently completing run." Several needsWakeAction trigger paths (first
12
- // run, quota-failure retry, first workflow-stage pass) complete a run
13
- // with no fresh comment driving it at all — in those cases latestComment
14
- // may still be pointing at an older, already-handled comment from a
15
- // different surface (e.g. a PR) and must not be trusted as this run's
16
- // trigger. This mirrors policy-engine.ts's needsWakeAction "is there an
17
- // unhandled human comment" check exactly, so a comment is only treated as
18
- // having driven this run when it's human-authored and not yet the
19
- // candidate's own lastHandledCommentId (read from the pre-completion
20
- // projection passed in as `candidate`/`projection`, since the completion
21
- // event that would update lastHandledCommentId for *this* run hasn't been
22
- // folded yet at the point this runs).
23
- function isFreshTriggeringComment(candidate) {
24
- const context = candidate.context;
25
- const handledCommentId = typeof context.lastHandledCommentId === 'string' ? context.lastHandledCommentId : undefined;
26
- return (candidate.latestComment !== undefined &&
27
- !candidate.latestComment.isBotAuthored &&
28
- candidate.latestComment.id !== handledCommentId);
29
- }
30
- export function createPublishIntentEvent(input) {
31
- const tokenCount = extractTokenCount(input.runnerResult.tokenUsage);
32
- const duration = formatDuration(input.startedAt, input.occurredAt);
33
- const failureRepeated = input.runnerResult.failureClass !== undefined &&
34
- input.previousFailureClass === input.runnerResult.failureClass;
35
- return createEventEnvelope({
36
- eventId: `${input.runId}-publish-intent`,
37
- workItemKey: input.projection.workItemKey,
38
- streamScope: 'work-item',
39
- direction: 'outbound',
40
- sourceSystem: 'wake',
41
- sourceEventType: PUBLISH_INTENT_REQUESTED_EVENT,
42
- sourceRefs: {
43
- repo: input.projection.issue.repo,
44
- issueNumber: input.projection.issue.number,
45
- runId: input.runId,
46
- // Carries the triggering comment's surface (set only when the human
47
- // reply that woke this run came from a correlated PR/review-thread
48
- // resource, per the ad1cf45 comment fold) through to the sink
49
- // router, so createOutboundSinkRouter's kind-based routing (Task 11,
50
- // sink-router.ts) can send the reply back to that surface instead of
51
- // defaulting to the issue thread. Without this, every reply landed
52
- // on the origin sink regardless of which surface triggered the run.
53
- //
54
- // Gated on isFreshTriggeringComment: latestComment is sticky (see
55
- // that function's comment) and several run-completion paths (first
56
- // run, quota retry, first workflow-stage pass) have no fresh
57
- // comment behind them at all — for those, threading the stale
58
- // latestComment.resourceUri would misroute the reply to whatever
59
- // surface last happened to comment, even long after that comment
60
- // was already replied to.
61
- //
62
- // Never threads a pr-review-thread surface specifically: this is
63
- // Wake's own status, approval-request, or question card: a milestone
64
- // message, not a targeted reply to one inline comment — burying it
65
- // as a reply deep in a single review thread makes it easy to miss.
66
- // Omitting resourceUri here falls back to sourceOrigin in
67
- // sink-router.ts, landing it on the correlated issue (or, for a
68
- // standalone PR-only work item, GitHub's shared issue/PR comments
69
- // endpoint posts it as a top-level PR comment instead). Replies to
70
- // individual review threads are the agent's own job now — see
71
- // prompts/revise.md — via `gh api .../replies`, not this card.
72
- ...(input.projection.latestComment?.resourceUri === undefined ||
73
- !isFreshTriggeringComment(input.projection) ||
74
- isReviewThreadResourceUri(input.projection.latestComment.resourceUri)
75
- ? {}
76
- : { resourceUri: input.projection.latestComment.resourceUri }),
77
- },
78
- occurredAt: input.occurredAt,
79
- ingestedAt: input.occurredAt,
80
- trigger: 'context-only',
81
- payload: {
82
- kind: input.sentinel === 'DONE' && input.approvalGated === true
83
- ? 'approval-request'
84
- : input.sentinel === 'BLOCKED'
85
- ? 'question'
86
- : input.sentinel === 'FAILED'
87
- ? 'failure'
88
- : 'status-update',
89
- origin: input.projection.origin ?? 'github',
90
- body: input.parsedRunnerResult.body,
91
- action: input.action,
92
- sentinel: input.sentinel,
93
- runId: input.runId,
94
- ...(input.runnerResult.session_id === undefined
95
- ? {}
96
- : { sessionId: input.runnerResult.session_id }),
97
- model: input.runnerResult.model,
98
- cli: input.runnerResult.cli,
99
- ...(input.runnerResult.routing === undefined
100
- ? {}
101
- : {
102
- runnerName: input.runnerResult.routing.runnerName,
103
- runnerKind: input.runnerResult.routing.runnerKind,
104
- runnerTier: input.runnerResult.routing.tier,
105
- runnerReason: input.runnerResult.routing.reason,
106
- }),
107
- ...(duration === undefined ? {} : { duration }),
108
- ...(tokenCount === undefined ? {} : { tokens: formatTokenCount(tokenCount) }),
109
- ...(input.runnerResult.tokenUsage?.costUsd === undefined
110
- ? {}
111
- : { cost: formatCostUsd(input.runnerResult.tokenUsage.costUsd) }),
112
- ...(input.workspacePath === undefined ? {} : { workspacePath: input.workspacePath }),
113
- idempotencyKey: `${input.runId}:result-comment`,
114
- deliveryState: 'PENDING',
115
- ...(failureRepeated ? { failureRepeated } : {}),
116
- ...(input.previousFailureClass === undefined
117
- ? {}
118
- : { previousFailureClass: input.previousFailureClass }),
119
- },
120
- derivedHints: {
121
- stage: input.sentinel === 'DONE' ? 'done' : input.projection.wake.stage,
122
- },
123
- });
124
- }
125
- export function createLabelsEvent(input) {
126
- const labelKind = input.statusLabel === 'wake:status.working' ? 'working-label' : 'completion-label';
127
- return createEventEnvelope({
128
- eventId: `${input.runId}-labels-${input.statusLabel.replace(/[^a-z0-9]+/gi, '-')}-${input.stageLabel.replace(/[^a-z0-9]+/gi, '-')}-${input.workflowLabel.replace(/[^a-z0-9]+/gi, '-')}`,
129
- workItemKey: input.projection.workItemKey,
130
- streamScope: 'work-item',
131
- direction: 'outbound',
132
- sourceSystem: 'wake',
133
- sourceEventType: LABELS_REQUESTED_EVENT,
134
- sourceRefs: {
135
- repo: input.projection.issue.repo,
136
- issueNumber: input.projection.issue.number,
137
- runId: input.runId,
138
- },
139
- occurredAt: input.occurredAt,
140
- ingestedAt: input.occurredAt,
141
- trigger: 'context-only',
142
- payload: {
143
- statusLabel: input.statusLabel,
144
- stageLabel: input.stageLabel,
145
- workflowLabel: input.workflowLabel,
146
- ...(input.frozenLabel === undefined ? {} : { frozenLabel: input.frozenLabel }),
147
- ...(input.scheduledLabel === undefined ? {} : { scheduledLabel: input.scheduledLabel }),
148
- origin: input.projection.origin ?? 'github',
149
- idempotencyKey: `${input.runId}:${labelKind}`,
150
- deliveryState: 'PENDING',
151
- },
152
- });
153
- }
@@ -1,249 +0,0 @@
1
- import { createWorkId } from '../lib/work-id.js';
2
- import { CORRELATION_REGISTERED_EVENT, UNRESOLVED_WORK_ITEM_KEY, WORK_ITEM_CREATED_EVENT, } from '../domain/schema.js';
3
- import { createEventEnvelope } from '../lib/event-log.js';
4
- // How an unkeyed source event becomes a work item — the correlation-resolution
5
- // subsystem described in docs/adrs/0001-correlating-external-resources-to-work-items.md.
6
- export function createEventResolver(deps) {
7
- // Events are stamped by reading the clock at the moment of stamping, never
8
- // from a frozen tick-start snapshot. `tickStartedAt` is the tick's *decision*
9
- // clock (policy/staleness), and reusing it to date events inverts them
10
- // against the work source's own poll-time ingestedAt — pollEvents() runs
11
- // after tickStartedAt is captured, so in production every polled upsert is
12
- // LATER than the tick's start. An event dated before the upsert that creates
13
- // the projection it folds into sorts ahead of it in rebuildFromEvents' global
14
- // replay, folds against `current === null`, and is silently dropped. Reading
15
- // per event also stays correct once ticks work items in parallel, where a
16
- // shared per-tick snapshot would tie every concurrent event on ingestedAt and
17
- // leave append order as the only discriminator.
18
- function eventStampNow() {
19
- return deps.clock.now().toISOString();
20
- }
21
- // Returns whichever of the two timestamps is unambiguously later, defaulting
22
- // to `left`. `right` wins only if it is later by BOTH the actual instant and
23
- // the lexicographic order rebuildFromEvents sorts on — the envelope schema is
24
- // `z.string().datetime({ offset: true })`, so a timestamp may legally carry a
25
- // non-UTC offset or differing sub-second precision, and lexicographic order
26
- // alone is not a reliable proxy for chronology across those formats. Falling
27
- // back to `left` (the source event's own exact string) is always safe: it
28
- // ties with that event under localeCompare, and the stable sort then preserves
29
- // append order, which puts the mint events after it — exactly what we need.
30
- function laterTimestamp(left, right) {
31
- const isLater = Date.parse(right) > Date.parse(left) && right.localeCompare(left) > 0;
32
- return isLater ? right : left;
33
- }
34
- // The two internal events a mint (or a heal) appends after the source event
35
- // that founded a work item: wake.workitem.created, then the
36
- // wake.correlation.registered that claims the originating resource as this
37
- // work item's primary representation. Their ids are derived from the work id,
38
- // so re-emitting them is idempotent — appendEventEnvelope dedups on the id.
39
- //
40
- // Ordering and timestamps matter, and not only for readability. Both fold
41
- // against the projection the source event creates, and applyEvent drops
42
- // anything that folds while `current === null`. So they must never sort
43
- // *before* that source event in rebuildFromEvents' globally-ordered replay —
44
- // if they did, replay would silently discard the registration, leaving
45
- // correlatedResources[] empty and the index unpopulated, while the events
46
- // still on record stop any later tick from re-registering. Permanent,
47
- // self-concealing loss (Task 5, round 3). Reading the clock here is already
48
- // after pollEvents(), but that alone is not a guarantee: the source event's
49
- // ingestedAt comes from the *source's* clock, which for a real source is
50
- // another machine's and can legitimately run ahead of ours. Anchoring on the
51
- // source event's own timestamp makes the ordering hold by construction rather
52
- // than by clock agreement; appending the source event first means a tie
53
- // resolves in its favour (the sort is stable, so equal timestamps keep append
54
- // order).
55
- function buildOriginCorrelationEvents(workItemKey, unkeyed, resourceUri) {
56
- const mintedAt = laterTimestamp(unkeyed.ingestedAt, eventStampNow());
57
- const sourceRefs = {
58
- ...unkeyed.sourceRefs,
59
- resourceUri,
60
- };
61
- const createdEvent = createEventEnvelope({
62
- eventId: `${workItemKey}-created`,
63
- workItemKey,
64
- streamScope: 'work-item',
65
- direction: 'internal',
66
- sourceSystem: 'wake',
67
- sourceEventType: WORK_ITEM_CREATED_EVENT,
68
- sourceRefs,
69
- occurredAt: mintedAt,
70
- ingestedAt: mintedAt,
71
- trigger: 'context-only',
72
- // The envelope's workItemKey already carries the identity.
73
- payload: {},
74
- });
75
- const registeredEvent = createEventEnvelope({
76
- eventId: `${workItemKey}-origin-correlation`,
77
- workItemKey,
78
- streamScope: 'work-item',
79
- direction: 'internal',
80
- sourceSystem: 'wake',
81
- sourceEventType: CORRELATION_REGISTERED_EVENT,
82
- sourceRefs,
83
- occurredAt: mintedAt,
84
- ingestedAt: mintedAt,
85
- trigger: 'context-only',
86
- payload: {
87
- resourceUri,
88
- role: 'representation',
89
- relation: 'primary',
90
- provenance: 'wake-created',
91
- },
92
- });
93
- return [createdEvent, registeredEvent];
94
- }
95
- // The central resolver (spec D1): sources name the *resource* an event came
96
- // from and never the work item, so between pollEvents() and the append every
97
- // inbound event's sourceRefs.resourceUri is resolved through the reverse
98
- // index to the canonical workItemKey, minting a work item on a miss. This is
99
- // the one mechanism — there is no founding-surface special case, and no
100
- // resolution is ever cached in process memory between ticks (CLAUDE.md: the
101
- // tick is a pure function of durable state; the index on disk *is* that
102
- // state).
103
- //
104
- // Each resolved event carries whether it is already `persisted`, so the
105
- // caller can skip re-appending it (appendEventEnvelope would only re-read it
106
- // and hand back the same envelope). Minting *is* registration, so a freshly
107
- // minted work item's correlatedResources[] is complete from its first event.
108
- async function resolveInboundEvent(unkeyed) {
109
- const { resourceUri } = unkeyed.sourceRefs;
110
- if (resourceUri === undefined) {
111
- // A programming error in the adapter, not a runtime condition to absorb.
112
- // Guessing an identity here would silently fork a duplicate work item
113
- // for work already in flight — exactly the corruption the reverse index
114
- // exists to prevent — so fail loudly instead.
115
- throw new Error(`cannot resolve inbound event ${unkeyed.eventId} from ${unkeyed.sourceSystem}: ` +
116
- 'sourceRefs.resourceUri is required for every unkeyed source event');
117
- }
118
- // An event we have already persisted was already resolved, on some earlier
119
- // tick, and its stamped key is the durable answer. Re-resolving it through
120
- // the index would be wrong as well as wasteful: if that work item has since
121
- // retracted this resource, the index no longer holds it, the lookup misses,
122
- // and a miss means mint — so a re-polled event (sources legitimately
123
- // re-emit the same eventId, e.g. an unchanged issue) would fork a duplicate
124
- // work item. Reusing the persisted key keeps resolution idempotent per
125
- // event id, which is what the append-only log already promises.
126
- const persisted = await deps.stateStore.readEventEnvelope(unkeyed.eventId);
127
- if (persisted !== null) {
128
- // Heal a partially minted work item. The index entry for a resource is
129
- // written only when its origin wake.correlation.registered event is
130
- // *folded*, several appends after the founding source event. A crash in
131
- // that window leaves the source event durable — so this branch suppresses
132
- // re-minting — while the index has no entry, and a later event on the
133
- // same resource would miss the index and fork a duplicate work item
134
- // (crash/restart safety, CLAUDE.md). If the index does not credit this
135
- // event's work item *and* its origin correlation never landed, re-emit
136
- // the mint tail (idempotent by id). The guard is the missing origin
137
- // event, not merely an empty index: a deliberately *retracted* resource
138
- // also resolves to undefined but keeps its origin-correlation event on
139
- // record, and must not be silently re-registered.
140
- const owner = await deps.resourceIndex.resolve(resourceUri);
141
- if (persisted.workItemKey !== UNRESOLVED_WORK_ITEM_KEY &&
142
- owner === undefined &&
143
- (await deps.stateStore.readEventEnvelope(`${persisted.workItemKey}-origin-correlation`)) ===
144
- null) {
145
- return [
146
- { envelope: persisted, persisted: true },
147
- ...buildOriginCorrelationEvents(persisted.workItemKey, unkeyed, resourceUri).map((envelope) => ({ envelope, persisted: false })),
148
- ];
149
- }
150
- return [{ envelope: persisted, persisted: true }];
151
- }
152
- const existingWorkItemKey = await deps.resourceIndex.resolve(resourceUri);
153
- if (existingWorkItemKey !== undefined) {
154
- return [
155
- {
156
- envelope: createEventEnvelope({ ...unkeyed, workItemKey: existingWorkItemKey }),
157
- persisted: false,
158
- },
159
- ];
160
- }
161
- // resourceUri itself misses the index (e.g. a review-thread comment's
162
- // resourceUri is unique per thread, never registered on its own), but the
163
- // adapter may have named a parent resource this one belongs to. Resolve
164
- // through that instead of minting — and register this exact resourceUri
165
- // as a secondary correlation so it's on record on the work item, even
166
- // though (being secondary) it still won't shortcut future lookups via the
167
- // index itself (ADR 0001 §5: the index is primary-only).
168
- if (unkeyed.sourceRefs.parentResourceUri !== undefined) {
169
- const parentWorkItemKey = await deps.resourceIndex.resolve(unkeyed.sourceRefs.parentResourceUri);
170
- if (parentWorkItemKey !== undefined) {
171
- const mintedAt = laterTimestamp(unkeyed.ingestedAt, eventStampNow());
172
- return [
173
- {
174
- envelope: createEventEnvelope({ ...unkeyed, workItemKey: parentWorkItemKey }),
175
- persisted: false,
176
- },
177
- {
178
- envelope: createEventEnvelope({
179
- eventId: `${parentWorkItemKey}-correlation-${resourceUri.replace(/[^a-z0-9]+/gi, '-')}`,
180
- workItemKey: parentWorkItemKey,
181
- streamScope: 'work-item',
182
- direction: 'internal',
183
- sourceSystem: 'wake',
184
- sourceEventType: CORRELATION_REGISTERED_EVENT,
185
- sourceRefs: unkeyed.sourceRefs,
186
- occurredAt: mintedAt,
187
- ingestedAt: mintedAt,
188
- trigger: 'context-only',
189
- payload: {
190
- resourceUri,
191
- role: 'review',
192
- relation: 'secondary',
193
- provenance: 'detected',
194
- },
195
- }),
196
- persisted: false,
197
- },
198
- ];
199
- }
200
- }
201
- if (!deps.qualifiesForMint(unkeyed, deps.config)) {
202
- return [
203
- {
204
- envelope: createEventEnvelope({ ...unkeyed, workItemKey: UNRESOLVED_WORK_ITEM_KEY }),
205
- persisted: false,
206
- },
207
- ];
208
- }
209
- const workItemKey = createWorkId();
210
- const keyed = createEventEnvelope({ ...unkeyed, workItemKey });
211
- return [
212
- { envelope: keyed, persisted: false },
213
- ...buildOriginCorrelationEvents(workItemKey, unkeyed, resourceUri).map((envelope) => ({
214
- envelope,
215
- persisted: false,
216
- })),
217
- ];
218
- }
219
- async function ingestInboundEvents(unkeyedEvents) {
220
- const ingested = [];
221
- for (const unkeyed of unkeyedEvents) {
222
- const resolved = await resolveInboundEvent(unkeyed);
223
- // Fold what was actually persisted, never the in-memory copy:
224
- // appendEventEnvelope is id-deduplicated and returns the *existing*
225
- // envelope when one is already on record. Folding our own copy instead
226
- // would let state/ diverge from events/ — and replay is defined by
227
- // events/, so the divergence would only surface after a rebuild. An event
228
- // already flagged `persisted` needs no second append: appendEventEnvelope
229
- // would only re-read it off disk and hand back the same envelope, and
230
- // every unchanged issue is re-polled every tick, so that read is the
231
- // dominant redundant cost this branch avoids.
232
- const events = [];
233
- for (const { envelope, persisted } of resolved) {
234
- events.push(persisted ? envelope : await deps.stateStore.appendEventEnvelope(envelope));
235
- }
236
- // Folded before the next event is resolved, because it is the fold of
237
- // the registration event that writes the index entry the *next* event on
238
- // the same resource resolves through. Deferring the fold to the end of
239
- // the batch would let a second event for the same ticket miss and mint a
240
- // duplicate work item. Every event in a poll batch shares the source's
241
- // one ingestedAt, so folding per event preserves exactly the order a
242
- // single batched fold would have produced.
243
- await deps.projectionUpdater.rebuildFromEvents(events);
244
- ingested.push(...events);
245
- }
246
- return ingested;
247
- }
248
- return { ingestInboundEvents };
249
- }
@@ -1,8 +0,0 @@
1
- import { builtInDefaultWorkflowDefinition, nextStage } from '../domain/workflows.js';
2
- export function createLifecycleService() {
3
- return {
4
- nextStageFromSentinel(stage, sentinel, workflow = builtInDefaultWorkflowDefinition) {
5
- return nextStage(stage, sentinel, workflow);
6
- },
7
- };
8
- }