@atolis-hq/wake 0.2.97 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (443) hide show
  1. package/README.md +5 -5
  2. package/dist/src/activities/agent/agent-activity-definition.js +26 -0
  3. package/dist/src/activities/agent/agent-activity.js +171 -0
  4. package/dist/src/activities/agent/agent-result.js +149 -0
  5. package/dist/src/activities/contracts/activity.js +10 -0
  6. package/dist/src/activities/contracts/config.js +2 -0
  7. package/dist/src/activities/contracts/event-schema.js +302 -0
  8. package/dist/src/activities/contracts/events.js +42 -0
  9. package/dist/src/activities/contracts/identifiers.js +29 -0
  10. package/dist/src/activities/contracts/registry.js +71 -0
  11. package/dist/src/activities/contracts/streams.js +17 -0
  12. package/dist/src/activities/contracts/vocabulary.js +58 -0
  13. package/dist/src/activities/index.js +21 -0
  14. package/dist/src/activities/pr/activity-support.js +111 -0
  15. package/dist/src/activities/pr/application.js +158 -0
  16. package/dist/src/activities/pr/approve.js +85 -0
  17. package/dist/src/activities/pr/capability.js +11 -0
  18. package/dist/src/activities/pr/decision-claim.js +76 -0
  19. package/dist/src/activities/pr/event-drafts.js +66 -0
  20. package/dist/src/activities/pr/intent.js +37 -0
  21. package/dist/src/activities/pr/merge-authority-gate.js +14 -0
  22. package/dist/src/activities/pr/merge.js +110 -0
  23. package/dist/src/activities/pr/policy.js +135 -0
  24. package/dist/src/activities/pr/projection.js +130 -0
  25. package/dist/src/activities/pr/vocabulary.js +30 -0
  26. package/dist/src/activities/review/authorization.js +22 -0
  27. package/dist/src/activities/review/contracts.js +22 -0
  28. package/dist/src/activities/review/signals.js +3 -0
  29. package/dist/src/bootstrap/analytics-projection.js +26 -0
  30. package/dist/src/bootstrap/board-projection.js +337 -0
  31. package/dist/src/bootstrap/composition-root.js +382 -0
  32. package/dist/src/bootstrap/config/load-config.js +51 -0
  33. package/dist/src/bootstrap/config/root-schema.js +134 -0
  34. package/dist/src/bootstrap/external-ref.js +12 -0
  35. package/dist/src/bootstrap/fake-provider-files.js +44 -0
  36. package/dist/src/bootstrap/fake-scenarios.js +22 -0
  37. package/dist/src/bootstrap/index.js +48 -0
  38. package/dist/src/bootstrap/initialise.js +436 -0
  39. package/dist/src/bootstrap/paths.js +15 -0
  40. package/dist/src/bootstrap/projection-runtime.js +27 -0
  41. package/dist/src/bootstrap/runner-quota-reporter.js +21 -0
  42. package/dist/src/bootstrap/runner-registry.js +30 -0
  43. package/dist/src/bootstrap/schedule-checkpoint-store.js +49 -0
  44. package/dist/src/bootstrap/self-update-application.js +195 -0
  45. package/dist/src/bootstrap/self-update-failure-log.js +33 -0
  46. package/dist/src/bootstrap/source-update-port.js +47 -0
  47. package/dist/src/bootstrap/status-publish-activity.js +42 -0
  48. package/dist/src/bootstrap/surface-api-applications.js +325 -0
  49. package/dist/src/bootstrap/surface-api-execution-applications.js +95 -0
  50. package/dist/src/bootstrap/surface-api-metadata.js +12 -0
  51. package/dist/src/bootstrap/surface-api-projection-pages.js +22 -0
  52. package/dist/src/bootstrap/surface-api-run-context.js +5 -0
  53. package/dist/src/bootstrap/surface-api-transcripts.js +57 -0
  54. package/dist/src/bootstrap/surface-api-work-applications.js +199 -0
  55. package/dist/src/bootstrap/surface-applications.js +7 -0
  56. package/dist/src/bootstrap/surface-cli-applications.js +701 -0
  57. package/dist/src/bootstrap/update-ledger.js +61 -0
  58. package/dist/src/bootstrap/update-maintenance-lease.js +176 -0
  59. package/dist/src/{version.js → bootstrap/version.js} +35 -51
  60. package/dist/src/control-plane/application/advance-once.js +184 -0
  61. package/dist/src/control-plane/application/control-plane-projection.js +42 -0
  62. package/dist/src/control-plane/application/control-plane-service.js +42 -0
  63. package/dist/src/control-plane/application/intake-pipeline.js +29 -0
  64. package/dist/src/control-plane/application/runner-control-service.js +66 -0
  65. package/dist/src/control-plane/application/runner-pipeline.js +57 -0
  66. package/dist/src/control-plane/application/schedule-service.js +47 -0
  67. package/dist/src/control-plane/application/work-cancellation-policy.js +31 -0
  68. package/dist/src/control-plane/contracts/commands.js +10 -0
  69. package/dist/src/control-plane/contracts/config.js +22 -0
  70. package/dist/src/control-plane/contracts/events.js +81 -0
  71. package/dist/src/control-plane/contracts/streams.js +5 -0
  72. package/dist/src/control-plane/domain/dispatch-policy.js +15 -0
  73. package/dist/src/control-plane/domain/quota-policy.js +26 -0
  74. package/dist/src/control-plane/domain/runner-quota.js +35 -0
  75. package/dist/src/control-plane/domain/schedule-policy.js +46 -0
  76. package/dist/src/control-plane/index.js +20 -0
  77. package/dist/src/control-plane/infrastructure/intake-host.js +24 -0
  78. package/dist/src/control-plane/infrastructure/resident-host.js +45 -0
  79. package/dist/src/control-plane/infrastructure/tick-host.js +35 -0
  80. package/dist/src/execution/application/activation-claim.js +50 -0
  81. package/dist/src/execution/application/active-run-cancellation.js +14 -0
  82. package/dist/src/execution/application/execution-activity.js +97 -0
  83. package/dist/src/execution/application/execution-projection.js +17 -0
  84. package/dist/src/execution/application/execution-service.js +372 -0
  85. package/dist/src/execution/application/execution-validation.js +26 -0
  86. package/dist/src/execution/application/recovery-service.js +212 -0
  87. package/dist/src/execution/application/run-lifecycle.js +115 -0
  88. package/dist/src/execution/application/run-liveness-service.js +80 -0
  89. package/dist/src/execution/application/run-repository.js +27 -0
  90. package/dist/src/execution/contracts/commands.js +1 -0
  91. package/dist/src/execution/contracts/config.js +35 -0
  92. package/dist/src/execution/contracts/control-plane.js +1 -0
  93. package/dist/src/execution/contracts/event-factory.js +53 -0
  94. package/dist/src/execution/contracts/events.js +274 -0
  95. package/dist/src/execution/contracts/identifiers.js +5 -0
  96. package/dist/src/execution/contracts/liveness.js +1 -0
  97. package/dist/src/execution/contracts/results.js +1 -0
  98. package/dist/src/execution/contracts/runner.js +15 -0
  99. package/dist/src/execution/contracts/streams.js +10 -0
  100. package/dist/src/execution/contracts/views.js +1 -0
  101. package/dist/src/execution/contracts/vocabulary.js +43 -0
  102. package/dist/src/execution/contracts/workspace.js +1 -0
  103. package/dist/src/execution/domain/run-result.js +34 -0
  104. package/dist/src/execution/domain/run.js +142 -0
  105. package/dist/src/execution/index.js +31 -0
  106. package/dist/src/execution/infrastructure/agent-runner-adapter.js +114 -0
  107. package/dist/src/execution/infrastructure/process-execution.js +29 -0
  108. package/dist/src/execution/infrastructure/prompt-templates.js +42 -0
  109. package/dist/src/execution/infrastructure/runners/claude.js +120 -0
  110. package/dist/src/execution/infrastructure/runners/codex.js +143 -0
  111. package/dist/src/execution/infrastructure/runners/command.js +4 -0
  112. package/dist/src/execution/infrastructure/runners/cursor.js +69 -0
  113. package/dist/src/execution/infrastructure/runners/fake-scenarios.js +99 -0
  114. package/dist/src/execution/infrastructure/runners/fake.js +65 -0
  115. package/dist/src/execution/infrastructure/runners/registry.js +26 -0
  116. package/dist/src/execution/infrastructure/transcript-store.js +223 -0
  117. package/dist/src/execution/infrastructure/transcripts.js +11 -0
  118. package/dist/src/execution/infrastructure/workspace/fake-workspace.js +19 -0
  119. package/dist/src/execution/infrastructure/workspace/git-workspace.js +241 -0
  120. package/dist/src/integrations/application/agent-run-publication-reactor.js +111 -0
  121. package/dist/src/integrations/application/artifact-registration-reactor.js +159 -0
  122. package/dist/src/integrations/application/poll-service.js +25 -0
  123. package/dist/src/integrations/application/terminal-agent-run-report.js +40 -0
  124. package/dist/src/integrations/application/work-admission.js +31 -0
  125. package/dist/src/integrations/application/work-conclusion.js +19 -0
  126. package/dist/src/integrations/contracts/artifact-events.js +60 -0
  127. package/dist/src/integrations/contracts/artifact-vocabulary.js +9 -0
  128. package/dist/src/integrations/contracts/config.js +14 -0
  129. package/dist/src/integrations/contracts/identifiers.js +5 -0
  130. package/dist/src/integrations/contracts/intake-rules.js +14 -0
  131. package/dist/src/integrations/contracts/intake.js +1 -0
  132. package/dist/src/integrations/contracts/outcome-vocabulary.js +7 -0
  133. package/dist/src/integrations/contracts/provider.js +37 -0
  134. package/dist/src/integrations/contracts/streams.js +10 -0
  135. package/dist/src/integrations/delivery/application/delivery-outcome-reactor.js +75 -0
  136. package/dist/src/integrations/delivery/application/delivery-projector.js +165 -0
  137. package/dist/src/integrations/delivery/application/delivery-service.js +173 -0
  138. package/dist/src/integrations/delivery/contracts/commands.js +1 -0
  139. package/dist/src/integrations/delivery/contracts/config.js +1 -0
  140. package/dist/src/integrations/delivery/contracts/event-factory.js +18 -0
  141. package/dist/src/integrations/delivery/contracts/events.js +86 -0
  142. package/dist/src/integrations/delivery/contracts/intents.js +89 -0
  143. package/dist/src/integrations/delivery/contracts/views.js +1 -0
  144. package/dist/src/integrations/delivery/contracts/vocabulary.js +22 -0
  145. package/dist/src/integrations/fake/durable-delivery-provider.js +48 -0
  146. package/dist/src/integrations/fake/external-sink.js +9 -0
  147. package/dist/src/integrations/fake/external-source.js +44 -0
  148. package/dist/src/integrations/fake/inbound-translator.js +130 -0
  149. package/dist/src/integrations/fake/provider.js +95 -0
  150. package/dist/src/integrations/github/application/agent-context-reader.js +54 -0
  151. package/dist/src/integrations/github/application/agent-run-comment.js +94 -0
  152. package/dist/src/integrations/github/application/comment-history-reader.js +43 -0
  153. package/dist/src/integrations/github/application/inbound-context.js +10 -0
  154. package/dist/src/integrations/github/application/inbound-review-signals.js +159 -0
  155. package/dist/src/integrations/github/application/inbound-translator.js +231 -0
  156. package/dist/src/integrations/github/application/inbound-watch-gate-signals.js +84 -0
  157. package/dist/src/integrations/github/application/intake-policy.js +23 -0
  158. package/dist/src/integrations/github/application/outbound-translator.js +47 -0
  159. package/dist/src/integrations/github/application/poll-service.js +29 -0
  160. package/dist/src/integrations/github/application/pull-request-translation.js +10 -0
  161. package/dist/src/integrations/github/application/resource-links.js +8 -0
  162. package/dist/src/integrations/github/application/review-command-translator.js +16 -0
  163. package/dist/src/integrations/github/application/wake-labels.js +95 -0
  164. package/dist/src/integrations/github/contracts/config.js +47 -0
  165. package/dist/src/integrations/github/contracts/events.js +127 -0
  166. package/dist/src/integrations/github/contracts/external-key.js +19 -0
  167. package/dist/src/integrations/github/contracts/payloads.js +9 -0
  168. package/dist/src/integrations/github/contracts/vocabulary.js +55 -0
  169. package/dist/src/integrations/github/index.js +31 -0
  170. package/dist/src/integrations/github/infrastructure/client-reads.js +214 -0
  171. package/dist/src/integrations/github/infrastructure/client.js +132 -0
  172. package/dist/src/integrations/github/infrastructure/content-fingerprint.js +10 -0
  173. package/dist/src/integrations/github/infrastructure/delivery.js +31 -0
  174. package/dist/src/integrations/github/infrastructure/etag-cache.js +56 -0
  175. package/dist/src/integrations/github/infrastructure/gh-auth.js +19 -0
  176. package/dist/src/integrations/github/infrastructure/issue-source.js +109 -0
  177. package/dist/src/integrations/github/infrastructure/pr-source.js +186 -0
  178. package/dist/src/integrations/github/infrastructure/review-source.js +70 -0
  179. package/dist/src/integrations/github/infrastructure/source.js +108 -0
  180. package/dist/src/integrations/github/provider.js +96 -0
  181. package/dist/src/integrations/index.js +30 -0
  182. package/dist/src/kernel/contracts/checkpoint-store.js +1 -0
  183. package/dist/src/kernel/contracts/clock.js +1 -0
  184. package/dist/src/kernel/contracts/commands.js +1 -0
  185. package/dist/src/kernel/contracts/event-journal.js +2 -0
  186. package/dist/src/kernel/contracts/event-schema.js +54 -0
  187. package/dist/src/kernel/contracts/events.js +11 -0
  188. package/dist/src/kernel/contracts/id-generator.js +1 -0
  189. package/dist/src/kernel/contracts/identifiers.js +8 -0
  190. package/dist/src/kernel/contracts/projection-store.js +1 -0
  191. package/dist/src/kernel/contracts/relations.js +1 -0
  192. package/dist/src/kernel/contracts/schema.js +17 -0
  193. package/dist/src/kernel/contracts/vocabulary.js +6 -0
  194. package/dist/src/kernel/domain/event-envelope.js +29 -0
  195. package/dist/src/kernel/domain/match-mode.js +11 -0
  196. package/dist/src/kernel/domain/relation.js +10 -0
  197. package/dist/src/kernel/index.js +17 -0
  198. package/dist/src/{lib/clock.js → kernel/infrastructure/system-clock.js} +3 -3
  199. package/dist/src/kernel/infrastructure/ulid-id-generator.js +9 -0
  200. package/dist/src/main.js +137 -1030
  201. package/dist/src/orchestration/application/accept-activity-outcome.js +25 -0
  202. package/dist/src/orchestration/application/accept-signal.js +35 -0
  203. package/dist/src/orchestration/application/advance-workflow.js +160 -0
  204. package/dist/src/orchestration/application/coordination-claims.js +107 -0
  205. package/dist/src/orchestration/application/group-budget-recorder.js +43 -0
  206. package/dist/src/orchestration/application/orchestration-projection.js +20 -0
  207. package/dist/src/orchestration/application/orchestration-repository.js +36 -0
  208. package/dist/src/orchestration/application/orchestration-service.js +82 -0
  209. package/dist/src/orchestration/application/request-child.js +118 -0
  210. package/dist/src/orchestration/application/signal-reactor.js +17 -0
  211. package/dist/src/orchestration/application/start-workflow.js +51 -0
  212. package/dist/src/orchestration/application/watch-reactor.js +82 -0
  213. package/dist/src/orchestration/contracts/activity-outcome.js +18 -0
  214. package/dist/src/orchestration/contracts/commands.js +1 -0
  215. package/dist/src/orchestration/contracts/config.js +128 -0
  216. package/dist/src/orchestration/contracts/event-decoder.js +263 -0
  217. package/dist/src/orchestration/contracts/events.js +41 -0
  218. package/dist/src/orchestration/contracts/identifiers.js +35 -0
  219. package/dist/src/orchestration/contracts/streams.js +38 -0
  220. package/dist/src/orchestration/contracts/views.js +1 -0
  221. package/dist/src/orchestration/contracts/vocabulary.js +30 -0
  222. package/dist/src/orchestration/domain/activation-policy.js +55 -0
  223. package/dist/src/orchestration/domain/approval-defaults.js +17 -0
  224. package/dist/src/orchestration/domain/child-policy.js +63 -0
  225. package/dist/src/orchestration/domain/compiler.js +162 -0
  226. package/dist/src/orchestration/domain/coordination-events.js +25 -0
  227. package/dist/src/orchestration/domain/decision-events.js +47 -0
  228. package/dist/src/orchestration/domain/interpreter.js +49 -0
  229. package/dist/src/orchestration/domain/operator-retry-policy.js +34 -0
  230. package/dist/src/orchestration/domain/retry-policy.js +26 -0
  231. package/dist/src/orchestration/domain/signal-policy.js +120 -0
  232. package/dist/src/orchestration/domain/supplemental-policy.js +61 -0
  233. package/dist/src/orchestration/domain/transition.js +55 -0
  234. package/dist/src/orchestration/domain/workflow-graph.js +41 -0
  235. package/dist/src/orchestration/domain/workflow-instance-events.js +236 -0
  236. package/dist/src/orchestration/domain/workflow-instance.js +41 -0
  237. package/dist/src/orchestration/domain/workflow-selector.js +21 -0
  238. package/dist/src/orchestration/index.js +19 -0
  239. package/dist/src/persistence/application/projection-runner.js +79 -0
  240. package/dist/src/persistence/filesystem/file-checkpoint-store.js +35 -0
  241. package/dist/src/persistence/filesystem/file-event-journal.js +143 -0
  242. package/dist/src/persistence/filesystem/file-lock.js +91 -0
  243. package/dist/src/persistence/filesystem/file-projection-store.js +64 -0
  244. package/dist/src/persistence/index.js +8 -0
  245. package/dist/src/persistence/memory/in-memory-checkpoint-store.js +14 -0
  246. package/dist/src/persistence/memory/in-memory-event-journal.js +88 -0
  247. package/dist/src/persistence/memory/in-memory-projection-store.js +17 -0
  248. package/dist/src/resources/application/lookup-projections.js +48 -0
  249. package/dist/src/resources/application/resource-lookup.js +16 -0
  250. package/dist/src/resources/application/resource-projections.js +81 -0
  251. package/dist/src/resources/application/resource-repository.js +18 -0
  252. package/dist/src/resources/application/resource-service.js +83 -0
  253. package/dist/src/resources/contracts/commands.js +1 -0
  254. package/dist/src/resources/contracts/config.js +2 -0
  255. package/dist/src/resources/contracts/events.js +83 -0
  256. package/dist/src/resources/contracts/identifiers.js +15 -0
  257. package/dist/src/resources/contracts/streams.js +6 -0
  258. package/dist/src/resources/contracts/views.js +1 -0
  259. package/dist/src/resources/contracts/vocabulary.js +67 -0
  260. package/dist/src/resources/domain/correlation.js +8 -0
  261. package/dist/src/resources/domain/resource.js +58 -0
  262. package/dist/src/resources/index.js +14 -0
  263. package/dist/src/surfaces/api/contracts/activities.js +1 -0
  264. package/dist/src/surfaces/api/contracts/board.js +2 -0
  265. package/dist/src/surfaces/api/contracts/common.js +46 -0
  266. package/dist/src/surfaces/api/contracts/control-plane.js +5 -0
  267. package/dist/src/surfaces/api/contracts/events.js +1 -0
  268. package/dist/src/surfaces/api/contracts/execution.js +1 -0
  269. package/dist/src/surfaces/api/contracts/index.js +13 -0
  270. package/dist/src/surfaces/api/contracts/observability.js +1 -0
  271. package/dist/src/surfaces/api/contracts/orchestration.js +1 -0
  272. package/dist/src/surfaces/api/contracts/resources.js +1 -0
  273. package/dist/src/surfaces/api/contracts/status.js +1 -0
  274. package/dist/src/surfaces/api/contracts/system.js +1 -0
  275. package/dist/src/surfaces/api/contracts/transport-values.js +39 -0
  276. package/dist/src/surfaces/api/contracts/work.js +17 -0
  277. package/dist/src/surfaces/api/http-server.js +121 -0
  278. package/dist/src/surfaces/api/presenters/activities.js +1 -0
  279. package/dist/src/surfaces/api/presenters/board.js +3 -0
  280. package/dist/src/surfaces/api/presenters/control-plane.js +1 -0
  281. package/dist/src/surfaces/api/presenters/events.js +1 -0
  282. package/dist/src/surfaces/api/presenters/execution.js +59 -0
  283. package/dist/src/surfaces/api/presenters/observability.js +1 -0
  284. package/dist/src/surfaces/api/presenters/orchestration.js +19 -0
  285. package/dist/src/surfaces/api/presenters/resources.js +15 -0
  286. package/dist/src/surfaces/api/presenters/status.js +3 -0
  287. package/dist/src/surfaces/api/presenters/system.js +14 -0
  288. package/dist/src/surfaces/api/presenters/work.js +16 -0
  289. package/dist/src/surfaces/api/problem-details.js +9 -0
  290. package/dist/src/surfaces/api/router.js +13 -0
  291. package/dist/src/surfaces/api/routes/activities.js +1 -0
  292. package/dist/src/surfaces/api/routes/applications.js +1 -0
  293. package/dist/src/surfaces/api/routes/commands.js +82 -0
  294. package/dist/src/surfaces/api/routes/control-plane.js +6 -0
  295. package/dist/src/surfaces/api/routes/events.js +1 -0
  296. package/dist/src/surfaces/api/routes/execution.js +8 -0
  297. package/dist/src/surfaces/api/routes/index.js +18 -0
  298. package/dist/src/surfaces/api/routes/observability.js +1 -0
  299. package/dist/src/surfaces/api/routes/orchestration.js +1 -0
  300. package/dist/src/surfaces/api/routes/pagination.js +78 -0
  301. package/dist/src/surfaces/api/routes/read.js +135 -0
  302. package/dist/src/surfaces/api/routes/resources.js +1 -0
  303. package/dist/src/surfaces/api/routes/responses.js +67 -0
  304. package/dist/src/surfaces/api/routes/system.js +1 -0
  305. package/dist/src/surfaces/api/routes/work.js +9 -0
  306. package/dist/src/surfaces/cli/commands/api.js +1 -0
  307. package/dist/src/surfaces/cli/commands/audit.js +10 -0
  308. package/dist/src/surfaces/cli/commands/correlate.js +2 -0
  309. package/dist/src/surfaces/cli/commands/doctor.js +6 -0
  310. package/dist/src/surfaces/cli/commands/init.js +39 -0
  311. package/dist/src/surfaces/cli/commands/sandbox-entrypoint.js +33 -0
  312. package/dist/src/surfaces/cli/commands/sandbox-setup.js +29 -0
  313. package/dist/src/surfaces/cli/commands/sandbox.js +105 -0
  314. package/dist/src/surfaces/cli/commands/self-update.js +38 -0
  315. package/dist/src/surfaces/cli/commands/smoke.js +16 -0
  316. package/dist/src/surfaces/cli/commands/start.js +1 -0
  317. package/dist/src/surfaces/cli/commands/stop.js +13 -0
  318. package/dist/src/surfaces/cli/commands/tick.js +1 -0
  319. package/dist/src/surfaces/cli/commands/ui.js +2 -0
  320. package/dist/src/surfaces/cli/commands/validate-state.js +5 -0
  321. package/dist/src/surfaces/cli/infrastructure/docker-cli.js +221 -0
  322. package/dist/src/surfaces/cli/infrastructure/process-log.js +86 -0
  323. package/dist/src/surfaces/cli/main.js +140 -0
  324. package/dist/src/surfaces/cli/usage.js +33 -0
  325. package/dist/src/surfaces/contracts/config.js +34 -0
  326. package/dist/src/surfaces/index.js +47 -0
  327. package/dist/src/surfaces/web-assets/assets/index-Bfn4FwZG.css +1 -0
  328. package/dist/src/surfaces/web-assets/assets/index-ipB6JPGU.js +1090 -0
  329. package/dist/src/surfaces/web-assets/index.html +13 -0
  330. package/dist/src/surfaces/web-host/asset-source.js +1 -0
  331. package/dist/src/surfaces/web-host/packaged-assets.js +44 -0
  332. package/dist/src/work/application/work-projection.js +59 -0
  333. package/dist/src/work/application/work-repository.js +18 -0
  334. package/dist/src/work/application/work-service.js +117 -0
  335. package/dist/src/work/contracts/commands.js +1 -0
  336. package/dist/src/work/contracts/config.js +2 -0
  337. package/dist/src/work/contracts/events.js +103 -0
  338. package/dist/src/work/contracts/identifiers.js +5 -0
  339. package/dist/src/work/contracts/streams.js +6 -0
  340. package/dist/src/work/contracts/views.js +1 -0
  341. package/dist/src/work/contracts/vocabulary.js +6 -0
  342. package/dist/src/work/domain/work-item.js +89 -0
  343. package/dist/src/work/index.js +11 -0
  344. package/docker/Dockerfile +10 -6
  345. package/docker/Dockerfile.packaged +3 -3
  346. package/package.json +29 -4
  347. package/prompts/implement.md +2 -2
  348. package/dist/src/adapters/claude/claude-runner.js +0 -529
  349. package/dist/src/adapters/codex/codex-runner.js +0 -503
  350. package/dist/src/adapters/cursor/cursor-runner.js +0 -418
  351. package/dist/src/adapters/docker/docker-cli.js +0 -150
  352. package/dist/src/adapters/fake/fake-artifact-verifier.js +0 -14
  353. package/dist/src/adapters/fake/fake-github-pull-request-activity-source.js +0 -77
  354. package/dist/src/adapters/fake/fake-resource-index.js +0 -21
  355. package/dist/src/adapters/fake/fake-runner.js +0 -77
  356. package/dist/src/adapters/fake/fake-ticketing-system.js +0 -185
  357. package/dist/src/adapters/fake/fake-workspace-manager.js +0 -81
  358. package/dist/src/adapters/fs/resource-index.js +0 -126
  359. package/dist/src/adapters/fs/self-update-ledger.js +0 -17
  360. package/dist/src/adapters/fs/state-store.js +0 -775
  361. package/dist/src/adapters/git/git-workspace-manager.js +0 -289
  362. package/dist/src/adapters/github/github-artifact-verifier.js +0 -38
  363. package/dist/src/adapters/github/github-auth.js +0 -16
  364. package/dist/src/adapters/github/github-client.js +0 -249
  365. package/dist/src/adapters/github/github-etag-cache.js +0 -57
  366. package/dist/src/adapters/github/github-issues-work-source.js +0 -692
  367. package/dist/src/adapters/github/github-pull-request-activity-source.js +0 -584
  368. package/dist/src/adapters/github/github-pull-request-merge-actor.js +0 -45
  369. package/dist/src/adapters/http/ui-assets.js +0 -1188
  370. package/dist/src/adapters/http/ui-data.js +0 -1107
  371. package/dist/src/adapters/http/ui-server.js +0 -458
  372. package/dist/src/adapters/runner/cli-command.js +0 -73
  373. package/dist/src/adapters/runner/prompt-templates.js +0 -76
  374. package/dist/src/adapters/runner/runner-cli-adapter.js +0 -112
  375. package/dist/src/adapters/runner/runner-registry.js +0 -139
  376. package/dist/src/adapters/runner/runtime-events.js +0 -32
  377. package/dist/src/adapters/runner/stage-prompt.js +0 -268
  378. package/dist/src/adapters/runner/transcripts.js +0 -25
  379. package/dist/src/cli/audit-command.js +0 -36
  380. package/dist/src/cli/correlate-command.js +0 -62
  381. package/dist/src/cli/doctor-command.js +0 -48
  382. package/dist/src/cli/init-command.js +0 -18
  383. package/dist/src/cli/sandbox-command.js +0 -258
  384. package/dist/src/cli/sandbox-entrypoint-command.js +0 -88
  385. package/dist/src/cli/sandbox-exec-logging.js +0 -7
  386. package/dist/src/cli/sandbox-resume.js +0 -79
  387. package/dist/src/cli/sandbox-setup-command.js +0 -31
  388. package/dist/src/cli/scaffold-assets.js +0 -100
  389. package/dist/src/cli/self-update-command.js +0 -198
  390. package/dist/src/cli/startup-preflight.js +0 -134
  391. package/dist/src/cli/stop-command.js +0 -46
  392. package/dist/src/cli/ui-command.js +0 -27
  393. package/dist/src/config/defaults.js +0 -10
  394. package/dist/src/config/discover-config-files.js +0 -11
  395. package/dist/src/config/load-config.js +0 -69
  396. package/dist/src/config/split-config.js +0 -14
  397. package/dist/src/core/active-run-recovery.js +0 -44
  398. package/dist/src/core/approval-intents.js +0 -16
  399. package/dist/src/core/audit-events.js +0 -82
  400. package/dist/src/core/control-plane.js +0 -192
  401. package/dist/src/core/event-builders.js +0 -153
  402. package/dist/src/core/event-resolver.js +0 -249
  403. package/dist/src/core/lifecycle-service.js +0 -8
  404. package/dist/src/core/live-execution.js +0 -81
  405. package/dist/src/core/outbox.js +0 -198
  406. package/dist/src/core/policy-engine.js +0 -389
  407. package/dist/src/core/projection-updater.js +0 -693
  408. package/dist/src/core/quota-backoff.js +0 -69
  409. package/dist/src/core/run-lease.js +0 -38
  410. package/dist/src/core/scheduled-workflow-source.js +0 -199
  411. package/dist/src/core/sink-router.js +0 -107
  412. package/dist/src/core/stale-run-reconciler.js +0 -352
  413. package/dist/src/core/tick-runner.js +0 -2442
  414. package/dist/src/core/workspace-cleanup.js +0 -117
  415. package/dist/src/domain/branch-naming.js +0 -14
  416. package/dist/src/domain/custom-commands.js +0 -58
  417. package/dist/src/domain/event-types.js +0 -158
  418. package/dist/src/domain/manual-labels.js +0 -1
  419. package/dist/src/domain/resource-uri.js +0 -38
  420. package/dist/src/domain/runner-routing.js +0 -127
  421. package/dist/src/domain/runtime-events.js +0 -36
  422. package/dist/src/domain/schema.js +0 -1233
  423. package/dist/src/domain/sources.js +0 -16
  424. package/dist/src/domain/stages.js +0 -36
  425. package/dist/src/domain/work-item-labels.js +0 -48
  426. package/dist/src/domain/work-item-lifecycle.js +0 -10
  427. package/dist/src/domain/work-item-status.js +0 -33
  428. package/dist/src/domain/workflows.js +0 -159
  429. package/dist/src/lib/deep-merge.js +0 -14
  430. package/dist/src/lib/detached-process-logging.js +0 -46
  431. package/dist/src/lib/event-log.js +0 -21
  432. package/dist/src/lib/format.js +0 -41
  433. package/dist/src/lib/json-file.js +0 -23
  434. package/dist/src/lib/lock.js +0 -181
  435. package/dist/src/lib/log-rotation.js +0 -42
  436. package/dist/src/lib/paths.js +0 -52
  437. package/dist/src/lib/process-identity.js +0 -54
  438. package/dist/src/lib/state-health.js +0 -30
  439. package/dist/src/lib/work-id.js +0 -19
  440. package/dist/src/lib/yaml-file.js +0 -20
  441. package/templates/SETUP.md +0 -115
  442. /package/dist/src/{core → activities/pr}/contracts.js +0 -0
  443. /package/dist/src/{domain/types.js → control-plane/contracts/views.js} +0 -0
