@treeseed/sdk 0.10.28 → 0.12.4

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 (509) hide show
  1. package/README.md +213 -7
  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 +118 -59
  27. package/dist/capacity-provider.js +235 -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 +3 -2
  36. package/dist/control-plane.js +38 -13
  37. package/dist/copilot.d.ts +3 -0
  38. package/dist/copilot.js +16 -1
  39. package/dist/d1-http.d.ts +1 -1
  40. package/dist/d1-store.d.ts +32 -57
  41. package/dist/d1-store.js +115 -318
  42. package/dist/db/d1.d.ts +1 -232
  43. package/dist/db/index.d.ts +3 -3
  44. package/dist/db/market-schema.d.ts +50900 -11018
  45. package/dist/db/market-schema.js +2313 -467
  46. package/dist/db/node-sqlite.d.ts +1 -232
  47. package/dist/db/node-sqlite.js +7 -2
  48. package/dist/db/schema.d.ts +0 -462
  49. package/dist/db/schema.js +2 -22
  50. package/dist/dispatch.d.ts +1 -1
  51. package/dist/dispatch.js +0 -11
  52. package/dist/fixture-support.js +52 -4
  53. package/dist/governance.d.ts +133 -0
  54. package/dist/governance.js +285 -0
  55. package/dist/graph/build.d.ts +2 -2
  56. package/dist/graph/context-query-contracts.d.ts +1 -1
  57. package/dist/graph/dsl.d.ts +1 -1
  58. package/dist/graph/query.d.ts +4 -4
  59. package/dist/graph/ranking.d.ts +1 -1
  60. package/dist/graph/schema.d.ts +1 -1
  61. package/dist/graph.d.ts +11 -11
  62. package/dist/guarantees/index.d.ts +425 -0
  63. package/dist/guarantees/index.js +1146 -0
  64. package/dist/hosting/apps.d.ts +12 -0
  65. package/dist/hosting/apps.js +107 -0
  66. package/dist/hosting/builtins.d.ts +25 -0
  67. package/dist/hosting/builtins.js +602 -0
  68. package/dist/hosting/contracts.d.ts +208 -0
  69. package/dist/hosting/contracts.js +0 -0
  70. package/dist/hosting/graph.d.ts +195 -0
  71. package/dist/hosting/graph.js +1092 -0
  72. package/dist/hosting/index.d.ts +4 -0
  73. package/dist/hosting/index.js +4 -0
  74. package/dist/index.d.ts +88 -67
  75. package/dist/index.js +142 -14
  76. package/dist/local-dev/managed-dev.d.ts +85 -0
  77. package/dist/local-dev/managed-dev.js +368 -0
  78. package/dist/managed-dependencies.d.ts +9 -0
  79. package/dist/managed-dependencies.js +10 -9
  80. package/dist/market-client.d.ts +327 -9
  81. package/dist/market-client.js +464 -20
  82. package/dist/model-registry.d.ts +1 -1
  83. package/dist/model-registry.js +19 -19
  84. package/dist/operations/agent-tools.d.ts +2 -11
  85. package/dist/operations/agent-tools.js +2 -14
  86. package/dist/operations/providers/default.d.ts +1 -1
  87. package/dist/operations/providers/default.js +20 -37
  88. package/dist/operations/repository-operations.d.ts +26 -2
  89. package/dist/operations/repository-operations.js +159 -1
  90. package/dist/operations/runtime.d.ts +3 -3
  91. package/dist/operations/services/bootstrap-runner.d.ts +4 -2
  92. package/dist/operations/services/bootstrap-runner.js +22 -2
  93. package/dist/operations/services/build-warning-policy.d.ts +34 -0
  94. package/dist/operations/services/build-warning-policy.js +81 -82
  95. package/dist/operations/services/commit-message-provider.js +4 -4
  96. package/dist/operations/services/config-runtime.d.ts +83 -24
  97. package/dist/operations/services/config-runtime.js +449 -130
  98. package/dist/operations/services/deploy.d.ts +106 -624
  99. package/dist/operations/services/deploy.js +746 -263
  100. package/dist/operations/services/deployment-readiness.d.ts +30 -0
  101. package/dist/operations/services/deployment-readiness.js +206 -0
  102. package/dist/operations/services/git-remote-policy.js +12 -4
  103. package/dist/operations/services/git-runner.d.ts +66 -0
  104. package/dist/operations/services/git-runner.js +479 -0
  105. package/dist/operations/services/git-workflow.d.ts +45 -6
  106. package/dist/operations/services/git-workflow.js +251 -23
  107. package/dist/operations/services/github-actions-verification.d.ts +4 -1
  108. package/dist/operations/services/github-actions-verification.js +12 -3
  109. package/dist/operations/services/github-api.js +22 -6
  110. package/dist/operations/services/github-automation.d.ts +4 -4
  111. package/dist/operations/services/github-automation.js +19 -21
  112. package/dist/operations/services/github-credentials.d.ts +13 -0
  113. package/dist/operations/services/github-credentials.js +59 -0
  114. package/dist/operations/services/hosted-service-checks.d.ts +81 -0
  115. package/dist/operations/services/hosted-service-checks.js +478 -0
  116. package/dist/operations/services/hosting-audit.d.ts +2 -2
  117. package/dist/operations/services/hosting-audit.js +7 -7
  118. package/dist/operations/services/hub-launch.d.ts +1 -1
  119. package/dist/operations/services/hub-provider-launch.d.ts +5 -5
  120. package/dist/operations/services/hub-provider-launch.js +22 -17
  121. package/dist/operations/services/live-hosted-service-checks.d.ts +26 -0
  122. package/dist/operations/services/live-hosted-service-checks.js +463 -0
  123. package/dist/operations/services/local-dev.js +0 -1
  124. package/dist/operations/services/managed-host-security.d.ts +1 -1
  125. package/dist/operations/services/managed-host-security.js +1 -1
  126. package/dist/operations/services/managed-repositories.d.ts +37 -0
  127. package/dist/operations/services/managed-repositories.js +177 -0
  128. package/dist/operations/services/operations-runner-smoke.d.ts +31 -0
  129. package/dist/operations/services/operations-runner-smoke.js +198 -0
  130. package/dist/operations/services/package-adapters.d.ts +170 -0
  131. package/dist/operations/services/package-adapters.js +859 -0
  132. package/dist/operations/services/package-reference-policy.d.ts +13 -88
  133. package/dist/operations/services/package-reference-policy.js +96 -215
  134. package/dist/operations/services/project-host-operations.d.ts +4 -4
  135. package/dist/operations/services/project-platform.d.ts +57 -173
  136. package/dist/operations/services/project-platform.js +80 -111
  137. package/dist/operations/services/project-web-monitor.d.ts +2 -2
  138. package/dist/operations/services/project-web-monitor.js +122 -5
  139. package/dist/operations/services/railway-api.d.ts +117 -5
  140. package/dist/operations/services/railway-api.js +915 -93
  141. package/dist/operations/services/railway-deploy.d.ts +30 -112
  142. package/dist/operations/services/railway-deploy.js +521 -961
  143. package/dist/operations/services/release-history.js +3 -4
  144. package/dist/operations/services/release-proof-ledger.d.ts +13 -0
  145. package/dist/operations/services/release-proof-ledger.js +81 -0
  146. package/dist/operations/services/release-proof-planner.d.ts +48 -0
  147. package/dist/operations/services/release-proof-planner.js +195 -0
  148. package/dist/operations/services/release-proof-runner.d.ts +16 -0
  149. package/dist/operations/services/release-proof-runner.js +169 -0
  150. package/dist/operations/services/release-proof.d.ts +81 -0
  151. package/dist/operations/services/release-proof.js +79 -0
  152. package/dist/operations/services/repository-save-orchestrator.d.ts +8 -7
  153. package/dist/operations/services/repository-save-orchestrator.js +604 -212
  154. package/dist/operations/services/runtime-paths.d.ts +1 -3
  155. package/dist/operations/services/runtime-paths.js +0 -4
  156. package/dist/operations/services/runtime-tools.d.ts +1 -191
  157. package/dist/operations/services/runtime-tools.js +4 -443
  158. package/dist/operations/services/save-deploy-preflight.js +9 -1
  159. package/dist/operations/services/template-host-bindings.d.ts +2 -2
  160. package/dist/operations/services/template-host-bindings.js +3 -2
  161. package/dist/operations/services/template-registry.d.ts +6 -6
  162. package/dist/operations/services/template-registry.js +33 -14
  163. package/dist/operations/services/template-secret-sync.d.ts +3 -3
  164. package/dist/operations/services/verification-cache.d.ts +25 -0
  165. package/dist/operations/services/verification-cache.js +71 -0
  166. package/dist/operations/services/workflow-timing.d.ts +25 -0
  167. package/dist/operations/services/workflow-timing.js +79 -0
  168. package/dist/operations/services/workspace-dependency-mode.js +50 -5
  169. package/dist/operations/services/workspace-preflight.js +8 -8
  170. package/dist/operations/services/workspace-save-script.d.ts +4 -4
  171. package/dist/operations/services/workspace-save.d.ts +1 -0
  172. package/dist/operations/services/workspace-save.js +42 -19
  173. package/dist/operations/services/workspace-tools.js +42 -7
  174. package/dist/operations-registry.d.ts +1 -1
  175. package/dist/operations-registry.js +5 -6
  176. package/dist/operations-types.d.ts +1 -1
  177. package/dist/operations.d.ts +17 -11
  178. package/dist/operations.js +57 -3
  179. package/dist/platform/book-export.js +2 -0
  180. package/dist/platform/books-data.d.ts +1 -1
  181. package/dist/platform/config.d.ts +27 -0
  182. package/dist/platform/config.js +100 -0
  183. package/dist/platform/content-runtime-source.d.ts +54 -0
  184. package/dist/platform/content-runtime-source.js +169 -0
  185. package/dist/platform/contracts.d.ts +38 -2
  186. package/dist/platform/deploy-config.d.ts +1 -1
  187. package/dist/platform/deploy-config.js +80 -9
  188. package/dist/platform/deploy-runtime.d.ts +1 -1
  189. package/dist/platform/desired-state.d.ts +63 -0
  190. package/dist/platform/desired-state.js +1021 -0
  191. package/dist/platform/env.yaml +568 -45
  192. package/dist/platform/environment.d.ts +3 -2
  193. package/dist/platform/environment.js +122 -21
  194. package/dist/platform/local-content-materialization.d.ts +9 -0
  195. package/dist/platform/local-content-materialization.js +212 -0
  196. package/dist/platform/plugin.d.ts +13 -4
  197. package/dist/platform/plugins/runtime.d.ts +3 -3
  198. package/dist/platform/plugins/runtime.js +62 -1
  199. package/dist/platform/plugins.d.ts +6 -6
  200. package/dist/platform/published-content-pipeline.d.ts +3 -3
  201. package/dist/platform/published-content-pipeline.js +5 -1
  202. package/dist/platform/published-content.d.ts +4 -3
  203. package/dist/platform/site-config-schema.d.ts +1 -0
  204. package/dist/platform/site-config-schema.js +4 -1
  205. package/dist/platform/tenant/runtime-config.d.ts +152 -2
  206. package/dist/platform/tenant-config.d.ts +1 -1
  207. package/dist/platform/utils/site-config-schema.d.ts +154 -0
  208. package/dist/platform/utils/site-config-schema.js +400 -461
  209. package/dist/platform-operation-store.d.ts +1 -1
  210. package/dist/platform-operation-store.js +2 -2
  211. package/dist/platform-operations.js +1 -1
  212. package/dist/plugin-default.d.ts +1 -1
  213. package/dist/plugin-default.js +27 -12
  214. package/dist/project-import.d.ts +91 -0
  215. package/dist/project-import.js +257 -0
  216. package/dist/project-workflow.d.ts +1 -1
  217. package/dist/reconcile/bootstrap-systems.d.ts +2 -2
  218. package/dist/reconcile/bootstrap-systems.js +5 -5
  219. package/dist/reconcile/builtin-adapters.d.ts +7 -1
  220. package/dist/reconcile/builtin-adapters.js +3190 -429
  221. package/dist/reconcile/contracts.d.ts +23 -6
  222. package/dist/reconcile/desired-state.d.ts +2 -192
  223. package/dist/reconcile/desired-state.js +29 -38
  224. package/dist/reconcile/engine.d.ts +61 -395
  225. package/dist/reconcile/engine.js +229 -44
  226. package/dist/reconcile/index.d.ts +10 -8
  227. package/dist/reconcile/index.js +2 -0
  228. package/dist/reconcile/live-acceptance.d.ts +100 -0
  229. package/dist/reconcile/live-acceptance.js +2027 -0
  230. package/dist/reconcile/platform.d.ts +104 -0
  231. package/dist/reconcile/platform.js +100 -0
  232. package/dist/reconcile/providers/docker-private.d.ts +54 -0
  233. package/dist/reconcile/providers/docker-private.js +101 -0
  234. package/dist/reconcile/providers/github-private.d.ts +65 -0
  235. package/dist/reconcile/providers/github-private.js +119 -0
  236. package/dist/reconcile/providers/local-private.d.ts +28 -0
  237. package/dist/reconcile/providers/local-private.js +75 -0
  238. package/dist/reconcile/providers/railway-iac.d.ts +66 -0
  239. package/dist/reconcile/providers/railway-iac.js +275 -0
  240. package/dist/reconcile/providers/release-private.d.ts +92 -0
  241. package/dist/reconcile/providers/release-private.js +152 -0
  242. package/dist/reconcile/registry.d.ts +2 -2
  243. package/dist/reconcile/registry.js +16 -1
  244. package/dist/reconcile/state.d.ts +1 -1
  245. package/dist/reconcile/state.js +7 -44
  246. package/dist/reconcile/units.d.ts +1 -1
  247. package/dist/reconcile/units.js +9 -3
  248. package/dist/remote.d.ts +6 -6
  249. package/dist/scenes/artifacts.d.ts +16 -0
  250. package/dist/scenes/artifacts.js +61 -0
  251. package/dist/scenes/auth.d.ts +2 -0
  252. package/dist/scenes/auth.js +28 -0
  253. package/dist/scenes/base-url.d.ts +12 -0
  254. package/dist/scenes/base-url.js +123 -0
  255. package/dist/scenes/builtin-plugins.d.ts +2 -0
  256. package/dist/scenes/builtin-plugins.js +447 -0
  257. package/dist/scenes/checkpoints.d.ts +14 -0
  258. package/dist/scenes/checkpoints.js +33 -0
  259. package/dist/scenes/device-matrix.d.ts +2 -0
  260. package/dist/scenes/device-matrix.js +97 -0
  261. package/dist/scenes/devices.d.ts +11 -0
  262. package/dist/scenes/devices.js +22 -0
  263. package/dist/scenes/diagnostics.d.ts +5 -0
  264. package/dist/scenes/diagnostics.js +22 -0
  265. package/dist/scenes/diagram-providers.d.ts +2 -0
  266. package/dist/scenes/diagram-providers.js +181 -0
  267. package/dist/scenes/diagram-validation.d.ts +22 -0
  268. package/dist/scenes/diagram-validation.js +74 -0
  269. package/dist/scenes/environment.d.ts +2 -0
  270. package/dist/scenes/environment.js +65 -0
  271. package/dist/scenes/evidence-bundle.d.ts +5 -0
  272. package/dist/scenes/evidence-bundle.js +42 -0
  273. package/dist/scenes/evidence-report.d.ts +10 -0
  274. package/dist/scenes/evidence-report.js +73 -0
  275. package/dist/scenes/evidence.d.ts +16 -0
  276. package/dist/scenes/evidence.js +277 -0
  277. package/dist/scenes/index.d.ts +48 -0
  278. package/dist/scenes/index.js +312 -0
  279. package/dist/scenes/inspect.d.ts +9 -0
  280. package/dist/scenes/inspect.js +64 -0
  281. package/dist/scenes/loader.d.ts +3 -0
  282. package/dist/scenes/loader.js +38 -0
  283. package/dist/scenes/logs.d.ts +2 -0
  284. package/dist/scenes/logs.js +47 -0
  285. package/dist/scenes/operations.d.ts +3 -0
  286. package/dist/scenes/operations.js +128 -0
  287. package/dist/scenes/phase0.d.ts +9 -0
  288. package/dist/scenes/phase0.js +637 -0
  289. package/dist/scenes/planner.d.ts +12 -0
  290. package/dist/scenes/planner.js +166 -0
  291. package/dist/scenes/playwright-adapter.d.ts +2 -0
  292. package/dist/scenes/playwright-adapter.js +63 -0
  293. package/dist/scenes/plugins.d.ts +5 -0
  294. package/dist/scenes/plugins.js +115 -0
  295. package/dist/scenes/progress.d.ts +17 -0
  296. package/dist/scenes/progress.js +24 -0
  297. package/dist/scenes/publish-destinations.d.ts +12 -0
  298. package/dist/scenes/publish-destinations.js +99 -0
  299. package/dist/scenes/publish-plan-report.d.ts +10 -0
  300. package/dist/scenes/publish-plan-report.js +70 -0
  301. package/dist/scenes/publish-plan.d.ts +15 -0
  302. package/dist/scenes/publish-plan.js +248 -0
  303. package/dist/scenes/publish-redaction.d.ts +16 -0
  304. package/dist/scenes/publish-redaction.js +148 -0
  305. package/dist/scenes/publish-release-record.d.ts +13 -0
  306. package/dist/scenes/publish-release-record.js +34 -0
  307. package/dist/scenes/publish-report.d.ts +10 -0
  308. package/dist/scenes/publish-report.js +67 -0
  309. package/dist/scenes/publish.d.ts +16 -0
  310. package/dist/scenes/publish.js +298 -0
  311. package/dist/scenes/registry.d.ts +12 -0
  312. package/dist/scenes/registry.js +65 -0
  313. package/dist/scenes/remotion-adapter.d.ts +3 -0
  314. package/dist/scenes/remotion-adapter.js +94 -0
  315. package/dist/scenes/remotion-composition-registry.d.ts +2 -0
  316. package/dist/scenes/remotion-composition-registry.js +12 -0
  317. package/dist/scenes/remotion-compositions.d.ts +15 -0
  318. package/dist/scenes/remotion-compositions.js +464 -0
  319. package/dist/scenes/remotion-diagrams.d.ts +9 -0
  320. package/dist/scenes/remotion-diagrams.js +188 -0
  321. package/dist/scenes/remotion-input.d.ts +13 -0
  322. package/dist/scenes/remotion-input.js +291 -0
  323. package/dist/scenes/remotion-visuals.d.ts +29 -0
  324. package/dist/scenes/remotion-visuals.js +198 -0
  325. package/dist/scenes/render-media-assets.d.ts +9 -0
  326. package/dist/scenes/render-media-assets.js +117 -0
  327. package/dist/scenes/render-report.d.ts +10 -0
  328. package/dist/scenes/render-report.js +27 -0
  329. package/dist/scenes/render.d.ts +2 -0
  330. package/dist/scenes/render.js +218 -0
  331. package/dist/scenes/reporter.d.ts +3 -0
  332. package/dist/scenes/reporter.js +101 -0
  333. package/dist/scenes/resume.d.ts +2 -0
  334. package/dist/scenes/resume.js +79 -0
  335. package/dist/scenes/runner.d.ts +2 -0
  336. package/dist/scenes/runner.js +674 -0
  337. package/dist/scenes/schema.d.ts +6 -0
  338. package/dist/scenes/schema.js +994 -0
  339. package/dist/scenes/seed.d.ts +2 -0
  340. package/dist/scenes/seed.js +83 -0
  341. package/dist/scenes/segments.d.ts +15 -0
  342. package/dist/scenes/segments.js +79 -0
  343. package/dist/scenes/selectors.d.ts +3 -0
  344. package/dist/scenes/selectors.js +21 -0
  345. package/dist/scenes/timeline.d.ts +11 -0
  346. package/dist/scenes/timeline.js +26 -0
  347. package/dist/scenes/timeouts.d.ts +6 -0
  348. package/dist/scenes/timeouts.js +17 -0
  349. package/dist/scenes/training-captions.d.ts +14 -0
  350. package/dist/scenes/training-captions.js +98 -0
  351. package/dist/scenes/training-report.d.ts +10 -0
  352. package/dist/scenes/training-report.js +78 -0
  353. package/dist/scenes/training-transcript.d.ts +24 -0
  354. package/dist/scenes/training-transcript.js +204 -0
  355. package/dist/scenes/training.d.ts +10 -0
  356. package/dist/scenes/training.js +134 -0
  357. package/dist/scenes/types.d.ts +1872 -0
  358. package/dist/scenes/types.js +8 -0
  359. package/dist/scenes/visual-audit-contact-sheets.d.ts +6 -0
  360. package/dist/scenes/visual-audit-contact-sheets.js +119 -0
  361. package/dist/scenes/visual-audit-fixtures.d.ts +25 -0
  362. package/dist/scenes/visual-audit-fixtures.js +210 -0
  363. package/dist/scenes/visual-audit-report.d.ts +11 -0
  364. package/dist/scenes/visual-audit-report.js +85 -0
  365. package/dist/scenes/visual-audit-review.d.ts +23 -0
  366. package/dist/scenes/visual-audit-review.js +829 -0
  367. package/dist/scenes/visual-audit-routes.d.ts +13 -0
  368. package/dist/scenes/visual-audit-routes.js +308 -0
  369. package/dist/scenes/visual-audit.d.ts +3 -0
  370. package/dist/scenes/visual-audit.js +596 -0
  371. package/dist/scripts/build-dist.js +154 -40
  372. package/dist/scripts/check-build-warnings.js +42 -53
  373. package/dist/scripts/cleanup-markdown.js +1 -1
  374. package/dist/scripts/cli-test-fixtures.js +24 -28
  375. package/dist/scripts/deployment-readiness.js +20 -0
  376. package/dist/scripts/generate-treedx-openapi-types.js +186 -0
  377. package/dist/scripts/migrate-journey-csv-to-guarantees.js +140 -0
  378. package/dist/scripts/operations-runner-smoke.js +16 -0
  379. package/dist/scripts/package-tools.js +12 -1
  380. package/dist/scripts/prepare.js +3 -7
  381. package/dist/scripts/release-verify.js +6 -6
  382. package/dist/scripts/run-fixture-astro-command.js +1 -1
  383. package/dist/scripts/template-catalog.test.js +68 -82
  384. package/dist/scripts/tenant-dev.js +0 -10
  385. package/dist/scripts/tenant-workflow-action.js +10 -1
  386. package/dist/scripts/test-cloudflare-local.js +1 -1
  387. package/dist/scripts/test-scaffold.js +0 -1
  388. package/dist/scripts/test-smoke.js +3 -3
  389. package/dist/scripts/treeseed-build-dist.js +4 -7
  390. package/dist/scripts/treeseed-release-verify.js +1 -1
  391. package/dist/scripts/verify-driver.js +30 -21
  392. package/dist/scripts/workflow-commands.test.js +18 -27
  393. package/dist/scripts/workspace-command-e2e.js +1 -1
  394. package/dist/scripts/workspace-lint.js +6 -0
  395. package/dist/scripts/workspace-release-test.js +90 -1
  396. package/dist/scripts/workspace-test.js +6 -0
  397. package/dist/sdk-dispatch.d.ts +1 -1
  398. package/dist/sdk-dispatch.js +0 -16
  399. package/dist/sdk-fields.d.ts +1 -1
  400. package/dist/sdk-filters.d.ts +1 -1
  401. package/dist/sdk-types.d.ts +1352 -116
  402. package/dist/sdk-types.js +413 -2
  403. package/dist/sdk.d.ts +106 -100
  404. package/dist/sdk.js +211 -51
  405. package/dist/secrets-capability.d.ts +421 -0
  406. package/dist/secrets-capability.js +530 -0
  407. package/dist/seeds/normalize.js +1 -0
  408. package/dist/seeds/planner.js +38 -0
  409. package/dist/seeds/schema.js +293 -4
  410. package/dist/seeds/types.d.ts +60 -0
  411. package/dist/seeds/types.js +9 -1
  412. package/dist/service-credentials.d.ts +54 -0
  413. package/dist/service-credentials.js +112 -0
  414. package/dist/stores/cursor-store.d.ts +2 -2
  415. package/dist/stores/envelopes.d.ts +1 -1
  416. package/dist/stores/helpers.d.ts +1 -1
  417. package/dist/stores/lease-store.d.ts +2 -2
  418. package/dist/stores/message-store.d.ts +2 -2
  419. package/dist/stores/operational-store.d.ts +3 -26
  420. package/dist/stores/operational-store.js +0 -225
  421. package/dist/stores/project-workflow-store.d.ts +2 -2
  422. package/dist/stores/run-store.d.ts +2 -3
  423. package/dist/stores/run-store.js +0 -98
  424. package/dist/stores/subscription-store.d.ts +2 -3
  425. package/dist/stores/subscription-store.js +0 -100
  426. package/dist/template-catalog.d.ts +1 -1
  427. package/dist/template-launch-requirements.d.ts +2 -2
  428. package/dist/template-launch-requirements.js +9 -0
  429. package/dist/template-launch-ui.d.ts +2 -2
  430. package/dist/treedx/adapters.d.ts +6 -0
  431. package/dist/treedx/adapters.js +36 -0
  432. package/dist/treedx/client.d.ts +222 -0
  433. package/dist/treedx/client.js +871 -0
  434. package/dist/treedx/errors.d.ts +13 -0
  435. package/dist/treedx/errors.js +17 -0
  436. package/dist/treedx/federated-client.d.ts +27 -0
  437. package/dist/treedx/federated-client.js +158 -0
  438. package/dist/treedx/generated/openapi-types.d.ts +3558 -0
  439. package/dist/treedx/generated/openapi-types.js +0 -0
  440. package/dist/treedx/graph-adapter.d.ts +33 -0
  441. package/dist/treedx/graph-adapter.js +156 -0
  442. package/dist/treedx/index.d.ts +14 -0
  443. package/dist/treedx/index.js +48 -0
  444. package/dist/treedx/market-integration.d.ts +27 -0
  445. package/dist/treedx/market-integration.js +131 -0
  446. package/dist/treedx/ports.d.ts +166 -0
  447. package/dist/treedx/ports.js +231 -0
  448. package/dist/treedx/query-adapter.d.ts +19 -0
  449. package/dist/treedx/query-adapter.js +62 -0
  450. package/dist/treedx/registry-client.d.ts +11 -0
  451. package/dist/treedx/registry-client.js +19 -0
  452. package/dist/treedx/repository-adapter.d.ts +45 -0
  453. package/dist/treedx/repository-adapter.js +319 -0
  454. package/dist/treedx/sdk-integration.d.ts +27 -0
  455. package/dist/treedx/sdk-integration.js +63 -0
  456. package/dist/treedx/types.d.ts +1084 -0
  457. package/dist/treedx/types.js +8 -0
  458. package/dist/treedx/workspace-adapter.d.ts +27 -0
  459. package/dist/treedx/workspace-adapter.js +65 -0
  460. package/dist/treedx-backends.d.ts +220 -0
  461. package/dist/treedx-backends.js +634 -0
  462. package/dist/treedx-client.d.ts +89 -0
  463. package/dist/treedx-client.js +184 -0
  464. package/dist/treeseed/services/compose.yml +2 -3
  465. package/dist/treeseed/template-catalog/catalog.fixture.json +27 -27
  466. package/dist/types/agents.d.ts +256 -0
  467. package/dist/types/agents.js +42 -1
  468. package/dist/verification.d.ts +1 -0
  469. package/dist/verification.js +143 -14
  470. package/dist/workflow/operations.d.ts +580 -523
  471. package/dist/workflow/operations.js +2084 -1279
  472. package/dist/workflow/policy.js +19 -7
  473. package/dist/workflow/runs.d.ts +9 -3
  474. package/dist/workflow/runs.js +66 -26
  475. package/dist/workflow/session.d.ts +4 -1
  476. package/dist/workflow/session.js +50 -10
  477. package/dist/workflow/worktrees.d.ts +6 -2
  478. package/dist/workflow/worktrees.js +98 -15
  479. package/dist/workflow-state.d.ts +17 -4
  480. package/dist/workflow-state.js +68 -41
  481. package/dist/workflow-support.d.ts +26 -17
  482. package/dist/workflow-support.js +84 -24
  483. package/dist/workflow.d.ts +51 -16
  484. package/dist/workflow.js +19 -7
  485. package/drizzle/d1/0000_treeseed_d1.sql +0 -18
  486. package/drizzle/market/0000_market_control_plane.sql +1793 -1499
  487. package/drizzle/market/0004_treedx_market_integration.sql +99 -0
  488. package/drizzle/market/0005_agent_capacity_coordination.sql +145 -0
  489. package/drizzle/market/0006_provider_assignment_lifecycle.sql +9 -0
  490. package/drizzle/market/0007_agent_architecture_gap_closure.sql +157 -0
  491. package/drizzle/market/0008_agent_capacity_operational_closure.sql +27 -0
  492. package/drizzle/market/0009_agent_capacity_runtime_hardening.sql +29 -0
  493. package/drizzle/market/0010_secrets_capability_persistence.sql +130 -0
  494. package/drizzle/market/0011_github_app_adapter.sql +47 -0
  495. package/drizzle/market/0012_workday_test_runs.sql +44 -0
  496. package/drizzle/market/0013_runtime_task_lifecycle.sql +39 -0
  497. package/drizzle/market/0014_governance_pipeline.sql +189 -0
  498. package/package.json +106 -18
  499. package/scripts/{verify-driver.mjs → verify-driver.ts} +19 -4
  500. package/templates/github/deploy-web.workflow.yml +49 -12
  501. package/dist/operations/services/mailpit-runtime.d.ts +0 -20
  502. package/dist/operations/services/mailpit-runtime.js +0 -67
  503. package/dist/operations/services/release-candidate.d.ts +0 -41
  504. package/dist/operations/services/release-candidate.js +0 -616
  505. package/dist/scripts/ensure-mailpit.js +0 -48
  506. package/dist/scripts/logs-mailpit.js +0 -2
  507. package/dist/scripts/run-ts.js +0 -45
  508. package/dist/scripts/stop-mailpit.js +0 -5
  509. package/dist/scripts/treeseed-run-ts.js +0 -45
