@treeseed/sdk 0.11.0 → 0.12.5

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 (473) hide show
  1. package/README.md +9 -4
  2. package/dist/agent-capacity.d.ts +916 -0
  3. package/dist/agent-capacity.js +1600 -0
  4. package/dist/agent-tools.d.ts +37 -0
  5. package/dist/agent-tools.js +301 -0
  6. package/dist/api/app.d.ts +1 -1
  7. package/dist/api/auth/d1-database.d.ts +2 -2
  8. package/dist/api/auth/d1-provider.d.ts +4 -4
  9. package/dist/api/auth/d1-store.d.ts +2 -2
  10. package/dist/api/auth/memory-provider.d.ts +1 -1
  11. package/dist/api/auth/tokens.d.ts +1 -1
  12. package/dist/api/config.d.ts +3 -1
  13. package/dist/api/config.js +34 -10
  14. package/dist/api/http.d.ts +2 -2
  15. package/dist/api/index.d.ts +10 -10
  16. package/dist/api/index.js +4 -2
  17. package/dist/api/operations-routes.d.ts +3 -3
  18. package/dist/api/operations.d.ts +1 -1
  19. package/dist/api/providers.d.ts +1 -1
  20. package/dist/api/providers.js +21 -4
  21. package/dist/api/railway.d.ts +3 -2
  22. package/dist/api/sdk-dispatch.d.ts +4 -4
  23. package/dist/api/sdk-routes.d.ts +2 -2
  24. package/dist/api/templates.d.ts +2 -2
  25. package/dist/api/types.d.ts +3 -2
  26. package/dist/capacity-provider.d.ts +117 -60
  27. package/dist/capacity-provider.js +215 -43
  28. package/dist/capacity.d.ts +2 -2
  29. package/dist/cli-tools.d.ts +1 -1
  30. package/dist/content-operations.d.ts +97 -0
  31. package/dist/content-operations.js +250 -0
  32. package/dist/content-store.d.ts +4 -4
  33. package/dist/control-plane-client.d.ts +13 -18
  34. package/dist/control-plane-client.js +8 -86
  35. package/dist/control-plane.d.ts +2 -2
  36. package/dist/copilot.d.ts +3 -0
  37. package/dist/copilot.js +16 -1
  38. package/dist/d1-http.d.ts +1 -1
  39. package/dist/d1-store.d.ts +32 -57
  40. package/dist/d1-store.js +115 -318
  41. package/dist/db/d1.d.ts +1 -232
  42. package/dist/db/index.d.ts +3 -3
  43. package/dist/db/market-schema.d.ts +49037 -11843
  44. package/dist/db/market-schema.js +1788 -50
  45. package/dist/db/node-sqlite.d.ts +1 -232
  46. package/dist/db/schema.d.ts +0 -462
  47. package/dist/db/schema.js +2 -22
  48. package/dist/dispatch.d.ts +1 -1
  49. package/dist/dispatch.js +0 -11
  50. package/dist/fixture-support.js +52 -4
  51. package/dist/governance.d.ts +133 -0
  52. package/dist/governance.js +285 -0
  53. package/dist/graph/build.d.ts +2 -2
  54. package/dist/graph/context-query-contracts.d.ts +1 -1
  55. package/dist/graph/dsl.d.ts +1 -1
  56. package/dist/graph/query.d.ts +4 -4
  57. package/dist/graph/ranking.d.ts +1 -1
  58. package/dist/graph/schema.d.ts +1 -1
  59. package/dist/graph.d.ts +11 -11
  60. package/dist/guarantees/index.d.ts +425 -0
  61. package/dist/guarantees/index.js +1146 -0
  62. package/dist/hosting/apps.d.ts +1 -1
  63. package/dist/hosting/builtins.d.ts +1 -1
  64. package/dist/hosting/builtins.js +9 -198
  65. package/dist/hosting/contracts.d.ts +3 -2
  66. package/dist/hosting/graph.d.ts +24 -21
  67. package/dist/hosting/graph.js +280 -294
  68. package/dist/hosting/index.d.ts +4 -4
  69. package/dist/index.d.ts +88 -74
  70. package/dist/index.js +81 -10
  71. package/dist/local-dev/managed-dev.d.ts +85 -0
  72. package/dist/local-dev/managed-dev.js +368 -0
  73. package/dist/managed-dependencies.d.ts +9 -0
  74. package/dist/managed-dependencies.js +10 -8
  75. package/dist/market-client.d.ts +265 -7
  76. package/dist/market-client.js +381 -9
  77. package/dist/model-registry.d.ts +1 -1
  78. package/dist/model-registry.js +19 -19
  79. package/dist/operations/agent-tools.d.ts +2 -11
  80. package/dist/operations/agent-tools.js +2 -14
  81. package/dist/operations/providers/default.d.ts +1 -1
  82. package/dist/operations/providers/default.js +20 -37
  83. package/dist/operations/repository-operations.d.ts +26 -2
  84. package/dist/operations/repository-operations.js +159 -1
  85. package/dist/operations/runtime.d.ts +3 -3
  86. package/dist/operations/services/bootstrap-runner.d.ts +1 -1
  87. package/dist/operations/services/build-warning-policy.d.ts +34 -0
  88. package/dist/operations/services/build-warning-policy.js +81 -82
  89. package/dist/operations/services/commit-message-provider.js +4 -4
  90. package/dist/operations/services/config-runtime.d.ts +73 -19
  91. package/dist/operations/services/config-runtime.js +276 -100
  92. package/dist/operations/services/deploy.d.ts +41 -622
  93. package/dist/operations/services/deploy.js +181 -213
  94. package/dist/operations/services/deployment-readiness.d.ts +1 -1
  95. package/dist/operations/services/deployment-readiness.js +38 -7
  96. package/dist/operations/services/git-remote-policy.js +12 -4
  97. package/dist/operations/services/git-runner.d.ts +66 -0
  98. package/dist/operations/services/git-runner.js +479 -0
  99. package/dist/operations/services/git-workflow.d.ts +43 -5
  100. package/dist/operations/services/git-workflow.js +242 -20
  101. package/dist/operations/services/github-actions-verification.d.ts +3 -1
  102. package/dist/operations/services/github-actions-verification.js +11 -3
  103. package/dist/operations/services/github-api.js +21 -5
  104. package/dist/operations/services/github-automation.d.ts +3 -3
  105. package/dist/operations/services/github-automation.js +15 -18
  106. package/dist/operations/services/github-credentials.js +2 -1
  107. package/dist/operations/services/hosted-service-checks.d.ts +19 -1
  108. package/dist/operations/services/hosted-service-checks.js +162 -11
  109. package/dist/operations/services/hosting-audit.d.ts +2 -2
  110. package/dist/operations/services/hosting-audit.js +7 -7
  111. package/dist/operations/services/hub-launch.d.ts +1 -1
  112. package/dist/operations/services/hub-provider-launch.d.ts +5 -5
  113. package/dist/operations/services/hub-provider-launch.js +19 -14
  114. package/dist/operations/services/live-hosted-service-checks.d.ts +2 -1
  115. package/dist/operations/services/live-hosted-service-checks.js +193 -80
  116. package/dist/operations/services/local-dev.js +0 -1
  117. package/dist/operations/services/managed-host-security.d.ts +1 -1
  118. package/dist/operations/services/managed-repositories.d.ts +37 -0
  119. package/dist/operations/services/managed-repositories.js +177 -0
  120. package/dist/operations/services/operations-runner-smoke.d.ts +3 -2
  121. package/dist/operations/services/operations-runner-smoke.js +22 -4
  122. package/dist/operations/services/package-adapters.d.ts +77 -2
  123. package/dist/operations/services/package-adapters.js +629 -56
  124. package/dist/operations/services/package-reference-policy.d.ts +12 -88
  125. package/dist/operations/services/package-reference-policy.js +81 -213
  126. package/dist/operations/services/project-host-operations.d.ts +4 -4
  127. package/dist/operations/services/project-platform.d.ts +19 -193
  128. package/dist/operations/services/project-platform.js +31 -103
  129. package/dist/operations/services/project-web-monitor.d.ts +2 -2
  130. package/dist/operations/services/project-web-monitor.js +97 -2
  131. package/dist/operations/services/railway-api.d.ts +36 -7
  132. package/dist/operations/services/railway-api.js +331 -100
  133. package/dist/operations/services/railway-deploy.d.ts +7 -95
  134. package/dist/operations/services/railway-deploy.js +334 -742
  135. package/dist/operations/services/release-history.js +3 -4
  136. package/dist/operations/services/release-proof-ledger.d.ts +13 -0
  137. package/dist/operations/services/release-proof-ledger.js +81 -0
  138. package/dist/operations/services/release-proof-planner.d.ts +48 -0
  139. package/dist/operations/services/release-proof-planner.js +195 -0
  140. package/dist/operations/services/release-proof-runner.d.ts +16 -0
  141. package/dist/operations/services/release-proof-runner.js +169 -0
  142. package/dist/operations/services/release-proof.d.ts +81 -0
  143. package/dist/operations/services/release-proof.js +79 -0
  144. package/dist/operations/services/repository-save-orchestrator.d.ts +6 -7
  145. package/dist/operations/services/repository-save-orchestrator.js +353 -174
  146. package/dist/operations/services/runtime-paths.d.ts +1 -3
  147. package/dist/operations/services/runtime-paths.js +0 -4
  148. package/dist/operations/services/runtime-tools.d.ts +1 -192
  149. package/dist/operations/services/runtime-tools.js +4 -444
  150. package/dist/operations/services/save-deploy-preflight.js +9 -1
  151. package/dist/operations/services/template-host-bindings.d.ts +2 -2
  152. package/dist/operations/services/template-host-bindings.js +3 -2
  153. package/dist/operations/services/template-registry.d.ts +6 -6
  154. package/dist/operations/services/template-registry.js +33 -14
  155. package/dist/operations/services/template-secret-sync.d.ts +3 -3
  156. package/dist/operations/services/workflow-timing.d.ts +25 -0
  157. package/dist/operations/services/workflow-timing.js +79 -0
  158. package/dist/operations/services/workspace-dependency-mode.js +41 -4
  159. package/dist/operations/services/workspace-preflight.js +8 -8
  160. package/dist/operations/services/workspace-save-script.d.ts +4 -4
  161. package/dist/operations/services/workspace-save.d.ts +1 -0
  162. package/dist/operations/services/workspace-save.js +41 -18
  163. package/dist/operations/services/workspace-tools.js +40 -6
  164. package/dist/operations-registry.d.ts +1 -1
  165. package/dist/operations-registry.js +5 -6
  166. package/dist/operations-types.d.ts +1 -1
  167. package/dist/operations.d.ts +17 -11
  168. package/dist/operations.js +57 -3
  169. package/dist/platform/book-export.js +2 -0
  170. package/dist/platform/books-data.d.ts +1 -1
  171. package/dist/platform/config.d.ts +27 -0
  172. package/dist/platform/config.js +100 -0
  173. package/dist/platform/content-runtime-source.d.ts +54 -0
  174. package/dist/platform/content-runtime-source.js +169 -0
  175. package/dist/platform/contracts.d.ts +6 -1
  176. package/dist/platform/deploy-config.d.ts +1 -1
  177. package/dist/platform/deploy-config.js +7 -1
  178. package/dist/platform/deploy-runtime.d.ts +1 -1
  179. package/dist/platform/desired-state.d.ts +66 -0
  180. package/dist/platform/desired-state.js +1052 -0
  181. package/dist/platform/env.yaml +414 -19
  182. package/dist/platform/environment.d.ts +2 -2
  183. package/dist/platform/environment.js +54 -22
  184. package/dist/platform/local-content-materialization.d.ts +9 -0
  185. package/dist/platform/local-content-materialization.js +212 -0
  186. package/dist/platform/plugin.d.ts +5 -5
  187. package/dist/platform/plugins/runtime.d.ts +3 -3
  188. package/dist/platform/plugins/runtime.js +62 -1
  189. package/dist/platform/plugins.d.ts +6 -6
  190. package/dist/platform/published-content-pipeline.d.ts +3 -3
  191. package/dist/platform/published-content-pipeline.js +5 -1
  192. package/dist/platform/published-content.d.ts +4 -3
  193. package/dist/platform/site-config-schema.d.ts +1 -0
  194. package/dist/platform/site-config-schema.js +4 -1
  195. package/dist/platform/tenant/runtime-config.d.ts +152 -2
  196. package/dist/platform/tenant-config.d.ts +1 -1
  197. package/dist/platform/utils/site-config-schema.d.ts +154 -0
  198. package/dist/platform/utils/site-config-schema.js +400 -461
  199. package/dist/platform-operation-store.d.ts +1 -1
  200. package/dist/plugin-default.d.ts +1 -1
  201. package/dist/plugin-default.js +27 -12
  202. package/dist/project-import.d.ts +91 -0
  203. package/dist/project-import.js +257 -0
  204. package/dist/project-workflow.d.ts +1 -1
  205. package/dist/reconcile/bootstrap-systems.d.ts +2 -2
  206. package/dist/reconcile/bootstrap-systems.js +3 -3
  207. package/dist/reconcile/builtin-adapters.d.ts +7 -1
  208. package/dist/reconcile/builtin-adapters.js +2924 -346
  209. package/dist/reconcile/contracts.d.ts +15 -2
  210. package/dist/reconcile/desired-state.d.ts +2 -193
  211. package/dist/reconcile/desired-state.js +24 -33
  212. package/dist/reconcile/engine.d.ts +60 -397
  213. package/dist/reconcile/engine.js +182 -18
  214. package/dist/reconcile/index.d.ts +10 -10
  215. package/dist/reconcile/live-acceptance.d.ts +22 -1
  216. package/dist/reconcile/live-acceptance.js +456 -44
  217. package/dist/reconcile/providers/docker-private.d.ts +54 -0
  218. package/dist/reconcile/providers/docker-private.js +101 -0
  219. package/dist/reconcile/providers/github-private.d.ts +65 -0
  220. package/dist/reconcile/providers/github-private.js +119 -0
  221. package/dist/reconcile/providers/local-private.d.ts +28 -0
  222. package/dist/reconcile/providers/local-private.js +75 -0
  223. package/dist/reconcile/providers/railway-iac.d.ts +66 -0
  224. package/dist/reconcile/providers/railway-iac.js +275 -0
  225. package/dist/reconcile/providers/release-private.d.ts +92 -0
  226. package/dist/reconcile/providers/release-private.js +152 -0
  227. package/dist/reconcile/registry.d.ts +2 -2
  228. package/dist/reconcile/registry.js +16 -1
  229. package/dist/reconcile/state.d.ts +1 -1
  230. package/dist/reconcile/state.js +3 -40
  231. package/dist/reconcile/units.d.ts +1 -1
  232. package/dist/reconcile/units.js +7 -1
  233. package/dist/remote.d.ts +6 -6
  234. package/dist/scenes/artifacts.d.ts +16 -0
  235. package/dist/scenes/artifacts.js +61 -0
  236. package/dist/scenes/auth.d.ts +2 -0
  237. package/dist/scenes/auth.js +28 -0
  238. package/dist/scenes/base-url.d.ts +12 -0
  239. package/dist/scenes/base-url.js +123 -0
  240. package/dist/scenes/builtin-plugins.d.ts +2 -0
  241. package/dist/scenes/builtin-plugins.js +447 -0
  242. package/dist/scenes/checkpoints.d.ts +14 -0
  243. package/dist/scenes/checkpoints.js +33 -0
  244. package/dist/scenes/device-matrix.d.ts +2 -0
  245. package/dist/scenes/device-matrix.js +97 -0
  246. package/dist/scenes/devices.d.ts +11 -0
  247. package/dist/scenes/devices.js +22 -0
  248. package/dist/scenes/diagnostics.d.ts +5 -0
  249. package/dist/scenes/diagnostics.js +22 -0
  250. package/dist/scenes/diagram-providers.d.ts +2 -0
  251. package/dist/scenes/diagram-providers.js +181 -0
  252. package/dist/scenes/diagram-validation.d.ts +22 -0
  253. package/dist/scenes/diagram-validation.js +74 -0
  254. package/dist/scenes/environment.d.ts +2 -0
  255. package/dist/scenes/environment.js +65 -0
  256. package/dist/scenes/evidence-bundle.d.ts +5 -0
  257. package/dist/scenes/evidence-bundle.js +42 -0
  258. package/dist/scenes/evidence-report.d.ts +10 -0
  259. package/dist/scenes/evidence-report.js +73 -0
  260. package/dist/scenes/evidence.d.ts +16 -0
  261. package/dist/scenes/evidence.js +277 -0
  262. package/dist/scenes/index.d.ts +48 -0
  263. package/dist/scenes/index.js +312 -0
  264. package/dist/scenes/inspect.d.ts +9 -0
  265. package/dist/scenes/inspect.js +64 -0
  266. package/dist/scenes/loader.d.ts +3 -0
  267. package/dist/scenes/loader.js +38 -0
  268. package/dist/scenes/logs.d.ts +2 -0
  269. package/dist/scenes/logs.js +47 -0
  270. package/dist/scenes/operations.d.ts +3 -0
  271. package/dist/scenes/operations.js +128 -0
  272. package/dist/scenes/phase0.d.ts +9 -0
  273. package/dist/scenes/phase0.js +637 -0
  274. package/dist/scenes/planner.d.ts +12 -0
  275. package/dist/scenes/planner.js +166 -0
  276. package/dist/scenes/playwright-adapter.d.ts +2 -0
  277. package/dist/scenes/playwright-adapter.js +63 -0
  278. package/dist/scenes/plugins.d.ts +5 -0
  279. package/dist/scenes/plugins.js +115 -0
  280. package/dist/scenes/progress.d.ts +17 -0
  281. package/dist/scenes/progress.js +24 -0
  282. package/dist/scenes/publish-destinations.d.ts +12 -0
  283. package/dist/scenes/publish-destinations.js +99 -0
  284. package/dist/scenes/publish-plan-report.d.ts +10 -0
  285. package/dist/scenes/publish-plan-report.js +70 -0
  286. package/dist/scenes/publish-plan.d.ts +15 -0
  287. package/dist/scenes/publish-plan.js +248 -0
  288. package/dist/scenes/publish-redaction.d.ts +16 -0
  289. package/dist/scenes/publish-redaction.js +148 -0
  290. package/dist/scenes/publish-release-record.d.ts +13 -0
  291. package/dist/scenes/publish-release-record.js +34 -0
  292. package/dist/scenes/publish-report.d.ts +10 -0
  293. package/dist/scenes/publish-report.js +67 -0
  294. package/dist/scenes/publish.d.ts +16 -0
  295. package/dist/scenes/publish.js +298 -0
  296. package/dist/scenes/registry.d.ts +12 -0
  297. package/dist/scenes/registry.js +65 -0
  298. package/dist/scenes/remotion-adapter.d.ts +3 -0
  299. package/dist/scenes/remotion-adapter.js +94 -0
  300. package/dist/scenes/remotion-composition-registry.d.ts +2 -0
  301. package/dist/scenes/remotion-composition-registry.js +12 -0
  302. package/dist/scenes/remotion-compositions.d.ts +15 -0
  303. package/dist/scenes/remotion-compositions.js +464 -0
  304. package/dist/scenes/remotion-diagrams.d.ts +9 -0
  305. package/dist/scenes/remotion-diagrams.js +188 -0
  306. package/dist/scenes/remotion-input.d.ts +13 -0
  307. package/dist/scenes/remotion-input.js +291 -0
  308. package/dist/scenes/remotion-visuals.d.ts +29 -0
  309. package/dist/scenes/remotion-visuals.js +198 -0
  310. package/dist/scenes/render-media-assets.d.ts +9 -0
  311. package/dist/scenes/render-media-assets.js +117 -0
  312. package/dist/scenes/render-report.d.ts +10 -0
  313. package/dist/scenes/render-report.js +27 -0
  314. package/dist/scenes/render.d.ts +2 -0
  315. package/dist/scenes/render.js +218 -0
  316. package/dist/scenes/reporter.d.ts +3 -0
  317. package/dist/scenes/reporter.js +101 -0
  318. package/dist/scenes/resume.d.ts +2 -0
  319. package/dist/scenes/resume.js +79 -0
  320. package/dist/scenes/runner.d.ts +2 -0
  321. package/dist/scenes/runner.js +674 -0
  322. package/dist/scenes/schema.d.ts +6 -0
  323. package/dist/scenes/schema.js +994 -0
  324. package/dist/scenes/seed.d.ts +2 -0
  325. package/dist/scenes/seed.js +83 -0
  326. package/dist/scenes/segments.d.ts +15 -0
  327. package/dist/scenes/segments.js +79 -0
  328. package/dist/scenes/selectors.d.ts +3 -0
  329. package/dist/scenes/selectors.js +21 -0
  330. package/dist/scenes/timeline.d.ts +11 -0
  331. package/dist/scenes/timeline.js +26 -0
  332. package/dist/scenes/timeouts.d.ts +6 -0
  333. package/dist/scenes/timeouts.js +17 -0
  334. package/dist/scenes/training-captions.d.ts +14 -0
  335. package/dist/scenes/training-captions.js +98 -0
  336. package/dist/scenes/training-report.d.ts +10 -0
  337. package/dist/scenes/training-report.js +78 -0
  338. package/dist/scenes/training-transcript.d.ts +24 -0
  339. package/dist/scenes/training-transcript.js +204 -0
  340. package/dist/scenes/training.d.ts +10 -0
  341. package/dist/scenes/training.js +134 -0
  342. package/dist/scenes/types.d.ts +1872 -0
  343. package/dist/scenes/types.js +8 -0
  344. package/dist/scenes/visual-audit-contact-sheets.d.ts +6 -0
  345. package/dist/scenes/visual-audit-contact-sheets.js +119 -0
  346. package/dist/scenes/visual-audit-fixtures.d.ts +25 -0
  347. package/dist/scenes/visual-audit-fixtures.js +210 -0
  348. package/dist/scenes/visual-audit-report.d.ts +11 -0
  349. package/dist/scenes/visual-audit-report.js +85 -0
  350. package/dist/scenes/visual-audit-review.d.ts +23 -0
  351. package/dist/scenes/visual-audit-review.js +829 -0
  352. package/dist/scenes/visual-audit-routes.d.ts +13 -0
  353. package/dist/scenes/visual-audit-routes.js +308 -0
  354. package/dist/scenes/visual-audit.d.ts +3 -0
  355. package/dist/scenes/visual-audit.js +596 -0
  356. package/dist/scripts/build-dist.js +154 -40
  357. package/dist/scripts/check-build-warnings.js +42 -53
  358. package/dist/scripts/cleanup-markdown.js +1 -1
  359. package/dist/scripts/cli-test-fixtures.js +24 -28
  360. package/dist/scripts/migrate-journey-csv-to-guarantees.js +140 -0
  361. package/dist/scripts/package-tools.js +12 -1
  362. package/dist/scripts/prepare.js +3 -7
  363. package/dist/scripts/release-verify.js +2 -5
  364. package/dist/scripts/run-fixture-astro-command.js +1 -1
  365. package/dist/scripts/template-catalog.test.js +68 -82
  366. package/dist/scripts/tenant-dev.js +0 -10
  367. package/dist/scripts/test-cloudflare-local.js +1 -1
  368. package/dist/scripts/test-scaffold.js +0 -1
  369. package/dist/scripts/test-smoke.js +3 -3
  370. package/dist/scripts/treeseed-build-dist.js +4 -7
  371. package/dist/scripts/treeseed-release-verify.js +1 -1
  372. package/dist/scripts/verify-driver.js +30 -21
  373. package/dist/scripts/workflow-commands.test.js +18 -27
  374. package/dist/scripts/workspace-command-e2e.js +1 -1
  375. package/dist/scripts/workspace-lint.js +6 -0
  376. package/dist/scripts/workspace-release-test.js +90 -1
  377. package/dist/scripts/workspace-test.js +6 -0
  378. package/dist/sdk-dispatch.d.ts +1 -1
  379. package/dist/sdk-dispatch.js +0 -16
  380. package/dist/sdk-fields.d.ts +1 -1
  381. package/dist/sdk-filters.d.ts +1 -1
  382. package/dist/sdk-types.d.ts +1184 -113
  383. package/dist/sdk-types.js +393 -0
  384. package/dist/sdk.d.ts +74 -79
  385. package/dist/sdk.js +27 -36
  386. package/dist/secrets-capability.d.ts +421 -0
  387. package/dist/secrets-capability.js +530 -0
  388. package/dist/seeds/normalize.js +1 -0
  389. package/dist/seeds/planner.js +38 -0
  390. package/dist/seeds/schema.js +293 -4
  391. package/dist/seeds/types.d.ts +60 -0
  392. package/dist/seeds/types.js +9 -1
  393. package/dist/service-credentials.d.ts +54 -0
  394. package/dist/service-credentials.js +112 -0
  395. package/dist/stores/cursor-store.d.ts +2 -2
  396. package/dist/stores/envelopes.d.ts +1 -1
  397. package/dist/stores/helpers.d.ts +1 -1
  398. package/dist/stores/lease-store.d.ts +2 -2
  399. package/dist/stores/message-store.d.ts +2 -2
  400. package/dist/stores/operational-store.d.ts +3 -26
  401. package/dist/stores/operational-store.js +0 -225
  402. package/dist/stores/project-workflow-store.d.ts +2 -2
  403. package/dist/stores/run-store.d.ts +2 -3
  404. package/dist/stores/run-store.js +0 -98
  405. package/dist/stores/subscription-store.d.ts +2 -3
  406. package/dist/stores/subscription-store.js +0 -100
  407. package/dist/template-catalog.d.ts +1 -1
  408. package/dist/template-launch-requirements.d.ts +2 -2
  409. package/dist/template-launch-ui.d.ts +2 -2
  410. package/dist/treedx/adapters.d.ts +6 -6
  411. package/dist/treedx/client.d.ts +1 -1
  412. package/dist/treedx/errors.d.ts +1 -1
  413. package/dist/treedx/federated-client.d.ts +3 -3
  414. package/dist/treedx/graph-adapter.d.ts +2 -2
  415. package/dist/treedx/index.d.ts +14 -14
  416. package/dist/treedx/market-integration.d.ts +1 -1
  417. package/dist/treedx/ports.d.ts +30 -30
  418. package/dist/treedx/query-adapter.d.ts +3 -3
  419. package/dist/treedx/registry-client.d.ts +2 -2
  420. package/dist/treedx/repository-adapter.d.ts +4 -4
  421. package/dist/treedx/repository-adapter.js +14 -3
  422. package/dist/treedx/sdk-integration.d.ts +3 -3
  423. package/dist/treedx/types.d.ts +2 -2
  424. package/dist/treedx/workspace-adapter.d.ts +2 -2
  425. package/dist/treedx-backends.d.ts +13 -11
  426. package/dist/treedx-backends.js +52 -50
  427. package/dist/treedx-client.d.ts +3 -0
  428. package/dist/treedx-client.js +10 -1
  429. package/dist/treeseed/services/compose.yml +2 -3
  430. package/dist/treeseed/template-catalog/catalog.fixture.json +4 -4
  431. package/dist/types/agents.d.ts +256 -0
  432. package/dist/types/agents.js +42 -1
  433. package/dist/verification.d.ts +1 -0
  434. package/dist/verification.js +143 -14
  435. package/dist/workflow/operations.d.ts +510 -559
  436. package/dist/workflow/operations.js +1891 -1342
  437. package/dist/workflow/policy.js +19 -7
  438. package/dist/workflow/runs.d.ts +9 -3
  439. package/dist/workflow/runs.js +66 -26
  440. package/dist/workflow/session.d.ts +4 -1
  441. package/dist/workflow/session.js +50 -10
  442. package/dist/workflow/worktrees.d.ts +6 -2
  443. package/dist/workflow/worktrees.js +98 -15
  444. package/dist/workflow-state.d.ts +5 -5
  445. package/dist/workflow-state.js +27 -17
  446. package/dist/workflow-support.d.ts +26 -25
  447. package/dist/workflow-support.js +27 -31
  448. package/dist/workflow.d.ts +46 -16
  449. package/dist/workflow.js +19 -7
  450. package/drizzle/d1/0000_treeseed_d1.sql +0 -18
  451. package/drizzle/market/0000_market_control_plane.sql +1793 -1499
  452. package/drizzle/market/0005_agent_capacity_coordination.sql +145 -0
  453. package/drizzle/market/0006_provider_assignment_lifecycle.sql +9 -0
  454. package/drizzle/market/0007_agent_architecture_gap_closure.sql +157 -0
  455. package/drizzle/market/0008_agent_capacity_operational_closure.sql +27 -0
  456. package/drizzle/market/0009_agent_capacity_runtime_hardening.sql +29 -0
  457. package/drizzle/market/0010_secrets_capability_persistence.sql +130 -0
  458. package/drizzle/market/0011_github_app_adapter.sql +47 -0
  459. package/drizzle/market/0012_workday_test_runs.sql +44 -0
  460. package/drizzle/market/0013_runtime_task_lifecycle.sql +39 -0
  461. package/drizzle/market/0014_governance_pipeline.sql +189 -0
  462. package/package.json +75 -18
  463. package/scripts/{verify-driver.mjs → verify-driver.ts} +19 -4
  464. package/templates/github/deploy-web.workflow.yml +12 -8
  465. package/dist/operations/services/mailpit-runtime.d.ts +0 -20
  466. package/dist/operations/services/mailpit-runtime.js +0 -67
  467. package/dist/operations/services/release-candidate.d.ts +0 -60
  468. package/dist/operations/services/release-candidate.js +0 -953
  469. package/dist/scripts/ensure-mailpit.js +0 -48
  470. package/dist/scripts/logs-mailpit.js +0 -2
  471. package/dist/scripts/run-ts.js +0 -45
  472. package/dist/scripts/stop-mailpit.js +0 -5
  473. package/dist/scripts/treeseed-run-ts.js +0 -45
