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,276 @@
1
+ /**
2
+ * ConfigManager (Spec §19): holds the active configuration, reloads it
3
+ * atomically (all-or-nothing) and manages non-persistent runtime overrides.
4
+ */
5
+ import { errorMessage, noopLogger, OrchestratorError, systemClock, ValidationError, } from '../core/index.js';
6
+ import { loadConfig } from './loader.js';
7
+ import { validateWorkflowParameters } from './parameters.js';
8
+ import { snapshotWorkflow, UnknownWorkflowError } from './snapshot.js';
9
+ /** Workflow settings that can be overridden at runtime. */
10
+ const OVERRIDE_KEYS = ['enabled', 'priority', 'maxConcurrent'];
11
+ /** Thrown by {@link ConfigManager.create} when the initial configuration is invalid. */
12
+ export class ConfigLoadError extends OrchestratorError {
13
+ errors;
14
+ warnings;
15
+ constructor(errors, warnings) {
16
+ super('config_invalid', `Configuration is invalid (${errors.length} error(s))`, {
17
+ details: { errors: errors.length },
18
+ });
19
+ this.errors = errors;
20
+ this.warnings = warnings;
21
+ }
22
+ }
23
+ /**
24
+ * Holds the active {@link LoadedConfig}. Use {@link ConfigManager.create} to
25
+ * load the initial configuration.
26
+ */
27
+ export class ConfigManager {
28
+ options;
29
+ active;
30
+ workflowOverrides = new Map();
31
+ globalOverrides = {};
32
+ listeners = new Set();
33
+ reloadChain = Promise.resolve();
34
+ clock;
35
+ logger;
36
+ loader;
37
+ /** Use {@link ConfigManager.create} unless you already have a loaded config. */
38
+ constructor(initial, options) {
39
+ this.options = options;
40
+ this.active = initial;
41
+ this.clock = options.clock ?? systemClock;
42
+ this.logger = options.logger ?? noopLogger;
43
+ this.loader = options.loader ?? loadConfig;
44
+ }
45
+ /**
46
+ * Load the configuration and create a manager.
47
+ * @throws ConfigLoadError if the configuration is invalid.
48
+ */
49
+ static async create(options) {
50
+ const loader = options.loader ?? loadConfig;
51
+ const result = await loader(options.configDir, {
52
+ dataDir: options.dataDir,
53
+ version: 1,
54
+ clock: options.clock ?? systemClock,
55
+ });
56
+ if (!result.ok)
57
+ throw new ConfigLoadError(result.errors, result.warnings);
58
+ return new ConfigManager(result.config, options);
59
+ }
60
+ /** The active configuration (immutable). */
61
+ get current() {
62
+ return this.active;
63
+ }
64
+ /**
65
+ * Reload the whole configuration. Only if loading and validation succeed
66
+ * completely is the new configuration activated (atomically); otherwise the
67
+ * active configuration stays untouched and the errors are returned.
68
+ * Concurrent calls are serialized.
69
+ */
70
+ reload() {
71
+ const next = this.reloadChain.then(() => this.doReload());
72
+ this.reloadChain = next.catch(() => undefined);
73
+ return next;
74
+ }
75
+ async doReload() {
76
+ const previous = this.active;
77
+ let result;
78
+ try {
79
+ result = await this.loader(this.options.configDir, {
80
+ dataDir: this.options.dataDir,
81
+ version: previous.version + 1,
82
+ clock: this.clock,
83
+ });
84
+ }
85
+ catch (err) {
86
+ const message = `Unexpected error while loading configuration: ${errorMessage(err)}`;
87
+ this.logger.error('config reload failed', { error: message });
88
+ return { ok: false, errors: [{ severity: 'error', file: '.', path: '', message }], warnings: [] };
89
+ }
90
+ if (!result.ok) {
91
+ this.logger.warn('config reload rejected, keeping active configuration', {
92
+ errors: result.errors.length,
93
+ version: previous.version,
94
+ });
95
+ return result;
96
+ }
97
+ const config = result.config;
98
+ const diff = diffWorkflows(previous, config);
99
+ const resetOverrides = [];
100
+ for (const [id, overrides] of [...this.workflowOverrides]) {
101
+ const next = Object.hasOwn(config.workflows, id) ? config.workflows[id] : undefined;
102
+ const before = previous.workflows[id];
103
+ if (!next || !before) {
104
+ // Workflow removed: all of its overrides disappear.
105
+ this.workflowOverrides.delete(id);
106
+ resetOverrides.push(id);
107
+ continue;
108
+ }
109
+ // Only reset the overrides whose configured value changed (Spec §19 "affected settings").
110
+ const remaining = { ...overrides };
111
+ let reset = false;
112
+ for (const key of OVERRIDE_KEYS) {
113
+ if (key in remaining && before[key] !== next[key]) {
114
+ delete remaining[key];
115
+ reset = true;
116
+ }
117
+ }
118
+ if (!reset)
119
+ continue;
120
+ resetOverrides.push(id);
121
+ if (Object.keys(remaining).length === 0)
122
+ this.workflowOverrides.delete(id);
123
+ else
124
+ this.workflowOverrides.set(id, remaining);
125
+ }
126
+ resetOverrides.sort();
127
+ if (this.globalOverrides.maxConcurrent !== undefined &&
128
+ previous.global.scheduler.maxConcurrent !== config.global.scheduler.maxConcurrent) {
129
+ this.globalOverrides = {};
130
+ resetOverrides.push('*');
131
+ }
132
+ this.active = config;
133
+ this.logger.info('config reloaded', { version: config.version, hash: config.hash, ...diff, resetOverrides });
134
+ this.emit({ kind: 'reload', config, previous, diff, resetOverrides });
135
+ return {
136
+ ok: true,
137
+ config,
138
+ previous,
139
+ changed: config.hash !== previous.hash,
140
+ diff,
141
+ resetOverrides,
142
+ warnings: result.warnings,
143
+ };
144
+ }
145
+ /** Register a change listener. */
146
+ onChange(listener) {
147
+ this.listeners.add(listener);
148
+ return () => {
149
+ this.listeners.delete(listener);
150
+ };
151
+ }
152
+ emit(event) {
153
+ for (const listener of [...this.listeners]) {
154
+ try {
155
+ listener(event);
156
+ }
157
+ catch (err) {
158
+ this.logger.error('config change listener failed', { error: errorMessage(err) });
159
+ }
160
+ }
161
+ }
162
+ requireWorkflow(workflowId) {
163
+ const wf = Object.hasOwn(this.active.workflows, workflowId) ? this.active.workflows[workflowId] : undefined;
164
+ if (!wf)
165
+ throw new UnknownWorkflowError(workflowId);
166
+ return wf;
167
+ }
168
+ /** Workflow with effective values, or `undefined` if unknown. */
169
+ getWorkflow(workflowId) {
170
+ const wf = Object.hasOwn(this.active.workflows, workflowId) ? this.active.workflows[workflowId] : undefined;
171
+ return wf ? this.effective(wf) : undefined;
172
+ }
173
+ /** All workflows with effective values, sorted by ID. */
174
+ listWorkflows() {
175
+ return Object.keys(this.active.workflows)
176
+ .sort()
177
+ .map((id) => this.effective(this.active.workflows[id]));
178
+ }
179
+ effective(config) {
180
+ const overrides = this.workflowOverrides.get(config.id) ?? {};
181
+ return {
182
+ config,
183
+ enabled: overrides.enabled ?? config.enabled,
184
+ priority: overrides.priority ?? config.priority,
185
+ maxConcurrent: overrides.maxConcurrent ?? config.maxConcurrent,
186
+ overrides: { ...overrides },
187
+ };
188
+ }
189
+ /** Effective global limit for automatic starts. */
190
+ get maxConcurrent() {
191
+ return this.globalOverrides.maxConcurrent ?? this.active.global.scheduler.maxConcurrent;
192
+ }
193
+ /** Current overrides (copies). */
194
+ getOverrides() {
195
+ return {
196
+ global: { ...this.globalOverrides },
197
+ workflows: Object.fromEntries([...this.workflowOverrides].map(([id, o]) => [id, { ...o }])),
198
+ };
199
+ }
200
+ /**
201
+ * Merge runtime overrides into the workflow's existing overrides. A key
202
+ * with value `undefined` removes that override.
203
+ * @throws UnknownWorkflowError, ValidationError
204
+ */
205
+ setWorkflowOverrides(workflowId, overrides) {
206
+ const wf = this.requireWorkflow(workflowId);
207
+ validateOverrides(overrides);
208
+ const merged = { ...(this.workflowOverrides.get(workflowId) ?? {}) };
209
+ for (const key of OVERRIDE_KEYS) {
210
+ if (!(key in overrides))
211
+ continue;
212
+ const value = overrides[key];
213
+ if (value === undefined)
214
+ delete merged[key];
215
+ else
216
+ merged[key] = value;
217
+ }
218
+ if (Object.keys(merged).length === 0)
219
+ this.workflowOverrides.delete(workflowId);
220
+ else
221
+ this.workflowOverrides.set(workflowId, merged);
222
+ this.emit({ kind: 'overrides', workflowId });
223
+ return this.effective(wf);
224
+ }
225
+ /** Remove all overrides of a workflow. */
226
+ clearWorkflowOverrides(workflowId) {
227
+ if (this.workflowOverrides.delete(workflowId))
228
+ this.emit({ kind: 'overrides', workflowId });
229
+ }
230
+ /**
231
+ * Override (number) or reset (`undefined`) the global `max_concurrent`.
232
+ * @throws ValidationError
233
+ */
234
+ setGlobalMaxConcurrent(value) {
235
+ if (value === undefined)
236
+ this.globalOverrides = {};
237
+ else {
238
+ validateOverrides({ maxConcurrent: value });
239
+ this.globalOverrides = { maxConcurrent: value };
240
+ }
241
+ this.emit({ kind: 'overrides', workflowId: null });
242
+ }
243
+ /** Snapshot of a workflow of the active configuration (see {@link snapshotWorkflow}). */
244
+ snapshotWorkflow(workflowId) {
245
+ return snapshotWorkflow(this.active, workflowId);
246
+ }
247
+ /**
248
+ * Validate manual-start parameters against the workflow's parameter schema.
249
+ * @throws UnknownWorkflowError
250
+ */
251
+ validateParameters(workflowId, input) {
252
+ return validateWorkflowParameters(this.requireWorkflow(workflowId), input);
253
+ }
254
+ }
255
+ function validateOverrides(o) {
256
+ if (o.enabled !== undefined && typeof o.enabled !== 'boolean') {
257
+ throw new ValidationError('Override "enabled" must be a boolean');
258
+ }
259
+ if (o.priority !== undefined && (typeof o.priority !== 'number' || !Number.isFinite(o.priority))) {
260
+ throw new ValidationError('Override "priority" must be a finite number');
261
+ }
262
+ if (o.maxConcurrent !== undefined && (!Number.isSafeInteger(o.maxConcurrent) || o.maxConcurrent < 1)) {
263
+ throw new ValidationError('Override "maxConcurrent" must be an integer ≥ 1');
264
+ }
265
+ }
266
+ /** Compare the workflows of two configurations by their hashes. */
267
+ export function diffWorkflows(previous, next) {
268
+ const before = previous.workflowHashes;
269
+ const after = next.workflowHashes;
270
+ return {
271
+ addedWorkflows: Object.keys(after).filter((id) => !(id in before)).sort(),
272
+ removedWorkflows: Object.keys(before).filter((id) => !(id in after)).sort(),
273
+ changedWorkflows: Object.keys(after).filter((id) => id in before && before[id] !== after[id]).sort(),
274
+ };
275
+ }
276
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/config/manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,334 @@
1
+ /**
2
+ * Normalized, validated configuration model (Spec §5, §17, §18).
3
+ *
4
+ * Produced by the loader from the YAML files: identifiers are camelCase,
5
+ * all durations are milliseconds, sizes are bytes, defaults are applied and
6
+ * `null` marks "not configured". Instances handed out by the loader are
7
+ * deeply frozen. No secret values are ever part of this model — identities
8
+ * and notification headers only carry the *names* of environment variables.
9
+ */
10
+ import type { FilterNode, HookName, NotificationEventType } from '../core/index.js';
11
+ /** HTTP server bind address. */
12
+ export interface ServerConfig {
13
+ host: string;
14
+ port: number;
15
+ /**
16
+ * Extra accepted `Host`/`Origin` host names (lower case, `name` = any port, `name:port` = exact).
17
+ * Loopback names are always accepted when bound to loopback (DNS-rebinding protection).
18
+ */
19
+ allowedHosts: readonly string[];
20
+ }
21
+ /** Scheduler settings. */
22
+ export interface SchedulerConfig {
23
+ /** Source polling interval (default 30s). */
24
+ pollingIntervalMs: number;
25
+ /** Global limit for automatically started runs (default 5). */
26
+ maxConcurrent: number;
27
+ }
28
+ /** Workspace cleanup policy after a run finished. */
29
+ export type WorkspaceCleanup = 'always' | 'on_success' | 'never';
30
+ /** Workspace settings. */
31
+ export interface WorkspaceConfig {
32
+ /** Absolute, normalized base directory (default `${dataDir}/workspaces`). */
33
+ baseDir: string;
34
+ cleanup: WorkspaceCleanup;
35
+ }
36
+ /** Retry policy of a lifecycle action. */
37
+ export interface RetryPolicy {
38
+ /** Total number of attempts (≥ 1). */
39
+ maxAttempts: number;
40
+ /** Pause between attempts. */
41
+ delayMs: number;
42
+ }
43
+ /** Lifecycle defaults. */
44
+ export interface LifecycleConfig {
45
+ /** Default retry policy of every action (default 3 × 30s). */
46
+ actionRetry: RetryPolicy;
47
+ }
48
+ /** Retention settings; `null` = `never` (keep forever). */
49
+ export interface RetentionConfig {
50
+ completedRunsMs: number | null;
51
+ failedRunsMs: number | null;
52
+ blockedRunsMs: number | null;
53
+ maxLogSizePerRunBytes: number;
54
+ cleanupIntervalMs: number;
55
+ }
56
+ /**
57
+ * Webhook notification channel (Spec §18). Exactly one of `url` / `urlEnv`
58
+ * is set. `url` may embed a token (e.g. Slack webhook URLs) and must be
59
+ * redacted before it is logged or returned by the API ({@link toPublicConfig}).
60
+ */
61
+ export interface WebhookChannelConfig {
62
+ id: string;
63
+ type: 'webhook';
64
+ url: string | null;
65
+ /** Name of the environment variable holding the URL. */
66
+ urlEnv: string | null;
67
+ /** HTTP header name → name of the environment variable holding its value. */
68
+ headersEnv: Readonly<Record<string, string>>;
69
+ /** Events delivered to this channel (default: the global `notifications.on`). */
70
+ on: readonly NotificationEventType[];
71
+ }
72
+ /** A notification channel. */
73
+ export type NotificationChannelConfig = WebhookChannelConfig;
74
+ /** Central orchestrator notifications. */
75
+ export interface NotificationsConfig {
76
+ /** Enabled events (default: all {@link NOTIFICATION_EVENT_TYPES}). */
77
+ on: readonly NotificationEventType[];
78
+ channels: readonly NotificationChannelConfig[];
79
+ }
80
+ /** Content of `config.yaml`. */
81
+ export interface GlobalConfig {
82
+ server: ServerConfig;
83
+ scheduler: SchedulerConfig;
84
+ workspace: WorkspaceConfig;
85
+ lifecycle: LifecycleConfig;
86
+ retention: RetentionConfig;
87
+ notifications: NotificationsConfig;
88
+ }
89
+ /** GitHub repository source. */
90
+ export interface GithubSourceConfig {
91
+ id: string;
92
+ type: 'github';
93
+ owner: string;
94
+ repository: string;
95
+ /** Default identity for reading API calls. */
96
+ identity: string;
97
+ }
98
+ /** A configured source (V1: only GitHub). */
99
+ export type SourceConfig = GithubSourceConfig;
100
+ /** GitHub App identity. The private key is read from `privateKeyEnv` at runtime. */
101
+ export interface GithubAppIdentityConfig {
102
+ id: string;
103
+ type: 'github_app';
104
+ appId: number;
105
+ installationId: number;
106
+ /** Name of the environment variable holding the PEM private key (never the key itself). */
107
+ privateKeyEnv: string;
108
+ }
109
+ /** A configured identity (V1: only GitHub Apps). */
110
+ export type IdentityConfig = GithubAppIdentityConfig;
111
+ /** Source trigger: polls one source. */
112
+ export interface SourceTriggerConfig {
113
+ type: 'source';
114
+ source: string;
115
+ }
116
+ /** Cron trigger. */
117
+ export interface ScheduleTriggerConfig {
118
+ type: 'schedule';
119
+ cron: string;
120
+ /** IANA time zone (default `UTC`). */
121
+ timezone: string;
122
+ }
123
+ /** Only manually started. */
124
+ export interface ManualTriggerConfig {
125
+ type: 'manual';
126
+ }
127
+ /** Workflow trigger. */
128
+ export type TriggerConfig = SourceTriggerConfig | ScheduleTriggerConfig | ManualTriggerConfig;
129
+ /** Shell condition (Spec §6): exit 0 = pass, 1 = fail, ≥ 2 = check error. */
130
+ export interface ShellCheckConfig {
131
+ type: 'shell';
132
+ command: string;
133
+ args: readonly string[];
134
+ /** Default 30s. */
135
+ timeoutMs: number;
136
+ /** Result cache TTL; `null` = no caching. */
137
+ cacheMs: number | null;
138
+ }
139
+ /** Item-level shell filter (workflows only, never views). */
140
+ export interface ShellFilterConfig {
141
+ command: string;
142
+ /** Default 30s. */
143
+ timeoutMs: number;
144
+ }
145
+ /** One item priority rule; the first matching rule wins (Spec §7). */
146
+ export interface ItemPriorityRule {
147
+ when: FilterNode;
148
+ value: number;
149
+ }
150
+ /** Item priority configuration. */
151
+ export interface ItemPriorityConfig {
152
+ rules: readonly ItemPriorityRule[];
153
+ default: number;
154
+ }
155
+ /** Shared properties of manual-start parameters. */
156
+ interface ParameterBase {
157
+ required: boolean;
158
+ description: string | null;
159
+ }
160
+ /** String parameter. */
161
+ export interface StringParameter extends ParameterBase {
162
+ type: 'string';
163
+ default: string | null;
164
+ }
165
+ /** Number parameter. */
166
+ export interface NumberParameter extends ParameterBase {
167
+ type: 'number';
168
+ default: number | null;
169
+ }
170
+ /** Boolean parameter. */
171
+ export interface BooleanParameter extends ParameterBase {
172
+ type: 'boolean';
173
+ default: boolean | null;
174
+ }
175
+ /** Enum parameter. */
176
+ export interface EnumParameter extends ParameterBase {
177
+ type: 'enum';
178
+ values: readonly string[];
179
+ default: string | null;
180
+ }
181
+ /** Declared manual-start parameter (Spec §5.5). */
182
+ export type ParameterDefinition = StringParameter | NumberParameter | BooleanParameter | EnumParameter;
183
+ /** Value of a parameter after validation. */
184
+ export type ParameterValue = string | number | boolean;
185
+ /** Reference to an identity whose short-lived token is exposed as env variable. */
186
+ export interface SecretRef {
187
+ identity: string;
188
+ }
189
+ /** Main worker execution (Spec §5.4, §8.3, §9). */
190
+ export interface ShellExecuteConfig {
191
+ type: 'shell';
192
+ command: string;
193
+ /** Argument templates (text mode). */
194
+ args: readonly string[];
195
+ /** Path template (default `{workspace.base_dir}/{workflow.id}/{run.id}`). */
196
+ workingDirectory: string;
197
+ /** Default true. */
198
+ createDirectory: boolean;
199
+ /** Env variable → value template (text mode). */
200
+ env: Readonly<Record<string, string>>;
201
+ /** Env variable → identity whose token is injected (only in memory). */
202
+ secrets: Readonly<Record<string, SecretRef>>;
203
+ timeout: {
204
+ maxDurationMs: number | null;
205
+ idleTimeoutMs: number | null;
206
+ };
207
+ /** Grace period between SIGTERM and SIGKILL on cancel/timeout (default 30s). */
208
+ cancelGraceMs: number;
209
+ }
210
+ /** Execution configuration (V1: shell only). */
211
+ export type ExecuteConfig = ShellExecuteConfig;
212
+ /** Shared properties of lifecycle actions. */
213
+ interface ActionBase {
214
+ /**
215
+ * Stable action ID within the hook: the configured `id` or `<hook>.<index>`
216
+ * (e.g. `on_start.0`). Used for the action journal and comment markers.
217
+ */
218
+ id: string;
219
+ continueOnError: boolean;
220
+ /** Effective retry policy (action override merged over `lifecycle.action_retry`). */
221
+ retry: RetryPolicy;
222
+ }
223
+ /** `source.update` action (V1: labels). */
224
+ export interface SourceUpdateActionConfig extends ActionBase {
225
+ type: 'source.update';
226
+ labels: {
227
+ add: readonly string[];
228
+ remove: readonly string[];
229
+ };
230
+ }
231
+ /**
232
+ * `source.comment` action. `identity` = action override; callers fall back
233
+ * to the workflow identity, then the source identity.
234
+ */
235
+ export interface SourceCommentActionConfig extends ActionBase {
236
+ type: 'source.comment';
237
+ /** Text template. */
238
+ message: string;
239
+ identity: string | null;
240
+ }
241
+ /** `shell` action. */
242
+ export interface ShellActionConfig extends ActionBase {
243
+ type: 'shell';
244
+ command: string;
245
+ args: readonly string[];
246
+ /** Default 5m. */
247
+ timeoutMs: number;
248
+ env: Readonly<Record<string, string>>;
249
+ }
250
+ /** A lifecycle action. */
251
+ export type LifecycleActionConfig = SourceUpdateActionConfig | SourceCommentActionConfig | ShellActionConfig;
252
+ /** All seven hooks; missing hooks are empty lists. */
253
+ export type HooksConfig = Readonly<Record<HookName, readonly LifecycleActionConfig[]>>;
254
+ /** A validated workflow. */
255
+ export interface WorkflowConfig {
256
+ id: string;
257
+ name: string;
258
+ /** Path of the defining file, relative to the config dir (e.g. `workflows/coder.yaml`). */
259
+ file: string;
260
+ enabled: boolean;
261
+ priority: number;
262
+ /** Per-workflow limit for automatic starts (default 1). */
263
+ maxConcurrent: number;
264
+ /** Default write identity of the workflow; `null` = source identity. */
265
+ identity: string | null;
266
+ trigger: TriggerConfig;
267
+ /** Declarative filter (source workflows only). */
268
+ filter: FilterNode | null;
269
+ shellFilter: ShellFilterConfig | null;
270
+ itemPriority: ItemPriorityConfig | null;
271
+ conditions: {
272
+ workflow: readonly ShellCheckConfig[];
273
+ item: readonly ShellCheckConfig[];
274
+ };
275
+ parameters: Readonly<Record<string, ParameterDefinition>>;
276
+ execute: ExecuteConfig;
277
+ retry: {
278
+ maxTechnicalFailures: number;
279
+ };
280
+ hooks: HooksConfig;
281
+ }
282
+ /** One view column. */
283
+ export interface ViewFieldConfig {
284
+ field: string;
285
+ /** Column label (default: field name). */
286
+ label: string;
287
+ /** Field holding the URL this column links to. */
288
+ link: string | null;
289
+ }
290
+ /** A read-only view. */
291
+ export interface ViewConfig {
292
+ id: string;
293
+ title: string;
294
+ file: string;
295
+ sources: readonly string[];
296
+ filter: FilterNode | null;
297
+ fields: readonly ViewFieldConfig[];
298
+ sort: {
299
+ field: string;
300
+ direction: 'asc' | 'desc';
301
+ } | null;
302
+ }
303
+ /** Complete, validated, immutable configuration. */
304
+ export interface LoadedConfig {
305
+ /** Absolute config directory it was loaded from. */
306
+ configDir: string;
307
+ /** Monotonic version assigned by the loader caller (ConfigManager: 1, 2, ...). */
308
+ version: number;
309
+ /** SHA-256 (hex) over the canonical normalized content. Equal content → equal hash. */
310
+ hash: string;
311
+ /** ISO-8601 load time. */
312
+ loadedAt: string;
313
+ global: GlobalConfig;
314
+ sources: Readonly<Record<string, SourceConfig>>;
315
+ identities: Readonly<Record<string, IdentityConfig>>;
316
+ workflows: Readonly<Record<string, WorkflowConfig>>;
317
+ views: Readonly<Record<string, ViewConfig>>;
318
+ /** SHA-256 per workflow definition (detects changed workflows on reload). */
319
+ workflowHashes: Readonly<Record<string, string>>;
320
+ }
321
+ /** Severity of a {@link ConfigIssue}. */
322
+ export type ConfigIssueSeverity = 'error' | 'warning';
323
+ /** A problem found while loading/validating. Never contains secret values. */
324
+ export interface ConfigIssue {
325
+ severity: ConfigIssueSeverity;
326
+ /** File relative to the config dir (`config.yaml`, `workflows/coder.yaml`, ...). */
327
+ file: string;
328
+ /** Dotted path inside the file, e.g. `execute.timeout.max_duration`, `on_start[1].message`; empty = whole file. */
329
+ path: string;
330
+ message: string;
331
+ /** 1-based line in the file, if known. */
332
+ line?: number;
333
+ }
334
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/config/model.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import type { GlobalConfig, IdentityConfig, SourceConfig, ViewConfig, WorkflowConfig } from './model.js';
2
+ import type { RawGlobalConfig, RawIdentitiesFile, RawSourcesFile, RawView, RawWorkflow } from './schemas.js';
3
+ /** Resolve a configured directory: absolute stays, relative is taken relative to the config dir. */
4
+ export declare function resolveConfigPath(configDir: string, value: string): string;
5
+ /**
6
+ * Resolve a configured command: absolute paths are normalized, relative paths
7
+ * containing `/` (e.g. `scripts/coder.sh`, `./x.sh`) are resolved against the
8
+ * config dir, bare names (e.g. `bash`) stay untouched for PATH lookup.
9
+ */
10
+ export declare function resolveCommand(configDir: string, command: string): string;
11
+ /** Normalize `config.yaml`. */
12
+ export declare function normalizeGlobal(raw: RawGlobalConfig, configDir: string, dataDir: string): GlobalConfig;
13
+ /** Normalize `sources.yaml`. */
14
+ export declare function normalizeSources(raw: RawSourcesFile): Record<string, SourceConfig>;
15
+ /** Normalize `identities.yaml`. */
16
+ export declare function normalizeIdentities(raw: RawIdentitiesFile): Record<string, IdentityConfig>;
17
+ /** Normalize one workflow file. */
18
+ export declare function normalizeWorkflow(raw: RawWorkflow, file: string, global: GlobalConfig, configDir: string): WorkflowConfig;
19
+ /** Normalize one view file. */
20
+ export declare function normalizeView(raw: RawView, file: string): ViewConfig;