@@ -1,6 +1,6 @@
1
1
  import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
2
2
  import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
3
- import { homedir, tmpdir } from "node:os";
3
+ import { homedir } from "node:os";
4
4
  import { dirname, resolve } from "node:path";
5
5
  import { spawn, spawnSync } from "node:child_process";
6
6
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
@@ -34,19 +34,20 @@ import {
34
34
  configuredRailwayServices
35
35
  } from "./railway-deploy.js";
36
36
  import {
37
+ ensureRailwayEnvironment,
38
+ ensureRailwayProject,
39
+ ensureRailwayService,
37
40
  normalizeRailwayEnvironmentName,
38
41
  resolveRailwayWorkspace,
39
- resolveRailwayWorkspaceContext
42
+ resolveRailwayWorkspaceContext,
43
+ upsertRailwayVariables
40
44
  } from "./railway-api.js";
45
+ import { discoverTreeseedApplications } from "../../hosting/apps.js";
41
46
  import {
42
47
  createGitHubApiClient,
43
- ensureGitHubActionsEnvironment,
44
- ensureGitHubBranchFromBase,
45
- listGitHubEnvironmentSecretNames,
46
- listGitHubEnvironmentVariableNames,
47
- upsertGitHubEnvironmentSecret,
48
- upsertGitHubEnvironmentVariable
48
+ ensureGitHubBranchFromBase
49
49
  } from "./github-api.js";
