adispatchd 0.0.0-stage → 0.1.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 (396) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -2
  3. package/dist/api/errors.d.ts +27 -0
  4. package/dist/api/errors.js +80 -0
  5. package/dist/api/errors.js.map +1 -0
  6. package/dist/api/index.d.ts +10 -0
  7. package/dist/api/index.js +11 -0
  8. package/dist/api/index.js.map +1 -0
  9. package/dist/api/logs.d.ts +30 -0
  10. package/dist/api/logs.js +88 -0
  11. package/dist/api/logs.js.map +1 -0
  12. package/dist/api/serialize.d.ts +65 -0
  13. package/dist/api/serialize.js +135 -0
  14. package/dist/api/serialize.js.map +1 -0
  15. package/dist/api/server.d.ts +89 -0
  16. package/dist/api/server.js +751 -0
  17. package/dist/api/server.js.map +1 -0
  18. package/dist/api/sse.d.ts +90 -0
  19. package/dist/api/sse.js +225 -0
  20. package/dist/api/sse.js.map +1 -0
  21. package/dist/app.d.ts +173 -0
  22. package/dist/app.js +488 -0
  23. package/dist/app.js.map +1 -0
  24. package/dist/cli/config-validate.d.ts +6 -0
  25. package/dist/cli/config-validate.js +39 -0
  26. package/dist/cli/config-validate.js.map +1 -0
  27. package/dist/cli/control.d.ts +31 -0
  28. package/dist/cli/control.js +186 -0
  29. package/dist/cli/control.js.map +1 -0
  30. package/dist/cli/http-client.d.ts +57 -0
  31. package/dist/cli/http-client.js +174 -0
  32. package/dist/cli/http-client.js.map +1 -0
  33. package/dist/cli/index.d.ts +14 -0
  34. package/dist/cli/index.js +14 -0
  35. package/dist/cli/index.js.map +1 -0
  36. package/dist/cli/init-templates.d.ts +20 -0
  37. package/dist/cli/init-templates.js +275 -0
  38. package/dist/cli/init-templates.js.map +1 -0
  39. package/dist/cli/init.d.ts +16 -0
  40. package/dist/cli/init.js +107 -0
  41. package/dist/cli/init.js.map +1 -0
  42. package/dist/cli/main.d.ts +2 -0
  43. package/dist/cli/main.js +25 -0
  44. package/dist/cli/main.js.map +1 -0
  45. package/dist/cli/program.d.ts +102 -0
  46. package/dist/cli/program.js +133 -0
  47. package/dist/cli/program.js.map +1 -0
  48. package/dist/cli/service.d.ts +27 -0
  49. package/dist/cli/service.js +252 -0
  50. package/dist/cli/service.js.map +1 -0
  51. package/dist/cli/start.d.ts +22 -0
  52. package/dist/cli/start.js +133 -0
  53. package/dist/cli/start.js.map +1 -0
  54. package/dist/cli/workflow-dry-run.d.ts +13 -0
  55. package/dist/cli/workflow-dry-run.js +144 -0
  56. package/dist/cli/workflow-dry-run.js.map +1 -0
  57. package/dist/config/field-catalog.d.ts +33 -0
  58. package/dist/config/field-catalog.js +172 -0
  59. package/dist/config/field-catalog.js.map +1 -0
  60. package/dist/config/filter-schema.d.ts +15 -0
  61. package/dist/config/filter-schema.js +110 -0
  62. package/dist/config/filter-schema.js.map +1 -0
  63. package/dist/config/index.d.ts +15 -0
  64. package/dist/config/index.js +16 -0
  65. package/dist/config/index.js.map +1 -0
  66. package/dist/config/issues.d.ts +27 -0
  67. package/dist/config/issues.js +37 -0
  68. package/dist/config/issues.js.map +1 -0
  69. package/dist/config/loader.d.ts +32 -0
  70. package/dist/config/loader.js +250 -0
  71. package/dist/config/loader.js.map +1 -0
  72. package/dist/config/manager.d.ts +153 -0
  73. package/dist/config/manager.js +276 -0
  74. package/dist/config/manager.js.map +1 -0
  75. package/dist/config/model.d.ts +334 -0
  76. package/dist/config/model.js +2 -0
  77. package/dist/config/model.js.map +1 -0
  78. package/dist/config/normalize.d.ts +20 -0
  79. package/dist/config/normalize.js +200 -0
  80. package/dist/config/normalize.js.map +1 -0
  81. package/dist/config/parameters.d.ts +37 -0
  82. package/dist/config/parameters.js +71 -0
  83. package/dist/config/parameters.js.map +1 -0
  84. package/dist/config/public.d.ts +6 -0
  85. package/dist/config/public.js +18 -0
  86. package/dist/config/public.js.map +1 -0
  87. package/dist/config/schemas.d.ts +538 -0
  88. package/dist/config/schemas.js +321 -0
  89. package/dist/config/schemas.js.map +1 -0
  90. package/dist/config/snapshot.d.ts +38 -0
  91. package/dist/config/snapshot.js +57 -0
  92. package/dist/config/snapshot.js.map +1 -0
  93. package/dist/config/validate.d.ts +33 -0
  94. package/dist/config/validate.js +346 -0
  95. package/dist/config/validate.js.map +1 -0
  96. package/dist/core/clock.d.ts +59 -0
  97. package/dist/core/clock.js +133 -0
  98. package/dist/core/clock.js.map +1 -0
  99. package/dist/core/duration.d.ts +19 -0
  100. package/dist/core/duration.js +93 -0
  101. package/dist/core/duration.js.map +1 -0
  102. package/dist/core/errors.d.ts +62 -0
  103. package/dist/core/errors.js +72 -0
  104. package/dist/core/errors.js.map +1 -0
  105. package/dist/core/ids.d.ts +57 -0
  106. package/dist/core/ids.js +88 -0
  107. package/dist/core/ids.js.map +1 -0
  108. package/dist/core/index.d.ts +13 -0
  109. package/dist/core/index.js +14 -0
  110. package/dist/core/index.js.map +1 -0
  111. package/dist/core/logger.d.ts +100 -0
  112. package/dist/core/logger.js +207 -0
  113. package/dist/core/logger.js.map +1 -0
  114. package/dist/core/paths.d.ts +84 -0
  115. package/dist/core/paths.js +138 -0
  116. package/dist/core/paths.js.map +1 -0
  117. package/dist/core/template.d.ts +136 -0
  118. package/dist/core/template.js +261 -0
  119. package/dist/core/template.js.map +1 -0
  120. package/dist/core/types.d.ts +544 -0
  121. package/dist/core/types.js +172 -0
  122. package/dist/core/types.js.map +1 -0
  123. package/dist/core/worker-protocol.d.ts +102 -0
  124. package/dist/core/worker-protocol.js +75 -0
  125. package/dist/core/worker-protocol.js.map +1 -0
  126. package/dist/executors/classify.d.ts +25 -0
  127. package/dist/executors/classify.js +54 -0
  128. package/dist/executors/classify.js.map +1 -0
  129. package/dist/executors/dispatcher.d.ts +35 -0
  130. package/dist/executors/dispatcher.js +68 -0
  131. package/dist/executors/dispatcher.js.map +1 -0
  132. package/dist/executors/env.d.ts +43 -0
  133. package/dist/executors/env.js +66 -0
  134. package/dist/executors/env.js.map +1 -0
  135. package/dist/executors/event-parser.d.ts +41 -0
  136. package/dist/executors/event-parser.js +106 -0
  137. package/dist/executors/event-parser.js.map +1 -0
  138. package/dist/executors/index.d.ts +12 -0
  139. package/dist/executors/index.js +13 -0
  140. package/dist/executors/index.js.map +1 -0
  141. package/dist/executors/log-capture.d.ts +57 -0
  142. package/dist/executors/log-capture.js +155 -0
  143. package/dist/executors/log-capture.js.map +1 -0
  144. package/dist/executors/process-identity.d.ts +124 -0
  145. package/dist/executors/process-identity.js +283 -0
  146. package/dist/executors/process-identity.js.map +1 -0
  147. package/dist/executors/shell-executor.d.ts +35 -0
  148. package/dist/executors/shell-executor.js +478 -0
  149. package/dist/executors/shell-executor.js.map +1 -0
  150. package/dist/executors/stream-redactor.d.ts +40 -0
  151. package/dist/executors/stream-redactor.js +89 -0
  152. package/dist/executors/stream-redactor.js.map +1 -0
  153. package/dist/executors/workspace.d.ts +10 -0
  154. package/dist/executors/workspace.js +47 -0
  155. package/dist/executors/workspace.js.map +1 -0
  156. package/dist/filters/evaluate.d.ts +77 -0
  157. package/dist/filters/evaluate.js +187 -0
  158. package/dist/filters/evaluate.js.map +1 -0
  159. package/dist/filters/fields.d.ts +35 -0
  160. package/dist/filters/fields.js +75 -0
  161. package/dist/filters/fields.js.map +1 -0
  162. package/dist/filters/index.d.ts +11 -0
  163. package/dist/filters/index.js +12 -0
  164. package/dist/filters/index.js.map +1 -0
  165. package/dist/filters/iso-date.d.ts +10 -0
  166. package/dist/filters/iso-date.js +42 -0
  167. package/dist/filters/iso-date.js.map +1 -0
  168. package/dist/filters/predicate.d.ts +24 -0
  169. package/dist/filters/predicate.js +178 -0
  170. package/dist/filters/predicate.js.map +1 -0
  171. package/dist/filters/priority.d.ts +51 -0
  172. package/dist/filters/priority.js +91 -0
  173. package/dist/filters/priority.js.map +1 -0
  174. package/dist/filters/pushdown.d.ts +12 -0
  175. package/dist/filters/pushdown.js +52 -0
  176. package/dist/filters/pushdown.js.map +1 -0
  177. package/dist/filters/shell-check.d.ts +110 -0
  178. package/dist/filters/shell-check.js +304 -0
  179. package/dist/filters/shell-check.js.map +1 -0
  180. package/dist/identities/github-app.d.ts +55 -0
  181. package/dist/identities/github-app.js +160 -0
  182. package/dist/identities/github-app.js.map +1 -0
  183. package/dist/identities/index.d.ts +6 -0
  184. package/dist/identities/index.js +7 -0
  185. package/dist/identities/index.js.map +1 -0
  186. package/dist/identities/jwt.d.ts +24 -0
  187. package/dist/identities/jwt.js +56 -0
  188. package/dist/identities/jwt.js.map +1 -0
  189. package/dist/lifecycle/context.d.ts +106 -0
  190. package/dist/lifecycle/context.js +170 -0
  191. package/dist/lifecycle/context.js.map +1 -0
  192. package/dist/lifecycle/engine.d.ts +185 -0
  193. package/dist/lifecycle/engine.js +551 -0
  194. package/dist/lifecycle/engine.js.map +1 -0
  195. package/dist/lifecycle/errors.d.ts +48 -0
  196. package/dist/lifecycle/errors.js +71 -0
  197. package/dist/lifecycle/errors.js.map +1 -0
  198. package/dist/lifecycle/index.d.ts +9 -0
  199. package/dist/lifecycle/index.js +9 -0
  200. package/dist/lifecycle/index.js.map +1 -0
  201. package/dist/lifecycle/performers.d.ts +66 -0
  202. package/dist/lifecycle/performers.js +179 -0
  203. package/dist/lifecycle/performers.js.map +1 -0
  204. package/dist/notifications/index.d.ts +6 -0
  205. package/dist/notifications/index.js +7 -0
  206. package/dist/notifications/index.js.map +1 -0
  207. package/dist/notifications/service.d.ts +115 -0
  208. package/dist/notifications/service.js +364 -0
  209. package/dist/notifications/service.js.map +1 -0
  210. package/dist/persistence/actions.d.ts +101 -0
  211. package/dist/persistence/actions.js +196 -0
  212. package/dist/persistence/actions.js.map +1 -0
  213. package/dist/persistence/blocks.d.ts +85 -0
  214. package/dist/persistence/blocks.js +140 -0
  215. package/dist/persistence/blocks.js.map +1 -0
  216. package/dist/persistence/cron-firings.d.ts +55 -0
  217. package/dist/persistence/cron-firings.js +70 -0
  218. package/dist/persistence/cron-firings.js.map +1 -0
  219. package/dist/persistence/database.d.ts +60 -0
  220. package/dist/persistence/database.js +124 -0
  221. package/dist/persistence/database.js.map +1 -0
  222. package/dist/persistence/errors.d.ts +39 -0
  223. package/dist/persistence/errors.js +67 -0
  224. package/dist/persistence/errors.js.map +1 -0
  225. package/dist/persistence/events.d.ts +72 -0
  226. package/dist/persistence/events.js +83 -0
  227. package/dist/persistence/events.js.map +1 -0
  228. package/dist/persistence/index.d.ts +18 -0
  229. package/dist/persistence/index.js +19 -0
  230. package/dist/persistence/index.js.map +1 -0
  231. package/dist/persistence/instance-lock.d.ts +26 -0
  232. package/dist/persistence/instance-lock.js +117 -0
  233. package/dist/persistence/instance-lock.js.map +1 -0
  234. package/dist/persistence/lock-keys.d.ts +16 -0
  235. package/dist/persistence/lock-keys.js +41 -0
  236. package/dist/persistence/lock-keys.js.map +1 -0
  237. package/dist/persistence/notifications.d.ts +113 -0
  238. package/dist/persistence/notifications.js +213 -0
  239. package/dist/persistence/notifications.js.map +1 -0
  240. package/dist/persistence/persistence.d.ts +46 -0
  241. package/dist/persistence/persistence.js +42 -0
  242. package/dist/persistence/persistence.js.map +1 -0
  243. package/dist/persistence/retention.d.ts +46 -0
  244. package/dist/persistence/retention.js +68 -0
  245. package/dist/persistence/retention.js.map +1 -0
  246. package/dist/persistence/runs.d.ts +215 -0
  247. package/dist/persistence/runs.js +417 -0
  248. package/dist/persistence/runs.js.map +1 -0
  249. package/dist/persistence/schema.d.ts +16 -0
  250. package/dist/persistence/schema.js +183 -0
  251. package/dist/persistence/schema.js.map +1 -0
  252. package/dist/persistence/sqlite.d.ts +49 -0
  253. package/dist/persistence/sqlite.js +131 -0
  254. package/dist/persistence/sqlite.js.map +1 -0
  255. package/dist/runs/controller.d.ts +307 -0
  256. package/dist/runs/controller.js +1078 -0
  257. package/dist/runs/controller.js.map +1 -0
  258. package/dist/runs/errors.d.ts +20 -0
  259. package/dist/runs/errors.js +26 -0
  260. package/dist/runs/errors.js.map +1 -0
  261. package/dist/runs/event-bus.d.ts +106 -0
  262. package/dist/runs/event-bus.js +105 -0
  263. package/dist/runs/event-bus.js.map +1 -0
  264. package/dist/runs/execution.d.ts +39 -0
  265. package/dist/runs/execution.js +146 -0
  266. package/dist/runs/execution.js.map +1 -0
  267. package/dist/runs/index.d.ts +12 -0
  268. package/dist/runs/index.js +13 -0
  269. package/dist/runs/index.js.map +1 -0
  270. package/dist/runs/retention.d.ts +64 -0
  271. package/dist/runs/retention.js +232 -0
  272. package/dist/runs/retention.js.map +1 -0
  273. package/dist/runs/workspace.d.ts +20 -0
  274. package/dist/runs/workspace.js +51 -0
  275. package/dist/runs/workspace.js.map +1 -0
  276. package/dist/scheduler/checks.d.ts +41 -0
  277. package/dist/scheduler/checks.js +111 -0
  278. package/dist/scheduler/checks.js.map +1 -0
  279. package/dist/scheduler/cron.d.ts +32 -0
  280. package/dist/scheduler/cron.js +83 -0
  281. package/dist/scheduler/cron.js.map +1 -0
  282. package/dist/scheduler/dry-run.d.ts +42 -0
  283. package/dist/scheduler/dry-run.js +167 -0
  284. package/dist/scheduler/dry-run.js.map +1 -0
  285. package/dist/scheduler/errors.d.ts +22 -0
  286. package/dist/scheduler/errors.js +22 -0
  287. package/dist/scheduler/errors.js.map +1 -0
  288. package/dist/scheduler/format.d.ts +3 -0
  289. package/dist/scheduler/format.js +73 -0
  290. package/dist/scheduler/format.js.map +1 -0
  291. package/dist/scheduler/index.d.ts +13 -0
  292. package/dist/scheduler/index.js +14 -0
  293. package/dist/scheduler/index.js.map +1 -0
  294. package/dist/scheduler/planner.d.ts +88 -0
  295. package/dist/scheduler/planner.js +255 -0
  296. package/dist/scheduler/planner.js.map +1 -0
  297. package/dist/scheduler/scheduler.d.ts +160 -0
  298. package/dist/scheduler/scheduler.js +680 -0
  299. package/dist/scheduler/scheduler.js.map +1 -0
  300. package/dist/scheduler/state.d.ts +26 -0
  301. package/dist/scheduler/state.js +25 -0
  302. package/dist/scheduler/state.js.map +1 -0
  303. package/dist/scheduler/types.d.ts +197 -0
  304. package/dist/scheduler/types.js +3 -0
  305. package/dist/scheduler/types.js.map +1 -0
  306. package/dist/service/index.d.ts +6 -0
  307. package/dist/service/index.js +7 -0
  308. package/dist/service/index.js.map +1 -0
  309. package/dist/service/install.d.ts +93 -0
  310. package/dist/service/install.js +250 -0
  311. package/dist/service/install.js.map +1 -0
  312. package/dist/service/unit.d.ts +50 -0
  313. package/dist/service/unit.js +171 -0
  314. package/dist/service/unit.js.map +1 -0
  315. package/dist/sources/github/adapter.d.ts +99 -0
  316. package/dist/sources/github/adapter.js +336 -0
  317. package/dist/sources/github/adapter.js.map +1 -0
  318. package/dist/sources/github/fields.d.ts +8 -0
  319. package/dist/sources/github/fields.js +72 -0
  320. package/dist/sources/github/fields.js.map +1 -0
  321. package/dist/sources/github/http.d.ts +100 -0
  322. package/dist/sources/github/http.js +288 -0
  323. package/dist/sources/github/http.js.map +1 -0
  324. package/dist/sources/github/index.d.ts +6 -0
  325. package/dist/sources/github/index.js +7 -0
  326. package/dist/sources/github/index.js.map +1 -0
  327. package/dist/sources/github/pushdown.d.ts +14 -0
  328. package/dist/sources/github/pushdown.js +47 -0
  329. package/dist/sources/github/pushdown.js.map +1 -0
  330. package/dist/sources/github/refs.d.ts +17 -0
  331. package/dist/sources/github/refs.js +61 -0
  332. package/dist/sources/github/refs.js.map +1 -0
  333. package/dist/sources/index.d.ts +6 -0
  334. package/dist/sources/index.js +7 -0
  335. package/dist/sources/index.js.map +1 -0
  336. package/dist/ui/index.d.ts +12 -0
  337. package/dist/ui/index.js +28 -0
  338. package/dist/ui/index.js.map +1 -0
  339. package/dist/ui/public/app.css +239 -0
  340. package/dist/ui/public/favicon.svg +1 -0
  341. package/dist/ui/public/index.html +27 -0
  342. package/dist/ui/public/js/client/api.js +68 -0
  343. package/dist/ui/public/js/client/app.js +146 -0
  344. package/dist/ui/public/js/client/dom.js +34 -0
  345. package/dist/ui/public/js/client/page.js +9 -0
  346. package/dist/ui/public/js/client/pages/actions.js +35 -0
  347. package/dist/ui/public/js/client/pages/blocked.js +58 -0
  348. package/dist/ui/public/js/client/pages/config.js +126 -0
  349. package/dist/ui/public/js/client/pages/dashboard.js +175 -0
  350. package/dist/ui/public/js/client/pages/run.js +367 -0
  351. package/dist/ui/public/js/client/pages/runs.js +72 -0
  352. package/dist/ui/public/js/client/pages/views.js +80 -0
  353. package/dist/ui/public/js/client/pages/workflows.js +291 -0
  354. package/dist/ui/public/js/client/types.js +1 -0
  355. package/dist/ui/public/js/client/ui.js +152 -0
  356. package/dist/ui/public/js/shared/dom.js +77 -0
  357. package/dist/ui/public/js/shared/events.js +88 -0
  358. package/dist/ui/public/js/shared/format.js +213 -0
  359. package/dist/ui/public/js/shared/logs.js +136 -0
  360. package/dist/ui/public/js/shared/params.js +90 -0
  361. package/dist/ui/public/js/shared/route.js +36 -0
  362. package/dist/ui/public/js/shared/sort.js +70 -0
  363. package/dist/ui/public/js/shared/sse.js +193 -0
  364. package/dist/ui/public/js/shared/throttle.js +65 -0
  365. package/dist/views/index.d.ts +6 -0
  366. package/dist/views/index.js +7 -0
  367. package/dist/views/index.js.map +1 -0
  368. package/dist/views/service.d.ts +131 -0
  369. package/dist/views/service.js +264 -0
  370. package/dist/views/service.js.map +1 -0
  371. package/docs/api.md +239 -0
  372. package/docs/configuration-reference.md +1785 -0
  373. package/docs/cron-semantics.md +96 -0
  374. package/docs/manual-tests/github-fixture/config.yaml +30 -0
  375. package/docs/manual-tests/github-fixture/helpers.sh +93 -0
  376. package/docs/manual-tests/github-fixture/identities.yaml +18 -0
  377. package/docs/manual-tests/github-fixture/scripts/test-worker.sh +100 -0
  378. package/docs/manual-tests/github-fixture/sources.yaml +13 -0
  379. package/docs/manual-tests/github-fixture/views/dependencies.yaml +17 -0
  380. package/docs/manual-tests/github-fixture/views/needs-maintainer.yaml +17 -0
  381. package/docs/manual-tests/github-fixture/workflows/coder-test.yaml +76 -0
  382. package/docs/manual-tests/github-fixture/workflows/commenter-test.yaml +63 -0
  383. package/docs/manual-tests/github-fixture/workflows/reviewer-test.yaml +60 -0
  384. package/docs/manual-tests/github.md +1308 -0
  385. package/docs/manual-tests/process-supervision.md +64 -0
  386. package/docs/manual-tests/systemd.md +68 -0
  387. package/docs/operations.md +271 -0
  388. package/docs/worker-protocol.md +145 -0
  389. package/examples/config/config.yaml +35 -0
  390. package/examples/config/identities.yaml +18 -0
  391. package/examples/config/sources.yaml +13 -0
  392. package/examples/config/views/needs-maintainer.yaml +15 -0
  393. package/examples/config/workflows/coder-project-a.yaml +86 -0
  394. package/examples/config/workflows/deploy.yaml +15 -0
  395. package/examples/config/workflows/nightly-maintenance.yaml +13 -0
  396. package/package.json +75 -4
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Command-line interface definition (Spec §4, §14, §19). The command tree is
3
+ * declared here; the behaviour lives in injectable handlers (see `main.ts`).
4
+ */
5
+ import { Command } from 'commander';
6
+ import { APP_VERSION } from '../app.js';
7
+ /** Exit code used by commands that are not implemented yet. */
8
+ export const EXIT_NOT_IMPLEMENTED = 70;
9
+ /** CLI I/O bound to the real process streams. */
10
+ export const processIo = {
11
+ stdout: (text) => process.stdout.write(text),
12
+ stderr: (text) => process.stderr.write(text),
13
+ setExitCode: (code) => {
14
+ process.exitCode = code;
15
+ },
16
+ };
17
+ const URL_HELP = 'base URL of the running instance (default: server.host/port from --config-dir, else http://127.0.0.1:8787)';
18
+ /** Build the `adispatch` command tree. */
19
+ export function createProgram(handlers = {}, io = processIo) {
20
+ const program = new Command('adispatch')
21
+ .description('Agent Dispatch Daemon (adispatchd) – configuration-driven orchestrator for shell processes and AI agents')
22
+ .version(APP_VERSION)
23
+ .option('--config-dir <path>', 'configuration directory (config.yaml, sources.yaml, workflows/, ...)')
24
+ .option('--data-dir <path>', 'data directory (SQLite database, logs, runs, workspaces)')
25
+ .configureOutput({ writeOut: io.stdout, writeErr: io.stderr })
26
+ .showHelpAfterError()
27
+ .addHelpText('after', [
28
+ '',
29
+ 'All commands:',
30
+ ' init create config-dir and data-dir with an example configuration',
31
+ ' start start the orchestrator (foreground)',
32
+ ' status show the status of the running instance',
33
+ ' pause | resume pause/resume automatic starts of the running instance',
34
+ ' drain finish active runs, start nothing new, then stop',
35
+ ' cancel-all cancel all runs (on_cancel), then stop',
36
+ ' config validate validate the configuration offline',
37
+ ' config reload reload the configuration of the running instance',
38
+ ' workflow dry-run <workflow> show candidate selection without starting anything',
39
+ ' service install install the systemd service (Linux)',
40
+ ' service status show the systemd service status',
41
+ ' service uninstall remove the systemd service',
42
+ '',
43
+ 'Docs: README.md, docs/operations.md, docs/worker-protocol.md, docs/api.md',
44
+ '',
45
+ ].join('\n'));
46
+ const run = (name, handler) => async (...args) => {
47
+ const cmd = args[args.length - 1];
48
+ if (!handler) {
49
+ io.stderr(`adispatch: "${name}" is not implemented yet\n`);
50
+ io.setExitCode(EXIT_NOT_IMPLEMENTED);
51
+ return;
52
+ }
53
+ io.setExitCode(await handler(cmd.optsWithGlobals()));
54
+ };
55
+ program
56
+ .command('init')
57
+ .description('create config-dir and data-dir with a commented example configuration (never overwrites files)')
58
+ .option('--port <port>', 'server.port for a newly created config.yaml (default 8787)')
59
+ .action(run('init', handlers.init));
60
+ program
61
+ .command('start')
62
+ .description('start the orchestrator (scheduler, HTTP API and web UI) in the foreground')
63
+ .option('--drain-timeout <duration>', 'on SIGTERM/SIGINT: wait this long for active runs before cancelling them', '10m')
64
+ .option('--cancel-timeout <duration>', 'time for cancelled runs incl. on_cancel before hooks are interrupted', '2m')
65
+ .option('--host <host>', 'override server.host')
66
+ .option('--port <port>', 'override server.port')
67
+ .action(run('start', handlers.start));
68
+ const control = (name, description, handler) => program
69
+ .command(name)
70
+ .description(description)
71
+ .option('--url <url>', URL_HELP)
72
+ .option('--json', 'print the JSON response')
73
+ .action(run(name, handler));
74
+ control('status', 'show scheduler state, limits, usage and counters of the running instance', handlers.status);
75
+ control('pause', 'pause automatic starts (running runs and manual starts are not affected)', handlers.pause);
76
+ control('resume', 'resume automatic starts', handlers.resume);
77
+ control('drain', 'start nothing new, let active runs finish, then stop the instance (exit 0)', handlers.drain)
78
+ .option('--wait', 'wait until the instance has stopped')
79
+ .option('--timeout <duration>', 'maximum wait time with --wait');
80
+ control('cancel-all', 'cancel all active runs (on_cancel runs), then stop the instance (exit 0)', handlers.cancelAll)
81
+ .option('--reason <text>', 'reason recorded for the cancelled runs')
82
+ .option('--wait', 'wait until the instance has stopped')
83
+ .option('--timeout <duration>', 'maximum wait time with --wait');
84
+ const config = program.command('config').description('configuration commands');
85
+ config
86
+ .command('validate')
87
+ .description('validate the configuration offline (syntax, schema, references, placeholders)')
88
+ .action(run('config validate', handlers.configValidate));
89
+ config
90
+ .command('reload')
91
+ .description('ask the running instance to reload its configuration (atomic; invalid YAML keeps the active config)')
92
+ .option('--url <url>', URL_HELP)
93
+ .option('--json', 'print the JSON response')
94
+ .action(run('config reload', handlers.configReload));
95
+ const workflow = program.command('workflow').description('workflow commands');
96
+ workflow
97
+ .command('dry-run')
98
+ .description('show candidate selection for a workflow without starting anything (running instance, else local)')
99
+ .argument('<workflow-id>', 'workflow ID')
100
+ .option('--json', 'print the structured result as JSON')
101
+ .option('--url <url>', URL_HELP)
102
+ .option('--local', 'always evaluate locally (needs --config-dir), even if an instance is running')
103
+ .action(async (workflowId, _opts, cmd) => {
104
+ if (!handlers.workflowDryRun) {
105
+ io.stderr('adispatch: "workflow dry-run" is not implemented yet\n');
106
+ io.setExitCode(EXIT_NOT_IMPLEMENTED);
107
+ return;
108
+ }
109
+ io.setExitCode(await handlers.workflowDryRun(workflowId, cmd.optsWithGlobals()));
110
+ });
111
+ const service = program.command('service').description('systemd service management (Linux)');
112
+ const serviceCommand = (name, description, handler) => service
113
+ .command(name)
114
+ .description(description)
115
+ .option('--name <unit>', 'unit name without .service', 'adispatchd')
116
+ .option('--unit-dir <path>', 'directory of unit files', '/etc/systemd/system')
117
+ .action(run(`service ${name}`, handler));
118
+ serviceCommand('install', 'install and enable the systemd service (needs root)', handlers.serviceInstall)
119
+ .option('--dry-run', 'only print the unit file and the planned steps')
120
+ .option('--user <name>', 'dedicated service user', 'adispatchd')
121
+ .option('--group <name>', 'service group (default: same as --user)')
122
+ .option('--create-user', 'create the service user if it does not exist')
123
+ .option('--node <path>', 'absolute node executable (default: the running node)')
124
+ .option('--entry <path>', 'absolute package entry point (default: this installation)')
125
+ .option('--env-file <path>', 'environment file for secrets ("none" to disable; default /etc/default/<name>)')
126
+ .option('--drain-timeout <duration>', 'drain timeout on systemctl stop', '10m')
127
+ .option('--cancel-timeout <duration>', 'cancel timeout after the drain timeout', '2m')
128
+ .option('--now', 'start the service immediately');
129
+ serviceCommand('status', 'show the systemd service status', handlers.serviceStatus);
130
+ serviceCommand('uninstall', 'stop, disable and remove the systemd unit (config and data are kept)', handlers.serviceUninstall).option('--dry-run', 'only print the planned steps');
131
+ return program;
132
+ }
133
+ //# sourceMappingURL=program.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/cli/program.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type SystemRunner, type UnitOptions } from '../service/index.js';
2
+ import type { CliIo, ServiceCliOptions } from './program.js';
3
+ /** Injectable environment (tests: platform, uid, runner – real systemd is never touched in tests). */
4
+ export interface ServiceDeps {
5
+ platform?: NodeJS.Platform;
6
+ /** Effective UID (default `process.geteuid()`). */
7
+ euid?: () => number;
8
+ runner?: SystemRunner;
9
+ /** Node executable (default `process.execPath`). */
10
+ execPath?: string;
11
+ /** Package entry point of this installation (default: `main.js` next to this file). */
12
+ entryPath?: string;
13
+ }
14
+ type Io = Pick<CliIo, 'stdout' | 'stderr'>;
15
+ /** `main.js` of this installation (`<package>/dist/cli/main.js`); in development the `.ts` source. */
16
+ export declare function defaultEntryPath(): string;
17
+ /** Warning if a worker's cancel grace cannot take effect within the cancel timeout. */
18
+ export declare function cancelGraceWarning(maxCancelGraceMs: number, cancelTimeoutMs: number): string | null;
19
+ /** Collect and validate the unit options from the CLI flags. */
20
+ export declare function unitOptionsFromCli(opts: ServiceCliOptions, deps: ServiceDeps, io: Io): Promise<UnitOptions>;
21
+ /** `service install`. */
22
+ export declare function createServiceInstallHandler(io: Io, deps?: ServiceDeps): (opts: ServiceCliOptions) => Promise<number>;
23
+ /** `service uninstall`. */
24
+ export declare function createServiceUninstallHandler(io: Io, deps?: ServiceDeps): (opts: ServiceCliOptions) => Promise<number>;
25
+ /** `service status`: `systemctl status <unit>` (read-only). */
26
+ export declare function createServiceStatusHandler(io: Io, deps?: ServiceDeps): (opts: ServiceCliOptions) => Promise<number>;
27
+ export {};
@@ -0,0 +1,252 @@
1
+ /**
2
+ * `service install | status | uninstall` (Spec §4, §14, §20.1) – Linux/systemd.
3
+ *
4
+ * `install` generates the unit with absolute node and package paths (never
5
+ * `npx`), a dedicated user, `Restart=on-failure`, `KillMode=mixed` and a
6
+ * `TimeoutStopSec` derived from drain/cancel timeouts and the largest
7
+ * `cancel_grace` of the configuration, sets ownership/permissions of
8
+ * config-dir (root:<group>, 0750/0640) and data-dir (<user>, 0750), writes an
9
+ * environment file template (never overwrites) and enables the unit.
10
+ * `--dry-run` prints the unit and the planned steps without changing
11
+ * anything (works on every platform). On non-Linux systems the real commands
12
+ * refuse with an explanation.
13
+ *
14
+ * Exit codes: 0 = ok, 1 = failed, 2 = usage error / unsupported platform.
15
+ */
16
+ import { existsSync, realpathSync } from 'node:fs';
17
+ import path from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { errorMessage, parseDuration } from '../core/index.js';
20
+ import { loadConfig } from '../config/index.js';
21
+ import { DEFAULT_SERVICE_USER, DEFAULT_UNIT_DIR, DEFAULT_UNIT_NAME, ServiceError, assertSafeServicePaths, formatCliDuration, executePlan, formatPlan, planInstall, planUninstall, renderSystemdUnit, systemRunner, unitFilePath, } from '../service/index.js';
22
+ /** Default `execute.cancel_grace` (Spec defaults, WI-02). */
23
+ const DEFAULT_APP_CANCEL_GRACE_MS = 30_000;
24
+ /** `main.js` of this installation (`<package>/dist/cli/main.js`); in development the `.ts` source. */
25
+ export function defaultEntryPath() {
26
+ const dir = path.dirname(fileURLToPath(import.meta.url));
27
+ const js = path.join(dir, 'main.js');
28
+ const file = existsSync(js) ? js : path.join(dir, 'main.ts');
29
+ try {
30
+ return realpathSync(file);
31
+ }
32
+ catch {
33
+ return file;
34
+ }
35
+ }
36
+ function unsupported(io, platform, command) {
37
+ io.stderr(`service ${command}: systemd service management is only supported on Linux (this is ${platform}).\n` +
38
+ ' On macOS run the orchestrator in the foreground: adispatch start --config-dir <dir> --data-dir <dir>\n' +
39
+ ' (or under launchd/your own supervisor). "service install --dry-run" prints the systemd unit anyway.\n');
40
+ return 2;
41
+ }
42
+ function duration(name, value, fallback) {
43
+ try {
44
+ return parseDuration(value ?? fallback);
45
+ }
46
+ catch (err) {
47
+ throw new ServiceError('service_invalid_option', `invalid --${name} "${value}": ${errorMessage(err)}`);
48
+ }
49
+ }
50
+ /**
51
+ * Largest `execute.cancel_grace` of the configuration. Outside dry runs the
52
+ * configuration must exist (`config.yaml`) and be valid – `install` changes
53
+ * ownership of the directory recursively, so a typo'd path must not pass.
54
+ * In dry runs a missing/invalid configuration only warns (default 30 s).
55
+ */
56
+ async function maxCancelGrace(configDir, dataDir, io, dryRun) {
57
+ const configFile = path.join(configDir, 'config.yaml');
58
+ const exists = existsSync(configFile);
59
+ const loaded = exists ? await loadConfig(configDir, { dataDir }) : null;
60
+ if (!loaded || !loaded.ok) {
61
+ const why = !exists
62
+ ? `${configFile} does not exist (create the configuration with "adispatch init" first)`
63
+ : `configuration in ${configDir} is invalid (${loaded?.ok === false ? loaded.errors.length : 0} error(s); see "config validate")`;
64
+ if (!dryRun)
65
+ throw new ServiceError('service_config_invalid', why);
66
+ io.stderr(`warning: ${why}; TimeoutStopSec assumes a cancel grace of 30s\n`);
67
+ return DEFAULT_APP_CANCEL_GRACE_MS;
68
+ }
69
+ return Math.max(DEFAULT_APP_CANCEL_GRACE_MS, ...Object.values(loaded.config.workflows).map((w) => w.execute.cancelGraceMs));
70
+ }
71
+ /** Resolve symlinks of existing paths (so `/srv/x -> /etc` cannot bypass the system-path check). */
72
+ function realOrResolved(p) {
73
+ const abs = path.resolve(p);
74
+ try {
75
+ return realpathSync(abs);
76
+ }
77
+ catch {
78
+ return abs;
79
+ }
80
+ }
81
+ /** Warning if a worker's cancel grace cannot take effect within the cancel timeout. */
82
+ export function cancelGraceWarning(maxCancelGraceMs, cancelTimeoutMs) {
83
+ if (maxCancelGraceMs < cancelTimeoutMs)
84
+ return null;
85
+ return (`the largest execute.cancel_grace (${formatCliDuration(maxCancelGraceMs)}) is not smaller than the cancel timeout ` +
86
+ `(${formatCliDuration(cancelTimeoutMs)}): on shutdown the orchestrator may stop before workers are SIGKILLed; ` +
87
+ 'raise --cancel-timeout or lower cancel_grace');
88
+ }
89
+ /** Collect and validate the unit options from the CLI flags. */
90
+ export async function unitOptionsFromCli(opts, deps, io) {
91
+ const dryRun = opts.dryRun === true;
92
+ if (!opts.configDir || !opts.dataDir) {
93
+ throw new ServiceError('service_invalid_option', 'service install: --config-dir and --data-dir are required (absolute paths recommended, e.g. /etc/adispatchd and /var/lib/adispatchd)');
94
+ }
95
+ const unitName = opts.name ?? DEFAULT_UNIT_NAME;
96
+ const user = opts.user ?? DEFAULT_SERVICE_USER;
97
+ // Check the paths as given and with symlinks resolved (e.g. /srv/x -> /etc, or /var -> /private/var on macOS).
98
+ assertSafeServicePaths({ configDir: path.resolve(opts.configDir), dataDir: path.resolve(opts.dataDir) });
99
+ const configDir = realOrResolved(opts.configDir);
100
+ const dataDir = realOrResolved(opts.dataDir);
101
+ assertSafeServicePaths({ configDir, dataDir });
102
+ const envFile = opts.envFile === 'none' ? null : path.resolve(opts.envFile ?? `/etc/default/${unitName}`);
103
+ return {
104
+ unitName,
105
+ user,
106
+ group: opts.group ?? user,
107
+ nodePath: path.resolve(opts.node ?? deps.execPath ?? process.execPath),
108
+ entryPath: path.resolve(opts.entry ?? deps.entryPath ?? defaultEntryPath()),
109
+ configDir,
110
+ dataDir,
111
+ envFile,
112
+ drainTimeoutMs: duration('drain-timeout', opts.drainTimeout, '10m'),
113
+ cancelTimeoutMs: duration('cancel-timeout', opts.cancelTimeout, '2m'),
114
+ maxCancelGraceMs: await maxCancelGrace(configDir, dataDir, io, dryRun),
115
+ };
116
+ }
117
+ function pathWarnings(unit) {
118
+ const warnings = [];
119
+ for (const [label, p] of [
120
+ ['node', unit.nodePath],
121
+ ['package', unit.entryPath],
122
+ ]) {
123
+ if (/^\/(root|home|Users)\//.test(p)) {
124
+ warnings.push(`${label} path ${p} lies in a home directory (nvm/user install?) – the service user "${unit.user}" may not be able to read it; ` +
125
+ 'prefer a system-wide node and a global install of a fixed version (npm install -g adispatchd@<version>) or pass --node/--entry');
126
+ }
127
+ }
128
+ return warnings;
129
+ }
130
+ async function userExists(runner, user) {
131
+ return (await runner.exec(['id', '-u', user])).code === 0;
132
+ }
133
+ /** `service install`. */
134
+ export function createServiceInstallHandler(io, deps = {}) {
135
+ return async (opts) => {
136
+ const platform = deps.platform ?? process.platform;
137
+ const runner = deps.runner ?? systemRunner;
138
+ const linux = platform === 'linux';
139
+ if (!opts.dryRun && !linux)
140
+ return unsupported(io, platform, 'install');
141
+ let unit;
142
+ let content;
143
+ try {
144
+ unit = await unitOptionsFromCli(opts, deps, io);
145
+ content = renderSystemdUnit(unit);
146
+ }
147
+ catch (err) {
148
+ io.stderr(`service install: ${errorMessage(err)}\n`);
149
+ return 2;
150
+ }
151
+ const warnings = pathWarnings(unit);
152
+ const graceWarning = cancelGraceWarning(unit.maxCancelGraceMs, unit.cancelTimeoutMs);
153
+ if (graceWarning)
154
+ warnings.push(graceWarning);
155
+ const unitDir = path.resolve(opts.unitDir ?? DEFAULT_UNIT_DIR);
156
+ // Probing the user is read-only (`id -u`); on non-Linux dry runs it is skipped.
157
+ const exists = linux ? await userExists(runner, unit.user) : true;
158
+ const input = {
159
+ unit,
160
+ unitDir,
161
+ createUser: opts.createUser === true,
162
+ userExists: exists,
163
+ envFileExists: unit.envFile !== null && runner.exists(unit.envFile),
164
+ startNow: opts.now === true,
165
+ dryRun: opts.dryRun === true,
166
+ };
167
+ let plan;
168
+ try {
169
+ plan = planInstall(input);
170
+ }
171
+ catch (err) {
172
+ io.stderr(`service install: ${errorMessage(err)}\n`);
173
+ return 1;
174
+ }
175
+ if (opts.dryRun) {
176
+ io.stdout(`# ${unitFilePath(unitDir, unit.unitName)}\n${content}\n`);
177
+ if (!linux)
178
+ io.stdout(`# note: this is ${platform}; the unit is only usable on Linux with systemd\n`);
179
+ io.stdout(`# planned steps (dry run, nothing was changed):\n${formatPlan(plan)}`);
180
+ for (const n of [...warnings, ...plan.notes])
181
+ io.stdout(`# note: ${n}\n`);
182
+ return 0;
183
+ }
184
+ const euid = deps.euid ?? (() => process.geteuid?.() ?? -1);
185
+ if (euid() !== 0) {
186
+ io.stderr('service install: must run as root (e.g. sudo "$(command -v node)" "$(command -v adispatch)" service install ...)\n');
187
+ return 1;
188
+ }
189
+ for (const w of warnings)
190
+ io.stderr(`warning: ${w}\n`);
191
+ if ((await runner.exec(['systemctl', '--version'])).code !== 0) {
192
+ io.stderr('service install: systemctl not found – is this a systemd system?\n');
193
+ return 1;
194
+ }
195
+ const result = await executePlan(plan, runner, io.stdout);
196
+ if (!result.ok) {
197
+ io.stderr(`service install failed at "${result.failedStep?.description}": ${result.error}\n`);
198
+ return 1;
199
+ }
200
+ for (const n of plan.notes)
201
+ io.stdout(`note: ${n}\n`);
202
+ io.stdout(`service ${unit.unitName} installed (${unitFilePath(unitDir, unit.unitName)})\n`);
203
+ return 0;
204
+ };
205
+ }
206
+ /** `service uninstall`. */
207
+ export function createServiceUninstallHandler(io, deps = {}) {
208
+ return async (opts) => {
209
+ const platform = deps.platform ?? process.platform;
210
+ const plan = planUninstall({ unitName: opts.name ?? DEFAULT_UNIT_NAME, unitDir: path.resolve(opts.unitDir ?? DEFAULT_UNIT_DIR) });
211
+ if (opts.dryRun) {
212
+ io.stdout(`# planned steps (dry run, nothing was changed):\n${formatPlan(plan)}`);
213
+ for (const n of plan.notes)
214
+ io.stdout(`# note: ${n}\n`);
215
+ return 0;
216
+ }
217
+ if (platform !== 'linux')
218
+ return unsupported(io, platform, 'uninstall');
219
+ const euid = deps.euid ?? (() => process.geteuid?.() ?? -1);
220
+ if (euid() !== 0) {
221
+ io.stderr('service uninstall: must run as root\n');
222
+ return 1;
223
+ }
224
+ const result = await executePlan(plan, deps.runner ?? systemRunner, io.stdout);
225
+ if (!result.ok) {
226
+ io.stderr(`service uninstall failed at "${result.failedStep?.description}": ${result.error}\n`);
227
+ return 1;
228
+ }
229
+ for (const n of plan.notes)
230
+ io.stdout(`note: ${n}\n`);
231
+ return 0;
232
+ };
233
+ }
234
+ /** `service status`: `systemctl status <unit>` (read-only). */
235
+ export function createServiceStatusHandler(io, deps = {}) {
236
+ return async (opts) => {
237
+ const platform = deps.platform ?? process.platform;
238
+ if (platform !== 'linux')
239
+ return unsupported(io, platform, 'status');
240
+ const unitName = opts.name ?? DEFAULT_UNIT_NAME;
241
+ const r = await (deps.runner ?? systemRunner).exec(['systemctl', 'status', '--no-pager', '--lines', '20', `${unitName}.service`]);
242
+ if (r.stdout)
243
+ io.stdout(r.stdout);
244
+ if (r.stderr)
245
+ io.stderr(r.stderr);
246
+ // systemctl status: 0 = active, 3 = inactive, 4 = unknown unit.
247
+ if (r.code === 4)
248
+ io.stderr(`unit ${unitName}.service is not installed (adispatch service install ...)\n`);
249
+ return r.code === 0 ? 0 : 1;
250
+ };
251
+ }
252
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/cli/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { type App, type AppOptions, type SignalTarget } from '../app.js';
2
+ import type { CliIo, StartCliOptions } from './program.js';
3
+ /** Parse the `start` flags (throws on invalid values). */
4
+ export declare function parseStartFlags(opts: StartCliOptions): {
5
+ drainTimeoutMs?: number;
6
+ cancelTimeoutMs?: number;
7
+ host?: string;
8
+ port?: number;
9
+ };
10
+ /** Injectable dependencies (tests). */
11
+ export interface StartDeps {
12
+ /** Extra app options (tests: Fake-GitHub fetch, env, port 0). */
13
+ appOptions?: Partial<AppOptions>;
14
+ /** Signal source (default `process`). */
15
+ signals?: SignalTarget;
16
+ /** Hard exit used as safety net if the event loop does not drain after stop (default `process.exit`). */
17
+ exit?: (code: number) => void;
18
+ /** Called once the app listens (tests). */
19
+ onStarted?: (app: App) => void;
20
+ }
21
+ /** Create the `start` handler. */
22
+ export declare function createStartHandler(io: Pick<CliIo, 'stdout' | 'stderr'>, deps?: StartDeps): (opts: StartCliOptions) => Promise<number>;
@@ -0,0 +1,133 @@
1
+ /**
2
+ * `start --config-dir <dir> [--data-dir <dir>] [--drain-timeout 10m]
3
+ * [--cancel-timeout 2m] [--host h] [--port p]` (Spec §4, §14): starts the
4
+ * orchestrator in the foreground, prints the URL, warns on non-loopback
5
+ * binds, handles SIGTERM/SIGINT (drain with `--drain-timeout`, then
6
+ * cancel-all with `--cancel-timeout`; a second signal cancels immediately)
7
+ * and exits with 0 after an orderly shutdown (also after an API drain /
8
+ * cancel-all), 2 on usage errors, {@link EXIT_CONFIG} (78, EX_CONFIG) on
9
+ * configuration/start errors a restart cannot fix (invalid configuration,
10
+ * instance lock held, database migration error; the systemd unit sets
11
+ * `RestartPreventExitStatus=78`), 1 on other startup errors or a fatal error.
12
+ */
13
+ import path from 'node:path';
14
+ import { errorMessage, formatDuration, isOrchestratorError, parseDuration } from '../core/index.js';
15
+ import { ConfigLoadError, formatConfigIssue } from '../config/index.js';
16
+ import { DEFAULT_CANCEL_TIMEOUT_MS, DEFAULT_DRAIN_TIMEOUT_MS, createApp, installSignalHandlers, isLoopback, } from '../app.js';
17
+ import { resolveUiDir } from '../ui/index.js';
18
+ import { EXIT_CONFIG } from '../service/index.js';
19
+ import { cancelGraceWarning } from './service.js';
20
+ function durationFlag(name, value) {
21
+ if (value === undefined)
22
+ return undefined;
23
+ try {
24
+ return parseDuration(value);
25
+ }
26
+ catch (err) {
27
+ throw new Error(`invalid --${name} "${value}": ${errorMessage(err)}`);
28
+ }
29
+ }
30
+ /** Parse the `start` flags (throws on invalid values). */
31
+ export function parseStartFlags(opts) {
32
+ const out = {};
33
+ const drain = durationFlag('drain-timeout', opts.drainTimeout);
34
+ const cancel = durationFlag('cancel-timeout', opts.cancelTimeout);
35
+ if (drain !== undefined)
36
+ out.drainTimeoutMs = drain;
37
+ if (cancel !== undefined)
38
+ out.cancelTimeoutMs = cancel;
39
+ if (opts.host !== undefined)
40
+ out.host = opts.host;
41
+ if (opts.port !== undefined) {
42
+ const port = Number(opts.port);
43
+ if (!Number.isInteger(port) || port < 0 || port > 65535)
44
+ throw new Error(`invalid --port "${opts.port}"`);
45
+ out.port = port;
46
+ }
47
+ return out;
48
+ }
49
+ /** Create the `start` handler. */
50
+ export function createStartHandler(io, deps = {}) {
51
+ return async (opts) => {
52
+ if (!opts.configDir) {
53
+ io.stderr('start: --config-dir is required\n');
54
+ return 2;
55
+ }
56
+ let flags;
57
+ try {
58
+ flags = parseStartFlags(opts);
59
+ }
60
+ catch (err) {
61
+ io.stderr(`start: ${errorMessage(err)}\n`);
62
+ return 2;
63
+ }
64
+ const configDir = path.resolve(opts.configDir);
65
+ const dataDir = path.resolve(opts.dataDir ?? 'data');
66
+ // Static web UI (WI-11): built assets from `dist/ui/public`; the API also runs without them.
67
+ const uiDir = deps.appOptions && 'uiDir' in deps.appOptions ? deps.appOptions.uiDir : (resolveUiDir() ?? undefined);
68
+ const appOptions = {
69
+ configDir,
70
+ dataDir,
71
+ ...flags,
72
+ ...(deps.appOptions ?? {}),
73
+ ...(uiDir ? { uiDir } : {}),
74
+ };
75
+ let app;
76
+ try {
77
+ app = await createApp(appOptions);
78
+ }
79
+ catch (err) {
80
+ if (err instanceof ConfigLoadError) {
81
+ io.stderr(`Configuration in ${configDir} is invalid:\n${err.errors.map((i) => ` ${formatConfigIssue(i)}\n`).join('')}`);
82
+ return EXIT_CONFIG;
83
+ }
84
+ if (isOrchestratorError(err, 'instance_locked') || isOrchestratorError(err, 'migration_error')) {
85
+ io.stderr(`start: ${err.message}\n`);
86
+ return EXIT_CONFIG;
87
+ }
88
+ io.stderr(`start: ${errorMessage(err)}\n`);
89
+ return 1;
90
+ }
91
+ let url;
92
+ try {
93
+ url = await app.start();
94
+ }
95
+ catch (err) {
96
+ io.stderr(`start: cannot listen: ${errorMessage(err)}\n`);
97
+ await app.shutdown({ mode: 'cancel', cancelTimeoutMs: 0 });
98
+ return 1;
99
+ }
100
+ io.stdout(`adispatchd listening on ${url} (config ${configDir}, data ${dataDir})\n`);
101
+ io.stdout(`SIGTERM/Ctrl-C: drain up to ${formatDuration(appOptions.drainTimeoutMs ?? DEFAULT_DRAIN_TIMEOUT_MS)}, ` +
102
+ `then cancel all runs (${formatDuration(appOptions.cancelTimeoutMs ?? DEFAULT_CANCEL_TIMEOUT_MS)}); a second signal cancels immediately\n`);
103
+ const graceWarning = cancelGraceWarning(Math.max(0, ...Object.values(app.config.current.workflows).map((w) => w.execute.cancelGraceMs)), appOptions.cancelTimeoutMs ?? DEFAULT_CANCEL_TIMEOUT_MS);
104
+ if (graceWarning)
105
+ io.stderr(`warning: ${graceWarning}\n`);
106
+ if (!uiDir)
107
+ io.stderr('Note: web UI assets not found (run `npm run build`); serving the API only.\n');
108
+ const host = new URL(url).hostname;
109
+ if (!isLoopback(host)) {
110
+ io.stderr(`WARNING: the HTTP API is bound to ${host} without authentication. Only expose it behind an authenticating reverse proxy or VPN ` +
111
+ '(add its host name to server.allowed_hosts; see docs/operations.md).\n');
112
+ }
113
+ const uninstall = installSignalHandlers(app, {
114
+ ...(deps.signals ? { target: deps.signals } : {}),
115
+ ...(appOptions.drainTimeoutMs !== undefined ? { drainTimeoutMs: appOptions.drainTimeoutMs } : {}),
116
+ ...(appOptions.cancelTimeoutMs !== undefined ? { cancelTimeoutMs: appOptions.cancelTimeoutMs } : {}),
117
+ ...(deps.exit ? { forceExit: deps.exit } : {}),
118
+ });
119
+ deps.onStarted?.(app);
120
+ const result = await app.stopped;
121
+ uninstall();
122
+ if (result.error)
123
+ io.stderr(`adispatchd stopped with error: ${result.error}\n`);
124
+ else
125
+ io.stdout('adispatchd stopped\n');
126
+ // Safety net: if some handle keeps the event loop alive, exit anyway (does not keep the process alive itself).
127
+ const exit = deps.exit ?? ((code) => process.exit(code));
128
+ const t = setTimeout(() => exit(result.exitCode), 5_000);
129
+ t.unref();
130
+ return result.exitCode;
131
+ };
132
+ }
133
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/cli/start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type Clock, type FetchLike } from '../core/index.js';
2
+ import type { CliIo, DryRunCliOptions } from './program.js';
3
+ /** Injectable dependencies (tests: Fake-GitHub `fetch`, key env). */
4
+ export interface WorkflowDryRunDeps {
5
+ /** HTTP client for GitHub (local variant). */
6
+ fetch?: FetchLike;
7
+ /** HTTP client for the orchestrator API (default global `fetch`). */
8
+ apiFetch?: FetchLike;
9
+ env?: Readonly<Record<string, string | undefined>>;
10
+ clock?: Clock;
11
+ }
12
+ /** Create the `workflow dry-run` handler. */
13
+ export declare function createWorkflowDryRunHandler(io: Pick<CliIo, 'stdout' | 'stderr'>, deps?: WorkflowDryRunDeps): (workflowId: string, opts: DryRunCliOptions) => Promise<number>;