@@ -1,11 +1,12 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { dirname, relative, resolve } from "node:path";
3
- import { spawnSync } from "node:child_process";
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { relative, resolve } from "node:path";
3
+ import { parse as parseYaml } from "yaml";
4
4
  import { loadCliDeployConfig } from "./runtime-tools.js";
5
+ import { resolveTreeseedMachineEnvironmentValues } from "./config-runtime.js";
5
6
  import { createPersistentDeployTarget, resolveTreeseedResourceIdentity } from "./deploy.js";
7
+ import { classifyTreeseedGitMode, runTreeseedGitText } from "./git-runner.js";
6
8
  import { discoverTreeseedApplications } from "../../hosting/apps.js";
7
9
  import { runPrefixedCommand, sleep } from "./bootstrap-runner.js";
8
- import { resolveTreeseedToolCommand } from "../../managed-dependencies.js";
9
10
  import {
10
11
  ensureRailwayEnvironment,
11
12
  ensureRailwayProject,
@@ -22,7 +23,6 @@ import {
22
23
  railwayGraphqlRequest,
23
24
  resolveRailwayApiToken,
24
25
  resolveRailwayApiUrl,
25
- resolveRailwayWorkspace,
26
26
  resolveRailwayWorkspaceContext,
27
27
  upsertRailwayVariables
28
28
  } from "./railway-api.js";
@@ -33,11 +33,12 @@ function normalizeScope(scope) {
33
33
  function resolveRailwayEnvironmentForScope(scope, configuredEnvironment) {
34
34
  return normalizeRailwayEnvironmentName(configuredEnvironment || normalizeScope(scope));
35
35
  }
36
- const RAILWAY_SERVICE_KEYS = ["api", "operationsRunner"];
36
+ const RAILWAY_SERVICE_KEYS = ["api", "operationsRunner", "capacityProviderManager", "capacityProviderRunner"];
37
37
  const HOSTED_PROJECT_SERVICE_KEYS = ["api"];
38
38
  const WORKER_RUNNER_BOOTSTRAP_INDEX = 1;
39
39
  const WORKER_RUNNER_VOLUME_MOUNT_PATH = "/data";
40
40
  const OPERATIONS_RUNNER_BOOTSTRAP_COUNT = 2;
41
+ const PUBLIC_TREEDX_NODE_SERVICE_KEY_PREFIX = "public-treedx-node-";
41
42
  function isTreeseedOperationsRunnerResourceName(value) {
42
43
  const normalized = String(value ?? "").trim().toLowerCase();
43
44
  if (!normalized) {
@@ -60,7 +61,7 @@ function shouldManageRailwaySchedules(scope, phase = "deploy") {
60
61
  return phase === "deploy" && (environment === "staging" || environment === "production");
61
62
  }
62
63
  function railwayServiceNameSuffix(serviceKey) {
63
- return serviceKey === "workdayManager" ? "workday-manager" : serviceKey === "workerRunner" ? "worker-runner" : serviceKey === "operationsRunner" ? "operations-runner" : serviceKey;
64
+ return serviceKey === "capacityProviderManager" ? "capacity-provider-manager" : serviceKey === "capacityProviderRunner" ? "capacity-provider-runner" : serviceKey === "workdayManager" ? "workday-manager" : serviceKey === "workerRunner" ? "worker-runner" : serviceKey === "operationsRunner" ? "operations-runner" : serviceKey;
64
65
  }
65
66
  function deriveRailwayWorkerRunnerServiceName(projectSlug, index = WORKER_RUNNER_BOOTSTRAP_INDEX) {
66
67
  const normalizedIndex = Math.max(1, Number.parseInt(String(index), 10) || WORKER_RUNNER_BOOTSTRAP_INDEX);
@@ -71,12 +72,49 @@ function deriveRailwayOperationsRunnerServiceName(baseServiceName, index = WORKE
71
72
  const base = String(baseServiceName ?? "").trim().replace(/-\d+$/u, "").replace(/-\d{2}$/u, "") || "treeseed-api-operations-runner";
72
73
  return `${base}-${String(normalizedIndex).padStart(2, "0")}`;
73
74
  }
75
+ function railwayImageRefEnvForService(serviceKey) {
76
+ if (serviceKey === "api") return "TREESEED_API_IMAGE_REF";
77
+ if (serviceKey === "operationsRunner") return "TREESEED_OPERATIONS_RUNNER_IMAGE_REF";
78
+ if (serviceKey === "capacityProviderManager") return "TREESEED_AGENT_MANAGER_IMAGE_REF";
79
+ if (serviceKey === "capacityProviderRunner") return "TREESEED_AGENT_RUNNER_IMAGE_REF";
80
+ if (isPublicTreeDxNodeServiceKey(serviceKey)) return "TREESEED_PUBLIC_TREEDX_IMAGE_REF";
81
+ return null;
82
+ }
83
+ function defaultRailwayImageRef(serviceKey, scope = "staging", env = process.env) {
84
+ if (serviceKey === "api") {
85
+ return envValue("TREESEED_API_IMAGE_REF", env) || null;
86
+ }
87
+ if (serviceKey === "operationsRunner") {
88
+ return envValue("TREESEED_OPERATIONS_RUNNER_IMAGE_REF", env) || null;
89
+ }
90
+ if (serviceKey === "capacityProviderManager") {
91
+ return envValue("TREESEED_AGENT_MANAGER_IMAGE_REF", env) || null;
92
+ }
93
+ if (serviceKey === "capacityProviderRunner") {
94
+ return envValue("TREESEED_AGENT_RUNNER_IMAGE_REF", env) || null;
95
+ }
96
+ if (isPublicTreeDxNodeServiceKey(serviceKey)) {
97
+ return envValue("TREESEED_PUBLIC_TREEDX_IMAGE_REF", env) || null;
98
+ }
99
+ return null;
100
+ }
101
+ function isPublicTreeDxNodeServiceKey(serviceKey) {
102
+ return String(serviceKey ?? "").startsWith(PUBLIC_TREEDX_NODE_SERVICE_KEY_PREFIX);
103
+ }
74
104
  function deriveRailwayWorkerRunnerVolumeName(serviceName, environmentName = "") {
75
105
  return `${serviceName}-volume`;
76
106
  }
77
107
  function deriveRailwayOperationsRunnerVolumeName(serviceName, environmentName = "") {
78
108
  return `${serviceName}-volume`;
79
109
  }
110
+ function deriveRailwayCapacityProviderRunnerServiceName(baseServiceName, index = WORKER_RUNNER_BOOTSTRAP_INDEX) {
111
+ const normalizedIndex = Math.max(1, Number.parseInt(String(index), 10) || WORKER_RUNNER_BOOTSTRAP_INDEX);
112
+ const base = String(baseServiceName ?? "").trim().replace(/-\d+$/u, "").replace(/-\d{2}$/u, "") || "treeseed-capacity-provider-runner";
113
+ return `${base}-${String(normalizedIndex).padStart(2, "0")}`;
114
+ }
115
+ function deriveRailwayCapacityProviderRunnerVolumeName(serviceName, environmentName = "") {
116
+ return `${serviceName}-volume`;
117
+ }
80
118
  function railwayServiceRuntimeStartCommand(service) {
81
119
  return service.startCommand;
82
120
  }
@@ -89,8 +127,8 @@ function normalizeScheduleExpressions(value) {
89
127
  }
90
128
  return [];
91
129
  }
92
- function envValue(name) {
93
- const value = process.env[name];
130
+ function envValue(name, env = process.env) {
131
+ const value = env?.[name];
94
132
  return typeof value === "string" && value.trim() ? value.trim() : "";
95
133
  }
96
134
  function relativeRailwayRootDir(tenantRoot, serviceRoot) {
@@ -271,7 +309,7 @@ function resolveRailwayAuthToken(env = process.env) {
271
309
  function buildRailwayCommandEnv(env = process.env) {
272
310
  const merged = { ...env };
273
311
  const token = resolveRailwayAuthToken(merged);
274
- const projectToken = configuredEnvValue(merged, "RAILWAY_TOKEN");
312
+ const projectToken = configuredEnvValue(merged, "TREESEED_RAILWAY_TOKEN");
275
313
  if (token) {
276
314
  merged.RAILWAY_API_TOKEN = token;
277
315
  } else {
@@ -280,15 +318,6 @@ function buildRailwayCommandEnv(env = process.env) {
280
318
  merged.RAILWAY_TOKEN = projectToken || void 0;
281
319
  return merged;
282
320
  }
283
- function buildRailwayDeployCommandEnv(env = process.env) {
284
- const merged = buildRailwayCommandEnv(env);
285
- if (shouldAttachRailwayDeployLogs(merged)) {
286
- merged.CI = "true";
287
- } else {
288
- merged.CI = void 0;
289
- }
290
- return merged;
291
- }
292
321
  function normalizeRailwaySchedule(schedule) {
293
322
  if (!schedule || typeof schedule !== "object") {
294
323
  return null;
@@ -338,47 +367,6 @@ function collectRailwaySchedules(value, seen = /* @__PURE__ */ new Set()) {
338
367
  visit(value);
339
368
  return matches;
340
369
  }
341
- function normalizeRailwayProjectList(payload) {
342
- try {
343
- const parsed = JSON.parse(payload);
344
- if (!Array.isArray(parsed)) {
345
- return [];
346
- }
347
- return parsed.map((entry) => {
348
- if (!entry || typeof entry !== "object") {
349
- return null;
350
- }
351
- const id = typeof entry.id === "string" ? entry.id.trim() : "";
352
- const name = typeof entry.name === "string" ? entry.name.trim() : "";
353
- if (!id && !name) {
354
- return null;
355
- }
356
- return { id, name };
357
- }).filter(Boolean);
358
- } catch {
359
- return [];
360
- }
361
- }
362
- function railwayMessage(result) {
363
- return `${result?.stderr ?? ""}
364
- ${result?.stdout ?? ""}`.trim();
365
- }
366
- function isRailwayAlreadyExistsMessage(result) {
367
- return /already exists|already taken|duplicate|has already been taken/iu.test(railwayMessage(result));
368
- }
369
- function isRailwayTransientFailure(result) {
370
- const message = railwayMessage(result);
371
- if (!message.trim() && result?.status === 1) {
372
- return true;
373
- }
374
- return /timed out|failed to fetch|error decoding response body|expected value at line 1 column 1|temporarily unavailable|econnreset|etimedout|failed to stream build logs|failed to retrieve build log/iu.test(message);
375
- }
376
- function sleepSync(milliseconds) {
377
- if (!Number.isFinite(milliseconds) || milliseconds <= 0) {
378
- return;
379
- }
380
- Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
381
- }
382
370
  function isRailwayScheduleCapabilityError(error) {
383
371
  const message = error instanceof Error ? error.message : String(error ?? "");
384
372
  return /cronTriggers|cronTriggerCreate|cronTriggerUpdate/iu.test(message);
@@ -451,42 +439,6 @@ mutation TreeseedScheduleUpdate($id: String!, $name: String!, $schedule: String!
451
439
  `.trim()
452
440
  };
453
441
  }
454
- function runRailway(args, { cwd, capture = false, allowFailure = false, input, env, retryTransient = true, retryAttempts = 3, retryDelayMs = 2e3, timeoutMs = 12e4 } = {}) {
455
- const effectiveEnv = buildRailwayCommandEnv({ ...process.env, ...env ?? {} });
456
- const railway = resolveTreeseedToolCommand("railway", { env: effectiveEnv });
457
- if (!railway) {
458
- throw new Error("Railway CLI is unavailable.");
459
- }
460
- const runWithEnv = (spawnEnv) => spawnSync(railway.command, [...railway.argsPrefix, ...args], {
461
- cwd,
462
- stdio: input !== void 0 ? ["pipe", capture ? "pipe" : "inherit", capture ? "pipe" : "inherit"] : capture ? "pipe" : "inherit",
463
- encoding: "utf8",
464
- env: spawnEnv,
465
- input,
466
- timeout: Number.isFinite(timeoutMs) && Number(timeoutMs) > 0 ? Number(timeoutMs) : void 0
467
- });
468
- let result = null;
469
- const maxAttempts = retryTransient && !allowFailure ? Math.max(1, Number(retryAttempts) || 1) : 1;
470
- for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
471
- result = runWithEnv(effectiveEnv);
472
- if (result.status === 0 || allowFailure || !isRailwayTransientFailure(result) || attempt === maxAttempts) {
473
- break;
474
- }
475
- sleepSync((Number(retryDelayMs) || 0) * attempt);
476
- }
477
- if (result?.error) {
478
- const errorMessage = result.error instanceof Error ? result.error.message : String(result.error);
479
- const timeoutMessage = /timed out|ETIMEDOUT/iu.test(errorMessage) ? `railway ${args.join(" ")} timed out after ${Math.round(Number(timeoutMs) / 1e3)}s` : errorMessage;
480
- if (!allowFailure) {
481
- throw new Error(timeoutMessage);
482
- }
483
- result.stderr = result.stderr || timeoutMessage;
484
- }
485
- if (result?.status !== 0 && !allowFailure) {
486
- throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${args.join(" ")} failed`);
487
- }
488
- return result;
489
- }
490
442
  async function waitForRailwayManagedDeploymentsSettled(tenantRoot, scope, {
491
443
  services = configuredRailwayServices(tenantRoot, scope),
492
444
  env = process.env,
@@ -659,263 +611,21 @@ query TreeseedRailwayDeploymentStatus($projectId: String!) {
659
611
  });
660
612
  return payload.data?.project ?? null;
661
613
  }
662
- function setRailwaySecretVariable({ cwd, service, environment, key, value, env = process.env, capture = false, allowFailure = false }) {
663
- const effectiveEnv = buildRailwayCommandEnv({
664
- ...process.env,
665
- ...env ?? {}
666
- });
667
- let result = null;
668
- for (let attempt = 0; attempt < 3; attempt += 1) {
669
- const railway = resolveTreeseedToolCommand("railway", { env: effectiveEnv });
670
- if (!railway) {
671
- throw new Error("Railway CLI is unavailable.");
672
- }
673
- result = spawnSync(railway.command, [
674
- ...railway.argsPrefix,
675
- "variable",
676
- "set",
677
- "--service",
678
- service,
679
- "--environment",
680
- environment,
681
- "--stdin",
682
- "--skip-deploys",
683
- key
684
- ], {
685
- cwd,
686
- stdio: ["pipe", capture ? "pipe" : "inherit", capture ? "pipe" : "inherit"],
687
- encoding: "utf8",
688
- env: effectiveEnv,
689
- input: `${value}
690
- `
691
- });
692
- if (result.status === 0) {
693
- return result;
694
- }
695
- if (!isRailwayTransientFailure(result)) {
696
- break;
697
- }
698
- }
699
- if (result?.status !== 0 && !allowFailure) {
700
- throw new Error(result?.stderr?.trim() || result?.stdout?.trim() || `railway variable set --stdin ${key} failed`);
701
- }
702
- return result;
703
- }
704
- function ensureRailwayProjectExists(service, { env = process.env } = {}) {
705
- const projectName = typeof service?.projectName === "string" ? service.projectName.trim() : "";
706
- const projectId = typeof service?.projectId === "string" ? service.projectId.trim() : "";
707
- const listed = runRailway(["list", "--json"], {
708
- cwd: service.rootDir,
709
- capture: true,
710
- allowFailure: true,
711
- env
712
- });
713
- if (listed.status === 0) {
714
- const match = normalizeRailwayProjectList(listed.stdout ?? "").find((entry) => entry.name === projectName || entry.id === projectName || entry.id === projectId);
715
- if (match) {
716
- return match;
717
- }
718
- }
719
- if (!projectName) {
720
- if (projectId) {
721
- return { id: projectId, name: "" };
722
- }
723
- throw new Error(`Railway service ${service?.key ?? service?.serviceName ?? service?.serviceId ?? "(unknown)"} is missing a projectName.`);
724
- }
725
- const args = ["init", "--name", projectName, "--json"];
726
- const workspace = resolveRailwayWorkspace(env);
727
- if (workspace) {
728
- args.push("--workspace", workspace);
729
- }
730
- const created = runRailway(args, {
731
- cwd: service.rootDir,
732
- capture: true,
733
- allowFailure: true,
734
- env
735
- });
736
- if (created.status !== 0 && !isRailwayAlreadyExistsMessage(created)) {
737
- throw new Error(railwayMessage(created) || `railway ${args.join(" ")} failed`);
738
- }
739
- return null;
740
- }
741
- function ensureRailwayEnvironmentExists(service, { env = process.env } = {}) {
742
- const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
743
- if (!environmentName) {
744
- return null;
745
- }
746
- const linkResult = runRailway(["environment", "link", environmentName, "--json"], {
747
- cwd: service.rootDir,
748
- capture: true,
749
- allowFailure: true,
750
- env
751
- });
752
- if (linkResult.status === 0) {
753
- return linkResult;
754
- }
755
- const createResult = runRailway(["environment", "new", environmentName, "--json"], {
756
- cwd: service.rootDir,
757
- capture: true,
758
- allowFailure: true,
759
- env
760
- });
761
- if (createResult.status !== 0 && !isRailwayAlreadyExistsMessage(createResult)) {
762
- throw new Error(railwayMessage(createResult) || `railway environment new ${environmentName} failed`);
763
- }
764
- const relinkResult = runRailway(["environment", "link", environmentName, "--json"], {
765
- cwd: service.rootDir,
766
- capture: true,
767
- allowFailure: true,
768
- env
769
- });
770
- if (relinkResult.status !== 0) {
771
- throw new Error(railwayMessage(relinkResult) || `railway environment link ${environmentName} failed`);
772
- }
773
- return relinkResult;
774
- }
775
- function ensureRailwayServiceExists(service, { env = process.env } = {}) {
776
- const serviceSelector = typeof (service?.serviceName ?? service?.serviceId) === "string" ? String(service.serviceName ?? service.serviceId).trim() : "";
777
- if (!serviceSelector) {
778
- throw new Error(`Railway service ${service?.key ?? "(unknown)"} is missing a service selector.`);
779
- }
780
- const statusArgs = ["service", "status", "--service", serviceSelector, "--environment", service.railwayEnvironment, "--json"];
781
- const statusResult = runRailway(statusArgs, {
782
- cwd: service.rootDir,
783
- capture: true,
784
- allowFailure: true,
785
- env
786
- });
787
- if (statusResult.status === 0) {
788
- return statusResult;
789
- }
790
- const createResult = runRailway(["add", "--service", serviceSelector, "--json"], {
791
- cwd: service.rootDir,
792
- capture: true,
793
- allowFailure: true,
794
- env
795
- });
796
- if (createResult.status !== 0 && !isRailwayAlreadyExistsMessage(createResult)) {
797
- throw new Error(railwayMessage(createResult) || `railway add --service ${serviceSelector} failed`);
798
- }
799
- const refreshed = runRailway(statusArgs, {
800
- cwd: service.rootDir,
801
- capture: true,
802
- allowFailure: true,
803
- env
804
- });
805
- if (refreshed.status !== 0) {
806
- throw new Error(railwayMessage(refreshed) || `railway service status --service ${serviceSelector} failed`);
807
- }
808
- return refreshed;
809
- }
810
- function ensureRailwayDatabaseServiceExists(service, {
811
- database = "postgres",
812
- env = process.env
813
- } = {}) {
814
- const serviceSelector = typeof (service?.serviceName ?? service?.serviceId) === "string" ? String(service.serviceName ?? service.serviceId).trim() : "";
815
- if (!serviceSelector) {
816
- throw new Error(`Railway database service ${service?.key ?? "(unknown)"} is missing a service selector.`);
817
- }
818
- const projectSelector = typeof service?.projectId === "string" && service.projectId.trim() ? service.projectId.trim() : typeof service?.projectName === "string" && service.projectName.trim() ? service.projectName.trim() : "";
819
- if (!projectSelector) {
820
- throw new Error(`Railway database service ${service?.key ?? serviceSelector} is missing a project selector.`);
821
- }
822
- const linkArgs = ["link", "--project", projectSelector];
823
- const workspace = resolveRailwayWorkspace(env);
824
- if (workspace) {
825
- linkArgs.push("--workspace", workspace);
826
- }
827
- const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
828
- if (environmentName) {
829
- linkArgs.push("--environment", environmentName);
830
- }
831
- const linkResult = runRailway(linkArgs, {
832
- cwd: service.rootDir,
833
- capture: true,
834
- allowFailure: true,
835
- env
836
- });
837
- if ((linkResult.status ?? 1) !== 0) {
838
- throw new Error(railwayMessage(linkResult) || `railway ${linkArgs.join(" ")} failed`);
839
- }
840
- const statusArgs = ["service", "status", "--service", serviceSelector, "--environment", service.railwayEnvironment, "--json"];
841
- const statusResult = runRailway(statusArgs, {
842
- cwd: service.rootDir,
843
- capture: true,
844
- allowFailure: true,
845
- env
846
- });
847
- if (statusResult.status === 0) {
848
- return statusResult;
849
- }
850
- const addResult = runRailway(["add", "--database", database, "--service", serviceSelector, "--json"], {
851
- cwd: service.rootDir,
852
- capture: true,
853
- allowFailure: true,
854
- env
855
- });
856
- if (addResult.status !== 0 && !isRailwayAlreadyExistsMessage(addResult)) {
857
- throw new Error(railwayMessage(addResult) || `railway add --database ${database} --service ${serviceSelector} failed`);
858
- }
859
- const refreshed = runRailway(statusArgs, {
860
- cwd: service.rootDir,
861
- capture: true,
862
- allowFailure: true,
863
- env
864
- });
865
- if (refreshed.status !== 0) {
866
- throw new Error(railwayMessage(refreshed) || `railway service status --service ${serviceSelector} failed`);
867
- }
868
- return refreshed;
869
- }
870
- function ensureRailwayProjectContext(service, { env = process.env, allowFailure = false, capture = false } = {}) {
871
- ensureRailwayProjectExists(service, { env });
872
- let projectSelector = service?.projectId ?? "";
873
- if ((!projectSelector || !String(projectSelector).trim()) && service?.projectName) {
874
- const listed = runRailway(["list", "--json"], {
875
- cwd: service.rootDir,
876
- capture: true,
877
- allowFailure: true,
878
- env
879
- });
880
- if (listed.status === 0) {
881
- const match = normalizeRailwayProjectList(listed.stdout ?? "").find((entry) => entry.name === service.projectName || entry.id === service.projectName);
882
- projectSelector = match?.id || match?.name || service.projectName;
883
- } else {
884
- projectSelector = service.projectName;
885
- }
886
- }
887
- projectSelector = typeof projectSelector === "string" ? projectSelector.trim() : "";
888
- if (typeof projectSelector !== "string" || projectSelector.trim().length === 0) {
889
- throw new Error(`Railway service ${service?.key ?? service?.serviceName ?? service?.serviceId ?? "(unknown)"} is missing a project selector.`);
890
- }
891
- const args = ["link", "--project", projectSelector];
892
- const workspace = resolveRailwayWorkspace(env);
893
- if (workspace) {
894
- args.push("--workspace", workspace);
895
- }
896
- const environmentName = normalizeRailwayEnvironmentName(service?.railwayEnvironment);
897
- if (environmentName) {
898
- args.push("--environment", environmentName);
899
- }
900
- runRailway(args, {
901
- cwd: service.rootDir,
902
- capture,
903
- allowFailure,
904
- env
905
- });
906
- if (environmentName) {
907
- ensureRailwayEnvironmentExists(service, { env });
908
- return runRailway(["environment", "link", environmentName, "--json"], {
909
- cwd: service.rootDir,
910
- capture,
911
- allowFailure,
912
- env
913
- });
914
- }
915
- return null;
916
- }
917
- function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, application = null) {
614
+ function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, application = null, machineConfigRoot = tenantRoot) {
918
615
  const normalizedScope = normalizeScope(scope);
616
+ const imageRefKeys = [
617
+ "TREESEED_API_IMAGE_REF",
618
+ "TREESEED_OPERATIONS_RUNNER_IMAGE_REF",
619
+ "TREESEED_AGENT_MANAGER_IMAGE_REF",
620
+ "TREESEED_AGENT_RUNNER_IMAGE_REF"
621
+ ];
622
+ let machineEnv = {};
623
+ try {
624
+ machineEnv = resolveTreeseedMachineEnvironmentValues(machineConfigRoot, normalizedScope, imageRefKeys);
625
+ } catch {
626
+ machineEnv = {};
627
+ }
628
+ const imageRefEnv = { ...process.env, ...machineEnv };
919
629
  let identity;
920
630
  try {
921
631
  identity = resolveTreeseedResourceIdentity(deployConfig, createPersistentDeployTarget(normalizedScope));
@@ -929,13 +639,14 @@ function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, app
929
639
  }
930
640
  const configuredOptionalServiceKeys = Object.keys(deployConfig.services ?? {}).filter((serviceKey) => RAILWAY_SERVICE_KEYS.includes(serviceKey));
931
641
  const serviceKeys = hostingKind === "hosted_project" ? [.../* @__PURE__ */ new Set([...HOSTED_PROJECT_SERVICE_KEYS, ...configuredOptionalServiceKeys])] : RAILWAY_SERVICE_KEYS;
932
- return serviceKeys.flatMap((serviceKey) => {
642
+ const configuredServices = serviceKeys.flatMap((serviceKey) => {
933
643
  const service = deployConfig.services?.[serviceKey];
934
644
  if (!service || service.enabled === false || (service.provider ?? "railway") !== "railway") {
935
645
  return [];
936
646
  }
937
- const defaultRootDir = ["api", "operationsRunner"].includes(serviceKey) ? "." : "packages/core";
938
- const serviceRoot = resolve(tenantRoot, service.railway?.rootDir ?? service.rootDir ?? defaultRootDir);
647
+ const isCapacityProviderService = String(serviceKey).startsWith("capacityProvider");
648
+ const defaultRootDir = ["api", "operationsRunner"].includes(serviceKey) ? "." : isCapacityProviderService ? "packages/agent" : "packages/core";
649
+ const serviceRoot = isCapacityProviderService ? resolveRailwayCapacityProviderRoot(tenantRoot, service) : resolve(tenantRoot, service.railway?.rootDir ?? service.rootDir ?? defaultRootDir);
939
650
  const railwayEnvironment = resolveRailwayEnvironmentForScope(
940
651
  normalizedScope,
941
652
  service.environments?.[normalizedScope]?.railwayEnvironment
@@ -943,47 +654,233 @@ function configuredRailwayServicesForConfig(tenantRoot, scope, deployConfig, app
943
654
  const publicBaseUrl = service.environments?.[normalizedScope]?.baseUrl ?? service.publicBaseUrl ?? null;
944
655
  const configuredServiceName = service.railway?.serviceName ?? (serviceKey === "workerRunner" ? deriveRailwayWorkerRunnerServiceName(identity.deploymentKey) : `${identity.deploymentKey}-${railwayServiceNameSuffix(serviceKey)}`);
945
656
  const configuredRunnerPool = service.railway?.runnerPool && typeof service.railway.runnerPool === "object" ? service.railway.runnerPool : null;
946
- const runnerPool = serviceKey === "operationsRunner" ? {
947
- bootstrapCount: Math.max(1, Number.parseInt(String(configuredRunnerPool?.bootstrapCount ?? OPERATIONS_RUNNER_BOOTSTRAP_COUNT), 10) || OPERATIONS_RUNNER_BOOTSTRAP_COUNT),
948
- maxRunners: Math.max(1, Number.parseInt(String(configuredRunnerPool?.maxRunners ?? configuredRunnerPool?.bootstrapCount ?? OPERATIONS_RUNNER_BOOTSTRAP_COUNT), 10) || OPERATIONS_RUNNER_BOOTSTRAP_COUNT),
657
+ const runnerPool = serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? {
658
+ bootstrapCount: Math.max(1, Number.parseInt(String(configuredRunnerPool?.bootstrapCount ?? (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)), 10) || (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)),
659
+ maxRunners: Math.max(1, Number.parseInt(String(configuredRunnerPool?.maxRunners ?? configuredRunnerPool?.bootstrapCount ?? (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)), 10) || (serviceKey === "capacityProviderRunner" ? 1 : OPERATIONS_RUNNER_BOOTSTRAP_COUNT)),
949
660
  volumeMountPath: service.railway?.volumeMountPath ?? configuredRunnerPool?.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH
950
661
  } : serviceKey === "workerRunner" ? {
951
662
  bootstrapIndex: WORKER_RUNNER_BOOTSTRAP_INDEX,
952
663
  volumeMountPath: WORKER_RUNNER_VOLUME_MOUNT_PATH
953
664
  } : null;
954
- const instanceCount = serviceKey === "operationsRunner" ? runnerPool.bootstrapCount : 1;
665
+ const instanceCount = serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? runnerPool.bootstrapCount : 1;
955
666
  return Array.from({ length: instanceCount }, (_, offset) => {
956
667
  const runnerIndex = offset + 1;
957
- const serviceName = serviceKey === "operationsRunner" ? deriveRailwayOperationsRunnerServiceName(configuredServiceName, runnerIndex) : configuredServiceName;
668
+ const serviceName = serviceKey === "operationsRunner" ? deriveRailwayOperationsRunnerServiceName(configuredServiceName, runnerIndex) : serviceKey === "capacityProviderRunner" ? deriveRailwayCapacityProviderRunnerServiceName(configuredServiceName, runnerIndex) : configuredServiceName;
669
+ const configuredImageRefEnv = service.railway?.imageRefEnv ?? railwayImageRefEnvForService(serviceKey);
670
+ const imageRef = service.railway?.imageRef ?? (configuredImageRefEnv ? envValue(configuredImageRefEnv, imageRefEnv) || null : null) ?? defaultRailwayImageRef(serviceKey, normalizedScope, imageRefEnv);
671
+ const sourcePolicy = resolveRailwayServiceSourcePolicy({
672
+ tenantRoot,
673
+ scope: normalizedScope,
674
+ serviceKey,
675
+ service,
676
+ serviceRoot,
677
+ imageRef
678
+ });
679
+ const resolvedImageRef = sourcePolicy.sourceMode === "image" ? imageRef : null;
958
680
  return {
959
681
  key: serviceKey,
960
- instanceKey: serviceKey === "operationsRunner" ? `${serviceKey}:${runnerIndex}` : serviceKey,
961
- runnerIndex: serviceKey === "operationsRunner" ? runnerIndex : null,
682
+ instanceKey: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? `${serviceKey}:${runnerIndex}` : serviceKey,
683
+ runnerIndex: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? runnerIndex : null,
962
684
  serviceConfig: service,
963
685
  scope: normalizedScope,
964
686
  projectId: service.railway?.projectId ?? null,
965
687
  projectName: service.railway?.projectName ?? identity.deploymentKey,
966
688
  serviceId: service.railway?.serviceId ?? null,
967
689
  serviceName,
968
- runnerId: serviceKey === "operationsRunner" ? serviceName : null,
690
+ runnerId: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? serviceName : null,
969
691
  rootDir: serviceRoot,
970
692
  publicBaseUrl,
971
693
  railwayEnvironment,
972
- buildCommand: service.railway?.buildCommand ?? null,
973
- startCommand: service.railway?.startCommand ?? null,
694
+ buildCommand: resolvedImageRef ? null : service.railway?.buildCommand ?? null,
695
+ startCommand: isCapacityProviderService ? null : resolvedImageRef ? null : service.railway?.startCommand ?? null,
696
+ imageRef: resolvedImageRef,
697
+ sourceMode: sourcePolicy.sourceMode,
698
+ sourceRepo: sourcePolicy.sourceRepo,
699
+ sourceBranch: sourcePolicy.sourceBranch,
700
+ sourceCommit: sourcePolicy.sourceCommit,
701
+ sourceRootDirectory: sourcePolicy.sourceRootDirectory,
702
+ dockerfilePath: sourcePolicy.sourceMode === "git" ? service.railway?.dockerfilePath ?? null : null,
974
703
  healthcheckPath: service.railway?.healthcheckPath ?? null,
975
704
  healthcheckTimeoutSeconds: service.railway?.healthcheckTimeoutSeconds ?? null,
976
705
  healthcheckIntervalSeconds: service.railway?.healthcheckIntervalSeconds ?? null,
977
706
  restartPolicy: service.railway?.restartPolicy ?? null,
978
707
  runtimeMode: service.railway?.runtimeMode ?? null,
979
- volumeMountPath: serviceKey === "operationsRunner" ? runnerPool.volumeMountPath : service.railway?.volumeMountPath ?? null,
708
+ volumeMountPath: serviceKey === "operationsRunner" || serviceKey === "capacityProviderRunner" ? runnerPool.volumeMountPath : service.railway?.volumeMountPath ?? null,
980
709
  schedule: normalizeScheduleExpressions(service.railway?.schedule),
981
710
  hostingKind,
982
711
  runnerPool,
983
- application
712
+ application,
713
+ secretRefs: Array.isArray(service.secretRefs) ? service.secretRefs : [],
714
+ variableRefs: Array.isArray(service.variableRefs) ? service.variableRefs : []
984
715
  };
985
716
  });
986
717
  }).filter(Boolean);
718
+ return [
719
+ ...configuredServices,
720
+ ...configuredPublicTreeDxRailwayServices({
721
+ tenantRoot,
722
+ scope: normalizedScope,
723
+ deployConfig,
724
+ identity,
725
+ hostingKind,
726
+ application,
727
+ imageRefEnv,
728
+ workspaceRoot: machineConfigRoot
729
+ })
730
+ ];
731
+ }
732
+ function configuredPublicTreeDxRailwayServices({ tenantRoot, scope, deployConfig, identity, hostingKind, application, imageRefEnv, workspaceRoot }) {
733
+ if (deployConfig.hosting?.kind !== "treeseed_control_plane") {
734
+ return [];
735
+ }
736
+ const railway = deployConfig.publicTreeDxFederation?.railway ?? {};
737
+ const nodePool = railway.nodePool && typeof railway.nodePool === "object" && !Array.isArray(railway.nodePool) ? railway.nodePool : {};
738
+ const bootstrapCount = Math.max(0, Number.parseInt(String(nodePool.bootstrapCount ?? 1), 10) || 0);
739
+ if (bootstrapCount <= 0) {
740
+ return [];
741
+ }
742
+ const configuredSource = railway.source && typeof railway.source === "object" && !Array.isArray(railway.source) ? railway.source : {};
743
+ const treeDxRoot = resolve(workspaceRoot ?? tenantRoot, "packages", "treedx");
744
+ const configuredMode = typeof railway.sourceMode === "string" ? railway.sourceMode : null;
745
+ const sourceMode = scope === "prod" ? "image" : configuredMode === "git" || configuredMode === "image" ? configuredMode : "git";
746
+ const repository = typeof railway.sourceRepo === "string" ? railway.sourceRepo : typeof configuredSource.repository === "string" ? configuredSource.repository : typeof configuredSource.repo === "string" ? configuredSource.repo : readTreeseedPackageRepository(treeDxRoot) ?? "treeseed-ai/treedx";
747
+ const sourceBranch = typeof railway.sourceBranch === "string" ? railway.sourceBranch : typeof configuredSource.branch === "string" ? configuredSource.branch : scope === "staging" ? "staging" : null;
748
+ const sourceRootDirectory = typeof railway.sourceRootDirectory === "string" ? railway.sourceRootDirectory : typeof configuredSource.rootDirectory === "string" ? configuredSource.rootDirectory : ".";
749
+ const projectName = typeof railway.projectName === "string" && railway.projectName.trim() ? railway.projectName.trim() : typeof imageRefEnv.TREESEED_PUBLIC_TREEDX_RAILWAY_PROJECT_NAME === "string" && imageRefEnv.TREESEED_PUBLIC_TREEDX_RAILWAY_PROJECT_NAME.trim() ? imageRefEnv.TREESEED_PUBLIC_TREEDX_RAILWAY_PROJECT_NAME.trim() : identity.deploymentKey;
750
+ const railwayEnvironment = resolveRailwayEnvironmentForScope(scope, railway.environmentName);
751
+ const baseImageRef = envValue("TREESEED_PUBLIC_TREEDX_IMAGE_REF", imageRefEnv) || "treeseed/treedx";
752
+ return Array.from({ length: bootstrapCount }, (_, offset) => {
753
+ const index = offset + 1;
754
+ const serviceName = `${PUBLIC_TREEDX_NODE_SERVICE_KEY_PREFIX}${String(index).padStart(2, "0")}`;
755
+ return {
756
+ key: serviceName,
757
+ instanceKey: serviceName,
758
+ runnerIndex: null,
759
+ serviceConfig: null,
760
+ scope,
761
+ projectId: typeof railway.projectId === "string" ? railway.projectId : null,
762
+ projectName,
763
+ serviceId: typeof railway.serviceId === "string" && bootstrapCount === 1 ? railway.serviceId : null,
764
+ serviceName,
765
+ runnerId: null,
766
+ rootDir: treeDxRoot,
767
+ publicBaseUrl: null,
768
+ railwayEnvironment,
769
+ buildCommand: sourceMode === "git" ? railway.buildCommand ?? null : null,
770
+ startCommand: sourceMode === "git" ? railway.startCommand ?? null : null,
771
+ imageRef: sourceMode === "image" ? baseImageRef : null,
772
+ sourceMode,
773
+ sourceRepo: sourceMode === "git" ? repository : null,
774
+ sourceBranch: sourceMode === "git" ? sourceBranch : null,
775
+ sourceCommit: sourceMode === "git" ? headCommitSafe(treeDxRoot) ?? headCommitSafe(tenantRoot) : null,
776
+ sourceRootDirectory: sourceMode === "git" ? sourceRootDirectory : null,
777
+ dockerfilePath: sourceMode === "git" ? railway.dockerfilePath ?? "/Dockerfile" : null,
778
+ healthcheckPath: railway.healthcheckPath ?? null,
779
+ healthcheckTimeoutSeconds: railway.healthcheckTimeoutSeconds ?? null,
780
+ healthcheckIntervalSeconds: railway.healthcheckIntervalSeconds ?? null,
781
+ restartPolicy: railway.restartPolicy ?? null,
782
+ runtimeMode: railway.runtimeMode ?? "replicated",
783
+ volumeMountPath: railway.volumeMountPath ?? "/data",
784
+ schedule: [],
785
+ hostingKind,
786
+ runnerPool: null,
787
+ application,
788
+ environmentVariables: {
789
+ PORT: "4000",
790
+ TREEDX_DATA_DIR: railway.volumeMountPath ?? "/data",
791
+ TREEDX_AUTH_MODE: "connected",
792
+ TREEDX_AUTH_VERIFIER: "hs256_dev",
793
+ TREEDX_ALLOW_DEV_VERIFIER_IN_PROD: "true",
794
+ TREEDX_EXEC_BACKEND: "container_sandbox",
795
+ TREEDX_FEDERATION_MODE: "connected_library",
796
+ TREEDX_JWT_AUDIENCE: "treedx-public-federation",
797
+ TREEDX_JWT_ISSUER: "https://api.treeseed.local/treedx",
798
+ TREEDX_BOOTSTRAP_TRUST_ACTOR_ID: "treeseed-api",
799
+ TREEDX_BOOTSTRAP_TRUST_TENANT_ID: "treeseed-control-plane",
800
+ TREEDX_BOOTSTRAP_TRUST_REPO_IDS: "*",
801
+ TREEDX_BOOTSTRAP_TRUST_REFS: "*",
802
+ TREEDX_BOOTSTRAP_TRUST_PATHS: "**",
803
+ TREEDX_SCOPE: "public_federation"
804
+ },
805
+ secretRefs: ["TREEDX_SECRET_KEY_BASE", "TREEDX_ADMIN_TOKEN", "TREEDX_JWT_HS256_SECRET"],
806
+ variableRefs: [
807
+ "PORT",
808
+ "TREEDX_DATA_DIR",
809
+ "TREEDX_AUTH_MODE",
810
+ "TREEDX_AUTH_VERIFIER",
811
+ "TREEDX_ALLOW_DEV_VERIFIER_IN_PROD",
812
+ "TREEDX_EXEC_BACKEND",
813
+ "TREEDX_FEDERATION_MODE",
814
+ "TREEDX_JWT_AUDIENCE",
815
+ "TREEDX_JWT_ISSUER",
816
+ "TREEDX_BOOTSTRAP_TRUST_ACTOR_ID",
817
+ "TREEDX_BOOTSTRAP_TRUST_TENANT_ID",
818
+ "TREEDX_BOOTSTRAP_TRUST_REPO_IDS",
819
+ "TREEDX_BOOTSTRAP_TRUST_REFS",
820
+ "TREEDX_BOOTSTRAP_TRUST_PATHS",
821
+ "TREEDX_SCOPE"
822
+ ]
823
+ };
824
+ });
825
+ }
826
+ function readTreeseedPackageRepository(packageRoot) {
827
+ const manifestPath = resolve(packageRoot, "treeseed.package.yaml");
828
+ if (!existsSync(manifestPath)) return null;
829
+ try {
830
+ const manifest = parseYaml(readFileSync(manifestPath, "utf8"));
831
+ const repository = manifest && typeof manifest === "object" && !Array.isArray(manifest) ? manifest.repository : null;
832
+ return typeof repository === "string" && /^[^/\s]+\/[^/\s]+$/u.test(repository.trim()) ? repository.trim() : null;
833
+ } catch {
834
+ return null;
835
+ }
836
+ }
837
+ function headCommitSafe(cwd) {
838
+ try {
839
+ return runTreeseedGitText(["rev-parse", "HEAD"], {
840
+ cwd,
841
+ mode: classifyTreeseedGitMode(["rev-parse", "HEAD"])
842
+ }).trim();
843
+ } catch {
844
+ return null;
845
+ }
846
+ }
847
+ function resolveRailwayServiceSourcePolicy({ tenantRoot, scope, serviceKey, service, serviceRoot, imageRef }) {
848
+ const configuredMode = typeof service.railway?.sourceMode === "string" ? service.railway.sourceMode : null;
849
+ const configuredSource = service.railway?.source && typeof service.railway.source === "object" && !Array.isArray(service.railway.source) ? service.railway.source : {};
850
+ const configuredRepo = typeof service.railway?.sourceRepo === "string" ? service.railway.sourceRepo : typeof configuredSource.repository === "string" ? configuredSource.repository : typeof configuredSource.repo === "string" ? configuredSource.repo : null;
851
+ const packageRepository = configuredRepo ?? readTreeseedPackageRepository(serviceRoot) ?? readTreeseedPackageRepository(tenantRoot);
852
+ const sourceEligible = ["api", "operationsRunner", "capacityProviderManager", "capacityProviderRunner"].includes(serviceKey);
853
+ const sourceMode = scope === "prod" ? "image" : configuredMode === "git" || configuredMode === "image" ? configuredMode : imageRef ? "image" : scope === "staging" && sourceEligible && packageRepository ? "git" : "git";
854
+ if (sourceMode !== "git") {
855
+ return {
856
+ sourceMode: "image",
857
+ sourceRepo: null,
858
+ sourceBranch: null,
859
+ sourceCommit: null,
860
+ sourceRootDirectory: null
861
+ };
862
+ }
863
+ return {
864
+ sourceMode: "git",
865
+ sourceRepo: packageRepository,
866
+ sourceBranch: typeof service.railway?.sourceBranch === "string" ? service.railway.sourceBranch : typeof configuredSource.branch === "string" ? configuredSource.branch : scope === "staging" ? "staging" : null,
867
+ sourceCommit: headCommitSafe(serviceRoot),
868
+ sourceRootDirectory: typeof service.railway?.sourceRootDirectory === "string" ? service.railway.sourceRootDirectory : typeof configuredSource.rootDirectory === "string" ? configuredSource.rootDirectory : "."
869
+ };
870
+ }
871
+ function resolveRailwayCapacityProviderRoot(tenantRoot, service) {
872
+ if (service.railway?.rootDir) {
873
+ return resolve(tenantRoot, service.railway.rootDir);
874
+ }
875
+ const candidates = [
876
+ resolve(tenantRoot, "..", "agent"),
877
+ resolve(tenantRoot, "packages", "agent"),
878
+ resolve(tenantRoot, "..", "..", "packages", "agent")
879
+ ];
880
+ const found = candidates.find(
881
+ (candidate) => existsSync(resolve(candidate, "treeseed.package.yaml")) || existsSync(resolve(candidate, "package.json"))
882
+ );
883
+ return found ?? resolve(tenantRoot, "packages", "agent");
987
884
  }
988
885
  function configuredRailwayServices(tenantRoot, scope) {
989
886
  const deployConfig = loadCliDeployConfig(tenantRoot);
@@ -996,7 +893,8 @@ function configuredRailwayServices(tenantRoot, scope) {
996
893
  id: application.id,
997
894
  root: application.root,
998
895
  relativeRoot: application.relativeRoot
999
- }
896
+ },
897
+ tenantRoot
1000
898
  ));
1001
899
  return [...direct, ...nested];
1002
900
  }
@@ -1094,7 +992,11 @@ function validateRailwayServiceConfiguration(tenantRoot, scope) {
1094
992
  if (!service.projectName && !service.projectId) {
1095
993
  issues.push(`${service.key}: set railway.projectName or railway.projectId in treeseed.site.yaml.`);
1096
994
  }
1097
- if (!existsSync(service.rootDir)) {
995
+ if (service.sourceMode === "git" && !service.sourceRepo) {
996
+ issues.push(`${service.key}: staging source builds require railway.source.repository or package repository metadata.`);
997
+ }
998
+ const usesExternalGitSource = service.sourceMode === "git" && Boolean(service.sourceRepo);
999
+ if (!service.imageRef && !usesExternalGitSource && !existsSync(service.rootDir)) {
1098
1000
  issues.push(`${service.key}: service root ${service.rootDir} does not exist.`);
1099
1001
  }
1100
1002
  if (service.schedule?.length && !service.startCommand) {
@@ -1116,7 +1018,7 @@ function validateRailwayDeployPrerequisites(tenantRoot, scope, { env = process.e
1116
1018
  const validation = validateRailwayServiceConfiguration(tenantRoot, scope);
1117
1019
  const token = resolveRailwayAuthToken(env);
1118
1020
  if (typeof token !== "string" || token.trim().length === 0) {
1119
- throw new Error("Configure RAILWAY_API_TOKEN before deploying Railway-managed services.");
1021
+ throw new Error("Configure TREESEED_RAILWAY_API_TOKEN before deploying Railway-managed services.");
1120
1022
  }
1121
1023
  return validation;
1122
1024
  }
@@ -1128,7 +1030,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
1128
1030
  const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
1129
1031
  const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
1130
1032
  if (typeof effectiveApiToken !== "string" || effectiveApiToken.trim().length === 0) {
1131
- throw new Error("Configure RAILWAY_API_TOKEN before deploying Railway-managed services.");
1033
+ throw new Error("Configure TREESEED_RAILWAY_API_TOKEN before deploying Railway-managed services.");
1132
1034
  }
1133
1035
  const results = [];
1134
1036
  try {
@@ -1154,7 +1056,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
1154
1056
  const current = await getRailwayServiceInstance({
1155
1057
  serviceId: target.service.id,
1156
1058
  environmentId: target.environment.id,
1157
- env: { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
1059
+ env: { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
1158
1060
  fetchImpl
1159
1061
  });
1160
1062
  const desired = {
@@ -1184,7 +1086,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
1184
1086
  environmentId: target.environment.id,
1185
1087
  startCommand: desired.command,
1186
1088
  cronSchedule: desired.schedule,
1187
- env: { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
1089
+ env: { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
1188
1090
  fetchImpl
1189
1091
  });
1190
1092
  results.push({
@@ -1214,7 +1116,7 @@ async function ensureRailwayScheduledJobs(tenantRoot, scope, { dryRun = false, f
1214
1116
  return results;
1215
1117
  }
1216
1118
  async function verifyRailwayScheduledJobs(tenantRoot, scope, { fetchImpl = fetch, apiToken, apiUrl, env = process.env } = {}) {
1217
- const effectiveApiToken = apiToken || env?.RAILWAY_API_TOKEN;
1119
+ const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
1218
1120
  const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
1219
1121
  const configured = configuredRailwayScheduledJobs(tenantRoot, scope);
1220
1122
  const checks = [];
@@ -1238,7 +1140,7 @@ async function verifyRailwayScheduledJobs(tenantRoot, scope, { fetchImpl = fetch
1238
1140
  const existing = await getRailwayServiceInstance({
1239
1141
  serviceId: target.service.id,
1240
1142
  environmentId: target.environment.id,
1241
- env: { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
1143
+ env: { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl },
1242
1144
  fetchImpl
1243
1145
  });
1244
1146
  checks.push({
@@ -1293,7 +1195,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
1293
1195
  } = {}) {
1294
1196
  const effectiveApiToken = apiToken || resolveRailwayAuthToken(env);
1295
1197
  const effectiveApiUrl = apiUrl || resolveRailwayApiUrl(env);
1296
- const effectiveEnv = { ...env, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl };
1198
+ const effectiveEnv = { ...env, TREESEED_RAILWAY_API_TOKEN: effectiveApiToken, RAILWAY_API_TOKEN: effectiveApiToken, TREESEED_RAILWAY_API_URL: effectiveApiUrl };
1297
1199
  const services = configuredRailwayServices(tenantRoot, scope);
1298
1200
  const checks = [];
1299
1201
  const deploymentStatusServices = [];
@@ -1353,18 +1255,19 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
1353
1255
  } : null,
1354
1256
  message: instance.id ? void 0 : `Railway service instance for ${target.service.name} is missing in ${target.environment.name}.`
1355
1257
  });
1356
- if (service.key === "workerRunner") {
1357
- const expectedVolumeName = deriveRailwayWorkerRunnerVolumeName(target.service.name, target.environment.name);
1258
+ const expectedVolumeMountPath = service.volumeMountPath ?? service.runnerPool?.volumeMountPath ?? null;
1259
+ if (expectedVolumeMountPath) {
1260
+ const expectedVolumeName = service.key === "operationsRunner" ? deriveRailwayOperationsRunnerVolumeName(target.service.name, target.environment.name) : service.key === "capacityProviderRunner" ? deriveRailwayCapacityProviderRunnerVolumeName(target.service.name, target.environment.name) : deriveRailwayWorkerRunnerVolumeName(target.service.name, target.environment.name);
1358
1261
  const volumes = await listRailwayVolumes({
1359
1262
  projectId: target.project.id,
1360
1263
  env: effectiveEnv,
1361
1264
  fetchImpl
1362
1265
  });
1363
1266
  const volume = volumes.find(
1364
- (candidate) => candidate.name === expectedVolumeName && candidate.instances.some((entry) => entry.serviceId === target.service.id && entry.environmentId === target.environment.id && entry.mountPath === WORKER_RUNNER_VOLUME_MOUNT_PATH)
1267
+ (candidate) => candidate.name === expectedVolumeName && candidate.instances.some((entry) => entry.serviceId === target.service.id && entry.environmentId === target.environment.id && entry.mountPath === expectedVolumeMountPath)
1365
1268
  ) ?? null;
1366
1269
  checks.push({
1367
- type: "worker-runner-volume",
1270
+ type: "service-volume",
1368
1271
  service: service.key,
1369
1272
  serviceName: target.service.name,
1370
1273
  serviceId: target.service.id,
@@ -1372,7 +1275,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
1372
1275
  environment: target.environment.name,
1373
1276
  environmentId: target.environment.id,
1374
1277
  volumeName: expectedVolumeName,
1375
- mountPath: WORKER_RUNNER_VOLUME_MOUNT_PATH,
1278
+ mountPath: expectedVolumeMountPath,
1376
1279
  ok: Boolean(volume),
1377
1280
  status: volume ? "checked" : "missing",
1378
1281
  observed: volume ? {
@@ -1380,7 +1283,7 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
1380
1283
  name: volume.name,
1381
1284
  instances: volume.instances
1382
1285
  } : null,
1383
- message: volume ? void 0 : `Railway worker-runner volume ${expectedVolumeName} is missing or is not mounted at ${WORKER_RUNNER_VOLUME_MOUNT_PATH}.`
1286
+ message: volume ? void 0 : `Railway volume ${expectedVolumeName} is missing or is not mounted on ${target.service.name} at ${expectedVolumeMountPath}.`
1384
1287
  });
1385
1288
  }
1386
1289
  }
@@ -1414,30 +1317,6 @@ async function verifyRailwayManagedResources(tenantRoot, scope, {
1414
1317
  checks
1415
1318
  };
1416
1319
  }
1417
- function shouldAttachRailwayDeployLogs(env = process.env) {
1418
- const configured = configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_ATTACH_LOGS");
1419
- if (configured === "1" || configured === "true") {
1420
- return true;
1421
- }
1422
- if (configured === "0" || configured === "false") {
1423
- return false;
1424
- }
1425
- return false;
1426
- }
1427
- function shouldUseVerboseRailwayDeploy(env = process.env) {
1428
- const configured = configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_VERBOSE");
1429
- if (configured === "1" || configured === "true") {
1430
- return true;
1431
- }
1432
- if (configured === "0" || configured === "false") {
1433
- return false;
1434
- }
1435
- return shouldAttachRailwayDeployLogs(env);
1436
- }
1437
- function railwayDeployCommandTimeoutMs(env = process.env) {
1438
- const configured = Number.parseInt(configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_COMMAND_TIMEOUT_MS"), 10);
1439
- return Number.isFinite(configured) && configured > 0 ? configured : 3e5;
1440
- }
1441
1320
  function railwayPhaseTimeoutMs(env = process.env, phase = "default") {
1442
1321
  const configured = Number.parseInt(configuredEnvValue(env, `TREESEED_RAILWAY_${String(phase).toUpperCase().replace(/[^A-Z0-9]+/gu, "_")}_TIMEOUT_MS`), 10);
1443
1322
  if (Number.isFinite(configured) && configured > 0) {
@@ -1467,10 +1346,6 @@ async function withRailwayPhaseTimeout(run, timeoutMs, message) {
1467
1346
  }
1468
1347
  }
1469
1348
  }
1470
- function shouldIncludeRailwayIgnoredFiles(env = process.env) {
1471
- const configured = configuredEnvValue(env, "TREESEED_RAILWAY_DEPLOY_INCLUDE_IGNORED");
1472
- return configured === "1" || configured === "true";
1473
- }
1474
1349
  function shouldRunRailwayPredeployBuild(env = process.env) {
1475
1350
  const configured = configuredEnvValue(env, "TREESEED_RAILWAY_PREDEPLOY_BUILD");
1476
1351
  if (configured === "1" || configured === "true") {
@@ -1481,56 +1356,6 @@ function shouldRunRailwayPredeployBuild(env = process.env) {
1481
1356
  }
1482
1357
  return configuredEnvValue(env, "CI") !== "true";
1483
1358
  }
1484
- function planRailwayServiceDeploy(service, { env = process.env, projectTokenMode = false } = {}) {
1485
- const serviceSelector = service.serviceName ?? service.serviceId;
1486
- const args = ["up"];
1487
- if (serviceSelector) {
1488
- args.push("--service", serviceSelector);
1489
- }
1490
- if (shouldIncludeRailwayIgnoredFiles(env)) {
1491
- args.push("--no-gitignore");
1492
- }
1493
- args.push(shouldAttachRailwayDeployLogs(env) ? "--ci" : "--detach");
1494
- if (shouldUseVerboseRailwayDeploy(env)) {
1495
- args.push("--verbose");
1496
- }
1497
- if (!projectTokenMode && service.projectId) {
1498
- args.push("--project", service.projectId);
1499
- }
1500
- const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
1501
- if (!projectTokenMode && environmentName) {
1502
- args.push("--environment", environmentName);
1503
- }
1504
- return {
1505
- command: "railway",
1506
- args,
1507
- cwd: service.rootDir
1508
- };
1509
- }
1510
- function planRailwayProjectEnvironmentLink(service) {
1511
- const args = ["link"];
1512
- if (service.projectId) {
1513
- args.push("--project", service.projectId);
1514
- }
1515
- const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
1516
- if (environmentName) {
1517
- args.push("--environment", environmentName);
1518
- }
1519
- args.push("--json");
1520
- return {
1521
- command: "railway",
1522
- args,
1523
- cwd: service.rootDir
1524
- };
1525
- }
1526
- function buildRailwayCliContextEnv(env, service) {
1527
- return {
1528
- ...env,
1529
- RAILWAY_PROJECT_ID: configuredEnvValue(service, "projectId") || configuredEnvValue(env, "RAILWAY_PROJECT_ID") || void 0,
1530
- RAILWAY_ENVIRONMENT_ID: configuredEnvValue(service, "environmentId") || configuredEnvValue(env, "RAILWAY_ENVIRONMENT_ID") || void 0,
1531
- RAILWAY_SERVICE_ID: configuredEnvValue(service, "serviceId") || configuredEnvValue(env, "RAILWAY_SERVICE_ID") || void 0
1532
- };
1533
- }
1534
1359
  async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
1535
1360
  if (service.key !== "api") {
1536
1361
  return null;
@@ -1545,7 +1370,7 @@ async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
1545
1370
  [
1546
1371
  "TREESEED_API_AUTH_APPROVAL_BASE_URL",
1547
1372
  "TREESEED_SITE_URL",
1548
- "BETTER_AUTH_URL"
1373
+ "TREESEED_BETTER_AUTH_URL"
1549
1374
  ].map((key) => [key, configuredEnvValue(env, key)]).filter(([, value]) => value)
1550
1375
  );
1551
1376
  if (Object.keys(variables).length === 0) {
@@ -1561,166 +1386,6 @@ async function syncRailwayApiDeviceLoginVariables(service, env, write, prefix) {
1561
1386
  write ? write(`[${prefix.scope}][${prefix.system}][${prefix.task}][vars] Synced device login approval URL variables for ${service.serviceName ?? serviceId}.`, "stdout") : null;
1562
1387
  return { variables: Object.keys(variables) };
1563
1388
  }
1564
- function buildRailwayLinkCommandEnv(env = process.env, service = {}) {
1565
- return buildRailwayCliContextEnv({
1566
- ...buildRailwayDeployCommandEnv({ ...env, RAILWAY_TOKEN: void 0 }),
1567
- RAILWAY_TOKEN: void 0
1568
- }, service);
1569
- }
1570
- function railwayCliConfigPath(env = process.env) {
1571
- const railwayHome = configuredEnvValue(env, "RAILWAY_HOME");
1572
- if (railwayHome) {
1573
- return resolve(railwayHome, "config.json");
1574
- }
1575
- const home = configuredEnvValue(env, "HOME");
1576
- if (!home) {
1577
- return "";
1578
- }
1579
- return resolve(home, ".railway", "config.json");
1580
- }
1581
- function readRailwayCliConfig(configPath) {
1582
- if (!configPath || !existsSync(configPath)) {
1583
- return {};
1584
- }
1585
- try {
1586
- const parsed = JSON.parse(readFileSync(configPath, "utf8"));
1587
- return parsed && typeof parsed === "object" ? parsed : {};
1588
- } catch {
1589
- return {};
1590
- }
1591
- }
1592
- function writeRailwayCliProjectConfig(service, { env = process.env, cwd = service.rootDir } = {}) {
1593
- const projectId = configuredEnvValue(service, "projectId");
1594
- const environmentId = configuredEnvValue(service, "environmentId");
1595
- const serviceId = configuredEnvValue(service, "serviceId");
1596
- const projectPath = cwd ? resolve(cwd) : "";
1597
- const configPath = railwayCliConfigPath(env);
1598
- if (!configPath || !projectPath || !projectId || !environmentId || !serviceId) {
1599
- return null;
1600
- }
1601
- const existing = readRailwayCliConfig(configPath);
1602
- const projects = existing.projects && typeof existing.projects === "object" ? existing.projects : {};
1603
- const next = {
1604
- ...existing,
1605
- projects: {
1606
- ...projects,
1607
- [projectPath]: {
1608
- projectPath,
1609
- name: configuredEnvValue(service, "projectName") || configuredEnvValue(service, "serviceName") || projectId,
1610
- project: projectId,
1611
- environment: environmentId,
1612
- environmentName: normalizeRailwayEnvironmentName(service.railwayEnvironment) || configuredEnvValue(service, "environmentName") || environmentId,
1613
- service: serviceId
1614
- }
1615
- },
1616
- user: existing.user && typeof existing.user === "object" ? existing.user : {
1617
- token: null,
1618
- accessToken: null,
1619
- refreshToken: null,
1620
- tokenExpiresAt: null
1621
- },
1622
- linkedFunctions: existing.linkedFunctions ?? null
1623
- };
1624
- mkdirSync(dirname(configPath), { recursive: true });
1625
- writeFileSync(configPath, `${JSON.stringify(next, null, 2)}
1626
- `, "utf8");
1627
- return {
1628
- configPath,
1629
- projectPath,
1630
- projectId,
1631
- environmentId,
1632
- serviceId
1633
- };
1634
- }
1635
- function planRailwayServiceLink(service, { env = process.env } = {}) {
1636
- const args = ["link"];
1637
- if (service.projectId) {
1638
- args.push("--project", service.projectId);
1639
- }
1640
- const workspace = resolveRailwayWorkspace(env);
1641
- if (workspace) {
1642
- args.push("--workspace", workspace);
1643
- }
1644
- const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment);
1645
- if (environmentName) {
1646
- args.push("--environment", environmentName);
1647
- }
1648
- const serviceSelector = service.serviceName ?? service.serviceId;
1649
- if (serviceSelector) {
1650
- args.push("--service", serviceSelector);
1651
- }
1652
- args.push("--json");
1653
- return {
1654
- command: "railway",
1655
- args,
1656
- cwd: service.rootDir
1657
- };
1658
- }
1659
- function railwayProjectTokenName(service) {
1660
- const environment = normalizeRailwayEnvironmentName(service.railwayEnvironment) || "environment";
1661
- const serviceName = String(service.serviceName ?? service.serviceId ?? service.key ?? "service").toLowerCase().replace(/[^a-z0-9-]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 48) || "service";
1662
- return `treeseed-ci-${environment}-${serviceName}`;
1663
- }
1664
- async function createRailwayCliProjectToken(service, { env = process.env } = {}) {
1665
- const projectId = configuredEnvValue(service, "projectId");
1666
- const environmentId = configuredEnvValue(service, "environmentId");
1667
- if (!projectId || !environmentId) {
1668
- return "";
1669
- }
1670
- const name = railwayProjectTokenName(service);
1671
- try {
1672
- const existingPayload = await railwayGraphqlRequest({
1673
- query: `
1674
- query TreeseedProjectTokens($projectId: String!) {
1675
- projectTokens(projectId: $projectId, first: 100) {
1676
- edges {
1677
- node {
1678
- id
1679
- name
1680
- projectId
1681
- environmentId
1682
- }
1683
- }
1684
- }
1685
- }
1686
- `.trim(),
1687
- variables: { projectId },
1688
- env
1689
- });
1690
- const existingTokens = railwayEdgeNodes(existingPayload.data?.projectTokens);
1691
- for (const token2 of existingTokens) {
1692
- if (token2?.name === name && token2?.projectId === projectId && token2?.environmentId === environmentId && token2?.id) {
1693
- await railwayGraphqlRequest({
1694
- query: `
1695
- mutation TreeseedProjectTokenDelete($id: String!) {
1696
- projectTokenDelete(id: $id)
1697
- }
1698
- `.trim(),
1699
- variables: { id: token2.id },
1700
- env
1701
- });
1702
- }
1703
- }
1704
- } catch {
1705
- }
1706
- const payload = await railwayGraphqlRequest({
1707
- query: `
1708
- mutation TreeseedProjectTokenCreate($input: ProjectTokenCreateInput!) {
1709
- projectTokenCreate(input: $input)
1710
- }
1711
- `.trim(),
1712
- variables: {
1713
- input: {
1714
- projectId,
1715
- environmentId,
1716
- name
1717
- }
1718
- },
1719
- env
1720
- });
1721
- const token = payload.data?.projectTokenCreate;
1722
- return typeof token === "string" && token.trim() ? token.trim() : "";
1723
- }
1724
1389
  async function resolveRailwayDeployProjectContext(service, { env = process.env } = {}) {
1725
1390
  if (service.projectId) {
1726
1391
  return service;
@@ -1745,8 +1410,8 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1745
1410
  writePhase(`sync-runtime-config:${stage}`, message);
1746
1411
  }
1747
1412
  };
1748
- const wantsInstanceConfig = service.buildCommand || service.startCommand || service.rootDir || service.healthcheckPath || service.healthcheckTimeoutSeconds !== null || service.healthcheckTimeoutSeconds !== void 0 || service.healthcheckIntervalSeconds !== null || service.healthcheckIntervalSeconds !== void 0 || service.restartPolicy || service.runtimeMode;
1749
- const wantsRunnerVolume = service.key === "workerRunner" || Boolean(service.volumeMountPath);
1413
+ const wantsInstanceConfig = service.buildCommand || service.startCommand || !(service.imageRef || service.sourceMode === "image") && service.rootDir || service.healthcheckPath || service.healthcheckTimeoutSeconds !== null || service.healthcheckTimeoutSeconds !== void 0 || service.healthcheckIntervalSeconds !== null || service.healthcheckIntervalSeconds !== void 0 || service.restartPolicy || service.runtimeMode;
1414
+ const wantsRunnerVolume = service.key === "workerRunner" || service.key === "operationsRunner" || service.key === "capacityProviderRunner";
1750
1415
  if (!wantsInstanceConfig && !wantsRunnerVolume) {
1751
1416
  writeSyncPhase("skip", "No runtime configuration changes requested.");
1752
1417
  return null;
@@ -1794,6 +1459,21 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1794
1459
  projectId: project.id,
1795
1460
  serviceId: service.serviceId,
1796
1461
  serviceName: service.serviceName,
1462
+ environmentId: environment.id,
1463
+ imageRef: service.imageRef,
1464
+ sourceRepo: service.sourceRepo,
1465
+ sourceBranch: service.sourceBranch,
1466
+ env
1467
+ }).then((result) => result.service);
1468
+ } else if (service.imageRef) {
1469
+ railwayService = await ensureRailwayService({
1470
+ projectId: project.id,
1471
+ serviceId: service.serviceId,
1472
+ serviceName: service.serviceName,
1473
+ environmentId: environment.id,
1474
+ imageRef: service.imageRef,
1475
+ sourceRepo: service.sourceRepo,
1476
+ sourceBranch: service.sourceBranch,
1797
1477
  env
1798
1478
  }).then((result) => result.service);
1799
1479
  }
@@ -1806,7 +1486,7 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1806
1486
  buildCommand: service.buildCommand,
1807
1487
  startCommand: railwayServiceRuntimeStartCommand(service),
1808
1488
  cronSchedule: service.schedule?.[0] ?? null,
1809
- rootDirectory: ".",
1489
+ rootDirectory: service.imageRef || service.sourceMode === "image" ? null : service.sourceRootDirectory ?? ".",
1810
1490
  healthcheckPath: service.healthcheckPath,
1811
1491
  healthcheckTimeoutSeconds: service.healthcheckTimeoutSeconds,
1812
1492
  healthcheckIntervalSeconds: service.healthcheckIntervalSeconds,
@@ -1822,6 +1502,14 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1822
1502
  serviceId: railwayService.id,
1823
1503
  variables: {
1824
1504
  TREESEED_SKIP_PACKAGE_PREPARE: "1",
1505
+ ...service.sourceMode === "git" ? {
1506
+ TREESEED_DEPLOY_SOURCE_MODE: "git",
1507
+ ...service.sourceRepo ? { TREESEED_DEPLOY_SOURCE_REPOSITORY: service.sourceRepo } : {},
1508
+ ...service.sourceBranch ? { TREESEED_DEPLOY_SOURCE_BRANCH: service.sourceBranch } : {},
1509
+ ...service.sourceCommit ? { TREESEED_DEPLOY_SOURCE_COMMIT: service.sourceCommit } : {}
1510
+ } : {
1511
+ TREESEED_DEPLOY_SOURCE_MODE: "image"
1512
+ },
1825
1513
  ...service.key === "operationsRunner" ? {
1826
1514
  NIXPACKS_APT_PKGS: "git",
1827
1515
  NIXPACKS_PKGS: "git",
@@ -1829,12 +1517,25 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1829
1517
  TREESEED_PLATFORM_RUNNER_DATA_DIR: service.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH,
1830
1518
  TREESEED_PLATFORM_RUNNER_ENVIRONMENT: normalizeScope(service.scope) === "prod" ? "production" : normalizeScope(service.scope),
1831
1519
  TREESEED_MANAGER_ID: normalizeScope(service.scope),
1832
- ...configuredEnvValue(env, "RAILWAY_API_TOKEN") ? { RAILWAY_API_TOKEN: configuredEnvValue(env, "RAILWAY_API_TOKEN") } : {},
1520
+ ...configuredEnvValue(env, "TREESEED_RAILWAY_API_TOKEN") ? { TREESEED_RAILWAY_API_TOKEN: configuredEnvValue(env, "TREESEED_RAILWAY_API_TOKEN") } : {},
1833
1521
  ...configuredEnvValue(env, "TREESEED_RAILWAY_WORKSPACE") ? { TREESEED_RAILWAY_WORKSPACE: configuredEnvValue(env, "TREESEED_RAILWAY_WORKSPACE") } : {},
1834
1522
  ...configuredEnvValue(env, "TREESEED_PLATFORM_RUNNER_SECRET") ? { TREESEED_PLATFORM_RUNNER_SECRET: configuredEnvValue(env, "TREESEED_PLATFORM_RUNNER_SECRET") } : {},
1835
1523
  ...configuredEnvValue(env, "TREESEED_API_BASE_URL") || configuredEnvValue(env, "TREESEED_URL") ? {
1836
1524
  TREESEED_API_BASE_URL: configuredEnvValue(env, "TREESEED_API_BASE_URL") || configuredEnvValue(env, "TREESEED_URL")
1837
1525
  } : {}
1526
+ } : {},
1527
+ ...String(service.key).startsWith("capacityProvider") ? {
1528
+ TREESEED_PROVIDER_ENVIRONMENT: normalizeScope(service.scope) === "prod" ? "production" : normalizeScope(service.scope),
1529
+ TREESEED_MANAGER_ID: normalizeScope(service.scope),
1530
+ TREESEED_MARKET_ID: normalizeScope(service.scope),
1531
+ TREESEED_PROVIDER_ROLE: service.key === "capacityProviderManager" ? "manager" : "runner",
1532
+ ...service.key === "capacityProviderRunner" ? {
1533
+ TREESEED_PROVIDER_DATA_DIR: service.volumeMountPath ?? WORKER_RUNNER_VOLUME_MOUNT_PATH,
1534
+ TREESEED_PROVIDER_RUNNER_ID: service.runnerId ?? railwayService.name
1535
+ } : {},
1536
+ ...configuredEnvValue(env, "TREESEED_MARKET_URL") ? { TREESEED_MARKET_URL: configuredEnvValue(env, "TREESEED_MARKET_URL") } : {},
1537
+ ...configuredEnvValue(env, "TREESEED_CAPACITY_PROVIDER_API_KEY") ? { TREESEED_CAPACITY_PROVIDER_API_KEY: configuredEnvValue(env, "TREESEED_CAPACITY_PROVIDER_API_KEY") } : {},
1538
+ ...configuredEnvValue(env, "TREESEED_CODEX_AUTH_JSON_B64") ? { TREESEED_CODEX_AUTH_JSON_B64: configuredEnvValue(env, "TREESEED_CODEX_AUTH_JSON_B64") } : {}
1838
1539
  } : {}
1839
1540
  },
1840
1541
  env
@@ -1847,7 +1548,7 @@ async function syncRailwayServiceRuntimeConfigurationAfterDeploy(tenantRoot, ser
1847
1548
  projectId: project.id,
1848
1549
  environmentId: environment.id,
1849
1550
  serviceId: railwayService.id,
1850
- name: service.key === "operationsRunner" ? deriveRailwayOperationsRunnerVolumeName(railwayService.name, environment.name) : deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
1551
+ name: service.key === "operationsRunner" ? deriveRailwayOperationsRunnerVolumeName(railwayService.name, environment.name) : service.key === "capacityProviderRunner" ? deriveRailwayCapacityProviderRunnerVolumeName(railwayService.name, environment.name) : deriveRailwayWorkerRunnerVolumeName(railwayService.name, environment.name),
1851
1552
  mountPath: volumeMountPath,
1852
1553
  env
1853
1554
  }) : null;
@@ -1896,12 +1597,11 @@ async function deployRailwayService(tenantRoot, service, {
1896
1597
  } = {}) {
1897
1598
  const timings = [];
1898
1599
  if (dryRun) {
1899
- const plan2 = planRailwayServiceDeploy(service, { env });
1900
1600
  return {
1901
1601
  service: service.key,
1902
1602
  status: "planned",
1903
- command: [plan2.command, ...plan2.args].join(" "),
1904
- cwd: plan2.cwd,
1603
+ command: "railway-api serviceInstanceDeployV2",
1604
+ cwd: service.rootDir,
1905
1605
  publicBaseUrl: service.publicBaseUrl,
1906
1606
  timings,
1907
1607
  transport: {
@@ -1916,7 +1616,6 @@ async function deployRailwayService(tenantRoot, service, {
1916
1616
  service: service.key
1917
1617
  });
1918
1618
  const commandEnv = buildRailwayCommandEnv({ ...process.env, ...env });
1919
- let railwayDeployEnv = buildRailwayDeployCommandEnv(commandEnv);
1920
1619
  const deployTransport = railwayDeployTransport(commandEnv);
1921
1620
  const taskPrefix = prefix ?? {
1922
1621
  scope: normalizeScope(deployService.scope ?? deployService.railwayEnvironment ?? "railway"),
@@ -1951,7 +1650,7 @@ async function deployRailwayService(tenantRoot, service, {
1951
1650
  ), {
1952
1651
  service: cliDeployService.key
1953
1652
  });
1954
- if (deployService.buildCommand && shouldRunRailwayPredeployBuild(commandEnv)) {
1653
+ if (deployService.buildCommand && !deployService.imageRef && shouldRunRailwayPredeployBuild(commandEnv)) {
1955
1654
  const buildResult = await timedRailwayPhase(timings, "railway:predeploy-build", () => runPrefixedCommand("bash", ["-lc", deployService.buildCommand], {
1956
1655
  cwd: deployService.rootDir,
1957
1656
  env: commandEnv,
@@ -1996,139 +1695,32 @@ async function deployRailwayService(tenantRoot, service, {
1996
1695
  } : null
1997
1696
  };
1998
1697
  }
1999
- const railway = resolveTreeseedToolCommand("railway", { env: commandEnv });
2000
- if (!railway) {
2001
- throw new Error("Railway CLI deploy fallback requested, but Railway CLI is unavailable.");
2002
- }
2003
- railwayDeployEnv = buildRailwayCliContextEnv(railwayDeployEnv, cliDeployService);
2004
- const hasCommandApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
2005
- let usesProjectToken = Boolean(configuredEnvValue(railwayDeployEnv, "RAILWAY_TOKEN"));
2006
- if (usesProjectToken) {
2007
- railwayDeployEnv = { ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0 };
2008
- }
2009
- writePhase("project-token", usesProjectToken || hasCommandApiToken ? "Using configured Railway authentication." : "Creating Railway project token.");
2010
- await timedRailwayPhase(timings, "railway:project-token", () => withRailwayPhaseTimeout(async () => {
2011
- if (usesProjectToken || hasCommandApiToken) {
2012
- return null;
2013
- }
2014
- const projectToken = await createRailwayCliProjectToken(cliDeployService, { env: commandEnv });
2015
- if (projectToken) {
2016
- railwayDeployEnv = buildRailwayCliContextEnv({ ...railwayDeployEnv, RAILWAY_API_TOKEN: void 0, RAILWAY_TOKEN: projectToken }, cliDeployService);
2017
- usesProjectToken = true;
2018
- } else if (configuredEnvValue(commandEnv, "CI") === "true") {
2019
- throw new Error(`Railway CI deploy requires a project token for ${cliDeployService.serviceName ?? cliDeployService.key}. Automatic project token creation did not return a token.`);
2020
- }
2021
- return null;
2022
- }, railwayPhaseTimeoutMs(commandEnv, "project_token"), `Railway project-token phase timed out for ${cliDeployService.serviceName ?? cliDeployService.key}.`), { service: cliDeployService.key });
2023
- const linkPlan = planRailwayServiceLink(cliDeployService, { env: commandEnv });
2024
- const plan = planRailwayServiceDeploy(cliDeployService, { env, projectTokenMode: usesProjectToken });
2025
- const hasRailwayApiToken = Boolean(configuredEnvValue(commandEnv, "RAILWAY_API_TOKEN"));
2026
- const cliConfig = configuredEnvValue(commandEnv, "CI") === "true" ? writeRailwayCliProjectConfig(cliDeployService, { env: railwayDeployEnv, cwd: plan.cwd }) : null;
2027
- const effectiveLinkPlan = hasRailwayApiToken ? linkPlan : usesProjectToken ? planRailwayProjectEnvironmentLink(cliDeployService) : linkPlan;
2028
- const railwayLinkEnv = hasRailwayApiToken ? buildRailwayLinkCommandEnv(commandEnv, cliDeployService) : railwayDeployEnv;
2029
- writePhase("link", `Linking Railway project context for ${cliDeployService.serviceName ?? cliDeployService.serviceId ?? cliDeployService.key}.`);
2030
- await timedRailwayPhase(timings, "railway:link", () => withRailwayPhaseTimeout(async () => {
2031
- if (cliConfig) {
2032
- write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][link] Wrote Railway CLI project context for ${cliConfig.projectPath}.`, "stdout") : null;
2033
- return;
2034
- }
2035
- const linkResult = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...effectiveLinkPlan.args], {
2036
- cwd: effectiveLinkPlan.cwd,
2037
- env: railwayLinkEnv,
2038
- write,
2039
- prefix: { ...taskPrefix, stage: "link" }
2040
- });
2041
- if (linkResult.status !== 0) {
2042
- throw new Error(linkResult.stderr?.trim() || linkResult.stdout?.trim() || `railway ${effectiveLinkPlan.args.join(" ")} failed with exit code ${linkResult.status ?? "unknown"} in ${effectiveLinkPlan.cwd}`);
2043
- }
2044
- }, railwayPhaseTimeoutMs(commandEnv, "link"), `Railway link phase timed out for ${cliDeployService.serviceName ?? cliDeployService.key}.`), { service: cliDeployService.key });
2045
- await timedRailwayPhase(timings, "railway:deploy", () => withRailwayPhaseTimeout(async () => {
2046
- let lastFailure = null;
2047
- for (let attempt = 1; attempt <= 5; attempt += 1) {
2048
- if (write && attempt === 1) {
2049
- write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][deploy] $ railway ${plan.args.join(" ")}`, "stdout");
2050
- }
2051
- const result = await runPrefixedCommand(railway.command, [...railway.argsPrefix, ...plan.args], {
2052
- cwd: plan.cwd,
2053
- env: railwayDeployEnv,
2054
- write,
2055
- prefix: taskPrefix,
2056
- timeoutMs: railwayDeployCommandTimeoutMs(commandEnv)
2057
- });
2058
- if (result.status === 0) {
2059
- lastFailure = null;
2060
- break;
2061
- }
2062
- lastFailure = result;
2063
- if (!isRailwayTransientFailure(result) || attempt === 5) {
2064
- throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${plan.args.join(" ")} failed with exit code ${result.status ?? "unknown"} in ${plan.cwd}`);
2065
- }
2066
- const backoffMs = 5e3 * attempt;
2067
- const warning = `Railway deploy for ${deployService.serviceName ?? deployService.serviceId ?? deployService.key} hit a transient failure; retrying in ${Math.round(backoffMs / 1e3)}s...`;
2068
- write ? write(`[${taskPrefix.scope}][${taskPrefix.system}][${taskPrefix.task}][retry] ${warning}`, "stderr") : console.warn(warning);
2069
- await sleep(backoffMs);
2070
- }
2071
- if (lastFailure) {
2072
- throw new Error(lastFailure.stderr?.trim() || lastFailure.stdout?.trim() || `railway ${plan.args.join(" ")} failed`);
2073
- }
2074
- }, railwayPhaseTimeoutMs(commandEnv, "deploy"), `Railway deploy phase timed out for ${cliDeployService.serviceName ?? cliDeployService.key}.`), { service: cliDeployService.key });
2075
- return {
2076
- service: deployService.key,
2077
- status: "deployed",
2078
- command: [plan.command, ...plan.args].join(" "),
2079
- cwd: plan.cwd,
2080
- publicBaseUrl: deployService.publicBaseUrl,
2081
- timings,
2082
- transport: {
2083
- railway: {
2084
- reconcile: "api",
2085
- deploy: "cli-fallback"
2086
- }
2087
- },
2088
- runtimeConfiguration: runtimeConfiguration ? {
2089
- updated: runtimeConfiguration.updated,
2090
- healthcheckPath: runtimeConfiguration.instance?.healthcheckPath ?? null,
2091
- healthcheckTimeoutSeconds: runtimeConfiguration.instance?.healthcheckTimeoutSeconds ?? null,
2092
- runtimeMode: runtimeConfiguration.instance?.runtimeMode ?? null,
2093
- volume: runtimeConfiguration.volume ?? null
2094
- } : null
2095
- };
1698
+ throw new Error(`Railway deployment for ${cliDeployService.serviceName ?? cliDeployService.serviceId ?? cliDeployService.key} requires Railway API deployment support. CLI deploy fallback has been removed.`);
2096
1699
  }
2097
1700
  export {
2098
1701
  buildRailwayCommandEnv,
2099
- buildRailwayDeployCommandEnv,
2100
- buildRailwayLinkCommandEnv,
2101
1702
  collectRailwayDeploymentStatusChecks,
2102
1703
  configuredRailwayScheduledJobs,
2103
1704
  configuredRailwayServices,
2104
1705
  deployRailwayService,
1706
+ deriveRailwayCapacityProviderRunnerServiceName,
1707
+ deriveRailwayCapacityProviderRunnerVolumeName,
2105
1708
  deriveRailwayOperationsRunnerServiceName,
2106
1709
  deriveRailwayOperationsRunnerVolumeName,
2107
1710
  deriveRailwayWorkerRunnerServiceName,
2108
1711
  deriveRailwayWorkerRunnerVolumeName,
2109
- ensureRailwayDatabaseServiceExists,
2110
- ensureRailwayEnvironmentExists,
2111
- ensureRailwayProjectContext,
2112
- ensureRailwayProjectExists,
2113
1712
  ensureRailwayScheduledJobs,
2114
- ensureRailwayServiceExists,
2115
1713
  findStaleTreeseedOperationsRunnerResources,
2116
- isRailwayTransientFailure,
2117
1714
  isTreeseedOperationsRunnerResourceName,
2118
1715
  isUsableRailwayToken,
2119
1716
  parseRailwayJsonOutput,
2120
- planRailwayServiceDeploy,
2121
- planRailwayServiceLink,
2122
1717
  railwayServiceRuntimeStartCommand,
2123
1718
  resolveRailwayAuthToken,
2124
1719
  resolveRailwayDeploymentProfile,
2125
- runRailway,
2126
- setRailwaySecretVariable,
2127
1720
  shouldRunRailwayPredeployBuild,
2128
1721
  validateRailwayDeployPrerequisites,
2129
1722
  validateRailwayServiceConfiguration,
2130
1723
  verifyRailwayManagedResources,
2131
1724
  verifyRailwayScheduledJobs,
2132
- waitForRailwayManagedDeploymentsSettled,
2133
- writeRailwayCliProjectConfig
1725
+ waitForRailwayManagedDeploymentsSettled
2134
1726
  };