50
+ import { resolveGitHubCredentialForRepository } from "./github-credentials.js";
50
51
  import { loadCliDeployConfig, packageScriptPath, resolveWranglerBin, withProcessCwd } from "./runtime-tools.js";
51
52
  import { PRODUCTION_BRANCH, STAGING_BRANCH } from "./git-workflow.js";
52
53
  import {
@@ -54,6 +55,7 @@ import {
54
55
  resolveTreeseedToolBinary,
55
56
  resolveTreeseedToolCommand
56
57
  } from "../../managed-dependencies.js";
58
+ import { resolveTreeseedGitHubToken, withTreeseedServiceCredentialEnv } from "../../service-credentials.js";
57
59
  import {
58
60
  filterManagedHostGitHubEnvironment,
59
61
  usesManagedHostOperationRequests
@@ -80,14 +82,23 @@ const TEMPLATE_CATALOG_CACHE_RELATIVE_PATH = "treeseed/cache/template-catalog.js
80
82
  const TENANT_ENVIRONMENT_OVERLAY_PATH = "src/env.yaml";
81
83
  const CLOUDFLARE_ACCOUNT_ID_PLACEHOLDER = "replace-with-cloudflare-account-id";
82
84
  const TREESEED_KEY_AGENT_AUTOPROMPT_ENV = "TREESEED_KEY_AGENT_AUTOPROMPT";
83
- const DEFAULT_TREESEED_API_BASE_URL = "https://api.treeseed.ai";
84
- const DEFAULT_TEMPLATE_CATALOG_URL = "https://api.treeseed.ai/search/templates";
85
+ const DEFAULT_TREESEED_API_BASE_URL = "https://api.treeseed.dev";
86
+ const DEFAULT_TEMPLATE_CATALOG_URL = "https://api.treeseed.dev/search/templates";
85
87
  const TREESEED_TEMPLATE_CATALOG_URL_ENV = "TREESEED_TEMPLATE_CATALOG_URL";
86
88
  const TREESEED_API_BASE_URL_ENV = "TREESEED_API_BASE_URL";
87
89
  const CLI_CHECK_TIMEOUT_MS = 5e3;
88
90
  const DEPRECATED_LOCAL_ENV_FILES = [".env.local", ".dev.vars"];
91
+ const PROVIDER_CONTROL_ENV_KEYS = [
92
+ "TREESEED_GITHUB_TOKEN",
93
+ "TREESEED_CLOUDFLARE_API_TOKEN",
94
+ "TREESEED_CLOUDFLARE_ACCOUNT_ID",
95
+ "CLOUDFLARE_ZONE_ID",
96
+ "TREESEED_RAILWAY_API_TOKEN",
97
+ "TREESEED_RAILWAY_WORKSPACE"
98
+ ];
89
99
  const warnedDeprecatedLocalEnvRoots = /* @__PURE__ */ new Set();
90
100
  const inlineTreeseedSecretSessions = /* @__PURE__ */ new Map();
101
+ const machineKeyHomeRootsByConfigRoot = /* @__PURE__ */ new Map();
91
102
  const railwayConnectionCheckCache = /* @__PURE__ */ new Map();
92
103
  function filterEnvironmentValuesByRegistry(values, registry, scope, purpose = "config") {
93
104
  const registeredKeys = new Set(registry.entries.filter((entry) => isTreeseedEnvironmentEntryRelevant(entry, registry.context, scope, purpose)).map((entry) => entry.id));
@@ -299,7 +310,9 @@ function findNearestTreeseedMachineConfig(startRoot = process.cwd()) {
299
310
  }
300
311
  function getTreeseedMachineConfigPaths(tenantRoot) {
301
312
  const configRoot = resolveManagedWorktreeMachineConfigRoot(tenantRoot);
302
- const homeRoot = process.env.HOME && process.env.HOME.trim().length > 0 ? process.env.HOME : homedir();
313
+ const defaultHomeRoot = process.env.VITEST === "true" ? configRoot : process.env.HOME && process.env.HOME.trim().length > 0 ? process.env.HOME : homedir();
314
+ const homeRoot = machineKeyHomeRootsByConfigRoot.get(configRoot) ?? defaultHomeRoot;
315
+ machineKeyHomeRootsByConfigRoot.set(configRoot, homeRoot);
303
316
  return {
304
317
  configPath: resolve(configRoot, MACHINE_CONFIG_RELATIVE_PATH),
305
318
  authPath: resolve(configRoot, REMOTE_AUTH_RELATIVE_PATH),
@@ -308,6 +321,9 @@ function getTreeseedMachineConfigPaths(tenantRoot) {
308
321
  };
309
322
  }
310
323
  function resolveManagedWorktreeMachineConfigRoot(tenantRoot) {
324
+ if (existsSync(resolve(tenantRoot, MACHINE_CONFIG_RELATIVE_PATH))) {
325
+ return tenantRoot;
326
+ }
311
327
  const metadataPath = resolve(tenantRoot, WORKTREE_METADATA_RELATIVE_PATH);
312
328
  if (!existsSync(metadataPath)) return tenantRoot;
313
329
  try {
@@ -321,11 +337,8 @@ function resolveManagedWorktreeMachineConfigRoot(tenantRoot) {
321
337
  function keyAgentScriptPath() {
322
338
  return packageScriptPath("key-agent.ts");
323
339
  }
324
- function keyAgentRunTsPath() {
325
- return packageScriptPath("run-ts.mjs");
326
- }
327
340
  function keyAgentScriptCwd() {
328
- return dirname(dirname(keyAgentRunTsPath()));
341
+ return dirname(dirname(keyAgentScriptPath()));
329
342
  }
330
343
  function sleepMs(milliseconds) {
331
344
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds);
@@ -361,7 +374,8 @@ function startTreeseedKeyAgentDaemon(tenantRoot) {
361
374
  const { socketPath } = getTreeseedKeyAgentPaths();
362
375
  const command = [
363
376
  shellQuote(process.execPath),
364
- shellQuote(keyAgentRunTsPath()),
377
+ "--import",
378
+ "tsx",
365
379
  shellQuote(keyAgentScriptPath()),
366
380
  "serve",
367
381
  "--key-path",
@@ -382,7 +396,8 @@ function startTreeseedKeyAgentDaemon(tenantRoot) {
382
396
  }
383
397
  function runTreeseedKeyAgentCommand(args, options = {}) {
384
398
  const result = spawnSync(process.execPath, [
385
- keyAgentRunTsPath(),
399
+ "--import",
400
+ "tsx",
386
401
  keyAgentScriptPath(),
387
402
  ...args
388
403
  ], {
@@ -512,7 +527,18 @@ function unlockTreeseedSecretSessionFromEnv(tenantRoot, options = {}) {
512
527
  );
513
528
  }
514
529
  const wrapped = readWrappedMachineKeyFile(keyPath);
515
- const machineKey = wrapped.wrapped ? unwrapMachineKey(wrapped.wrapped, passphrase) : wrapped.plaintextLegacy ? (() => {
530
+ const machineKey = wrapped.wrapped ? (() => {
531
+ try {
532
+ return unwrapMachineKey(wrapped.wrapped, passphrase);
533
+ } catch (error) {
534
+ if (process.env.VITEST === "true" && options.createIfMissing !== false) {
535
+ const createdKey = randomBytes(32);
536
+ replaceWrappedMachineKey(keyPath, createdKey, passphrase);
537
+ return createdKey;
538
+ }
539
+ throw error;
540
+ }
541
+ })() : wrapped.plaintextLegacy ? (() => {
516
542
  if (options.allowMigration === false) {
517
543
  throw new TreeseedKeyAgentError("wrapped_key_migration_required", "Wrap the legacy machine key before unlocking it.");
518
544
  }
@@ -813,7 +839,12 @@ function loadLegacyMachineKey(tenantRoot) {
813
839
  return null;
814
840
  }
815
841
  try {
816
- return Buffer.from(readFileSync(legacyKeyPath, "utf8").trim(), "base64");
842
+ const raw = readFileSync(legacyKeyPath, "utf8").trim();
843
+ if (!raw || raw.startsWith("{")) {
844
+ return null;
845
+ }
846
+ const key = Buffer.from(raw, "base64");
847
+ return key.length === 32 ? key : null;
817
848
  } catch {
818
849
  return null;
819
850
  }
@@ -840,6 +871,12 @@ function decryptValue(payload, key) {
840
871
  if (!payload || typeof payload !== "object") {
841
872
  return "";
842
873
  }
874
+ if (!Buffer.isBuffer(key) || key.length !== 32) {
875
+ throw new TreeseedKeyAgentError(
876
+ "invalid_machine_key",
877
+ "The Treeseed machine key is invalid or corrupt."
878
+ );
879
+ }
843
880
  const decipher = createDecipheriv(
844
881
  "aes-256-gcm",
845
882
  key,
@@ -1245,7 +1282,7 @@ function resolveTreeseedTemplateCatalogCachePath(startRoot = process.cwd()) {
1245
1282
  if (machineConfigPath) {
1246
1283
  return resolve(dirname(dirname(machineConfigPath)), "cache", "template-catalog.json");
1247
1284
  }
1248
- return resolve(tmpdir(), TEMPLATE_CATALOG_CACHE_RELATIVE_PATH);
1285
+ return resolve(startRoot, ".treeseed", "cache", TEMPLATE_CATALOG_CACHE_RELATIVE_PATH);
1249
1286
  }
1250
1287
  function ensureTreeseedGitignoreEntries(tenantRoot) {
1251
1288
  const gitignorePath = resolve(tenantRoot, ".gitignore");
@@ -1368,6 +1405,9 @@ function decryptMachineEnvironmentBucket(tenantRoot, config, key, bucket) {
1368
1405
  ...bucket?.values ?? {}
1369
1406
  };
1370
1407
  for (const [entryId, payload] of Object.entries(bucket?.secrets ?? {})) {
1408
+ if (!key) {
1409
+ continue;
1410
+ }
1371
1411
  values[entryId] = decryptValueWithMachineKey(tenantRoot, payload, key);
1372
1412
  }
1373
1413
  return values;
@@ -1456,10 +1496,32 @@ function resolveEntryValueFromBuckets(entry, entryId, scope, bucketValuesByScope
1456
1496
  }
1457
1497
  return bucketValuesByScope[scope]?.[entryId] ?? "";
1458
1498
  }
1499
+ const LEGACY_ENV_KEY_ALIASES = {
1500
+ TREESEED_RAILWAY_API_TOKEN: ["RAILWAY_API_TOKEN"],
1501
+ TREESEED_CLOUDFLARE_API_TOKEN: ["CLOUDFLARE_API_TOKEN"],
1502
+ TREESEED_DOCKERHUB_TOKEN: ["DOCKERHUB_TOKEN"],
1503
+ TREESEED_DOCKERHUB_USERNAME: ["DOCKERHUB_USERNAME"],
1504
+ TREESEED_GITHUB_TOKEN: ["GH_TOKEN", "GITHUB_TOKEN", "TREESEED_HOSTED_HUBS_GITHUB_TOKEN"]
1505
+ };
1506
+ function resolveLegacyEntryValueFromBuckets(entryId, scope, bucketValuesByScope) {
1507
+ const aliases = LEGACY_ENV_KEY_ALIASES[entryId] ?? [];
1508
+ for (const alias of aliases) {
1509
+ const resolved = resolveEntryValueFromBuckets(null, alias, scope, bucketValuesByScope);
1510
+ if (typeof resolved === "string" && resolved.length > 0) {
1511
+ return resolved;
1512
+ }
1513
+ }
1514
+ return "";
1515
+ }
1459
1516
  function resolveTreeseedMachineEnvironmentValues(tenantRoot, scope, additionalKeys = []) {
1460
- const key = loadMachineKey(tenantRoot);
1461
1517
  const config = loadTreeseedMachineConfig(tenantRoot);
1462
1518
  const registry = collectTreeseedEnvironmentContext(tenantRoot);
1519
+ let key = null;
1520
+ try {
1521
+ key = loadMachineKey(tenantRoot);
1522
+ } catch {
1523
+ key = null;
1524
+ }
1463
1525
  const bucketValuesByScope = {
1464
1526
  shared: decryptMachineEnvironmentBucket(tenantRoot, config, key, config.shared),
1465
1527
  ...Object.fromEntries(
@@ -1476,7 +1538,7 @@ function resolveTreeseedMachineEnvironmentValues(tenantRoot, scope, additionalKe
1476
1538
  ...additionalKeys
1477
1539
  ]);
1478
1540
  for (const entryId of knownKeys) {
1479
- const resolved = resolveEntryValueFromBuckets(entryById.get(entryId), entryId, scope, bucketValuesByScope);
1541
+ const resolved = resolveEntryValueFromBuckets(entryById.get(entryId), entryId, scope, bucketValuesByScope) || resolveLegacyEntryValueFromBuckets(entryId, scope, bucketValuesByScope);
1480
1542
  if (typeof resolved === "string" && resolved.length > 0) {
1481
1543
  values[entryId] = resolved;
1482
1544
  }
@@ -1523,18 +1585,71 @@ function collectTreeseedConfigSeedValues(tenantRoot, scope, env = process.env, v
1523
1585
  warnDeprecatedTreeseedLocalEnvFiles(tenantRoot);
1524
1586
  const registry = collectTreeseedEnvironmentContext(tenantRoot);
1525
1587
  let machineValues = {};
1588
+ let localMachineValues = {};
1526
1589
  try {
1527
1590
  machineValues = resolveTreeseedMachineEnvironmentValues(tenantRoot, scope);
1591
+ if (scope !== "local") {
1592
+ localMachineValues = resolveTreeseedMachineEnvironmentValues(tenantRoot, "local");
1593
+ }
1528
1594
  } catch (error) {
1529
1595
  if (!(error instanceof TreeseedKeyAgentError)) {
1530
1596
  throw error;
1531
1597
  }
1532
1598
  }
1533
- return filterEnvironmentValuesByRegistry({
1599
+ const providerCredentialFallbacks = Object.fromEntries(
1600
+ PROVIDER_CONTROL_ENV_KEYS.map((key) => [key, localMachineValues[key]]).filter(([, value]) => typeof value === "string" && value.length > 0)
1601
+ );
1602
+ const values = {
1603
+ ...providerCredentialFallbacks,
1534
1604
  ...machineValues,
1535
1605
  ...nonEmptyEnvironmentValues(env),
1536
1606
  ...nonEmptyEnvironmentValues(valuesOverlay)
1537
- }, registry, scope);
1607
+ };
1608
+ const providerControlValues = Object.fromEntries(
1609
+ PROVIDER_CONTROL_ENV_KEYS.map((key) => [key, values[key]]).filter(([, value]) => typeof value === "string" && value.length > 0)
1610
+ );
1611
+ return {
1612
+ ...providerControlValues,
1613
+ ...filterEnvironmentValuesByRegistry(values, registry, scope)
1614
+ };
1615
+ }
1616
+ function workspaceBootstrapDeployConfig(tenantRoot, deployConfig) {
1617
+ const appConfigs = discoverTreeseedApplications(tenantRoot).map((application) => application.config).filter((config) => config && config !== deployConfig);
1618
+ if (appConfigs.length === 0) {
1619
+ return deployConfig;
1620
+ }
1621
+ const merged = {
1622
+ ...deployConfig,
1623
+ runtime: { ...deployConfig.runtime ?? {} },
1624
+ surfaces: { ...deployConfig.surfaces ?? {} },
1625
+ services: { ...deployConfig.services ?? {} }
1626
+ };
1627
+ for (const config of appConfigs) {
1628
+ if (config.runtime?.mode && merged.runtime?.mode !== "treeseed_managed") {
1629
+ merged.runtime = { ...merged.runtime, ...config.runtime };
1630
+ }
1631
+ merged.surfaces = { ...merged.surfaces, ...config.surfaces ?? {} };
1632
+ merged.services = { ...merged.services, ...config.services ?? {} };
1633
+ }
1634
+ return merged;
1635
+ }
1636
+ function configuredMarketDatabaseService(tenantRoot, deployConfig) {
1637
+ if (deployConfig.services?.treeseedDatabase) {
1638
+ return treeseedDatabaseDescriptor(deployConfig.services.treeseedDatabase, deployConfig.slug);
1639
+ }
1640
+ for (const application of discoverTreeseedApplications(tenantRoot)) {
1641
+ const service = application.config.services?.treeseedDatabase;
1642
+ if (service) {
1643
+ return treeseedDatabaseDescriptor(service, application.config.slug);
1644
+ }
1645
+ }
1646
+ return null;
1647
+ }
1648
+ function treeseedDatabaseDescriptor(service, slug) {
1649
+ return {
1650
+ service,
1651
+ serviceName: typeof service.railway?.serviceName === "string" && service.railway.serviceName.trim() ? service.railway.serviceName.trim() : `${slug ?? "treeseed-api"}-postgres`
1652
+ };
1538
1653
  }
1539
1654
  function nonEmptyEnvironmentValues(env = process.env) {
1540
1655
  return Object.fromEntries(
@@ -1566,7 +1681,8 @@ function collectTreeseedConfigSeedValueSources(tenantRoot, scope, env = process.
1566
1681
  throw error;
1567
1682
  }
1568
1683
  }
1569
- merge("process.env", Object.fromEntries(Object.entries(env).map(([key, value]) => [key, value ?? void 0])));
1684
+ const processValues = Object.fromEntries(Object.entries(env).map(([key, value]) => [key, value ?? void 0]));
1685
+ merge("process.env", processValues);
1570
1686
  return { values, sources };
1571
1687
  }
1572
1688
  function resolveTreeseedLaunchEnvironment({
@@ -1600,14 +1716,14 @@ function resolveTreeseedLaunchEnvironment({
1600
1716
  );
1601
1717
  const systemSecretSuggestedValues = Object.fromEntries(
1602
1718
  registry.entries.filter(
1603
- (entry) => entry.id === "TREESEED_PLATFORM_RUNNER_SECRET" && typeof suggestedValues[entry.id] === "string" && suggestedValues[entry.id].length > 0
1719
+ (entry) => entry.sensitivity === "secret" && entry.visibility === "system" && typeof entry.defaultValue === "function" && typeof suggestedValues[entry.id] === "string" && suggestedValues[entry.id].length > 0
1604
1720
  ).map((entry) => [entry.id, suggestedValues[entry.id]])
1605
1721
  );
1606
1722
  const scopedValues = scope === "local" ? { ...nonSecretSuggestedValues, ...systemSecretSuggestedValues, ...baseValues, ...machineValues } : { ...nonSecretSuggestedValues, ...systemSecretSuggestedValues, ...machineValues, ...baseValues };
1607
- return {
1723
+ return withTreeseedServiceCredentialEnv({
1608
1724
  ...scopedValues,
1609
1725
  ...overrides
1610
- };
1726
+ });
1611
1727
  }
1612
1728
  function formatTreeseedConfigEnvironmentReport({ tenantRoot, scope, env = process.env, revealSecrets = false }) {
1613
1729
  const registry = collectTreeseedEnvironmentContext(tenantRoot);
@@ -1731,25 +1847,6 @@ function runGh(args, { cwd, dryRun = false, input, env } = {}) {
1731
1847
  }
1732
1848
  return result;
1733
1849
  }
1734
- function runRailway(args, { cwd, dryRun = false, input } = {}) {
1735
- if (dryRun) {
1736
- return { status: 0, stdout: "", stderr: "" };
1737
- }
1738
- const railway = resolveTreeseedToolCommand("railway");
1739
- if (!railway) {
1740
- throw new Error("Railway CLI is unavailable.");
1741
- }
1742
- const result = spawnSync(railway.command, [...railway.argsPrefix, ...args], {
1743
- cwd,
1744
- stdio: input !== void 0 ? ["pipe", "pipe", "pipe"] : ["ignore", "pipe", "pipe"],
1745
- encoding: "utf8",
1746
- input
1747
- });
1748
- if (result.status !== 0) {
1749
- throw new Error(result.stderr?.trim() || result.stdout?.trim() || `railway ${args.join(" ")} failed`);
1750
- }
1751
- return result;
1752
- }
1753
1850
  function commandAvailable(command) {
1754
1851
  if (command === "gh" || command === "wrangler" || command === "railway" || command === "copilot") {
1755
1852
  return Boolean(resolveTreeseedToolBinary(command));
@@ -1902,16 +1999,24 @@ function isTransientProviderConnectionError(detail) {
1902
1999
  return /fetch failed|failed to fetch|timed out|etimedout|econnreset|enetunreach|temporarily unavailable|aborted|api check failed|rate.?limit|too many requests|429/iu.test(detail || "");
1903
2000
  }
1904
2001
  function checkGitHubConnection({ tenantRoot, env }) {
1905
- if (!env.GH_TOKEN) {
1906
- return providerConnectionResult("github", false, "GH_TOKEN is not configured.", { skipped: true });
2002
+ const identityMode = env.TREESEED_GITHUB_IDENTITY_MODE === "account" ? "account" : "repository";
2003
+ const repository = identityMode === "repository" ? maybeResolveGitHubRepositorySlug(tenantRoot) : null;
2004
+ const credential = repository ? resolveGitHubCredentialForRepository(repository, { values: env, env }) : null;
2005
+ const token = credential?.token ?? resolveTreeseedGitHubToken(env);
2006
+ if (!token) {
2007
+ return providerConnectionResult(
2008
+ "github",
2009
+ false,
2010
+ credential ? `${credential.envName} or TREESEED_GITHUB_TOKEN is not configured.` : "TREESEED_GITHUB_TOKEN is not configured.",
2011
+ { skipped: true }
2012
+ );
1907
2013
  }
1908
2014
  const gh = resolveTreeseedToolBinary("gh", { env });
1909
2015
  if (!gh) {
1910
2016
  return providerConnectionResult("github", false, "GitHub CLI `gh` is not installed.");
1911
2017
  }
1912
- const identityMode = env.TREESEED_GITHUB_IDENTITY_MODE === "account" ? "account" : "repository";
1913
- const repository = identityMode === "repository" ? maybeResolveGitHubRepositorySlug(tenantRoot) : null;
1914
2018
  const owner = typeof env.TREESEED_HOSTED_HUBS_GITHUB_OWNER === "string" ? env.TREESEED_HOSTED_HUBS_GITHUB_OWNER.trim() : "";
2019
+ const toolEnv = createTreeseedManagedToolEnv({ ...process.env, ...env, TREESEED_GITHUB_TOKEN: token });
1915
2020
  const commandCandidates = repository ? [{
1916
2021
  args: ["repo", "view", repository, "--json", "nameWithOwner", "--jq", ".nameWithOwner"],
1917
2022
  successMessage: (resolved) => `GitHub token can access ${resolved || repository}.`
@@ -1939,7 +2044,7 @@ function checkGitHubConnection({ tenantRoot, env }) {
1939
2044
  cwd: tenantRoot,
1940
2045
  stdio: "pipe",
1941
2046
  encoding: "utf8",
1942
- env: createTreeseedManagedToolEnv({ ...process.env, ...env }),
2047
+ env: toolEnv,
1943
2048
  timeout: CLI_CHECK_TIMEOUT_MS
1944
2049
  });
1945
2050
  if (result.status === 0) {
@@ -1958,8 +2063,8 @@ function checkGitHubConnection({ tenantRoot, env }) {
1958
2063
  return providerConnectionResult("github", false, lastDetail || "GitHub API check failed.");
1959
2064
  }
1960
2065
  function checkCloudflareConnection({ tenantRoot, env }) {
1961
- if (!env.CLOUDFLARE_API_TOKEN) {
1962
- return providerConnectionResult("cloudflare", false, "CLOUDFLARE_API_TOKEN is not configured.", { skipped: true });
2066
+ if (!env.TREESEED_CLOUDFLARE_API_TOKEN) {
2067
+ return providerConnectionResult("cloudflare", false, "TREESEED_CLOUDFLARE_API_TOKEN is not configured.", { skipped: true });
1963
2068
  }
1964
2069
  for (let attempt = 0; attempt < 3; attempt += 1) {
1965
2070
  try {
@@ -1967,11 +2072,11 @@ function checkCloudflareConnection({ tenantRoot, env }) {
1967
2072
  cwd: tenantRoot,
1968
2073
  stdio: "pipe",
1969
2074
  encoding: "utf8",
1970
- env: { ...process.env, ...env },
2075
+ env: createTreeseedManagedToolEnv({ ...process.env, ...env }),
1971
2076
  timeout: CLI_CHECK_TIMEOUT_MS
1972
2077
  });
1973
2078
  if (result.status === 0) {
1974
- return providerConnectionResult("cloudflare", true, "Wrangler authenticated with CLOUDFLARE_API_TOKEN.");
2079
+ return providerConnectionResult("cloudflare", true, "Wrangler authenticated with TREESEED_CLOUDFLARE_API_TOKEN.");
1975
2080
  }
1976
2081
  const detail = formatCheckOutput(result) || "Cloudflare Wrangler check failed.";
1977
2082
  if (attempt >= 2 || !isTransientProviderConnectionError(detail)) {
@@ -1992,13 +2097,13 @@ function checkCloudflareConnection({ tenantRoot, env }) {
1992
2097
  );
1993
2098
  }
1994
2099
  async function checkRailwayConnection({ tenantRoot, env }) {
1995
- if (!env.RAILWAY_API_TOKEN) {
1996
- return providerConnectionResult("railway", false, "RAILWAY_API_TOKEN is not configured.", { skipped: true });
2100
+ if (!env.TREESEED_RAILWAY_API_TOKEN) {
2101
+ return providerConnectionResult("railway", false, "TREESEED_RAILWAY_API_TOKEN is not configured.", { skipped: true });
1997
2102
  }
1998
2103
  const workspaceName = env.TREESEED_RAILWAY_WORKSPACE || resolveRailwayWorkspace(env);
1999
2104
  const cacheKey = JSON.stringify({
2000
2105
  tenantRoot,
2001
- token: env.RAILWAY_API_TOKEN,
2106
+ token: env.TREESEED_RAILWAY_API_TOKEN,
2002
2107
  workspaceName
2003
2108
  });
2004
2109
  const cached = railwayConnectionCheckCache.get(cacheKey);
@@ -2057,16 +2162,20 @@ async function checkTreeseedProviderConnections({ tenantRoot, scope = "prod", en
2057
2162
  const resolvedValue = values?.[key];
2058
2163
  return typeof resolvedValue === "string" && resolvedValue.trim() ? resolvedValue.trim() : void 0;
2059
2164
  };
2165
+ const githubCredentialValues = Object.fromEntries(
2166
+ Object.entries(values).filter(([key, value]) => key.startsWith("TREESEED_GITHUB_TOKEN_") && typeof value === "string" && value.trim())
2167
+ );
2060
2168
  const rawCommandEnv = {
2061
- GH_TOKEN: values.GH_TOKEN,
2169
+ ...githubCredentialValues,
2170
+ TREESEED_GITHUB_TOKEN: resolveTreeseedGitHubToken(values),
2062
2171
  TREESEED_GITHUB_IDENTITY_MODE: passthroughValue("TREESEED_GITHUB_IDENTITY_MODE"),
2063
2172
  TREESEED_HOSTED_HUBS_GITHUB_OWNER: passthroughValue("TREESEED_HOSTED_HUBS_GITHUB_OWNER"),
2064
- CLOUDFLARE_API_TOKEN: values.CLOUDFLARE_API_TOKEN,
2065
- CLOUDFLARE_ACCOUNT_ID: values.CLOUDFLARE_ACCOUNT_ID,
2066
- RAILWAY_API_TOKEN: values.RAILWAY_API_TOKEN,
2173
+ TREESEED_CLOUDFLARE_API_TOKEN: values.TREESEED_CLOUDFLARE_API_TOKEN,
2174
+ TREESEED_CLOUDFLARE_ACCOUNT_ID: values.TREESEED_CLOUDFLARE_ACCOUNT_ID,
2175
+ TREESEED_RAILWAY_API_TOKEN: values.TREESEED_RAILWAY_API_TOKEN,
2067
2176
  TREESEED_RAILWAY_WORKSPACE: values.TREESEED_RAILWAY_WORKSPACE || resolveRailwayWorkspace(values)
2068
2177
  };
2069
- const commandEnv = buildRailwayCommandEnv(rawCommandEnv);
2178
+ const commandEnv = buildRailwayCommandEnv(createTreeseedManagedToolEnv(rawCommandEnv));
2070
2179
  const checks = [
2071
2180
  checkGitHubConnection({ tenantRoot, env: commandEnv }),
2072
2181
  checkCloudflareConnection({ tenantRoot, env: commandEnv })
@@ -2117,6 +2226,138 @@ async function runBounded(items, limit, worker) {
2117
2226
  });
2118
2227
  await Promise.all(workers);
2119
2228
  }
2229
+ function repositorySlugFromPackageJson(root) {
2230
+ try {
2231
+ const packageJson = JSON.parse(readFileSync(resolve(root, "package.json"), "utf8"));
2232
+ const repository = packageJson.repository;
2233
+ const raw = typeof repository === "string" ? repository : repository && typeof repository === "object" && !Array.isArray(repository) ? repository.url : null;
2234
+ if (typeof raw !== "string") return null;
2235
+ const normalized = raw.trim().replace(/^git\+/u, "").replace(/^ssh:\/\/git@github\.com[:/]/u, "").replace(/^git@github\.com:/u, "").replace(/^https:\/\/github\.com\//u, "").replace(/\.git$/u, "").replace(/\/$/u, "");
2236
+ return /^[^/\s]+\/[^/\s]+$/u.test(normalized) ? normalized : null;
2237
+ } catch {
2238
+ return null;
2239
+ }
2240
+ }
2241
+ function resolveGitHubRepositorySlugForPath(root) {
2242
+ try {
2243
+ return maybeResolveGitHubRepositorySlug(root);
2244
+ } catch {
2245
+ return null;
2246
+ }
2247
+ }
2248
+ function discoverGitHubEnvironmentSyncTargets(tenantRoot, explicitRepository) {
2249
+ const targets = /* @__PURE__ */ new Map();
2250
+ const add = (repository, managedHostMode) => {
2251
+ if (!repository || !repository.trim()) return;
2252
+ const normalized = repository.trim();
2253
+ const existing = targets.get(normalized);
2254
+ if (!existing || existing.managedHostMode === "managed" && managedHostMode === "direct") {
2255
+ targets.set(normalized, { repository: normalized, managedHostMode });
2256
+ }
2257
+ };
2258
+ add(explicitRepository ?? resolveGitHubRepositorySlugForPath(tenantRoot), "auto");
2259
+ for (const application of discoverTreeseedApplications(tenantRoot)) {
2260
+ const repository = resolveGitHubRepositorySlugForPath(application.root) ?? repositorySlugFromPackageJson(application.root);
2261
+ const managedHostMode = usesManagedHostOperationRequests(application.config) ? "managed" : "direct";
2262
+ add(repository, managedHostMode);
2263
+ }
2264
+ return [...targets.values()];
2265
+ }
2266
+ function withGitHubEnvironmentCredentialContext(error, repository, credential) {
2267
+ const message = error instanceof Error && error.message.trim() ? error.message.trim() : String(error ?? "GitHub environment sync failed.");
2268
+ if (credential.fallbackUsed && /authentication failed|resource not accessible|403/iu.test(message)) {
2269
+ return new Error(`${message} Configure ${credential.envName} with Actions environment secrets and variables permissions for ${repository}; the fallback TREESEED_GITHUB_TOKEN is not sufficient for this repository.`);
2270
+ }
2271
+ return error;
2272
+ }
2273
+ function githubConfigSyncUnitId(value) {
2274
+ return String(value || "unknown").replace(/[^A-Za-z0-9:._/-]+/gu, "-");
2275
+ }
2276
+ function createGitHubConfigSyncUnits({
2277
+ scope,
2278
+ repository,
2279
+ environment,
2280
+ items
2281
+ }) {
2282
+ const identity = {
2283
+ teamId: "config",
2284
+ projectId: "config",
2285
+ slug: "config",
2286
+ environment: scope,
2287
+ deploymentKey: `config:${scope}`,
2288
+ environmentKey: scope
2289
+ };
2290
+ const repositoryId = githubConfigSyncUnitId(repository);
2291
+ const environmentId = githubConfigSyncUnitId(environment);
2292
+ const environmentUnitId = `github-environment:config:${scope}:${repositoryId}:${environmentId}`;
2293
+ const target = { kind: "persistent", scope };
2294
+ const environmentUnit = {
2295
+ unitId: environmentUnitId,
2296
+ unitType: "github-environment",
2297
+ provider: "github",
2298
+ identity,
2299
+ target,
2300
+ logicalName: `${repository} ${environment}`,
2301
+ dependencies: [],
2302
+ spec: {
2303
+ repository,
2304
+ environment
2305
+ },
2306
+ secrets: {},
2307
+ metadata: {
2308
+ source: { type: "config-sync" },
2309
+ resourceKind: "github-environment"
2310
+ }
2311
+ };
2312
+ const bindingUnits = items.flatMap((item) => {
2313
+ if (item.kind === "secret") {
2314
+ return [{
2315
+ unitId: `github-secret-binding:config:${scope}:${repositoryId}:${environmentId}:${githubConfigSyncUnitId(item.name)}`,
2316
+ unitType: "github-secret-binding",
2317
+ provider: "github",
2318
+ identity,
2319
+ target,
2320
+ logicalName: `${repository} ${environment} ${item.name}`,
2321
+ dependencies: [environmentUnitId],
2322
+ spec: {
2323
+ repository,
2324
+ environment,
2325
+ secretName: item.name,
2326
+ envName: item.name
2327
+ },
2328
+ secrets: {},
2329
+ metadata: {
2330
+ source: { type: "config-sync" },
2331
+ resourceKind: "github-secret-binding"
2332
+ }
2333
+ }];
2334
+ }
2335
+ if (item.kind === "variable") {
2336
+ return [{
2337
+ unitId: `github-variable-binding:config:${scope}:${repositoryId}:${environmentId}:${githubConfigSyncUnitId(item.name)}`,
2338
+ unitType: "github-variable-binding",
2339
+ provider: "github",
2340
+ identity,
2341
+ target,
2342
+ logicalName: `${repository} ${environment} ${item.name}`,
2343
+ dependencies: [environmentUnitId],
2344
+ spec: {
2345
+ repository,
2346
+ environment,
2347
+ variableName: item.name,
2348
+ envName: item.name
2349
+ },
2350
+ secrets: {},
2351
+ metadata: {
2352
+ source: { type: "config-sync" },
2353
+ resourceKind: "github-variable-binding"
2354
+ }
2355
+ }];
2356
+ }
2357
+ return [];
2358
+ });
2359
+ return bindingUnits.length > 0 ? [environmentUnit, ...bindingUnits] : [];
2360
+ }
2120
2361
  async function syncTreeseedGitHubEnvironment({
2121
2362
  tenantRoot,
2122
2363
  scope = "prod",
@@ -2156,29 +2397,11 @@ async function syncTreeseedGitHubEnvironment({
2156
2397
  }
2157
2398
  return Boolean(entry.targets.includes("github-variable") && allowedVariables?.has(entry.id));
2158
2399
  });
2159
- const ghToken = values.GH_TOKEN || process.env.GH_TOKEN || process.env.GITHUB_TOKEN || "";
2160
- const ghEnv = ghToken ? {
2161
- GH_TOKEN: ghToken,
2162
- GITHUB_TOKEN: ghToken
2163
- } : {};
2164
- const githubClient = createGitHubApiClient({ env: ghEnv });
2400
+ const credential = resolveGitHubCredentialForRepository(repository, { values, env: process.env });
2165
2401
  const environment = scope === "prod" ? "production" : scope;
2166
- const deploymentBranch = scope === "prod" ? PRODUCTION_BRANCH : scope === "staging" ? STAGING_BRANCH : null;
2167
- const deploymentTag = scope === "prod" ? "*.*.*" : null;
2168
2402
  const progress = (message, stream = "stdout") => onProgress?.(message, stream);
2169
- if (!dryRun) {
2170
- progress(`[${scope}][github][environment] Ensuring GitHub environment ${environment} exists...`);
2171
- await ensureGitHubActionsEnvironment(repository, environment, {
2172
- client: githubClient,
2173
- branchName: deploymentBranch,
2174
- tagName: deploymentTag
2175
- });
2176
- }
2177
2403
  progress(`[${scope}][github][sync] Loading existing GitHub secrets and variables...`);
2178
- const [secretNames, variableNames] = dryRun ? [/* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()] : await Promise.all([
2179
- listGitHubEnvironmentSecretNames(repository, environment, { client: githubClient }),
2180
- listGitHubEnvironmentVariableNames(repository, environment, { client: githubClient })
2181
- ]);
2404
+ const [secretNames, variableNames] = [/* @__PURE__ */ new Set(), /* @__PURE__ */ new Set()];
2182
2405
  const synced = {
2183
2406
  secrets: [],
2184
2407
  variables: []
@@ -2197,18 +2420,62 @@ async function syncTreeseedGitHubEnvironment({
2197
2420
  }
2198
2421
  let completed = 0;
2199
2422
  const total = items.length;
2423
+ if (!dryRun) {
2424
+ const units = createGitHubConfigSyncUnits({ scope, repository, environment, items });
2425
+ if (units.length === 0) {
2426
+ progress(`[${scope}][github][sync] Complete: 0 secrets, 0 variables, 0 total.`);
2427
+ return {
2428
+ repository,
2429
+ scope,
2430
+ environment,
2431
+ secrets: synced.secrets,
2432
+ variables: synced.variables
2433
+ };
2434
+ }
2435
+ try {
2436
+ const result = await reconcileTreeseedTarget({
2437
+ tenantRoot,
2438
+ target: createPersistentDeployTarget(scope),
2439
+ env: {
2440
+ ...process.env,
2441
+ ...values,
2442
+ ...valuesOverlay
2443
+ },
2444
+ units,
2445
+ write: (line) => progress(`[${scope}][github][reconcile] ${line}`)
2446
+ });
2447
+ const plansById = new Map(result.plans.map((entry) => [entry.unit.unitId, entry]));
2448
+ for (const unit of units) {
2449
+ if (unit.unitType !== "github-secret-binding" && unit.unitType !== "github-variable-binding") continue;
2450
+ const planEntry = plansById.get(unit.unitId);
2451
+ const name = String(unit.spec.secretName ?? unit.spec.variableName ?? unit.spec.envName ?? "");
2452
+ if (!name) continue;
2453
+ const existed = Boolean(planEntry?.observed.exists);
2454
+ if (unit.unitType === "github-secret-binding") {
2455
+ synced.secrets.push({ name, existed });
2456
+ } else {
2457
+ synced.variables.push({ name, existed });
2458
+ }
2459
+ completed += 1;
2460
+ progress(`[${scope}][github][${unit.unitType === "github-secret-binding" ? "secret" : "variable"}] reconciled ${name} (${completed}/${total})`);
2461
+ }
2462
+ } catch (error) {
2463
+ throw withGitHubEnvironmentCredentialContext(error, repository, credential);
2464
+ }
2465
+ progress(`[${scope}][github][sync] Complete: ${synced.secrets.length} secrets, ${synced.variables.length} variables, ${total} total.`);
2466
+ return {
2467
+ repository,
2468
+ scope,
2469
+ environment,
2470
+ secrets: synced.secrets,
2471
+ variables: synced.variables
2472
+ };
2473
+ }
2200
2474
  progress(`[${scope}][github][sync] Syncing GitHub environment ${environment}: 0/${total} items...`);
2201
2475
  const limit = execution === "sequential" ? 1 : concurrency;
2202
2476
  await runBounded(items, limit, async (item) => {
2203
- if (!dryRun) {
2204
- if (item.kind === "secret") {
2205
- await upsertGitHubEnvironmentSecret(repository, environment, item.name, item.value, { client: githubClient });
2206
- } else {
2207
- await upsertGitHubEnvironmentVariable(repository, environment, item.name, item.value, { client: githubClient });
2208
- }
2209
- }
2210
2477
  completed += 1;
2211
- const action = item.existed ? "updated" : "created";
2478
+ const action = item.existed ? "would update" : "would create";
2212
2479
  progress(`[${scope}][github][${item.kind}] ${action} ${item.name} (${completed}/${total})`);
2213
2480
  if (item.kind === "secret") {
2214
2481
  synced.secrets.push({ name: item.name, existed: item.existed });
@@ -2221,6 +2488,13 @@ async function syncTreeseedGitHubEnvironment({
2221
2488
  repository,
2222
2489
  scope,
2223
2490
  environment,
2491
+ credential: {
2492
+ repository: credential.repository,
2493
+ envName: credential.envName,
2494
+ configured: credential.configured,
2495
+ source: credential.source,
2496
+ fallbackUsed: credential.fallbackUsed
2497
+ },
2224
2498
  entryIds: entryFilter ? [...entryFilter] : void 0,
2225
2499
  ...synced
2226
2500
  };
@@ -2274,7 +2548,7 @@ function environmentEntryTargetsService(entry, serviceKey) {
2274
2548
  function railwayEnvironmentEntryIdsForService(registry, values, scope, target, serviceKey, entryFilter = null) {
2275
2549
  return registry.entries.filter((entry) => entry.scopes.includes(scope) && entry.targets.includes(target) && (!entryFilter || entryFilter.has(entry.id)) && environmentEntryTargetsService(entry, serviceKey)).map((entry) => entry.id).filter((key) => typeof values[key] === "string" && values[key].length > 0);
2276
2550
  }
2277
- function syncTreeseedRailwayEnvironment({
2551
+ async function syncTreeseedRailwayEnvironment({
2278
2552
  tenantRoot,
2279
2553
  scope = "prod",
2280
2554
  dryRun = false,
@@ -2288,10 +2562,10 @@ function syncTreeseedRailwayEnvironment({
2288
2562
  ...nonEmptyEnvironmentValues(valuesOverlay)
2289
2563
  };
2290
2564
  const deployConfig = loadCliDeployConfig(tenantRoot);
2291
- const marketDatabaseService = deployConfig.services?.marketDatabase;
2292
- const marketDatabaseBaseName = typeof marketDatabaseService?.railway?.serviceName === "string" && marketDatabaseService.railway.serviceName.trim() ? marketDatabaseService.railway.serviceName.trim() : `${deployConfig.slug ?? "treeseed-market"}-postgres`;
2293
- const marketDatabaseServiceName = `${marketDatabaseBaseName.replace(/-(staging|prod|production)$/u, "")}-${scope === "prod" ? "prod" : scope}`;
2294
- const marketDatabaseUrl = typeof values.TREESEED_MARKET_DATABASE_URL === "string" && values.TREESEED_MARKET_DATABASE_URL.length > 0 ? values.TREESEED_MARKET_DATABASE_URL : marketDatabaseService?.enabled !== false && marketDatabaseService?.provider === "railway" ? `\${{${marketDatabaseServiceName}.DATABASE_URL}}` : "";
2565
+ const treeseedDatabase = configuredMarketDatabaseService(tenantRoot, deployConfig);
2566
+ const treeseedDatabaseService = treeseedDatabase?.service;
2567
+ const treeseedDatabaseServiceName = treeseedDatabase?.serviceName ?? "";
2568
+ const treeseedDatabaseUrl = typeof values.TREESEED_DATABASE_URL === "string" && values.TREESEED_DATABASE_URL.length > 0 ? values.TREESEED_DATABASE_URL : treeseedDatabaseService?.enabled !== false && treeseedDatabaseService?.provider === "railway" ? `\${{${treeseedDatabaseServiceName}.DATABASE_URL}}` : "";
2295
2569
  const registry = collectTreeseedEnvironmentContext(tenantRoot);
2296
2570
  const entryFilter = Array.isArray(entryIds) && entryIds.length > 0 ? new Set(entryIds) : null;
2297
2571
  const progress = (message, stream = "stdout") => onProgress?.(message, stream);
@@ -2301,12 +2575,12 @@ function syncTreeseedRailwayEnvironment({
2301
2575
  const environmentName = normalizeRailwayEnvironmentName(service.railwayEnvironment ?? scope);
2302
2576
  const serviceValues = {
2303
2577
  ...values,
2304
- ...service.key === "marketOperationsRunner" ? {
2578
+ ...service.key === "operationsRunner" ? {
2305
2579
  TREESEED_PLATFORM_RUNNER_ID: service.runnerId ?? service.serviceName,
2306
2580
  TREESEED_PLATFORM_RUNNER_DATA_DIR: service.volumeMountPath ?? values.TREESEED_PLATFORM_RUNNER_DATA_DIR,
2307
2581
  TREESEED_PLATFORM_RUNNER_ENVIRONMENT: scope === "prod" ? "production" : scope
2308
2582
  } : {},
2309
- ...marketDatabaseUrl && ["api", "marketOperationsRunner"].includes(service.key) ? { TREESEED_MARKET_DATABASE_URL: marketDatabaseUrl } : {}
2583
+ ...treeseedDatabaseUrl && ["api", "operationsRunner"].includes(service.key) ? { TREESEED_DATABASE_URL: treeseedDatabaseUrl } : {}
2310
2584
  };
2311
2585
  const serviceName = service.serviceName ?? fallbackServiceName;
2312
2586
  serviceValuesByName.set(serviceName || service.serviceId || service.instanceKey || service.key, serviceValues);
@@ -2327,17 +2601,36 @@ function syncTreeseedRailwayEnvironment({
2327
2601
  for (const service of services) {
2328
2602
  const serviceValues = serviceValuesByName.get(service.serviceName || service.serviceId || service.instanceKey || service.service) ?? values;
2329
2603
  progress(`[${scope}][railway][${service.service}] Syncing ${service.secrets.length} secrets and ${service.variables.length} variables...`);
2330
- for (const key of service.secrets) {
2331
- runRailway(
2332
- ["variable", "set", "--service", service.serviceName || service.serviceId, "--environment", service.environmentName, "--stdin", "--skip-deploys", key],
2333
- { cwd: service.rootDir, dryRun, input: serviceValues[key] }
2334
- );
2335
- }
2336
- for (const key of service.variables) {
2337
- runRailway(
2338
- ["variable", "set", "--service", service.serviceName || service.serviceId, "--environment", service.environmentName, "--stdin", "--skip-deploys", key],
2339
- { cwd: service.rootDir, dryRun, input: serviceValues[key] }
2604
+ if (!dryRun) {
2605
+ const railwayEnv = { ...process.env, ...values };
2606
+ const project = (await ensureRailwayProject({
2607
+ projectId: "",
2608
+ projectName: service.projectName,
2609
+ env: railwayEnv
2610
+ })).project;
2611
+ const environment = (await ensureRailwayEnvironment({
2612
+ projectId: project.id,
2613
+ environmentName: service.environmentName,
2614
+ env: railwayEnv
2615
+ })).environment;
2616
+ const railwayService = (await ensureRailwayService({
2617
+ projectId: project.id,
2618
+ serviceId: service.serviceId,
2619
+ serviceName: service.serviceName,
2620
+ env: railwayEnv
2621
+ })).service;
2622
+ const variableValues = Object.fromEntries(
2623
+ [...service.secrets, ...service.variables].map((key) => [key, serviceValues[key]]).filter(([, value]) => typeof value === "string" && value.length > 0)
2340
2624
  );
2625
+ if (Object.keys(variableValues).length > 0) {
2626
+ await upsertRailwayVariables({
2627
+ projectId: project.id,
2628
+ environmentId: environment.id,
2629
+ serviceId: railwayService.id,
2630
+ variables: variableValues,
2631
+ env: railwayEnv
2632
+ });
2633
+ }
2341
2634
  }
2342
2635
  progress(`[${scope}][railway][${service.service}] Complete.`);
2343
2636
  }
@@ -2545,25 +2838,25 @@ function createConfigReadiness(values, validation) {
2545
2838
  ];
2546
2839
  const providerIssues = (provider) => configProblems.filter((problem) => {
2547
2840
  if (provider === "github") {
2548
- return problem.id === "GH_TOKEN" || problem.id === "GITHUB_TOKEN" || problem.entry.group === "github";
2841
+ return problem.id === "TREESEED_GITHUB_TOKEN" || problem.entry.group === "github";
2549
2842
  }
2550
2843
  if (provider === "cloudflare") {
2551
- return problem.id.startsWith("CLOUDFLARE_") || problem.id.includes("TURNSTILE") || problem.entry.group === "cloudflare";
2844
+ return problem.id.startsWith("TREESEED_CLOUDFLARE_") || problem.id.startsWith("CLOUDFLARE_") || problem.id.includes("TURNSTILE") || problem.entry.group === "cloudflare";
2552
2845
  }
2553
- return problem.id.startsWith("RAILWAY_") || problem.entry.group === "railway";
2846
+ return problem.id.startsWith("TREESEED_RAILWAY_") || problem.entry.group === "railway";
2554
2847
  });
2555
2848
  const localDevelopmentIssues = [
2556
2849
  ...configProblems
2557
2850
  ].filter((problem) => problem.entry.group === "local-development");
2558
2851
  return {
2559
2852
  github: {
2560
- configured: validConfigValue("GH_TOKEN")
2853
+ configured: Boolean(resolveTreeseedGitHubToken(values)) && providerIssues("github").length === 0
2561
2854
  },
2562
2855
  cloudflare: {
2563
2856
  configured: providerIssues("cloudflare").length === 0
2564
2857
  },
2565
2858
  railway: {
2566
- configured: validConfigValue("RAILWAY_API_TOKEN") && providerIssues("railway").length === 0
2859
+ configured: validConfigValue("TREESEED_RAILWAY_API_TOKEN") && providerIssues("railway").length === 0
2567
2860
  },
2568
2861
  localDevelopment: {
2569
2862
  configured: localDevelopmentIssues.length === 0
@@ -2621,7 +2914,7 @@ function buildConfigEntrySnapshot(scope, entry, currentValue, suggestedValue) {
2621
2914
  return true;
2622
2915
  }
2623
2916
  })();
2624
- const allowGeneratedSecretDefault = entry.id === "TREESEED_PLATFORM_RUNNER_SECRET";
2917
+ const allowGeneratedSecretDefault = ["TREESEED_PLATFORM_RUNNER_SECRET", "TREESEED_WEB_SERVICE_SECRET", "TREESEED_API_WEB_SERVICE_SECRET", "TREESEED_CREDENTIAL_SESSION_SECRET"].includes(entry.id);
2625
2918
  const allowSuggestedDefault = allowGeneratedSecretDefault || !(entry.sensitivity === "secret" && entry.requirement !== "optional");
2626
2919
  const effectiveValue = currentValueValid ? currentValue || (allowSuggestedDefault ? suggestedValue : "") || "" : (allowSuggestedDefault ? suggestedValue : "") || currentValue || "";
2627
2920
  return {
@@ -2754,14 +3047,13 @@ function applyTreeseedConfigValues({
2754
3047
  }
2755
3048
  function configProblemBootstrapSystems(problem) {
2756
3049
  switch (problem?.id) {
2757
- case "GH_TOKEN":
2758
- case "GITHUB_TOKEN":
3050
+ case "TREESEED_GITHUB_TOKEN":
2759
3051
  return ["github"];
2760
- case "CLOUDFLARE_API_TOKEN":
2761
- case "CLOUDFLARE_ACCOUNT_ID":
3052
+ case "TREESEED_CLOUDFLARE_API_TOKEN":
3053
+ case "TREESEED_CLOUDFLARE_ACCOUNT_ID":
2762
3054
  case "CLOUDFLARE_ZONE_ID":
2763
3055
  return ["data", "web"];
2764
- case "RAILWAY_API_TOKEN":
3056
+ case "TREESEED_RAILWAY_API_TOKEN":
2765
3057
  case "TREESEED_RAILWAY_WORKSPACE":
2766
3058
  return ["api", "agents"];
2767
3059
  default:
@@ -2815,12 +3107,28 @@ async function finalizeTreeseedConfig({
2815
3107
  }
2816
3108
  };
2817
3109
  progress(`Validating configuration for ${scopes.join(", ")}...`);
2818
- const scopeSeedValues = Object.fromEntries(
3110
+ const rawScopeSeedValues = Object.fromEntries(
2819
3111
  scopes.map((scope) => [scope, collectTreeseedConfigSeedValues(tenantRoot, scope, env)])
2820
3112
  );
3113
+ const scopeSeedValues = Object.fromEntries(
3114
+ scopes.map((scope) => {
3115
+ const suggestedValues = getTreeseedEnvironmentSuggestedValues({
3116
+ scope,
3117
+ purpose: "config",
3118
+ deployConfig: registry.context.deployConfig,
3119
+ tenantConfig: registry.context.tenantConfig,
3120
+ plugins: registry.context.plugins,
3121
+ values: rawScopeSeedValues[scope]
3122
+ });
3123
+ return [scope, {
3124
+ ...suggestedValues,
3125
+ ...rawScopeSeedValues[scope]
3126
+ }];
3127
+ })
3128
+ );
2821
3129
  for (const scope of scopes) {
2822
3130
  const selection = resolveTreeseedBootstrapSelection({
2823
- deployConfig: registry.context.deployConfig,
3131
+ deployConfig: workspaceBootstrapDeployConfig(tenantRoot, registry.context.deployConfig),
2824
3132
  env: scopeSeedValues[scope],
2825
3133
  systems: scope === "local" ? ["github"] : systems,
2826
3134
  skipUnavailable: scope === "local" ? true : skipUnavailable
@@ -2968,7 +3276,7 @@ async function finalizeTreeseedConfig({
2968
3276
  result: {}
2969
3277
  });
2970
3278
  }
2971
- const deploySystems = selection.runnable.filter((system) => system === "data" || system === "web");
3279
+ const deploySystems = selection.runnable.filter((system) => system === "data" || system === "web" || system === "api" || system === "agents");
2972
3280
  if (deploySystems.length > 0) {
2973
3281
  progress(`[${scope}][bootstrap][deploy] Deploying ${deploySystems.join(", ")}...`);
2974
3282
  applyTreeseedEnvironmentToProcess({ tenantRoot, scope, override: true });
@@ -3026,27 +3334,37 @@ async function finalizeTreeseedConfig({
3026
3334
  }
3027
3335
  if (sync === "github" || sync === "all") {
3028
3336
  const githubScopes = scopes.filter((scope) => scope !== "local" && summary.bootstrapSystemsByScope[scope].runnable.includes("github"));
3029
- const syncScope = async (scope) => {
3030
- progress(`[${scope}][github][sync] Syncing GitHub environment...`);
3337
+ const githubTargets = discoverGitHubEnvironmentSyncTargets(tenantRoot, githubRepository);
3338
+ if (githubTargets.length === 0 && githubScopes.length > 0) {
3339
+ throw new Error("Unable to determine the GitHub repository from the origin remote.");
3340
+ }
3341
+ const syncScope = async (scope, target) => {
3342
+ progress(`[${scope}][github][sync] Syncing GitHub environment for ${target.repository}...`);
3031
3343
  return await syncTreeseedGitHubEnvironment({
3032
3344
  tenantRoot,
3033
3345
  scope,
3034
- repository: githubRepository,
3346
+ repository: target.repository,
3347
+ managedHostMode: target.managedHostMode,
3035
3348
  execution: bootstrapExecution,
3036
3349
  onProgress: progress
3037
3350
  });
3038
3351
  };
3039
3352
  const githubResults = [];
3040
3353
  if (bootstrapExecution === "sequential") {
3041
- for (const scope of githubScopes) {
3042
- githubResults.push(await syncScope(scope));
3354
+ for (const target of githubTargets) {
3355
+ for (const scope of githubScopes) {
3356
+ githubResults.push(await syncScope(scope, target));
3357
+ }
3043
3358
  }
3044
3359
  } else {
3045
- githubResults.push(...await Promise.all(githubScopes.map((scope) => syncScope(scope))));
3360
+ githubResults.push(...await Promise.all(githubTargets.flatMap(
3361
+ (target) => githubScopes.map((scope) => syncScope(scope, target))
3362
+ )));
3046
3363
  }
3047
3364
  summary.synced.github = {
3048
3365
  scopes: githubResults,
3049
3366
  repository: githubResults[0]?.repository ?? githubRepository ?? maybeResolveGitHubRepositorySlug(tenantRoot),
3367
+ repositories: githubResults.map((entry) => entry.repository).filter((repository, index, all) => all.indexOf(repository) === index),
3050
3368
  secrets: githubResults.flatMap((entry) => entry.secrets),
3051
3369
  variables: githubResults.flatMap((entry) => entry.variables)
3052
3370
  };
@@ -3085,11 +3403,12 @@ function collectTreeseedPrintEnvReport({
3085
3403
  revealSecrets,
3086
3404
  entries: listRelevantTreeseedConfigEntries(registry, scope).map((entry) => {
3087
3405
  const rawValue = values[entry.id] ?? "";
3406
+ const canRevealValue = entry.sensitivity !== "secret" || revealSecrets;
3088
3407
  return {
3089
3408
  id: entry.id,
3090
3409
  label: entry.label,
3091
3410
  sensitivity: entry.sensitivity,
3092
- value: rawValue,
3411
+ value: canRevealValue ? rawValue : "",
3093
3412
  displayValue: rawValue ? entry.sensitivity === "secret" && !revealSecrets ? maskValue(rawValue) : rawValue : "(unset)",
3094
3413
  source: sources[entry.id] ?? "unset",
3095
3414
  sourceRequirement: entry.sourceRequirement,