package/dist/src/main.js CHANGED
@@ -1,1063 +1,170 @@
1
- #!/usr/bin/env node
2
1
  import { spawn } from 'node:child_process';
3
- import { existsSync } from 'node:fs';
4
- import { access, chmod, copyFile, mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises';
5
- import { dirname, join, resolve } from 'node:path';
6
- import { createInterface } from 'node:readline/promises';
7
- import { fileURLToPath } from 'node:url';
8
- import { createDockerCli, } from './adapters/docker/docker-cli.js';
9
- import { createFileBackedFakeTicketingSystem } from './adapters/fake/fake-ticketing-system.js';
10
- import { createFakeWorkspaceManager } from './adapters/fake/fake-workspace-manager.js';
11
- import { createGitWorkspaceManager } from './adapters/git/git-workspace-manager.js';
12
- import { createRunnerCliAdapter } from './adapters/runner/runner-cli-adapter.js';
13
- import { createRegistryRunner, runnerKindForOverride } from './adapters/runner/runner-registry.js';
14
- import { createResourceIndex } from './adapters/fs/resource-index.js';
15
- import { createStateStore } from './adapters/fs/state-store.js';
16
- import { readSelfUpdateLedger, writeSelfUpdateLedger, } from './adapters/fs/self-update-ledger.js';
17
- import { resolveGitHubToken } from './adapters/github/github-auth.js';
18
- import { createGitHubArtifactVerifier } from './adapters/github/github-artifact-verifier.js';
19
- import { createGitHubClient } from './adapters/github/github-client.js';
20
- import { createGitHubIssuesWorkSource } from './adapters/github/github-issues-work-source.js';
21
- import { createGitHubPullRequestActivitySource } from './adapters/github/github-pull-request-activity-source.js';
22
- import { createGitHubPullRequestMergeActor } from './adapters/github/github-pull-request-merge-actor.js';
23
- import { runAuditCommand } from './cli/audit-command.js';
24
- import { runCorrelateCommand } from './cli/correlate-command.js';
25
- import { runDoctorCommand } from './cli/doctor-command.js';
26
- import { runInitCommand } from './cli/init-command.js';
27
- import { runSandboxCommand } from './cli/sandbox-command.js';
28
- import { runSandboxEntrypointCommand } from './cli/sandbox-entrypoint-command.js';
29
- import { runSandboxSetupCommand } from './cli/sandbox-setup-command.js';
30
- import { collectStartupPreflightFailures, runStartupPreflight } from './cli/startup-preflight.js';
31
- import { runUiCommand } from './cli/ui-command.js';
32
- import { loadWakeConfig } from './config/load-config.js';
33
- import { createActiveRunRecovery } from './core/active-run-recovery.js';
34
- import { createControlPlane } from './core/control-plane.js';
35
- import { createOutboundSinkRouter, createWorkSourceFanIn } from './core/sink-router.js';
36
- import { createScheduledWorkflowSource } from './core/scheduled-workflow-source.js';
37
- import { createTickRunner } from './core/tick-runner.js';
38
- import { systemClock } from './lib/clock.js';
39
- import { createDetachedProcessLogSink } from './lib/detached-process-logging.js';
40
- import { readJsonFile } from './lib/json-file.js';
41
- import { resolveLogMaxBytes, resolveLogRotateCheckIntervalMs } from './lib/log-rotation.js';
42
- import { StateHealthError } from './lib/state-health.js';
43
- import { configuredTicketSource } from './domain/sources.js';
44
- import { wakeVersion } from './version.js';
45
- function commandArgsBeforeTerminator(args) {
46
- const terminatorIndex = args.indexOf('--');
47
- if (terminatorIndex === -1) {
48
- return args;
49
- }
50
- return args.slice(0, terminatorIndex);
51
- }
52
- export function readFlagBeforeCommandTerminator(name, args) {
53
- const scopedArgs = commandArgsBeforeTerminator(args);
54
- const index = scopedArgs.indexOf(name);
55
- if (index === -1) {
56
- return undefined;
57
- }
58
- return scopedArgs[index + 1];
59
- }
60
- // Walks up from this file's own directory until it finds a package.json,
61
- // rather than assuming a fixed number of directory levels — the file
62
- // running is `dist/src/main.js` for a built/packaged install (two levels
63
- // below the package root) but `src/main.ts` for a `tsx` dev invocation
64
- // (only one level below), so a fixed `resolve(..., '..', '..')` overshoots
65
- // the root by one directory in the latter case.
66
- function resolvePackageRoot() {
67
- let dir = dirname(fileURLToPath(import.meta.url));
68
- for (;;) {
69
- if (existsSync(join(dir, 'package.json'))) {
70
- return dir;
71
- }
72
- const parent = dirname(dir);
73
- if (parent === dir) {
74
- throw new Error(`Could not locate package root (no package.json found above ${dir})`);
75
- }
76
- dir = parent;
77
- }
78
- }
79
- export async function hasDockerfile(wakeRoot) {
80
- try {
81
- await access(resolve(wakeRoot, 'docker', 'Dockerfile'));
82
- return true;
83
- }
84
- catch {
85
- return false;
86
- }
87
- }
88
- function routesOnlyToFake(config) {
89
- return Object.values(config.tiers).every((candidates) => {
90
- const first = candidates[0];
91
- return first !== undefined && config.runners[first]?.kind === 'fake';
92
- });
93
- }
94
- async function resolveSelfLogin(githubClient) {
95
- if (githubClient === undefined) {
96
- return undefined;
97
- }
98
- try {
99
- return await githubClient.getAuthenticatedLogin();
100
- }
101
- catch (error) {
102
- console.error(`wake: failed to resolve authenticated GitHub login; continuing without self-login bot detection: ${String(error)}`);
103
- return undefined;
104
- }
105
- }
106
- export function formatTickFailureDetails(runRecord) {
107
- if (runRecord === null) {
108
- return null;
109
- }
110
- const summary = runRecord.summary?.trim();
111
- const exitCode = runRecord.metadata !== undefined && typeof runRecord.metadata.exitCode === 'number'
112
- ? runRecord.metadata.exitCode
113
- : undefined;
114
- const stderr = runRecord.metadata !== undefined && typeof runRecord.metadata.stderr === 'string'
115
- ? runRecord.metadata.stderr.trim()
116
- : '';
117
- if (summary === undefined && exitCode === undefined && stderr.length === 0) {
118
- return null;
119
- }
120
- const lines = ['Tick failure details:', `runId: ${runRecord.runId}`];
121
- if (exitCode !== undefined) {
122
- lines.push(`exitCode: ${exitCode}`);
123
- }
124
- if (summary !== undefined) {
125
- lines.push('', 'Summary:', summary);
126
- }
127
- if (stderr.length > 0) {
128
- lines.push('', 'stderr:', stderr);
2
+ import { access } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { pathToFileURL } from 'node:url';
5
+ import { createCompositionRoot, createSurfaceApplications, initialiseWakeRoot, loadConfig, wakeVersion, } from './bootstrap/index.js';
6
+ import { parseWakeCommand, runWakeCommand, sandboxUsage, usage, } from './surfaces/index.js';
7
+ export async function main(argv = process.argv.slice(2), dependencies) {
8
+ const suppliedArguments = normalizeDeveloperAlias(argv);
9
+ const output = dependencies?.output ?? productionOutput();
10
+ if (writePrecompositionCommand(suppliedArguments, output))
11
+ return;
12
+ const resolvedDependencies = dependencies ?? productionDependencies();
13
+ const bypassSandbox = suppliedArguments.includes('--no-sandbox');
14
+ const command = parseWakeCommand(suppliedArguments.filter((argument) => argument !== '--no-sandbox'));
15
+ const wakeRoot = resolveWakeRoot(command);
16
+ if (command.kind === 'init') {
17
+ const result = await (resolvedDependencies.initialise ?? initialiseWakeRoot)(wakeRoot);
18
+ resolvedDependencies.output.write(`${JSON.stringify(result)}\n`);
19
+ return;
129
20
  }
130
- return lines.join('\n');
131
- }
132
- async function runCommand(command, args, env = process.env) {
133
- await new Promise((resolveRun, reject) => {
134
- const child = spawn(command, args, {
135
- cwd: process.cwd(),
136
- env,
137
- stdio: 'inherit',
138
- });
139
- child.on('error', reject);
140
- child.on('close', (exitCode) => {
141
- if (exitCode === 0) {
142
- resolveRun();
143
- return;
144
- }
145
- reject(new Error(`${command} ${args.join(' ')} failed with exit code ${exitCode ?? 1}`));
21
+ if (resolvedDependencies.sandboxRuntime !== undefined) {
22
+ const sandboxRuntime = resolvedDependencies.sandboxRuntime;
23
+ const ranInSandbox = await runInSandboxIfAvailable({
24
+ commandKind: command.kind,
25
+ bypassSandbox,
26
+ hasDockerfile: () => sandboxRuntime.hasDockerfile(wakeRoot),
27
+ exec: () => sandboxRuntime.exec(wakeRoot, rewriteSandboxArguments(suppliedArguments)),
146
28
  });
147
- });
148
- }
149
- function parseGithubRepoSlug(remoteUrl) {
150
- const match = /github\.com[:/]([^/]+\/[^/]+?)(?:\.git)?$/.exec(remoteUrl.trim());
151
- if (match === null) {
152
- throw new Error(`Could not parse a GitHub owner/repo from origin remote: ${remoteUrl}`);
29
+ if (ranInSandbox)
30
+ return;
153
31
  }
154
- return match[1];
155
- }
156
- async function runCommandCapture(command, args) {
157
- return await new Promise((resolveRun, reject) => {
158
- const child = spawn(command, args, {
159
- cwd: process.cwd(),
160
- env: process.env,
161
- stdio: ['ignore', 'pipe', 'inherit'],
162
- });
163
- let stdout = '';
164
- child.stdout.on('data', (chunk) => {
165
- stdout += chunk.toString();
32
+ const applications = await resolvedDependencies.compose(wakeRoot);
33
+ if (applications.sandboxRuntime !== undefined) {
34
+ const sandboxRuntime = applications.sandboxRuntime;
35
+ const ranInSandbox = await runInSandboxIfAvailable({
36
+ commandKind: command.kind,
37
+ bypassSandbox,
38
+ hasDockerfile: () => sandboxRuntime.hasDockerfile(),
39
+ exec: () => sandboxRuntime.exec(rewriteSandboxArguments(suppliedArguments)),
166
40
  });
167
- child.on('error', reject);
168
- child.on('close', (exitCode) => {
169
- if (exitCode === 0) {
170
- resolveRun(stdout);
171
- return;
172
- }
173
- reject(new Error(`${command} ${args.join(' ')} failed with exit code ${exitCode ?? 1}`));
174
- });
175
- });
176
- }
177
- const codexBootstrapHome = '/home/wake/.codex';
178
- const codexRuntimeHome = '/home/wake/.codex-runtime';
179
- const sshHome = '/home/wake/.ssh';
180
- const sshKeyPath = join(sshHome, 'id_ed25519');
181
- async function prepareCodexHome() {
182
- await mkdir(codexRuntimeHome, { recursive: true });
183
- const bootstrapConfig = join(codexBootstrapHome, 'config.toml');
184
- if (existsSync(bootstrapConfig)) {
185
- await copyFile(bootstrapConfig, join(codexRuntimeHome, 'config.toml'));
186
- }
187
- const bootstrapAuth = join(codexBootstrapHome, 'auth.json');
188
- const runtimeAuth = join(codexRuntimeHome, 'auth.json');
189
- if (existsSync(bootstrapAuth) && !existsSync(runtimeAuth)) {
190
- await copyFile(bootstrapAuth, runtimeAuth);
191
- }
192
- process.env.CODEX_HOME = codexRuntimeHome;
193
- }
194
- async function ensureSshKey() {
195
- if (!existsSync(sshKeyPath)) {
196
- await mkdir(sshHome, { recursive: true, mode: 0o700 });
197
- await chmod(sshHome, 0o700);
198
- await runCommand('ssh-keygen', ['-t', 'ed25519', '-f', sshKeyPath, '-N', '']);
199
- }
200
- // Display the public key to the user
201
- const publicKeyPath = join(sshHome, 'id_ed25519.pub');
202
- const publicKey = await readFile(publicKeyPath, 'utf-8');
203
- console.log(publicKey);
204
- }
205
- async function promptYesNo(message) {
206
- const rl = createInterface({ input: process.stdin, output: process.stdout });
207
- try {
208
- const answer = (await rl.question(`${message} `)).trim().toLowerCase();
209
- return answer === 'y' || answer === 'yes';
210
- }
211
- finally {
212
- rl.close();
41
+ if (ranInSandbox)
42
+ return;
213
43
  }
44
+ await runWakeCommand(command, applications, resolvedDependencies.output, resolvedDependencies.signal);
214
45
  }
215
- async function runSandboxSetup() {
216
- await runSandboxSetupCommand({
217
- prompt: promptYesNo,
218
- runInteractive: (command, args) => runCommand(command, args),
219
- ensureSshKey,
220
- prepareCodexHome,
221
- log: (message) => console.log(message),
222
- });
223
- }
224
- const NGROK_TUNNELS_URL = 'http://127.0.0.1:4040/api/tunnels';
225
- const NGROK_DISCOVERY_ATTEMPTS = 30;
226
- const NGROK_DISCOVERY_INTERVAL_MS = 1000;
227
- async function discoverNgrokUrl() {
228
- for (let attempt = 0; attempt < NGROK_DISCOVERY_ATTEMPTS; attempt++) {
229
- try {
230
- const response = await fetch(NGROK_TUNNELS_URL, { signal: AbortSignal.timeout(1000) });
231
- if (response.ok) {
232
- const body = (await response.json());
233
- const tunnels = body.tunnels ?? [];
234
- const httpsTunnel = tunnels.find((tunnel) => typeof tunnel.public_url === 'string' && tunnel.public_url.startsWith('https://'));
235
- const anyTunnel = httpsTunnel ?? tunnels.find((tunnel) => typeof tunnel.public_url === 'string');
236
- if (typeof anyTunnel?.public_url === 'string') {
237
- return anyTunnel.public_url;
238
- }
239
- }
240
- }
241
- catch {
242
- // ignore and retry
243
- }
244
- await new Promise((resolveSleep) => setTimeout(resolveSleep, NGROK_DISCOVERY_INTERVAL_MS));
245
- }
246
- return undefined;
46
+ function normalizeDeveloperAlias(arguments_) {
47
+ if (arguments_[0] !== 'dev' || arguments_[1] !== 'sandbox')
48
+ return arguments_;
49
+ return ['sandbox', ...arguments_.slice(2)];
247
50
  }
248
- function createSandboxEntrypointDeps() {
249
- const children = new Map();
250
- return {
251
- env: process.env,
252
- spawnDetached: (command, args, options) => {
253
- const logSink = options?.logFile !== undefined
254
- ? createDetachedProcessLogSink(options.logFile, {
255
- maxBytes: resolveLogMaxBytes(process.env),
256
- rotateCheckIntervalMs: resolveLogRotateCheckIntervalMs(process.env),
257
- })
258
- : undefined;
259
- const child = spawn(command, args, {
260
- cwd: process.cwd(),
261
- env: process.env,
262
- stdio: ['ignore', 'pipe', 'pipe'],
263
- detached: true,
264
- });
265
- if (typeof child.pid === 'number') {
266
- children.set(child.pid, child);
267
- }
268
- const forwardOutput = (chunk) => {
269
- logSink?.write(chunk);
270
- };
271
- child.stdout?.on('data', forwardOutput);
272
- child.stderr?.on('data', forwardOutput);
273
- // Registered here (at spawn time) so it runs before any exit listener
274
- // waitForExit attaches later — though it wouldn't matter either way:
275
- // waitForExit captures the ChildProcess reference synchronously from
276
- // `children` when it's called (before the child can possibly have
277
- // exited) and attaches its own listener directly to that reference,
278
- // so it never re-reads `children` inside the exit callback. Deleting
279
- // the map entry here is therefore safe regardless of ordering.
280
- child.on('exit', () => {
281
- if (typeof child.pid === 'number') {
282
- children.delete(child.pid);
283
- }
284
- logSink?.close().catch(() => { });
285
- });
286
- return { pid: child.pid ?? -1 };
287
- },
288
- waitForExit: (pid) => new Promise((resolveExit) => {
289
- const child = children.get(pid);
290
- if (child === undefined) {
291
- resolveExit(1);
292
- return;
293
- }
294
- child.on('exit', (code) => resolveExit(code ?? 1));
295
- }),
296
- writeFile: (path, content) => writeFile(path, content, 'utf-8'),
297
- sleep: (ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms)),
298
- discoverNgrokUrl,
299
- log: (message) => console.log(message),
300
- ensureDir: async (path) => {
301
- await mkdir(path, { recursive: true });
302
- },
303
- removeFile: (path) => rm(path, { force: true }),
304
- };
51
+ function writePrecompositionCommand(arguments_, output) {
52
+ return writeMetaCommand(arguments_, output) || writeSandboxHelpCommand(arguments_, output);
305
53
  }
306
- async function runSandboxEntrypoint() {
307
- await runSandboxEntrypointCommand(createSandboxEntrypointDeps());
308
- }
309
- async function readTickRequestId(path) {
310
- try {
311
- const request = await readJsonFile(path);
312
- return typeof request.requestId === 'string' && request.requestId.length > 0
313
- ? request.requestId
314
- : null;
54
+ function writeMetaCommand(arguments_, output) {
55
+ if (isHelpCommand(arguments_)) {
56
+ output.write(`${usage}\n`);
57
+ return true;
315
58
  }
316
- catch {
317
- return null;
59
+ if (isVersionCommand(arguments_)) {
60
+ output.write(`${wakeVersion}\n`);
61
+ return true;
318
62
  }
63
+ return false;
319
64
  }
320
- async function inspectDockerImage(image) {
321
- return await new Promise((resolveInspect, reject) => {
322
- const child = spawn('docker', ['image', 'inspect', image], {
323
- cwd: process.cwd(),
324
- env: process.env,
325
- stdio: 'ignore',
326
- });
327
- child.on('error', reject);
328
- child.on('close', (exitCode) => {
329
- resolveInspect(exitCode === 0);
330
- });
331
- });
332
- }
333
- async function inspectDockerContainer(containerName) {
334
- return await new Promise((resolveInspect, reject) => {
335
- const child = spawn('docker', ['container', 'inspect', '-f', '{{.State.Running}}', containerName], {
336
- cwd: process.cwd(),
337
- env: process.env,
338
- stdio: ['ignore', 'pipe', 'ignore'],
339
- });
340
- let stdout = '';
341
- child.stdout.on('data', (chunk) => {
342
- stdout += chunk.toString();
343
- });
344
- child.on('error', reject);
345
- child.on('close', (exitCode) => {
346
- if (exitCode !== 0) {
347
- resolveInspect(null);
348
- return;
349
- }
350
- resolveInspect(stdout.trim() === 'true' ? 'running' : 'stopped');
351
- });
352
- });
353
- }
354
- async function inspectDockerContainerImage(containerName) {
355
- return await new Promise((resolveInspect, reject) => {
356
- const child = spawn('docker', ['container', 'inspect', '-f', '{{.Config.Image}}', containerName], {
357
- cwd: process.cwd(),
358
- env: process.env,
359
- stdio: ['ignore', 'pipe', 'ignore'],
360
- });
361
- let stdout = '';
362
- child.stdout.on('data', (chunk) => {
363
- stdout += chunk.toString();
364
- });
365
- child.on('error', reject);
366
- child.on('close', (exitCode) => {
367
- if (exitCode !== 0) {
368
- resolveInspect(null);
369
- return;
370
- }
371
- const image = stdout.trim();
372
- resolveInspect(image.length > 0 ? image : null);
373
- });
374
- });
375
- }
376
- async function dockerDaemonReachable() {
377
- return await new Promise((resolveReachable) => {
378
- const child = spawn('docker', ['info'], {
379
- cwd: process.cwd(),
380
- env: process.env,
381
- stdio: 'ignore',
382
- });
383
- child.on('error', () => resolveReachable(false));
384
- child.on('close', (exitCode) => resolveReachable(exitCode === 0));
385
- });
65
+ function writeSandboxHelpCommand(arguments_, output) {
66
+ if (arguments_[0] !== 'sandbox')
67
+ return false;
68
+ if (arguments_.length !== 1 && !['--help', '-h', 'help'].includes(arguments_[1] ?? ''))
69
+ return false;
70
+ output.write(`${sandboxUsage}\n`);
71
+ return true;
386
72
  }
387
- /**
388
- * Builds the same `DockerCli` client the `sandbox` command path uses, so
389
- * `wake doctor`'s Docker/sandbox reachability checks reuse one Docker CLI
390
- * invocation implementation instead of duplicating it.
391
- */
392
- function createHostDockerCli() {
393
- return createDockerCli({
394
- // BuildKit is required for the Dockerfile's cache-mount syntax
395
- // (`RUN --mount=type=cache`), which keeps `npm`/`apt` package
396
- // caches warm across builds even when a layer above them changes.
397
- run: (dockerArgs) => runCommand('docker', dockerArgs, { ...process.env, DOCKER_BUILDKIT: '1' }),
398
- inspectImage: inspectDockerImage,
399
- inspectContainer: inspectDockerContainer,
400
- inspectContainerImage: inspectDockerContainerImage,
401
- spawnExec: (dockerArgs) => {
402
- const child = spawn('docker', dockerArgs, {
403
- cwd: process.cwd(),
404
- env: process.env,
405
- stdio: ['inherit', 'pipe', 'pipe'],
406
- });
407
- // stdio: ['inherit', 'pipe', 'pipe'] guarantees stdout/stderr are
408
- // non-null pipes; child_process's types don't encode that.
409
- return child;
410
- },
411
- });
73
+ function isHelpCommand(arguments_) {
74
+ return arguments_.length === 0 || ['--help', '-h', 'help'].includes(arguments_[0] ?? '');
412
75
  }
413
- /**
414
- * Runs `wake --version` inside the sandbox container via `docker exec` and
415
- * returns the trimmed stdout, so `wake doctor` can compare it against the
416
- * installed host CLI version. Stderr is discarded (surfaced only as an
417
- * empty/mismatched version, which the caller already treats as a notice).
418
- */
419
- async function execVersionInContainer(docker, containerName, devMode) {
420
- let stdout = '';
421
- const command = devMode === 'source' ? ['node', '/app/dist/src/main.js', '--version'] : ['wake', '--version'];
422
- await docker.execCaptured(containerName, command, {
423
- onStdout: (line) => {
424
- stdout += line;
425
- },
426
- onStderr: () => { },
427
- });
428
- return stdout.trim();
76
+ function isVersionCommand(arguments_) {
77
+ return ['--version', '-v'].includes(arguments_[0] ?? '');
429
78
  }
430
- async function readFileIfExists(path) {
431
- try {
432
- return await readFile(path, 'utf8');
433
- }
434
- catch {
435
- return null;
79
+ function resolveWakeRoot(command) {
80
+ if ('wakeRoot' in command && command.wakeRoot !== undefined)
81
+ return command.wakeRoot;
82
+ if ('arguments' in command) {
83
+ const explicitWakeRoot = operationalWakeRoot(command.arguments);
84
+ if (explicitWakeRoot !== undefined)
85
+ return explicitWakeRoot;
86
+ if (command.kind === 'init')
87
+ return initWakeRoot(command.arguments) ?? process.cwd();
436
88
  }
89
+ return process.cwd();
437
90
  }
438
- /**
439
- * Compares the wake-home's `prompts/*.md` and `docker/Dockerfile` (both
440
- * user-owned files, never auto-overwritten after scaffolding see
441
- * `scaffold-assets.ts`/`sandbox-command.ts`'s `ensureDockerfile`) against the
442
- * currently-shipped defaults under `resolvePackageRoot()`, byte-for-byte.
443
- * Only files present in *both* locations are compared: a prompt file the
444
- * user hasn't customized locally, or one only shipped in a newer/older CLI
445
- * version, is not drift.
446
- */
447
- async function diffPromptsAndDockerfile(input) {
448
- const drifted = [];
449
- let promptFileNames;
450
- try {
451
- promptFileNames = (await readdir(resolve(input.wakeRoot, 'prompts'))).filter((name) => name.endsWith('.md'));
452
- }
453
- catch {
454
- promptFileNames = [];
455
- }
456
- for (const fileName of promptFileNames) {
457
- const local = await readFileIfExists(resolve(input.wakeRoot, 'prompts', fileName));
458
- const shipped = await readFileIfExists(resolve(input.packageRoot, 'prompts', fileName));
459
- if (local !== null && shipped !== null && local !== shipped) {
460
- drifted.push(`prompts/${fileName}`);
461
- }
462
- }
463
- // Mirrors ensureDockerfile's template selection in sandbox-command.ts: a
464
- // "source" dev mode wake-home was seeded from docker/Dockerfile, a
465
- // "packaged" one from docker/Dockerfile.packaged.
466
- const dockerfileTemplateName = (input.devMode ?? 'packaged') === 'source' ? 'Dockerfile' : 'Dockerfile.packaged';
467
- const localDockerfile = await readFileIfExists(resolve(input.wakeRoot, 'docker', 'Dockerfile'));
468
- const shippedDockerfile = await readFileIfExists(resolve(input.packageRoot, 'docker', dockerfileTemplateName));
469
- if (localDockerfile !== null &&
470
- shippedDockerfile !== null &&
471
- localDockerfile !== shippedDockerfile) {
472
- drifted.push('docker/Dockerfile');
473
- }
474
- return drifted;
91
+ function initWakeRoot(arguments_) {
92
+ const positional = arguments_[0];
93
+ return positional !== undefined && !positional.startsWith('--') ? positional : undefined;
475
94
  }
476
- export async function buildRuntime(args) {
477
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', args) ?? process.cwd());
478
- const stateStore = createStateStore({ wakeRoot });
479
- await stateStore.ensureWakeRoot();
480
- const config = await loadWakeConfig({
481
- wakeRoot,
482
- });
483
- const resourceIndex = createResourceIndex({ paths: stateStore.paths });
484
- const prTrackingEnabled = config.sources.github.enabled && config.sources.github.pullRequests.enabled;
485
- // Resolved once and shared: resolveGitHubToken shells out to `gh auth
486
- // token`, so building a separate client per consumer would triple that
487
- // subprocess spawn on every startup for no benefit — all three consumers
488
- // talk to the same GitHub account under the same config.
489
- const githubClient = config.sources.github.enabled
490
- ? createGitHubClient(await resolveGitHubToken())
491
- : undefined;
492
- // Resolved once alongside the client: the login Wake itself posts as, so
493
- // both GitHub work sources can recognize a comment Wake's own agent posted
494
- // by direct API/CLI call (not through formatWakeComment, so it never
495
- // carries the wake:agent marker) as bot-authored instead of a fresh human
496
- // reply that would re-trigger another run against itself.
497
- const selfLogin = await resolveSelfLogin(githubClient);
498
- const artifactVerifier = prTrackingEnabled && githubClient !== undefined
499
- ? createGitHubArtifactVerifier({ client: githubClient })
500
- : undefined;
501
- const prMergeActor = prTrackingEnabled && githubClient !== undefined
502
- ? createGitHubPullRequestMergeActor({ client: githubClient })
503
- : undefined;
504
- const ticketingSystem = githubClient !== undefined
505
- ? createGitHubIssuesWorkSource({
506
- client: githubClient,
507
- stateStore,
508
- config,
509
- resourceIndex,
510
- now: () => systemClock.now(),
511
- ...(selfLogin === undefined ? {} : { selfLogin }),
512
- })
513
- : await createFileBackedFakeTicketingSystem({
514
- fixturePath: stateStore.paths.issueFixtureFile,
515
- now: () => systemClock.now(),
516
- });
517
- const sourceName = configuredTicketSource(config);
518
- const sinkName = sourceName;
519
- const pullRequestActivitySource = prTrackingEnabled && githubClient !== undefined
520
- ? createGitHubPullRequestActivitySource({
521
- client: githubClient,
522
- stateStore,
523
- config,
524
- resourceIndex,
525
- now: () => systemClock.now(),
526
- ...(selfLogin === undefined ? {} : { selfLogin }),
527
- })
528
- : null;
529
- const workSource = createWorkSourceFanIn([
530
- {
531
- source: 'wake-schedule',
532
- pollEvents: createScheduledWorkflowSource({
533
- config,
534
- stateStore,
535
- now: () => systemClock.now(),
536
- }).pollEvents,
537
- },
538
- {
539
- source: sourceName,
540
- pollEvents: ticketingSystem.pollEvents,
541
- },
542
- ...(pullRequestActivitySource === null
543
- ? []
544
- : [{ source: 'github-pr', pollEvents: pullRequestActivitySource.pollEvents }]),
545
- ]);
546
- const outboundSink = createOutboundSinkRouter({
547
- sinks: [
548
- {
549
- sink: sinkName,
550
- deliverIntent: ticketingSystem.deliverIntent,
551
- },
552
- ...(pullRequestActivitySource === null
553
- ? []
554
- : [{ sink: 'github-pr', deliverIntent: pullRequestActivitySource.deliverIntent }]),
555
- ],
556
- config,
557
- });
558
- const runnerOverride = readFlagBeforeCommandTerminator('--runner', args);
559
- if (runnerOverride !== undefined &&
560
- runnerOverride !== 'fake' &&
561
- config.runners[runnerOverride] === undefined) {
562
- throw new Error(`Unsupported runner override: ${runnerOverride}`);
563
- }
564
- const runner = createRegistryRunner({
565
- config,
566
- cwd: process.cwd(),
567
- ...(runnerOverride === undefined ? {} : { override: runnerOverride }),
568
- });
569
- const workspaceManager = (runnerOverride !== undefined
570
- ? runnerKindForOverride(config, runnerOverride) === 'fake'
571
- : routesOnlyToFake(config))
572
- ? createFakeWorkspaceManager(stateStore.paths.workspaceRoot)
573
- : createGitWorkspaceManager({ wakeRoot });
574
- const tickRunner = createTickRunner({
575
- clock: systemClock,
576
- config,
577
- stateStore,
578
- workSource,
579
- outboundSink,
580
- runner,
581
- workspaceManager,
582
- resourceIndex,
583
- ...(artifactVerifier === undefined ? {} : { artifactVerifier }),
584
- ...(prMergeActor === undefined ? {} : { prMergeActor }),
585
- });
95
+ async function runInSandboxIfAvailable(input) {
96
+ if (input.bypassSandbox || !isRuntimeCommand(input.commandKind))
97
+ return false;
98
+ if (!(await input.hasDockerfile()))
99
+ return false;
100
+ await input.exec();
101
+ return true;
102
+ }
103
+ function isRuntimeCommand(kind) {
104
+ return ['tick', 'start', 'ui', 'smoke', 'audit', 'correlate', 'validate-state'].includes(kind);
105
+ }
106
+ function rewriteSandboxArguments(arguments_) {
107
+ const withoutBypass = arguments_.filter((argument) => argument !== '--no-sandbox');
108
+ const wakeRootIndex = withoutBypass.indexOf('--wake-root');
109
+ const rewritten = wakeRootIndex === -1
110
+ ? [...withoutBypass, '--wake-root', '/wake']
111
+ : withoutBypass.map((argument, index) => (index === wakeRootIndex + 1 ? '/wake' : argument));
112
+ return [...rewritten, '--no-sandbox'];
113
+ }
114
+ function operationalWakeRoot(arguments_) {
115
+ const index = arguments_.indexOf('--wake-root');
116
+ return index === -1 ? undefined : arguments_[index + 1];
117
+ }
118
+ function productionDependencies() {
119
+ const controller = new AbortController();
120
+ process.once('SIGINT', () => controller.abort());
121
+ process.once('SIGTERM', () => controller.abort());
586
122
  return {
587
- config,
588
- runnerAdapter: null,
589
- runner,
590
- stateStore,
591
- tickRunner,
592
- workspaceManager,
593
- };
594
- }
595
- async function runTick(args) {
596
- const runtime = await buildRuntime(args);
597
- await runtime.stateStore.assertStateHealthy();
598
- const outcome = await runtime.tickRunner.runTick();
599
- console.log(JSON.stringify(outcome, null, 2));
600
- if (outcome.status !== 'processed' ||
601
- outcome.sentinel !== 'FAILED' ||
602
- outcome.runId === undefined) {
603
- return;
604
- }
605
- const runRecord = await runtime.stateStore.readRunRecord(outcome.runId);
606
- const details = formatTickFailureDetails(runRecord);
607
- if (details !== null) {
608
- console.error(details);
609
- }
610
- }
611
- export function createResidentControlPlane(runtime) {
612
- return createControlPlane({
613
- tickRunner: runtime.tickRunner,
614
- intervalMs: runtime.config.scheduler.intervalMs,
615
- maxIntervalMs: runtime.config.scheduler.maxIntervalMs,
616
- isPaused: () => runtime.stateStore.isPaused(),
617
- logger: {
618
- info(message) {
619
- console.log(message);
620
- },
621
- error(message) {
622
- console.error(message);
623
- },
624
- },
625
- sleep(ms) {
626
- return new Promise((resolveSleep) => {
627
- setTimeout(resolveSleep, ms);
628
- });
123
+ initialise: initialiseWakeRoot,
124
+ sandboxRuntime: productionSandboxRuntime(),
125
+ async compose(wakeRoot) {
126
+ const root = await createCompositionRoot(wakeRoot);
127
+ return createSurfaceApplications(root).cli;
629
128
  },
630
- readTickRequest() {
631
- return readTickRequestId(runtime.stateStore.paths.tickRequestFile);
632
- },
633
- });
634
- }
635
- async function runStart(args) {
636
- const runtime = await buildRuntime(args);
637
- await runtime.stateStore.assertStateHealthy();
638
- const runnerOverride = readFlagBeforeCommandTerminator('--runner', args);
639
- await runStartupPreflight(runtime.config, {
640
- ...(runnerOverride === undefined ? {} : { runnerOverride }),
641
- workspaceManager: runtime.workspaceManager,
642
- });
643
- const controlPlane = createResidentControlPlane(runtime);
644
- const stop = () => controlPlane.stop();
645
- process.on('SIGINT', stop);
646
- process.on('SIGTERM', stop);
647
- await controlPlane.start();
648
- }
649
- function printStateHealthReport(report) {
650
- if (report.healthy) {
651
- console.log('wake validate-state: control-plane state is healthy');
652
- return;
653
- }
654
- console.error('wake validate-state: control-plane state is unhealthy');
655
- for (const issue of report.issues) {
656
- console.error(` - ${issue.surface} ${issue.kind}: ${issue.path}: ${issue.message}`);
657
- }
658
- }
659
- async function runValidateState(args) {
660
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', args) ?? process.cwd());
661
- const stateStore = createStateStore({ wakeRoot });
662
- await stateStore.ensureWakeRoot();
663
- const report = await stateStore.validateStateHealth();
664
- printStateHealthReport(report);
665
- if (!report.healthy) {
666
- process.exitCode = 1;
667
- }
668
- }
669
- function resolveSmokEntry(config, kind) {
670
- for (const entry of Object.values(config.runners)) {
671
- if (entry.kind === 'fake') {
672
- continue;
673
- }
674
- if (kind === undefined || entry.kind === kind) {
675
- return entry;
676
- }
677
- }
678
- return null;
679
- }
680
- async function runUi(args) {
681
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', args) ?? process.cwd());
682
- const stateStore = createStateStore({ wakeRoot });
683
- await stateStore.ensureWakeRoot();
684
- const config = await loadWakeConfig({
685
- wakeRoot,
686
- });
687
- const server = await runUiCommand({
688
- args,
689
- stateStore,
690
- resourceIndex: createResourceIndex({ paths: stateStore.paths }),
691
- config,
692
- readFlag: readFlagBeforeCommandTerminator,
693
- });
694
- const stop = () => {
695
- void server.close().then(() => process.exit(0));
129
+ output: productionOutput(),
130
+ signal: controller.signal,
696
131
  };
697
- process.on('SIGINT', stop);
698
- process.on('SIGTERM', stop);
699
- await new Promise(() => { });
700
- }
701
- async function runCorrelate(args) {
702
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', args) ?? process.cwd());
703
- const stateStore = createStateStore({ wakeRoot });
704
- await stateStore.ensureWakeRoot();
705
- await runCorrelateCommand({
706
- args,
707
- stateStore,
708
- resourceIndex: createResourceIndex({ paths: stateStore.paths }),
709
- clock: systemClock,
710
- readFlag: readFlagBeforeCommandTerminator,
711
- });
712
132
  }
713
- async function runAudit(args) {
714
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', args) ?? process.cwd());
715
- const stateStore = createStateStore({ wakeRoot });
716
- await stateStore.ensureWakeRoot();
717
- await runAuditCommand({
718
- args,
719
- stateStore,
720
- });
133
+ function productionOutput() {
134
+ return { write: (value) => process.stdout.write(value) };
721
135
  }
722
- async function runSmoke(args) {
723
- const runtime = await buildRuntime(args);
724
- const explicitKind = args[0] === 'claude' || args[0] === 'codex' || args[0] === 'cursor' ? args[0] : undefined;
725
- const smokeArgs = explicitKind === undefined ? args : args.slice(1);
726
- const entry = resolveSmokEntry(runtime.config, explicitKind);
727
- if (entry === null) {
728
- throw new Error('Smoke tests require a real runner entry (`claude`, `codex`, or `cursor`) in config.runners.');
729
- }
730
- const runnerAdapter = createRunnerCliAdapter({
731
- entry,
732
- cwd: process.cwd(),
733
- });
734
- const result = await runnerAdapter.smoke(smokeArgs);
735
- console.log(JSON.stringify(result, null, 2));
736
- }
737
- async function runDoctor(args) {
738
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', args) ?? process.cwd());
739
- const stateStore = createStateStore({ wakeRoot });
740
- await stateStore.ensureWakeRoot();
741
- const config = await loadWakeConfig({
742
- wakeRoot,
743
- });
744
- const docker = createHostDockerCli();
745
- const packageRoot = resolvePackageRoot();
746
- const containerName = config.sandbox.containerName;
747
- const image = config.sandbox.image;
748
- const workspaceManager = createGitWorkspaceManager({ wakeRoot });
749
- const deps = {
750
- collectPreflightFailures: (doctorConfig) => collectStartupPreflightFailures(doctorConfig, { workspaceManager }),
751
- resolveGitHubToken,
752
- hasDockerfile,
753
- dockerReachable: dockerDaemonReachable,
754
- inspectImage: async (imageToInspect) => {
136
+ function productionSandboxRuntime() {
137
+ return {
138
+ async hasDockerfile(wakeRoot) {
755
139
  try {
756
- return await inspectDockerImage(imageToInspect);
140
+ await access(join(wakeRoot, 'docker', 'Dockerfile'));
141
+ return true;
757
142
  }
758
143
  catch {
759
144
  return false;
760
145
  }
761
146
  },
762
- wakeRoot,
763
- image,
764
- containerRunning: async () => (await inspectDockerContainer(containerName)) === 'running',
765
- execVersionInContainer: () => execVersionInContainer(docker, containerName, config.dev?.mode),
766
- installedVersion: wakeVersion,
767
- diffPromptsAndDockerfile: () => diffPromptsAndDockerfile({ wakeRoot, packageRoot, devMode: config.dev?.mode }),
147
+ async exec(wakeRoot, arguments_) {
148
+ const config = await loadConfig(wakeRoot);
149
+ const invocation = config.host.development.mode === 'source' ? ['node', '/app/dist/src/main.js'] : ['wake'];
150
+ await runDocker([
151
+ 'exec',
152
+ '-i',
153
+ config.host.sandbox.containerName,
154
+ ...invocation,
155
+ ...arguments_,
156
+ ]);
157
+ },
768
158
  };
769
- const report = await runDoctorCommand(config, deps);
770
- if (report.failures.length > 0) {
771
- console.log('Failures:');
772
- for (const failure of report.failures) {
773
- console.log(` - ${failure}`);
774
- }
775
- }
776
- if (report.notices.length > 0) {
777
- console.log('Notices:');
778
- for (const notice of report.notices) {
779
- console.log(` - ${notice}`);
780
- }
781
- }
782
- if (report.failures.length === 0 && report.notices.length === 0) {
783
- console.log('wake doctor: no issues found');
784
- }
785
- if (report.failures.length > 0) {
786
- process.exitCode = 1;
787
- }
788
159
  }
789
- export class CliUsageError extends Error {
790
- }
791
- export function printUsage(stream) {
792
- stream.write([
793
- 'Wake an autonomous agent control plane for software development.',
794
- '',
795
- 'Usage:',
796
- ' wake init <path> Scaffold a new Wake home directory',
797
- ' wake sandbox <subcommand> Build/run/manage the Docker sandbox (build, up, update, down, stop, self-update, setup, exec, logs, resume)',
798
- ' wake tick Run one control-plane tick',
799
- ' wake start Run the resident loop',
800
- ' wake validate-state Validate .wake/ control-plane state health',
801
- ' wake stop Stop the sandbox container gracefully',
802
- ' wake smoke Smoke-test the configured runner',
803
- ' wake ui Run the control-plane UI server',
804
- ' wake audit Show autonomous decision audit history',
805
- ' wake correlate Manually correlate a resource to a work item',
806
- ' wake doctor Diagnose config/GitHub/Docker/sandbox setup problems',
807
- ' wake --version Print the installed Wake version',
808
- ' wake --help Show this message',
809
- '',
810
- 'Getting started:',
811
- ' 1. wake init ./wake-home',
812
- ' 2. cd wake-home && wake start',
813
- '',
814
- 'Runtime commands (tick/start/ui/smoke/audit/correlate/validate-state) auto-delegate into the sandbox',
815
- 'when docker/Dockerfile exists at --wake-root (i.e. after `wake sandbox build`),',
816
- 'defaulting --wake-root to the current directory. Pass --no-sandbox to run',
817
- 'directly on the host instead.',
818
- '',
819
- ].join('\n'));
820
- }
821
- const runtimeCommands = new Set([
822
- 'tick',
823
- 'start',
824
- 'ui',
825
- 'smoke',
826
- 'audit',
827
- 'correlate',
828
- 'validate-state',
829
- ]);
830
- export async function dispatchMainCommand(input) {
831
- const command = input.args[0] ?? 'help';
832
- if (command === '--version' || command === '-v') {
833
- console.log(wakeVersion);
834
- return;
835
- }
836
- if (command === '--help' || command === '-h' || command === 'help') {
837
- printUsage(process.stdout);
838
- return;
839
- }
840
- if (command === 'init') {
841
- await input.runInit(input.args.slice(1));
842
- return;
843
- }
844
- if (command === 'sandbox') {
845
- await input.runSandbox(input.args.slice(1));
846
- return;
847
- }
848
- if (command === 'sandbox-setup') {
849
- await input.runSandboxSetup(input.args.slice(1));
850
- return;
851
- }
852
- if (command === 'sandbox-entrypoint') {
853
- await input.runSandboxEntrypoint(input.args.slice(1));
854
- return;
855
- }
856
- if (command === 'stop') {
857
- await input.runSandbox(['stop', ...input.args.slice(1)]);
858
- return;
859
- }
860
- if (command === 'doctor') {
861
- // Host-only, like init/sandbox/stop above: doctor's job is to report on
862
- // sandbox reachability from the outside, so it must never auto-delegate
863
- // into the sandbox the way runtimeCommands below does.
864
- await input.runDoctor(input.args.slice(1));
865
- return;
866
- }
867
- if (runtimeCommands.has(command)) {
868
- const commandArgs = input.args.slice(1);
869
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', commandArgs) ?? process.cwd());
870
- const host = commandArgs.includes('--no-sandbox');
871
- if (!host && (await hasDockerfile(wakeRoot))) {
872
- await input.execIntoSandbox(input.args);
873
- return;
874
- }
875
- const hostArgs = commandArgs.filter((arg) => arg !== '--no-sandbox');
876
- if (command === 'tick') {
877
- await input.runTick(hostArgs);
878
- }
879
- else if (command === 'start') {
880
- await input.runStart(hostArgs);
881
- }
882
- else if (command === 'ui') {
883
- await input.runUi(hostArgs);
884
- }
885
- else if (command === 'audit') {
886
- if (input.runAudit === undefined) {
887
- throw new CliUsageError('audit command is not available in this runtime');
888
- }
889
- await input.runAudit(hostArgs);
890
- }
891
- else if (command === 'smoke') {
892
- await input.runSmoke(hostArgs);
893
- }
894
- else if (command === 'correlate') {
895
- await input.runCorrelate(hostArgs);
896
- }
897
- else {
898
- if (input.runValidateState === undefined) {
899
- throw new CliUsageError('validate-state command is not available in this runtime');
900
- }
901
- await input.runValidateState(hostArgs);
902
- }
903
- return;
904
- }
905
- printUsage(process.stderr);
906
- throw new CliUsageError(`Unknown command: ${input.args.join(' ')}`);
907
- }
908
- async function main() {
909
- const args = process.argv.slice(2);
910
- const runSandbox = async (commandArgs) => {
911
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', commandArgs) ?? process.cwd());
912
- const stateStore = createStateStore({ wakeRoot });
913
- await stateStore.ensureWakeRoot();
914
- const config = await loadWakeConfig({
915
- wakeRoot,
916
- });
917
- const docker = createHostDockerCli();
918
- const recoverActiveRuns = createActiveRunRecovery({
919
- clock: systemClock,
920
- config,
921
- stateStore,
922
- resourceIndex: createResourceIndex({ paths: stateStore.paths }),
923
- }).recoverActiveRuns;
924
- const repoRoot = config.dev?.repoRoot;
925
- const selfUpdate = commandArgs[0] === 'self-update' &&
926
- config.dev?.mode === 'source' &&
927
- repoRoot !== undefined &&
928
- repoRoot.length > 0
929
- ? {
930
- git: {
931
- latestTag: async () => {
932
- await runCommand('git', ['-C', repoRoot, 'fetch', '--tags']);
933
- const output = await runCommandCapture('git', [
934
- '-C',
935
- repoRoot,
936
- 'tag',
937
- '--list',
938
- 'v*',
939
- '--sort=-v:refname',
940
- ]);
941
- const [latest] = output.split('\n').filter((line) => line.trim().length > 0);
942
- if (latest === undefined) {
943
- throw new Error('No version tags found in repo');
944
- }
945
- return latest.trim();
946
- },
947
- isWorkingTreeClean: async () => {
948
- const output = await runCommandCapture('git', [
949
- '-C',
950
- repoRoot,
951
- 'status',
952
- '--porcelain',
953
- ]);
954
- return output.trim().length === 0;
955
- },
956
- checkoutTag: async (tag) => {
957
- await runCommand('git', ['-C', repoRoot, 'checkout', tag]);
958
- },
959
- },
960
- issueReporter: {
961
- createIssue: async (issue) => {
962
- const remoteUrl = await runCommandCapture('git', [
963
- '-C',
964
- repoRoot,
965
- 'remote',
966
- 'get-url',
967
- 'origin',
968
- ]);
969
- const repoSlug = parseGithubRepoSlug(remoteUrl);
970
- await runCommand('gh', [
971
- 'issue',
972
- 'create',
973
- '--repo',
974
- repoSlug,
975
- '--title',
976
- issue.title,
977
- '--body',
978
- issue.body,
979
- ]);
980
- },
981
- },
982
- readLedger: () => readSelfUpdateLedger(resolve(wakeRoot, 'self-update-ledger.json')),
983
- writeLedger: (ledger) => writeSelfUpdateLedger(resolve(wakeRoot, 'self-update-ledger.json'), ledger),
984
- }
985
- : undefined;
986
- await runSandboxCommand({
987
- args: commandArgs,
988
- config,
989
- wakeRoot,
990
- containerHomeRoot: stateStore.paths.containerHomeRoot,
991
- docker,
992
- packagedTemplatesRoot: resolve(resolvePackageRoot(), 'docker'),
993
- stateStore,
994
- recoverActiveRuns,
995
- sleep: (ms) => new Promise((resolveSleep) => setTimeout(resolveSleep, ms)),
996
- logger: {
997
- info(message) {
998
- console.log(message);
999
- },
1000
- error(message) {
1001
- console.error(message);
1002
- },
1003
- },
1004
- selfUpdate,
1005
- });
1006
- };
1007
- await dispatchMainCommand({
1008
- args,
1009
- runInit: async (commandArgs) => {
1010
- await runInitCommand({
1011
- cwd: process.cwd(),
1012
- args: commandArgs,
1013
- repoRoot: resolvePackageRoot(),
1014
- });
1015
- },
1016
- runSandbox,
1017
- runSandboxSetup: async () => {
1018
- await runSandboxSetup();
1019
- },
1020
- runSandboxEntrypoint: async () => {
1021
- await runSandboxEntrypoint();
1022
- },
1023
- runTick,
1024
- runStart,
1025
- runSmoke,
1026
- runUi,
1027
- runAudit,
1028
- runCorrelate,
1029
- runValidateState,
1030
- execIntoSandbox: async (commandArgs) => {
1031
- const withoutBypassFlag = commandArgs.filter((arg) => arg !== '--no-sandbox');
1032
- const wakeRootIndex = withoutBypassFlag.indexOf('--wake-root');
1033
- const rewritten = wakeRootIndex === -1
1034
- ? [...withoutBypassFlag, '--wake-root', '/wake']
1035
- : withoutBypassFlag.map((arg, index) => (index === wakeRootIndex + 1 ? '/wake' : arg));
1036
- const wakeRoot = resolve(readFlagBeforeCommandTerminator('--wake-root', commandArgs) ?? process.cwd());
1037
- const stateStore = createStateStore({ wakeRoot });
1038
- await stateStore.ensureWakeRoot();
1039
- const config = await loadWakeConfig({
1040
- wakeRoot,
1041
- });
1042
- const wakeInvocation = config.dev?.mode === 'source' ? ['node', '/app/dist/src/main.js'] : ['wake'];
1043
- await runSandbox(['exec', '--', ...wakeInvocation, ...rewritten]);
1044
- },
1045
- runDoctor,
160
+ function runDocker(arguments_) {
161
+ return new Promise((resolve, reject) => {
162
+ const child = spawn('docker', arguments_, { stdio: 'inherit' });
163
+ child.once('error', reject);
164
+ child.once('close', (code) => code === 0
165
+ ? resolve()
166
+ : reject(new Error('docker ' + arguments_.join(' ') + ' exited with code ' + String(code))));
1046
167
  });
1047
168
  }
1048
- main().catch((error) => {
1049
- if (error instanceof CliUsageError) {
1050
- console.error(error.message);
1051
- }
1052
- else if (error instanceof StateHealthError) {
1053
- console.error(error.message);
1054
- for (const issue of error.issues) {
1055
- console.error(` - ${issue.surface} ${issue.kind}: ${issue.path}: ${issue.message}`);
1056
- }
1057
- process.exitCode = 1;
1058
- }
1059
- else {
1060
- console.error(error);
1061
- }
1062
- process.exitCode = 1;
1063
- });
169
+ if (process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href)
170
+ await main();