@flisk-sh/flisk 0.0.0-stage → 1.3.190

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 (440) hide show
  1. package/CHANGELOG.md +492 -0
  2. package/LICENSE +21 -0
  3. package/README.md +479 -2
  4. package/Tiltfile +151 -0
  5. package/cli/bin/flisk.js +42 -0
  6. package/cli/dist/agent-runtimes/custom.js +335 -0
  7. package/cli/dist/agent-runtimes/registry.js +34 -0
  8. package/cli/dist/backend-frameworks/elysia.js +38 -0
  9. package/cli/dist/backend-frameworks/express.js +49 -0
  10. package/cli/dist/backend-frameworks/fastify.js +43 -0
  11. package/cli/dist/backend-frameworks/h3.js +37 -0
  12. package/cli/dist/backend-frameworks/koa.js +47 -0
  13. package/cli/dist/backend-frameworks/mcp.js +86 -0
  14. package/cli/dist/backend-frameworks/nestjs.js +55 -0
  15. package/cli/dist/backend-frameworks/registry.js +134 -0
  16. package/cli/dist/backend-frameworks/types.js +1 -0
  17. package/cli/dist/backend-languages/bun.js +76 -0
  18. package/cli/dist/backend-languages/go.js +125 -0
  19. package/cli/dist/backend-languages/node.js +122 -0
  20. package/cli/dist/backend-languages/python.js +94 -0
  21. package/cli/dist/backend-languages/registry.js +37 -0
  22. package/cli/dist/backend-languages/rust.js +82 -0
  23. package/cli/dist/backend-languages/types.js +1 -0
  24. package/cli/dist/cli.js +29 -0
  25. package/cli/dist/commands/__tests__/project-e2e-helpers.js +49 -0
  26. package/cli/dist/commands/__tests__/ui-loading-screen.test.js +16 -0
  27. package/cli/dist/commands/agent.js +182 -0
  28. package/cli/dist/commands/completion-candidates.js +116 -0
  29. package/cli/dist/commands/completion.js +843 -0
  30. package/cli/dist/commands/config.js +362 -0
  31. package/cli/dist/commands/doctor.js +1504 -0
  32. package/cli/dist/commands/down.js +114 -0
  33. package/cli/dist/commands/eject.js +108 -0
  34. package/cli/dist/commands/help.js +152 -0
  35. package/cli/dist/commands/import.js +164 -0
  36. package/cli/dist/commands/logs.js +119 -0
  37. package/cli/dist/commands/maintainers.js +102 -0
  38. package/cli/dist/commands/mcp.js +28 -0
  39. package/cli/dist/commands/networks.js +306 -0
  40. package/cli/dist/commands/project.js +447 -0
  41. package/cli/dist/commands/projects.js +103 -0
  42. package/cli/dist/commands/registry.js +53 -0
  43. package/cli/dist/commands/resource.js +992 -0
  44. package/cli/dist/commands/resources.js +127 -0
  45. package/cli/dist/commands/restart.js +89 -0
  46. package/cli/dist/commands/runtime.js +75 -0
  47. package/cli/dist/commands/stack.js +171 -0
  48. package/cli/dist/commands/stacks.js +71 -0
  49. package/cli/dist/commands/status.js +211 -0
  50. package/cli/dist/commands/ui.js +725 -0
  51. package/cli/dist/commands/up.js +609 -0
  52. package/cli/dist/commands/upgrade.js +840 -0
  53. package/cli/dist/commands/version.js +10 -0
  54. package/cli/dist/components/Accessible.js +11 -0
  55. package/cli/dist/components/BaseTooltip.js +30 -0
  56. package/cli/dist/components/DetailPanel.js +33 -0
  57. package/cli/dist/components/FileTree.js +51 -0
  58. package/cli/dist/components/ResourceSelectInput.js +42 -0
  59. package/cli/dist/components/ResourceTable.js +35 -0
  60. package/cli/dist/components/ServiceIssues.js +13 -0
  61. package/cli/dist/components/TUIHeader.js +27 -0
  62. package/cli/dist/components/TabBar.js +27 -0
  63. package/cli/dist/components/Tooltip.js +13 -0
  64. package/cli/dist/components/index.js +11 -0
  65. package/cli/dist/components/ui-theme.js +120 -0
  66. package/cli/dist/config/platform-standards.js +182 -0
  67. package/cli/dist/frontend-frameworks/lit.js +64 -0
  68. package/cli/dist/frontend-frameworks/preact.js +62 -0
  69. package/cli/dist/frontend-frameworks/qwik.js +61 -0
  70. package/cli/dist/frontend-frameworks/react.js +69 -0
  71. package/cli/dist/frontend-frameworks/registry.js +83 -0
  72. package/cli/dist/frontend-frameworks/solid.js +62 -0
  73. package/cli/dist/frontend-frameworks/svelte.js +67 -0
  74. package/cli/dist/frontend-frameworks/tanstack-router.js +101 -0
  75. package/cli/dist/frontend-frameworks/types.js +1 -0
  76. package/cli/dist/frontend-frameworks/vanilla.js +59 -0
  77. package/cli/dist/frontend-frameworks/vue.js +72 -0
  78. package/cli/dist/generator/__tests__/golden-helpers.js +43 -0
  79. package/cli/dist/generator/extension-fetch.js +291 -0
  80. package/cli/dist/generator/resource-templates.js +133 -0
  81. package/cli/dist/generator/template-engine.js +801 -0
  82. package/cli/dist/index.js +10 -0
  83. package/cli/dist/mcp/server.js +101 -0
  84. package/cli/dist/mcp/tools.js +351 -0
  85. package/cli/dist/program.js +37 -0
  86. package/cli/dist/types/index.js +38 -0
  87. package/cli/dist/utils/agent-host.js +36 -0
  88. package/cli/dist/utils/atomic-write.js +36 -0
  89. package/cli/dist/utils/bun-floor.js +9 -0
  90. package/cli/dist/utils/bun-requirement.js +10 -0
  91. package/cli/dist/utils/cache.js +63 -0
  92. package/cli/dist/utils/cold-preflight.js +257 -0
  93. package/cli/dist/utils/command-helpers.js +57 -0
  94. package/cli/dist/utils/constants.js +160 -0
  95. package/cli/dist/utils/discovery-context.js +71 -0
  96. package/cli/dist/utils/discovery-paths.js +93 -0
  97. package/cli/dist/utils/docker.js +34 -0
  98. package/cli/dist/utils/doctor-crashloop.js +161 -0
  99. package/cli/dist/utils/doctor-fix.js +391 -0
  100. package/cli/dist/utils/doctor-host.js +66 -0
  101. package/cli/dist/utils/doctor-report.js +78 -0
  102. package/cli/dist/utils/doctor-runtime.js +880 -0
  103. package/cli/dist/utils/doctor-starlark.js +132 -0
  104. package/cli/dist/utils/doctor-wiring.js +698 -0
  105. package/cli/dist/utils/down-cleanup.js +125 -0
  106. package/cli/dist/utils/env-validator.js +266 -0
  107. package/cli/dist/utils/errors.js +175 -0
  108. package/cli/dist/utils/exec-async.js +31 -0
  109. package/cli/dist/utils/file-helpers.js +104 -0
  110. package/cli/dist/utils/formatting.js +165 -0
  111. package/cli/dist/utils/generated-paths.js +51 -0
  112. package/cli/dist/utils/help-command.js +11 -0
  113. package/cli/dist/utils/host-port-config.js +140 -0
  114. package/cli/dist/utils/host-port-plan.js +100 -0
  115. package/cli/dist/utils/json-output.js +29 -0
  116. package/cli/dist/utils/machine-output.js +33 -0
  117. package/cli/dist/utils/paths.js +43 -0
  118. package/cli/dist/utils/platform.js +58 -0
  119. package/cli/dist/utils/port-assignment.js +75 -0
  120. package/cli/dist/utils/port-conflict-fix.js +25 -0
  121. package/cli/dist/utils/port-fallback-notice.js +17 -0
  122. package/cli/dist/utils/port-listener-probe.js +20 -0
  123. package/cli/dist/utils/project-config-defaults.js +17 -0
  124. package/cli/dist/utils/project-features.js +91 -0
  125. package/cli/dist/utils/project-templates.js +32 -0
  126. package/cli/dist/utils/prompt.js +97 -0
  127. package/cli/dist/utils/resource-features.js +184 -0
  128. package/cli/dist/utils/resource-kind.js +9 -0
  129. package/cli/dist/utils/schema-version-gate.js +45 -0
  130. package/cli/dist/utils/search-status.js +12 -0
  131. package/cli/dist/utils/secret-redaction.js +73 -0
  132. package/cli/dist/utils/service-config-checks.js +189 -0
  133. package/cli/dist/utils/service-manifest.js +254 -0
  134. package/cli/dist/utils/service-runtime-state.js +66 -0
  135. package/cli/dist/utils/service-urls.js +112 -0
  136. package/cli/dist/utils/services.js +360 -0
  137. package/cli/dist/utils/shared-infra.js +45 -0
  138. package/cli/dist/utils/shared-platform-postgres.js +232 -0
  139. package/cli/dist/utils/single-flight.js +21 -0
  140. package/cli/dist/utils/smoke.js +401 -0
  141. package/cli/dist/utils/spinner.js +40 -0
  142. package/cli/dist/utils/stack-features.js +15 -0
  143. package/cli/dist/utils/stack-status.js +14 -0
  144. package/cli/dist/utils/startup-report.js +78 -0
  145. package/cli/dist/utils/status-message.js +21 -0
  146. package/cli/dist/utils/status-ports.js +33 -0
  147. package/cli/dist/utils/suggestions.js +63 -0
  148. package/cli/dist/utils/tar.js +46 -0
  149. package/cli/dist/utils/tdk-version.js +51 -0
  150. package/cli/dist/utils/terminal-layout.js +19 -0
  151. package/cli/dist/utils/tilt-events.js +194 -0
  152. package/cli/dist/utils/tilt-logs.js +61 -0
  153. package/cli/dist/utils/tilt-port-owner.js +63 -0
  154. package/cli/dist/utils/tilt-process.js +54 -0
  155. package/cli/dist/utils/tilt-resource-state.js +32 -0
  156. package/cli/dist/utils/tilt-startup.js +49 -0
  157. package/cli/dist/utils/tilt-unreachable-message.js +9 -0
  158. package/cli/dist/utils/tilt.js +104 -0
  159. package/cli/dist/utils/ui-keymap.js +129 -0
  160. package/cli/dist/utils/ui-service-state.js +34 -0
  161. package/cli/dist/utils/up-only.js +28 -0
  162. package/cli/dist/utils/up-readiness.js +118 -0
  163. package/cli/dist/utils/url-actions.js +103 -0
  164. package/cli/dist/utils/validation.js +62 -0
  165. package/cli/dist/utils/which.js +56 -0
  166. package/cli/dist/utils/windows-doctor.js +176 -0
  167. package/cli/dist-bundle/chunk-6EA4DGCY.js +2 -0
  168. package/cli/dist-bundle/chunk-BZ4H7MM4.js +3 -0
  169. package/cli/dist-bundle/chunk-CLCUIDBH.js +510 -0
  170. package/cli/dist-bundle/cli.js +2017 -0
  171. package/cli/dist-bundle/cold-preflight-SY26O2IG.js +2 -0
  172. package/cli/dist-bundle/devtools-ZUHXW33W.js +5 -0
  173. package/cli/dist-bundle/extension-fetch-J4FFH7TJ.js +2 -0
  174. package/cli/package.json +83 -0
  175. package/cli/shared-platform-engineering/docker-templates/bun-hoisted-symlink-fix.sh +25 -0
  176. package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +466 -0
  177. package/cli/shared-platform-engineering/docker-templates/install-deps.sh +154 -0
  178. package/cli/shared-platform-engineering/docker-templates/prisma-bun-client-link-fix.sh +14 -0
  179. package/cli/shared-platform-engineering/docker-templates/prisma-normalize-client.sh +58 -0
  180. package/cli/templates/.tiltignore.hbs +72 -0
  181. package/cli/templates/TILT_RESOURCE_DEFAULTS.star.hbs +220 -0
  182. package/cli/templates/TILT_TECH_STACK.star.hbs +149 -0
  183. package/cli/templates/Tiltfile.hbs +381 -0
  184. package/cli/templates/spec.master.hbs +192 -0
  185. package/discovery/AGENTS.md +362 -0
  186. package/discovery/TILT_DISCOVERY.star +429 -0
  187. package/discovery/Tiltfile +58 -0
  188. package/discovery/config.star +265 -0
  189. package/discovery/constants.star +167 -0
  190. package/discovery/deterministic.star +213 -0
  191. package/discovery/discovery_daemon.star +193 -0
  192. package/discovery/discovery_orchestrator.star +492 -0
  193. package/discovery/filtering.star +7 -0
  194. package/discovery/identity-management-backend/service.yaml +26 -0
  195. package/discovery/identity-management-frontend/service.yaml +29 -0
  196. package/discovery/identity-sdk/service.yaml +9 -0
  197. package/discovery/incremental_discovery.star +215 -0
  198. package/discovery/indexing.star +9 -0
  199. package/discovery/json_manifest_scanner.star +57 -0
  200. package/discovery/libraries.star +48 -0
  201. package/discovery/loading.star +25 -0
  202. package/discovery/manifest/constants.star +106 -0
  203. package/discovery/manifest/loading.star +418 -0
  204. package/discovery/manifest/normalize.star +289 -0
  205. package/discovery/manifest/validation.star +110 -0
  206. package/discovery/normalization.star +13 -0
  207. package/discovery/registry.star +562 -0
  208. package/discovery/resource_snapshot.py +384 -0
  209. package/discovery/resource_snapshot.star +145 -0
  210. package/discovery/schemas.star +3 -0
  211. package/discovery/services/platform/cdc/debezium/nats-connector/service.yaml +9 -0
  212. package/discovery/services/platform/cdc/nats-http-bridge/service.yaml +9 -0
  213. package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +26 -0
  214. package/discovery/services/platform/synthetic-monitor/service.yaml +9 -0
  215. package/discovery/test_resource_snapshot.py +253 -0
  216. package/discovery/validation.star +80 -0
  217. package/discovery/versioning.star +3 -0
  218. package/engine/AGENTS.md +706 -0
  219. package/engine/README.md +31 -0
  220. package/engine/REFACTORING_MANIFEST_SYSTEM.md +974 -0
  221. package/engine/Tiltfile +86 -0
  222. package/engine/assets/docker/golden-layers.Dockerfile +204 -0
  223. package/engine/assets/docker/wake-gateway/Dockerfile +28 -0
  224. package/engine/assets/docker/wake-gateway/decide.test.ts +177 -0
  225. package/engine/assets/docker/wake-gateway/decide.ts +135 -0
  226. package/engine/assets/docker/wake-gateway/server.ts +363 -0
  227. package/engine/assets/scripts/cleanup-completed-migrator-images.sh +39 -0
  228. package/engine/assets/scripts/cleanup-tilt-images.sh +122 -0
  229. package/engine/assets/scripts/mac-m1-resource-monitor.sh +123 -0
  230. package/engine/config.star +5 -0
  231. package/engine/entrypoint.star +101 -0
  232. package/engine/lifecycle/orchestrator.star +263 -0
  233. package/engine/paths.star +719 -0
  234. package/engine/schemas/project-schema.json +147 -0
  235. package/engine/schemas/service-schema.json +537 -0
  236. package/engine/scripts/README.md +89 -0
  237. package/engine/scripts/build-and-publish-lib.sh +207 -0
  238. package/engine/scripts/check-lib-publish.sh +87 -0
  239. package/engine/scripts/debug-container.sh +265 -0
  240. package/engine/scripts/generate-manifest.sh +200 -0
  241. package/engine/spec.master +702 -0
  242. package/engine/spec.master.example +341 -0
  243. package/engine/topologies/README.md +33 -0
  244. package/engine/topologies/platform/docker/AGENTS.md +59 -0
  245. package/engine/topologies/platform/docker/auth/auth.star +207 -0
  246. package/engine/topologies/platform/docker/build/frontend_build_plan.star +65 -0
  247. package/engine/topologies/platform/docker/build/golden_image.star +37 -0
  248. package/engine/topologies/platform/docker/build/golden_image_build.star +144 -0
  249. package/engine/topologies/platform/docker/build/golden_image_constants.star +100 -0
  250. package/engine/topologies/platform/docker/build/golden_image_dockerfile.star +263 -0
  251. package/engine/topologies/platform/docker/compose/compose.star +637 -0
  252. package/engine/topologies/platform/docker/compose/compose_helpers.star +54 -0
  253. package/engine/topologies/platform/docker/compose/traefik_standalone.star +171 -0
  254. package/engine/topologies/platform/docker/config/bunignore.star +144 -0
  255. package/engine/topologies/platform/docker/config/dockerignore.star +152 -0
  256. package/engine/topologies/platform/docker/config/healthcheck.star +58 -0
  257. package/engine/topologies/platform/docker/constants.star +211 -0
  258. package/engine/topologies/platform/docker/dockerfile/dockerfile.star +56 -0
  259. package/engine/topologies/platform/docker/dockerfile/language_dockerfile.star +264 -0
  260. package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +76 -0
  261. package/engine/topologies/platform/docker/index.star +40 -0
  262. package/engine/topologies/platform/docker/layers/bun_helpers.star +25 -0
  263. package/engine/topologies/platform/docker/layers/infisical/index.star +42 -0
  264. package/engine/topologies/platform/docker/layers/infisical/infisical_docker.star +264 -0
  265. package/engine/topologies/platform/docker/layers/l1_base_layers.star +89 -0
  266. package/engine/topologies/platform/docker/layers/l2_dependency_layers.star +147 -0
  267. package/engine/topologies/platform/docker/layers/l3_builder_layers.star +229 -0
  268. package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +282 -0
  269. package/engine/topologies/platform/docker/layers/prisma/constants.star +138 -0
  270. package/engine/topologies/platform/docker/layers/prisma/db_readiness.star +98 -0
  271. package/engine/topologies/platform/docker/layers/prisma/filesystem_setup.star +131 -0
  272. package/engine/topologies/platform/docker/layers/prisma/migrate_script.star +100 -0
  273. package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +128 -0
  274. package/engine/topologies/platform/docker/layers/prisma/prisma_runtime.star +205 -0
  275. package/engine/topologies/platform/docker/layers/prisma/secret_resolution.star +121 -0
  276. package/engine/topologies/platform/docker/networking/api_path_constants.star +206 -0
  277. package/engine/topologies/platform/docker/networking/sablier_container_cycle.star +31 -0
  278. package/engine/topologies/platform/docker/networking/traefik.star +266 -0
  279. package/engine/topologies/platform/docker/networking/traefik_constants.star +148 -0
  280. package/engine/topologies/platform/docker/networking/traefik_helpers.star +162 -0
  281. package/engine/topologies/platform/docker/networking/traefik_static_routes.star +165 -0
  282. package/engine/topologies/platform/docker/secrets/env_secrets.star +74 -0
  283. package/engine/topologies/platform/docker/secrets/infisical.star +109 -0
  284. package/engine/topologies/platform/net/AGENTS.md +64 -0
  285. package/engine/topologies/platform/net/proxy.star +6 -0
  286. package/engine/topologies/platform/registries/local.star +6 -0
  287. package/engine/topologies/platform/registries/verdaccio_loader.star +20 -0
  288. package/engine/topologies/platform/security/AGENTS.md +49 -0
  289. package/engine/topologies/platform/security/secrets.star +241 -0
  290. package/engine/topologies/platform/state/AGENTS.md +64 -0
  291. package/engine/topologies/platform/state/relational.star +6 -0
  292. package/engine/topologies/tilt/common/AGENTS.md +59 -0
  293. package/engine/topologies/tilt/common/utils.star +409 -0
  294. package/engine/topologies/tilt/common/utils_debug.star +71 -0
  295. package/engine/topologies/tilt/common/utils_deterministic.star +170 -0
  296. package/engine/topologies/tilt/common/utils_docker_networks.star +54 -0
  297. package/engine/topologies/tilt/common/utils_env.star +92 -0
  298. package/engine/topologies/tilt/common/utils_output.star +99 -0
  299. package/engine/topologies/tilt/config/AGENTS.md +68 -0
  300. package/engine/topologies/tilt/config/defaults.star +5 -0
  301. package/engine/topologies/tilt/config/feature_flags.star +12 -0
  302. package/engine/topologies/tilt/config/global.star +57 -0
  303. package/engine/topologies/tilt/config/profiles.star +398 -0
  304. package/engine/topologies/tilt/generators/agents_md.star +64 -0
  305. package/engine/topologies/tilt/generators/api_gateway.star +147 -0
  306. package/engine/topologies/tilt/generators/index.star +126 -0
  307. package/engine/topologies/tilt/generators/infisical/README.md +424 -0
  308. package/engine/topologies/tilt/generators/infisical/examples.star +314 -0
  309. package/engine/topologies/tilt/generators/infisical/index.star +59 -0
  310. package/engine/topologies/tilt/generators/infisical/machine_identity.star +422 -0
  311. package/engine/topologies/tilt/generators/infisical/organization.star +536 -0
  312. package/engine/topologies/tilt/generators/infisical/path_manager.star +478 -0
  313. package/engine/topologies/tilt/generators/infisical/secrets_generator.star +422 -0
  314. package/engine/topologies/tilt/generators/nginx_conf.star +145 -0
  315. package/engine/topologies/tilt/generators/npmrc.star +132 -0
  316. package/engine/topologies/tilt/generators/tsconfig.star +25 -0
  317. package/engine/topologies/tilt/generators/typescript/backend_library_tsconfig.star +73 -0
  318. package/engine/topologies/tilt/generators/typescript/backend_tsconfig.star +137 -0
  319. package/engine/topologies/tilt/generators/typescript/common.star +9 -0
  320. package/engine/topologies/tilt/generators/typescript/frontend_library_tsconfig.star +78 -0
  321. package/engine/topologies/tilt/generators/typescript/frontend_tsconfig.star +140 -0
  322. package/engine/topologies/tilt/generators/typescript/include.star +25 -0
  323. package/engine/topologies/tilt/generators/typescript/playwright_config.star +42 -0
  324. package/engine/topologies/tilt/generators/typescript/prisma_config.star +51 -0
  325. package/engine/topologies/tilt/generators/validators.star +868 -0
  326. package/engine/topologies/tilt/generators/vite/backend.star +80 -0
  327. package/engine/topologies/tilt/generators/vite/frameworks/lit.star +92 -0
  328. package/engine/topologies/tilt/generators/vite/frameworks/preact.star +94 -0
  329. package/engine/topologies/tilt/generators/vite/frameworks/qwik.star +94 -0
  330. package/engine/topologies/tilt/generators/vite/frameworks/react.star +128 -0
  331. package/engine/topologies/tilt/generators/vite/frameworks/solid.star +94 -0
  332. package/engine/topologies/tilt/generators/vite/frameworks/svelte.star +94 -0
  333. package/engine/topologies/tilt/generators/vite/frameworks/vanilla.star +92 -0
  334. package/engine/topologies/tilt/generators/vite/frameworks/vue.star +94 -0
  335. package/engine/topologies/tilt/generators/vite/frontend.star +153 -0
  336. package/engine/topologies/tilt/generators/vite/generators.star +45 -0
  337. package/engine/topologies/tilt/generators/vite/helpers.star +256 -0
  338. package/engine/topologies/tilt/generators/vite/library.star +67 -0
  339. package/engine/topologies/tilt/generators/vite/sdk.star +75 -0
  340. package/engine/topologies/tilt/generators/vite/templates.star +460 -0
  341. package/engine/topologies/tilt/generators/vite_config.star +24 -0
  342. package/engine/topologies/tilt/manifest/AGENTS.md +61 -0
  343. package/engine/topologies/tilt/manifest/README.md +679 -0
  344. package/engine/topologies/tilt/manifest/__init__.star +220 -0
  345. package/engine/topologies/tilt/manifest/constants.star +262 -0
  346. package/engine/topologies/tilt/manifest/errors.star +268 -0
  347. package/engine/topologies/tilt/manifest/integration.star +348 -0
  348. package/engine/topologies/tilt/manifest/json_to_yaml.py +61 -0
  349. package/engine/topologies/tilt/manifest/loader.star +239 -0
  350. package/engine/topologies/tilt/manifest/mapper.star +229 -0
  351. package/engine/topologies/tilt/manifest/parser.star +490 -0
  352. package/engine/topologies/tilt/manifest/schema.star +502 -0
  353. package/engine/topologies/tilt/manifest/tests/test_integration.star +278 -0
  354. package/engine/topologies/tilt/manifest/tests/test_loader_parser.star +475 -0
  355. package/engine/topologies/tilt/manifest/tests/test_manifest.star +319 -0
  356. package/engine/topologies/tilt/manifest/tests/test_validator.star +472 -0
  357. package/engine/topologies/tilt/manifest/validator.star +744 -0
  358. package/engine/topologies/tilt/manifest/yaml_to_json.py +20 -0
  359. package/engine/topologies/tilt/resources/AGENTS.md +71 -0
  360. package/engine/topologies/tilt/resources/build_concurrency.star +56 -0
  361. package/engine/topologies/tilt/resources/conditions.star +5 -0
  362. package/engine/topologies/tilt/resources/databases.star +246 -0
  363. package/engine/topologies/tilt/resources/declaration.star +5 -0
  364. package/engine/topologies/tilt/resources/deps.star +5 -0
  365. package/engine/topologies/tilt/resources/infra-loader.star +504 -0
  366. package/engine/topologies/tilt/resources/libs.star +32 -0
  367. package/engine/topologies/tilt/resources/libs_discovery.star +104 -0
  368. package/engine/topologies/tilt/resources/libs_paths.star +81 -0
  369. package/engine/topologies/tilt/resources/libs_resource_definition.star +153 -0
  370. package/engine/topologies/tilt/resources/libs_setup.star +166 -0
  371. package/engine/topologies/tilt/resources/libs_tsconfig.star +39 -0
  372. package/engine/topologies/tilt/resources/orchestrator/apply.star +79 -0
  373. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +864 -0
  374. package/engine/topologies/tilt/resources/orchestrator/apply_manifest_orchestration.star +90 -0
  375. package/engine/topologies/tilt/resources/orchestrator/apply_migrator_orchestration.star +150 -0
  376. package/engine/topologies/tilt/resources/orchestrator/apply_resource_validation.star +38 -0
  377. package/engine/topologies/tilt/resources/orchestrator/apply_runtime_flags.star +46 -0
  378. package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +193 -0
  379. package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/AGENTS.md +75 -0
  380. package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/index.star +23 -0
  381. package/engine/topologies/tilt/resources/orchestrator/generators/dependencies/resolver.star +136 -0
  382. package/engine/topologies/tilt/resources/orchestrator/generators/env.star +219 -0
  383. package/engine/topologies/tilt/resources/orchestrator/generators/frontend.star +172 -0
  384. package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +577 -0
  385. package/engine/topologies/tilt/resources/orchestrator/helpers.star +35 -0
  386. package/engine/topologies/tilt/resources/orchestrator.star +56 -0
  387. package/engine/topologies/tilt/resources/ordering.star +5 -0
  388. package/engine/topologies/tilt/resources/shared-platform-postgres.star +30 -0
  389. package/engine/topologies/tilt/resources/triggers.star +5 -0
  390. package/engine/topologies/tilt/resources/watchers.star +304 -0
  391. package/engine/where-things-live.star +719 -0
  392. package/examples/tdk-example/LICENSE +21 -0
  393. package/examples/tdk-example/README.md +23 -0
  394. package/examples/tdk-example/TILT_SERVICE_DEFAULTS.star +42 -0
  395. package/examples/tdk-example/TILT_TECH_STACK.star +67 -0
  396. package/examples/tdk-example/Tiltfile +25 -0
  397. package/examples/tdk-example/services/platform/messaging/docker-compose.yml +26 -0
  398. package/examples/tdk-example/services/shop/orders-api/package.json +20 -0
  399. package/examples/tdk-example/services/shop/orders-api/service.json +14 -0
  400. package/examples/tdk-example/services/shop/orders-api/src/index.ts +81 -0
  401. package/examples/tdk-example/services/shop/orders-app/index.html +12 -0
  402. package/examples/tdk-example/services/shop/orders-app/package.json +23 -0
  403. package/examples/tdk-example/services/shop/orders-app/public/.gitkeep +0 -0
  404. package/examples/tdk-example/services/shop/orders-app/service.json +9 -0
  405. package/examples/tdk-example/services/shop/orders-app/src/main.tsx +9 -0
  406. package/examples/tdk-example/services/shop/orders-app/src/orders.tsx +67 -0
  407. package/examples/tdk-example/services/shop/orders-app/src/style.css +15 -0
  408. package/examples/tdk-example/services/shop/orders-worker/package.json +18 -0
  409. package/examples/tdk-example/services/shop/orders-worker/service.json +13 -0
  410. package/examples/tdk-example/services/shop/orders-worker/src/index.ts +33 -0
  411. package/ext/Tiltfile +66 -0
  412. package/ext/ide-components/README.md +221 -0
  413. package/ext/ide-components/code_viewer/server.py +208 -0
  414. package/ext/ide-components/config_inspector/server.py +1052 -0
  415. package/ext/ide-components/file_browser/server.py +287 -0
  416. package/ext/ide-components/shared/config_service.py +471 -0
  417. package/ext/ide-components/shared/file_utils.py +300 -0
  418. package/ext/ide-components/shared/http_utils.py +234 -0
  419. package/ext/ide-components/shared/static/styles.css +1334 -0
  420. package/ext/ide-components/shared/syntax_highlighter.py +142 -0
  421. package/ext/ide-components/shared/template_engine.py +125 -0
  422. package/ext/ide-components/shared/templates/base.html +121 -0
  423. package/ext/ide-components/shared/test_config_service.py +328 -0
  424. package/ext/ide-components/shared/tilt_integration.py +160 -0
  425. package/ext/ui-enhancements/cron-status-server.sh +51 -0
  426. package/ext/ui-enhancements/cron-status-tracker.sh +148 -0
  427. package/ext/ui-enhancements/extension.yaml +36 -0
  428. package/ext/ui-enhancements/tiltfile.py +101 -0
  429. package/ext/ui-enhancements/ui/cron-jobs-tab.css +396 -0
  430. package/ext/ui-enhancements/ui/help-panel.css +279 -0
  431. package/ext/ui-enhancements/ui/icons.css +125 -0
  432. package/ext/ui-enhancements/ui/tooltips.css +114 -0
  433. package/package.json +94 -4
  434. package/shared-platform-engineering/docker-templates/bun-hoisted-symlink-fix.sh +25 -0
  435. package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +466 -0
  436. package/shared-platform-engineering/docker-templates/install-deps.sh +154 -0
  437. package/shared-platform-engineering/docker-templates/prisma-bun-client-link-fix.sh +14 -0
  438. package/shared-platform-engineering/docker-templates/prisma-normalize-client.sh +58 -0
  439. package/specs/specs/TILT_SERVICE_DEFAULTS.star +207 -0
  440. package/specs/specs/TILT_TECH_STACK.star +161 -0
@@ -0,0 +1,864 @@
1
+ # Copyright (c) 2026 Flisk contributors
2
+ # SPDX-License-Identifier: MIT
3
+ # =============================================================================
4
+ # 🧩 ORCHESTRATOR APPLY - COMPOSE RESOURCE REGISTRATION (Refactored)
5
+ # =============================================================================
6
+
7
+ # === INLINED CONSTANTS for pure extension loading ===
8
+ OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
9
+ # === END INLINED CONSTANTS ===
10
+
11
+
12
+ load("../../common/utils_debug.star", "debug_log")
13
+ load('../../../platform/docker/index.star', 'Docker')
14
+ load('../../../platform/docker/build/frontend_build_plan.star', 'frontend_build_plan')
15
+ load('../../../platform/docker/constants.star', 'PlatformDockerConstants')
16
+ load('../../../tilt/manifest/constants.star', 'BASE_PORT_FRONTEND', 'BASE_PORT_BACKEND')
17
+ load('../../../platform/docker/networking/traefik_static_routes.star', 'generate_static_wake_route', 'normalize_abs_path')
18
+ load('../../../platform/docker/networking/sablier_container_cycle.star', 'sablier_middleware_suffix')
19
+ # Shared platform Postgres force-start path. infra-loader.star must not load
20
+ # apply_compose (no circular load): it only loads platform/docker + registries.
21
+ load('../infra-loader.star', 'Infra')
22
+ load('../shared-platform-postgres.star',
23
+ _shared_postgres_names = 'SHARED_POSTGRES_DEPENDENCY_NAMES',
24
+ _is_shared_platform_postgres_dependency = 'is_shared_platform_postgres_dependency',
25
+ _manifest_needs_shared_platform_postgres = 'manifest_needs_shared_platform_postgres')
26
+
27
+ load('./builders/typescript.star', 'TypescriptBuilders')
28
+
29
+
30
+ # Public wrappers for shared platform Postgres helpers. Starlark `load` does not
31
+ # re-export loaded names. Canonical list + predicates live in
32
+ # shared-platform-postgres.star — do not hardcode a second copy of the names here.
33
+
34
+ def is_shared_platform_postgres_dependency(name):
35
+ """True when a dependsOn name is one of the shared platform Postgres aliases."""
36
+ return _is_shared_platform_postgres_dependency(name)
37
+
38
+
39
+ def manifest_needs_shared_platform_postgres(manifest):
40
+ """True when a manifest's dependsOn lists postgres or database-management."""
41
+ return _manifest_needs_shared_platform_postgres(manifest)
42
+
43
+
44
+ def selected_for_shared_platform_postgres(name, ctx):
45
+ """Use the same focus selection later passed to set_enabled_resources."""
46
+ if not ctx.get('focus_mode', False):
47
+ return True
48
+ return name in (ctx.get('focus_enabled_resources') or [])
49
+
50
+
51
+ def force_start_shared_platform_postgres_once(ctx, should_enable, resource_name=""):
52
+ """Force-start shared platform Postgres at most once per Tiltfile evaluation.
53
+
54
+ `register_compose_resources` runs per stack and can see unselected nested
55
+ services; two selected services that both `dependsOn` Postgres would otherwise call
56
+ `Infra.force_start_postgres` twice (docker_compose + dc_resource each time).
57
+ Module-level mutable flags are unusable — Tilt freezes Starlark globals — so
58
+ the guard lives on `ctx`, a dict the Tiltfile already owns for this run.
59
+
60
+ Returns True when this call performed the force-start, False when it skipped
61
+ (already started this run, or database-management is already on).
62
+ """
63
+ if ctx.get('_shared_platform_postgres_force_started', False):
64
+ debug_log("COMPOSE: shared platform Postgres already force-started this run; skip for '{}'".format(resource_name))
65
+ return False
66
+ if should_enable('database-management'):
67
+ return False
68
+ project_root_for_env = ctx.get('project_root', '')
69
+ root_prefix = (project_root_for_env + '/') if project_root_for_env else ''
70
+ env_candidate = (project_root_for_env + '/.env') if project_root_for_env else '.env'
71
+ env_file = _env_file_if_exists(env_candidate)
72
+ write_fn = ctx.get('write_file', None)
73
+ if write_fn == None:
74
+ fail("dependsOn postgres/database-management on selected resource '{}' requires ctx.write_file to materialize services/platform/database-management/docker-compose.yml".format(resource_name))
75
+ debug_log("COMPOSE: force-starting shared platform Postgres once (selected '{}' dependsOn)".format(resource_name))
76
+ Infra.force_start_postgres(should_enable, root_prefix=root_prefix, env_file=env_file, write_fn=write_fn)
77
+ ctx['_shared_platform_postgres_force_started'] = True
78
+ return True
79
+
80
+
81
+ def _env_file_if_exists(env_file):
82
+ """.env is gitignored (no .env.example shipped) across every Flisk example repo, so a
83
+ fresh clone must not hard-require it: docker_compose()'s env_file kwarg type-checks as
84
+ path|string (rejects None), so only return a path when the file actually exists."""
85
+ exists = str(local("test -f '" + env_file + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes'
86
+ return env_file if exists else None
87
+
88
+
89
+ def _docker_compose_app(compose_paths, project_name, env_file):
90
+ resolved_env_file = _env_file_if_exists(env_file)
91
+ if resolved_env_file:
92
+ docker_compose(compose_paths, project_name=project_name, env_file=resolved_env_file)
93
+ else:
94
+ docker_compose(compose_paths, project_name=project_name)
95
+
96
+
97
+ def _build_infra_dependencies(resource_name, should_enable, ctx, has_backend=False):
98
+ infra_deps = []
99
+ if should_enable('database-management'):
100
+ infra_deps.append('postgres')
101
+ if has_backend:
102
+ infra_deps.append('provision-db-' + resource_name)
103
+ if should_enable(PlatformDockerConstants.VERDACCIO_RESOURCE_NAME):
104
+ project_root = ctx.get('project_root', '')
105
+ verdaccio_compose = ((project_root.rstrip('/') + '/') if project_root else '') + 'docker-compose.verdaccio.yml'
106
+ if str(local("test -f '" + verdaccio_compose + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
107
+ infra_deps.append(PlatformDockerConstants.VERDACCIO_RESOURCE_NAME)
108
+ if should_enable('golden-image') and ctx.get('golden_image_resource'):
109
+ infra_deps.append(ctx['golden_image_resource'])
110
+ return infra_deps
111
+
112
+
113
+ def _resolve_dependency_to_resource(dep_name, all_services_map):
114
+ """
115
+ Resolve a short dependency name (e.g., 'identity') to the full YAML resource name.
116
+
117
+ The discovery registry creates YAML resources with names like:
118
+ - 'identity-management-backend-yaml' for identity backend
119
+ - 'api-gateway-yaml' for api-gateway
120
+
121
+ But manifests reference them as short names like 'identity' or 'api-gateway'.
122
+
123
+ Shared platform Postgres aliases (`postgres`, `database-management`) resolve
124
+ to the literal Tilt resource `postgres` in BOTH feature states — they must
125
+ NOT fall through to `postgres-yaml` or any other name.
126
+ """
127
+ # Shared platform Postgres: exact names only (typos stay on the normal path).
128
+ if is_shared_platform_postgres_dependency(dep_name):
129
+ return 'postgres'
130
+
131
+ # Check if already a full YAML resource name
132
+ if dep_name in all_services_map:
133
+ return dep_name
134
+
135
+ # Try with -yaml suffix (for resources already resolved)
136
+ yaml_name = dep_name + '-yaml'
137
+ if yaml_name in all_services_map:
138
+ return yaml_name
139
+
140
+ # Try to find matching service by stack/short name
141
+ for resource_name, resource_info in all_services_map.items():
142
+ # Check if this service's stack matches the dependency
143
+ resource_domain = resource_info.get('stack', '')
144
+ if resource_domain == dep_name:
145
+ # Return the first resource of this service with -yaml suffix
146
+ resources = resource_info.get('resources', [])
147
+ if resources:
148
+ # Prefer backend resources over frontends
149
+ for res in resources:
150
+ if not res.get('frontend', False):
151
+ return res['name'] + '-yaml'
152
+ # Fallback to first resource
153
+ return resources[0]['name'] + '-yaml'
154
+
155
+ # Try pattern matching: identity -> identity-*-yaml
156
+ for resource_name in all_services_map.keys():
157
+ if resource_name.startswith(dep_name + '-') and resource_name.endswith('-yaml'):
158
+ return resource_name
159
+
160
+ # Return original with -yaml suffix as last resort
161
+ return dep_name + '-yaml'
162
+
163
+
164
+ def resolve_dependency_to_resource(dep_name, all_services_map):
165
+ """Public wrapper over `_resolve_dependency_to_resource` (exported for tests)."""
166
+ return _resolve_dependency_to_resource(dep_name, all_services_map)
167
+
168
+
169
+ def build_infra_dependencies(resource_name, should_enable, ctx=None, has_backend=False):
170
+ """Public wrapper over `_build_infra_dependencies` (exported for tests).
171
+
172
+ feature off → no postgres; feature on → has postgres (plus backend
173
+ provision-db edge when has_backend is true).
174
+ """
175
+ return _build_infra_dependencies(resource_name, should_enable, ctx if ctx != None else {}, has_backend)
176
+
177
+
178
+ def build_resource_deps(res, res_name, manifest, resource_config, infra_deps, config_gen_resources=None, resource_manifests=None, runtime_flags=None, all_services_map=None):
179
+ """Public wrapper over `_build_resource_deps` (exported for tests).
180
+
181
+ Ensures the dependsOn→resource_deps edge is exercised by tests: feature off
182
+ + dependsOn postgres → postgres edge present; feature on + dependsOn →
183
+ exactly one postgres edge (infra_deps already carries it).
184
+ """
185
+ default_runtime_flags = {
186
+ 'enforce_migrator_deps': False,
187
+ 'auto_init_apps': True,
188
+ 'disable_app_replicas': False,
189
+ }
190
+ return _build_resource_deps(
191
+ res, res_name, manifest, resource_config, infra_deps,
192
+ config_gen_resources if config_gen_resources != None else {},
193
+ resource_manifests if resource_manifests != None else {},
194
+ runtime_flags if runtime_flags != None else default_runtime_flags,
195
+ all_services_map,
196
+ )
197
+
198
+
199
+ def _build_resource_deps(res, res_name, manifest, resource_config, infra_deps, config_gen_resources, resource_manifests, runtime_flags, all_services_map=None):
200
+ # Drop self-deps: shared infra_deps always includes verdaccio when enabled, so
201
+ # registering verdaccio itself would otherwise produce resource_deps=['verdaccio'].
202
+ res_deps = [dep for dep in infra_deps if dep != res_name]
203
+ if res_name in config_gen_resources:
204
+ res_deps.append(config_gen_resources[res_name])
205
+ if res.get('frontend', False):
206
+ backend_name = manifest.get('backendName', res_name.replace('frontend', 'backend'))
207
+ if backend_name != res_name and backend_name in resource_manifests:
208
+ res_deps.append(backend_name)
209
+ elif runtime_flags['enforce_migrator_deps'] and resource_config.get('has_migrator', False):
210
+ migrator_name = resource_config['name'] + '-db-migrator'
211
+ if migrator_name not in res_deps:
212
+ res_deps.append(migrator_name)
213
+
214
+ # NEW: Resolve dependsOn from manifest
215
+ internal_deps = manifest.get('dependsOn', [])
216
+ for dep in internal_deps:
217
+ resolved_dep = _resolve_dependency_to_resource(dep, all_services_map)
218
+ if resolved_dep and resolved_dep != res_name and resolved_dep not in res_deps:
219
+ res_deps.append(resolved_dep)
220
+
221
+ return res_deps
222
+
223
+
224
+ def resource_defers_start(manifest):
225
+ """True when a manifest opts into `sablier.enable` + `sablier.deferStart`
226
+ AND the licensed sablier module is actually active.
227
+
228
+ deferStart stays behind the same TDK_LICENSE_KEY gate as the rest of
229
+ `sablier` (an explicit product decision, not just the opt-in manifest
230
+ flag): the free-tier stub's sablier_middleware_suffix() always reports
231
+ `enabled=False` regardless of what the manifest says, so checking through
232
+ it here -- rather than reading manifest['sablier']['enable'] directly --
233
+ is what keeps deferStart off for unlicensed projects. Without this check,
234
+ a project with no license would still get "no container created or
235
+ started," silently bypassing the license boundary for the disable-the-
236
+ container half of the feature even though the Docker-label wake half
237
+ stays correctly disabled.
238
+
239
+ A deferred resource's image still builds (docker_build has no auto_init
240
+ gate), but its dc_resource/run-only/replica resources are held back with
241
+ auto_init=False: no container is created or started until the Traefik
242
+ static route wakes it on first request (see openspec/changes/
243
+ prioritized-cold-start)."""
244
+ _, sablier_licensed_and_enabled = sablier_middleware_suffix(manifest, '')
245
+ sablier = manifest.get('sablier', {}) if manifest else {}
246
+ defers_start = bool(sablier.get('enable', False) and sablier.get('deferStart', False))
247
+ if defers_start and not sablier_licensed_and_enabled:
248
+ print("⚠️ '{}' requests sablier.deferStart but the licensed Sablier overlay is disabled; starting normally".format(manifest.get('name', 'resource')))
249
+ if not sablier_licensed_and_enabled:
250
+ return False
251
+ return defers_start
252
+
253
+
254
+ def resolve_manifest_dependency_names(manifest, all_services_map):
255
+ """Resolve a manifest's `dependsOn` short names to full resource names,
256
+ reusing the same `_resolve_dependency_to_resource` that `_build_resource_deps`
257
+ already trusts for Tilt's own resource_deps ordering -- an ambiguous name
258
+ behaves identically here as it already does there."""
259
+ resolved = []
260
+ for dep in (manifest.get('dependsOn', []) if manifest else []):
261
+ resolved_dep = _resolve_dependency_to_resource(dep, all_services_map)
262
+ if resolved_dep and resolved_dep not in resolved:
263
+ resolved.append(resolved_dep)
264
+ return resolved
265
+
266
+
267
+ def resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map):
268
+ """Of a deferStart resource's manifest dependencies, resolve the subset
269
+ that are themselves deferStart resources, for the wake gateway's
270
+ X-Wake-Deps (see generate_static_wake_route's `dependencies` param and
271
+ openspec/changes/prioritized-cold-start design.md D5).
272
+
273
+ A dependsOn name `_resolve_dependency_to_resource` can't map to an exact
274
+ resource (its own fallback branches -- see that function) won't be a key
275
+ in `resource_manifests` either, so it's quietly excluded here rather than
276
+ guessed at -- consistent with D5's existing stance. Always-on infra
277
+ (database, NATS) is never itself a deferStart resource (D5), so in
278
+ practice this only ever picks up the one case D5 flags as mattering: a
279
+ deferStart resource depending on another."""
280
+ dependencies = []
281
+ for resolved_dep in resolve_manifest_dependency_names(manifest, all_services_map):
282
+ dep_manifest = resource_manifests.get(resolved_dep)
283
+ if not dep_manifest or not resource_defers_start(dep_manifest):
284
+ continue
285
+ dep_service_name = all_services_map.get(resolved_dep, {}).get('name', '')
286
+ if not dep_service_name:
287
+ continue
288
+ dependencies.append((resolved_dep, PlatformDockerConstants.compose_project_name(dep_service_name)))
289
+ return dependencies
290
+
291
+
292
+ def _register_replicas(config, auto_init_apps):
293
+ """Register additional replica resources for high-availability services."""
294
+ replicas = config.get('replicas', 1)
295
+ if replicas <= 1:
296
+ return
297
+ # Docker compose generates replicas starting from 1 (e.g., service-1, service-2)
298
+ # Primary is the base name (service), replicas are service-1, service-2, etc.
299
+ for i in range(1, replicas):
300
+ replica_name = config['res_name'] + '-' + str(i)
301
+ dc_resource(
302
+ replica_name,
303
+ labels=config['labels'],
304
+ resource_deps=config['res_deps'],
305
+ auto_init=auto_init_apps,
306
+ )
307
+
308
+
309
+ def _live_update_sync_source(project_root, full_res_path, sync_path):
310
+ """Local path Tilt watches for a live-update sync.
311
+
312
+ Tilt resolves sync() local paths against the Tiltfile directory (.tdk/.tdk-out), not
313
+ the docker_build context, so a project-relative path never matches the changed files
314
+ and every edit falls back to a full image rebuild ("Found file(s) not matching any
315
+ sync"). Anchor it at the project root, like the Dockerfile and build context.
316
+ """
317
+ relative_path = full_res_path + '/' + sync_path
318
+ if project_root:
319
+ return project_root.rstrip('/') + '/' + relative_path
320
+ return relative_path
321
+
322
+
323
+ def _build_live_update_rules(res_path, full_res_path, syncs, project_root='', language='bun', go_live_reload=False):
324
+ """Build live update sync and run rules for a resource.
325
+
326
+ Python backends reload their own process after a sync (uvicorn --reload), so they have
327
+ no Bun install step. A changed pyproject.toml is not synced, so Tilt rebuilds the image instead.
328
+ Rust backends, and Go backends without `dev.liveReload`, have no live update (see the early return).
329
+ """
330
+ # Go and Rust are compiled into the image and have no reload process, so syncing sources would leave the
331
+ # old binary running. Return before any sync() step is built (Tilt rejects sync steps that are created
332
+ # but never used): no live-update rules means Tilt rebuilds the image when a watched file changes.
333
+ if language == 'rust' or (language == 'go' and not go_live_reload):
334
+ return []
335
+
336
+ if go_live_reload:
337
+ # Opted-in Go development loop: sync the sources into the development image, where the flisk-go-watch script rebuilds and restarts.
338
+ # Dependency and Dockerfile changes cannot be picked up by a restart, so they fall back to a full image rebuild.
339
+ source_dir = _live_update_sync_source(project_root, full_res_path, '')
340
+ return [
341
+ fall_back_on([
342
+ source_dir + 'go.mod',
343
+ source_dir + 'go.sum',
344
+ source_dir + OUTPUT.AUTOGENERATED_FOLDER,
345
+ ]),
346
+ sync(source_dir.rstrip('/'), '/app/' + full_res_path),
347
+ ]
348
+
349
+ live_update_rules = []
350
+ for sync_path in syncs:
351
+ # Python and Node images never read the Bun registry config, and the engine does not
352
+ # generate it for provider-owned languages, so there is nothing to sync.
353
+ if language == 'python' and (
354
+ sync_path.endswith('.npmrc.docker.autogenerated') or sync_path.endswith('bunfig.docker.autogenerated.toml')
355
+ ):
356
+ continue
357
+ if language == 'node' and (
358
+ sync_path.endswith('.npmrc.docker.autogenerated') or sync_path.endswith('bunfig.docker.autogenerated.toml')
359
+ ):
360
+ continue
361
+ full_sync_path = _live_update_sync_source(project_root, full_res_path, sync_path)
362
+ dest = '/app/' + full_res_path + '/' + sync_path
363
+ live_update_rules.append(sync(full_sync_path, dest))
364
+
365
+ if language == 'python' or language == 'node':
366
+ return live_update_rules
367
+
368
+ package_json_path = '/app/' + full_res_path + '/package.json'
369
+ bun_lock_path = '/app/' + full_res_path + '/bun.lock'
370
+ live_update_rules.append(run('cd /app/' + full_res_path + ' && bun install',
371
+ trigger=[package_json_path, bun_lock_path]))
372
+ return live_update_rules
373
+
374
+
375
+ def _app_image_name(resource_name, res_name):
376
+ """The image ref docker_build builds and the app compose service declares (project-scoped; see constants.star)."""
377
+ return PlatformDockerConstants.app_image_name(resource_name, res_name)
378
+
379
+
380
+ def _wake_compose_invocation(project_root, resource_path, res_name, resource_name):
381
+ """Compose files, env file and image for the wake gateway's direct start.
382
+
383
+ The same files/--env-file the `-run-only` resource passes, as absolute
384
+ normalized paths: the gateway mounts the project at the same normalized
385
+ root (traefik_standalone.star), so these resolve identically there.
386
+ Returns None without a project root (paths would be relative to Tilt's cwd).
387
+ """
388
+ if not project_root:
389
+ return None
390
+ root = normalize_abs_path(project_root)
391
+ compose_dir = root + '/' + resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER
392
+ files = [compose_dir + '/docker-compose.app.autogenerated.yml']
393
+ port_override = compose_dir + '/docker-compose.port-override.yml'
394
+ if os.path.exists(port_override):
395
+ files.append(port_override)
396
+ env_file = root + '/.env'
397
+ return {
398
+ 'compose_files': files,
399
+ 'env_file': env_file if os.path.exists(env_file) else '',
400
+ 'image': _app_image_name(resource_name, res_name),
401
+ }
402
+
403
+
404
+ def _image_target(config):
405
+ """The Dockerfile target Tilt builds and the deferStart prebuild must match: `development` for Go with `dev.liveReload`."""
406
+ return 'development' if Docker.go_live_reload(config.get('manifest', {})) else 'production'
407
+
408
+
409
+ def _register_docker_build(config, live_update_rules):
410
+ """Register docker_build with live_update for hot-reload support."""
411
+ TypescriptBuilders.build_typescript_service(
412
+ _app_image_name(config['resource_name'], config['res_name']),
413
+ config.get('project_root', '') or '.',
414
+ _resolve_dockerfile(config),
415
+ live_update_rules,
416
+ config['res_deps'],
417
+ target = _image_target(config),
418
+ )
419
+
420
+
421
+ def _register_deferred_image_prebuild(config, auto_init_apps):
422
+ """Build a deferStart resource's image during `flisk up` without creating its container.
423
+
424
+ `auto_init=False` on the dc_resource skips its docker_build too (confirmed
425
+ live on tdk-erp-system, task 7.2), so a fresh project's first request would
426
+ find no image and the wake gateway would fall back to `tilt trigger`, which
427
+ queues behind every other build. This local_resource builds the same image
428
+ (same Dockerfile and target as docker_build: `production`, or `development` for Go with `dev.liveReload`; host network, and an allowlist
429
+ .dockerignore equivalent to docker_build's only=/ignore=) under the tag the
430
+ compose service declares, so the gateway can start it directly.
431
+ """
432
+ project_root = config.get('project_root', '')
433
+ dockerfile = _resolve_dockerfile(config)
434
+ prebuild_dockerfile = dockerfile + '.prebuild'
435
+ # The same target _register_docker_build picks: a Go service with `dev.liveReload` runs the development image (the watcher), so
436
+ # prebuilding `production` under the same tag would start the compiled binary with no reload.
437
+ target = _image_target(config)
438
+ ignore_content = TypescriptBuilders.prebuild_dockerignore(dockerfile, project_root, config['res_path'])
439
+ # BuildKit reads `<dockerfile>.dockerignore` for `-f <dockerfile>`; the
440
+ # original Dockerfile already has a (denylist) one, hence the copy.
441
+ cmd = (
442
+ "cp '" + dockerfile + "' '" + prebuild_dockerfile + "'"
443
+ + " && printf '%s' '" + ignore_content + "' > '" + prebuild_dockerfile + ".dockerignore'"
444
+ + " && docker build --network host --target " + target
445
+ + " -f '" + prebuild_dockerfile + "'"
446
+ + " -t '" + _app_image_name(config['resource_name'], config['res_name']) + "'"
447
+ + " '" + (project_root or '.') + "'"
448
+ )
449
+ local_resource(
450
+ name=config['res_name'] + '-image',
451
+ cmd=cmd,
452
+ labels=config['labels'],
453
+ resource_deps=config['res_deps'],
454
+ auto_init=auto_init_apps,
455
+ )
456
+
457
+
458
+ def _resolve_dockerfile(config):
459
+ """Absolute (when project_root is set) path of a resource's Dockerfile."""
460
+ project_root = config.get('project_root', '')
461
+ # Use custom dockerfile from config if specified, otherwise use autogenerated default
462
+ # The res_path is relative to project_root (e.g., 'services/product/...')
463
+ # The dockerfile config is relative to res_path (e.g., '.autogenerated/Dockerfile...')
464
+ rel_dockerfile = config.get('dockerfile', '')
465
+ if rel_dockerfile:
466
+ if rel_dockerfile.startswith('/'):
467
+ dockerfile = config['res_path'] + rel_dockerfile
468
+ else:
469
+ dockerfile = config['res_path'] + '/' + rel_dockerfile
470
+ else:
471
+ dockerfile = config['res_path'] + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.app.autogenerated'
472
+ # Prepend project_root to make absolute path from the Tilt working directory
473
+ if project_root:
474
+ if dockerfile.startswith('/'):
475
+ dockerfile = project_root + dockerfile
476
+ else:
477
+ dockerfile = project_root + '/' + dockerfile
478
+ return dockerfile
479
+
480
+
481
+ def _register_run_only_resource(config, resource_path, compose_project_name, auto_init_apps=True):
482
+ """Register a run-only local resource for docker compose up."""
483
+ project_root = config.get('project_root', '')
484
+ compose_dir = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER
485
+ compose_file = compose_dir + '/docker-compose.app.autogenerated.yml'
486
+ port_override = compose_dir + '/docker-compose.port-override.yml'
487
+ env_file = '.env'
488
+ if project_root:
489
+ root = project_root.rstrip('/')
490
+ compose_file = root + '/' + compose_file
491
+ port_override = root + '/' + port_override
492
+ env_file = root + '/.env'
493
+ compose_files = '-f ' + compose_file
494
+ if str(local("test -f '" + port_override + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
495
+ compose_files = compose_files + ' -f ' + port_override
496
+ # .env is gitignored (no .env.example shipped) across every Flisk example repo, so a
497
+ # fresh clone must not hard-require it: only pass --env-file when it actually exists.
498
+ env_file_flag = ''
499
+ if str(local("test -f '" + env_file + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
500
+ env_file_flag = ' --env-file ' + env_file
501
+ local_resource(
502
+ name=config['res_name'] + '-run-only',
503
+ cmd='docker compose -p '
504
+ + compose_project_name
505
+ + ' '
506
+ + compose_files
507
+ + env_file_flag
508
+ + ' up -d --no-build '
509
+ + config['res_name'],
510
+ labels=config['labels'] + ['run-only'],
511
+ # The run-only Compose command uses the image produced by the main
512
+ # resource. Keep it behind that resource so --no-build cannot race
513
+ # the ImageBuild and fail with a missing image.
514
+ resource_deps=config['res_deps'] + [config['res_name']],
515
+ auto_init=auto_init_apps,
516
+ allow_parallel=True,
517
+ )
518
+
519
+
520
+ def _register_single_resource(config, resource_path, compose_project_name, auto_init_apps):
521
+ """Register a single dc_resource with optional docker_build and run-only resource."""
522
+ app_type = config.get('app_type', 'backend')
523
+ res_name = config['res_name']
524
+
525
+ # A sablier.enable + sablier.deferStart resource is held back from flisk up's
526
+ # normal bring-up: its container is never created or started here, only via
527
+ # the Traefik wake path on first request. auto_init=False also skips the
528
+ # dc_resource's docker_build, so its image is built by a separate
529
+ # `<name>-image` resource instead (_register_deferred_image_prebuild).
530
+ defers_start = resource_defers_start(config.get('manifest', {}))
531
+ effective_auto_init = auto_init_apps and not defers_start
532
+
533
+ debug_log("REGISTER: Registering '{}' app_type='{}' auto_init={}".format(res_name, app_type, effective_auto_init))
534
+
535
+ # Skip docker_build for libraries and SDKs - they don't have Dockerfiles
536
+ if app_type not in ['library', 'sdk', 'bring-your-own'] and config.get('syncs'):
537
+ debug_log("REGISTER: '{}' has syncs, calling docker_build".format(res_name))
538
+ live_update_rules = _build_live_update_rules(
539
+ config['res_path'],
540
+ config['res_path'],
541
+ config['syncs'],
542
+ project_root=config.get('project_root', ''),
543
+ language=config.get('manifest', {}).get('language', 'bun'),
544
+ go_live_reload=Docker.go_live_reload(config.get('manifest', {})),
545
+ )
546
+ _register_docker_build(config, live_update_rules)
547
+ if defers_start:
548
+ _register_deferred_image_prebuild(config, auto_init_apps)
549
+ else:
550
+ debug_log("REGISTER: '{}' skipping docker_build (app_type='{}', syncs={})".format(res_name, app_type, config.get('syncs')))
551
+
552
+ debug_log("REGISTER: Calling dc_resource for '{}' with deps={}".format(res_name, config['res_deps']))
553
+ dc_resource(
554
+ config['res_name'],
555
+ labels=config['labels'],
556
+ resource_deps=config['res_deps'],
557
+ auto_init=effective_auto_init,
558
+ )
559
+ debug_log("REGISTER: dc_resource completed for '{}'".format(res_name))
560
+
561
+ _register_run_only_resource(config, resource_path, compose_project_name, effective_auto_init)
562
+ _register_replicas(config, effective_auto_init)
563
+
564
+
565
+ def _register_dc_resources(resource_configs, resource_path, compose_project_name, auto_init_apps):
566
+ """Register all dc_resources for the service."""
567
+ for config in resource_configs:
568
+ _register_single_resource(config, resource_path, compose_project_name, auto_init_apps)
569
+
570
+
571
+ # appTypes whose containers get DATABASE_URL and therefore need their logical database provisioned. Bring-your-own
572
+ # containers receive DATABASE_URL too (docs/byo.md), so without provisioning they point at a database that never exists.
573
+ DATABASE_APP_TYPES = ['backend', 'bring-your-own']
574
+
575
+
576
+ def resource_needs_database(manifest):
577
+ """True when a resource of this manifest receives DATABASE_URL and needs its database provisioned."""
578
+ return (manifest or {}).get('appType') in DATABASE_APP_TYPES
579
+
580
+
581
+ def _has_backend_resource(resource_config, resource_manifests):
582
+ """Check if service has a resource that needs the provisioned database (backend or bring-your-own)."""
583
+ for resource in resource_config.get('resources', []):
584
+ manifest = resource_manifests.get(resource['name'], {})
585
+ if resource_needs_database(manifest):
586
+ return True
587
+ return False
588
+
589
+
590
+ def _should_skip_frontend(res, should_enable):
591
+ """Check if frontend resource should be skipped (backends-only mode)."""
592
+ return res.get('frontend', False) and should_enable('backends-only')
593
+
594
+
595
+ def _register_frontend_typecheck(res, service_dir, typecheck_cmd):
596
+ """Non-blocking `<service>-typecheck` resource: runs the planned tsc command so type errors show in Tilt without gating the image.
597
+
598
+ The command runs on the host, so TypeScript must resolve from the service directory (`bun install`, at the
599
+ service or workspace root). Without it the resource fails with that instruction instead of a bare module error.
600
+ """
601
+ local_resource(
602
+ name=res['name'] + '-typecheck',
603
+ cmd="cd '" + service_dir + "' && { bunx tsc --version >/dev/null 2>&1 || { echo 'typecheck needs host dependencies: run bun install in " + service_dir + "'; exit 1; }; } && " + typecheck_cmd,
604
+ deps=[service_dir + '/src', service_dir + '/tsconfig.json'],
605
+ labels=['app.' + res['name'], 'typecheck'],
606
+ # tsc --noEmit writes no files, so it can run alongside the image builds.
607
+ allow_parallel=True,
608
+ )
609
+
610
+
611
+ def _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable, project_root=''):
612
+ """Process a frontend resource and return compose entry."""
613
+ target_path = res.get('target_path', manifest.get('target_path', '/usr/share/nginx/html'))
614
+ use_nginx = 'nginx' in target_path or target_path == '/usr/share/nginx/html'
615
+ port = res.get('port', manifest.get('port', BASE_PORT_FRONTEND))
616
+ service_dir = (project_root.rstrip('/') + '/' if project_root else '') + full_res_path
617
+ plan = frontend_build_plan(service_dir + '/package.json')
618
+ Docker.frontend(
619
+ res_path=full_res_path,
620
+ resource_name=res['name'],
621
+ port=port,
622
+ target_path=target_path,
623
+ use_nginx=use_nginx,
624
+ use_golden=should_enable('golden-image'),
625
+ build_cmd=plan['build_cmd'],
626
+ )
627
+ if plan['typecheck']:
628
+ _register_frontend_typecheck(res, service_dir, plan['typecheck_cmd'])
629
+ return Docker.frontend_compose(resource_path=resource_path, resource_name=resource_name, res=res, manifest=manifest)
630
+
631
+
632
+ def _process_backend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable):
633
+ """Process a backend resource and return compose entry."""
634
+ if manifest.get('appType') != 'bring-your-own':
635
+ Docker.backend(
636
+ res_path=full_res_path,
637
+ resource_name=res['name'],
638
+ port=None, # Use default BASE_PORT_BACKEND
639
+ build_cmd=res.get('start_command', 'bun run build'),
640
+ use_golden=should_enable('golden-image'),
641
+ )
642
+ return Docker.backend_compose(resource_path=resource_path, resource_name=resource_name, res=res, manifest=manifest)
643
+
644
+
645
+ def _build_resource_config(res, manifest, resource_config, full_res_path, infra_deps,
646
+ config_gen_resources, resource_manifests, runtime_flags, all_services_map=None, project_root=''):
647
+ """Build configuration dict for a single resource."""
648
+ res_name = res['name']
649
+ res_deps = _build_resource_deps(
650
+ res, res_name, manifest, resource_config, infra_deps,
651
+ config_gen_resources, resource_manifests, runtime_flags, all_services_map,
652
+ )
653
+ replicas = manifest.get('replicas', 1)
654
+ if runtime_flags['disable_app_replicas']:
655
+ replicas = 1
656
+
657
+ # Extract environment variables from manifest params
658
+ env_vars = manifest.get('params', {})
659
+
660
+ return {
661
+ 'res_name': res_name,
662
+ 'resource_name': resource_config['name'],
663
+ 'res_deps': res_deps,
664
+ 'labels': ['app.' + res_name],
665
+ 'replicas': replicas,
666
+ 'syncs': res.get('syncs', []),
667
+ 'app_type': manifest.get('appType', 'backend'),
668
+ 'dockerfile': res.get('dockerfile', manifest.get('dockerfile', OUTPUT.AUTOGENERATED_FOLDER + '/Dockerfile.app.autogenerated')),
669
+ 'res_path': full_res_path,
670
+ 'env': env_vars,
671
+ 'project_root': project_root,
672
+ 'manifest': manifest,
673
+ }
674
+
675
+
676
+ def count_routable_backends_by_stack(resource_config, resource_manifests, default_stack):
677
+ """Count the backends of each stack that get a Traefik route (workers, frontends, SDKs, libraries and unproxied BYO do not)."""
678
+ counts = {}
679
+ for resource in resource_config.get('resources', []):
680
+ manifest = resource_manifests.get(resource['name'], {})
681
+ app_type = manifest.get('appType', 'backend')
682
+ if resource.get('frontend', False) or app_type in ['frontend', 'worker', 'library', 'sdk', 'infra']:
683
+ continue
684
+ if app_type == 'bring-your-own' and not manifest.get('exposeViaProxy', True):
685
+ continue
686
+ stack = manifest.get('stack', default_stack)
687
+ counts[stack] = counts.get(stack, 0) + 1
688
+ return counts
689
+
690
+
691
+ def register_compose_resources(resource_config, ctx, runtime_flags, manifest_state):
692
+ """Register all compose resources for a service."""
693
+ resource_name = resource_config.get('name', '')
694
+ resource_path = resource_config.get('path', '')
695
+
696
+ debug_log("COMPOSE: register_compose_resources called for '{}' path='{}'".format(resource_name, resource_path))
697
+
698
+ if not resource_name:
699
+ print("⚠️ Skipping service without name")
700
+ return {'compose_project_name': ''}
701
+
702
+ if not resource_path:
703
+ # Silently skip services without paths - these may be library references
704
+ # or incomplete manifests
705
+ debug_log("COMPOSE: SKIPPING '{}' - no path".format(resource_name))
706
+ return {'compose_project_name': ''}
707
+
708
+ debug_log("COMPOSE: Proceeding with '{}' - creating compose resources".format(resource_name))
709
+ should_enable = ctx['should_enable']
710
+ write_file = ctx['write_file']
711
+ compose_project_name = PlatformDockerConstants.compose_project_name(resource_name)
712
+
713
+ resource_manifests = manifest_state['resource_manifests']
714
+ config_gen_resources = manifest_state['config_gen_resources']
715
+ has_backend = _has_backend_resource(resource_config, resource_manifests)
716
+ infra_deps = _build_infra_dependencies(resource_name, should_enable, ctx, has_backend)
717
+
718
+ # Build map of all services for dependency resolution
719
+ # This maps short names like 'identity' to full resource names
720
+ all_services_map = {}
721
+ all_services = ctx.get('all_services', [])
722
+ for svc in all_services:
723
+ svc_name = svc.get('name', '')
724
+ if svc_name:
725
+ all_services_map[svc_name] = svc
726
+ # Also map resource names
727
+ for res in svc.get('resources', []):
728
+ res_name = res.get('name', '')
729
+ if res_name:
730
+ all_services_map[res_name] = svc
731
+
732
+ # Selection-bound shared platform Postgres start signal.
733
+ # Only enabled resources in THIS stack are evaluated. Registration sees
734
+ # unselected siblings before Tilt's enabled-resource filter runs.
735
+ # When database-management is off and any selected resource's
736
+ # manifest depends on postgres/database-management, force-start the shared
737
+ # platform Postgres via the existing infra loader (materializes
738
+ # services/platform/database-management/docker-compose.yml + registers the
739
+ # existing `postgres` Tilt resource). Does NOT open migrators/provision-db/Prisma.
740
+ # Idempotent across services: force_start_shared_platform_postgres_once
741
+ # guards on ctx so two selected dependents do not register postgres twice.
742
+ if not should_enable('database-management'):
743
+ for res in resource_config.get('resources', []):
744
+ if not selected_for_shared_platform_postgres(res.get('name', ''), ctx):
745
+ continue
746
+ res_manifest = resource_manifests.get(res['name'], {})
747
+ if manifest_needs_shared_platform_postgres(res_manifest):
748
+ debug_log("COMPOSE: selected '{}' dependsOn shared platform Postgres; force-starting postgres".format(res.get('name', '')))
749
+ force_start_shared_platform_postgres_once(ctx, should_enable, res.get('name', ''))
750
+ break
751
+
752
+ resource_entries = []
753
+ resource_configs = []
754
+ stack_backend_counts = count_routable_backends_by_stack(resource_config, resource_manifests, resource_name)
755
+
756
+ for res in resource_config.get('resources', []):
757
+ if _should_skip_frontend(res, should_enable):
758
+ continue
759
+
760
+ full_res_path = res.get('_resource_path', resource_path + '/' + res['name'])
761
+ manifest = resource_manifests.get(res['name'], {})
762
+ if manifest:
763
+ # Tell the Traefik label generator how many routable backends share this stack (see _stack_is_shared in networking/traefik.star).
764
+ manifest = dict(manifest)
765
+ manifest['_stackBackendCount'] = stack_backend_counts.get(manifest.get('stack', resource_name), 1)
766
+
767
+ # Skip non-app resources - they don't use the golden app Dockerfile pipeline.
768
+ # infra (e.g. verdaccio) is loaded via registries/verdaccio_loader.star instead.
769
+ # Building verdaccio as a backend produced broken COPY paths and missing package.json.
770
+ app_type = manifest.get('appType', 'backend')
771
+ if app_type in ['library', 'sdk', 'infra']:
772
+ debug_log("COMPOSE: Skipping '{}' appType='{}' (not an app container)".format(res.get('name', ''), app_type))
773
+ continue
774
+
775
+ if res.get('frontend', False):
776
+ entry = _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable, ctx.get('project_root', ''))
777
+ else:
778
+ entry = _process_backend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable)
779
+ # A deferStart resource has no container Traefik can discover via
780
+ # labels until its first request creates one (D2/D4) -- give it a
781
+ # static file-provider route instead, pointed at the wake gateway.
782
+ # Scoped to backends for now, matching the proposal's motivating
783
+ # case; frontend support is a natural follow-up, not implemented
784
+ # here. Dependency waking (D5): Flisk's real infra dependencies
785
+ # (database, NATS, a resource's own migrator) live in
786
+ # separately-registered compose files that `depends_on` cannot
787
+ # reference (confirmed empirically, see design.md D5), and they're
788
+ # always-on infra that's essentially never actually cold, so they
789
+ # never show up here regardless. The one real case D5 flags as
790
+ # mattering -- a peer resource that is itself deferStart -- is
791
+ # resolved via the manifest's own `dependsOn` below.
792
+ if resource_defers_start(manifest) and write_file:
793
+ internal_port = res.get('port', manifest.get('port', BASE_PORT_BACKEND))
794
+ static_route_path = PlatformDockerConstants.TRAEFIK_DYNAMIC_DIR_REL + '/' + res['name'] + '.yml'
795
+ compose_invocation = _wake_compose_invocation(
796
+ ctx.get('project_root', ''), resource_path, res['name'], resource_name,
797
+ ) or {}
798
+ write_file(static_route_path, generate_static_wake_route(
799
+ resource_entry_name=res['name'],
800
+ compose_project_name=compose_project_name,
801
+ manifest=manifest,
802
+ internal_port=internal_port,
803
+ gateway_host=PlatformDockerConstants.TRAEFIK_WAKE_GATEWAY_CONTAINER,
804
+ gateway_port=PlatformDockerConstants.TRAEFIK_WAKE_GATEWAY_PORT,
805
+ dependencies=resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map),
806
+ compose_files=compose_invocation.get('compose_files'),
807
+ env_file=compose_invocation.get('env_file', ''),
808
+ image=compose_invocation.get('image', ''),
809
+ ))
810
+
811
+ resource_entries.append(entry)
812
+ built_config = _build_resource_config(
813
+ res, manifest, resource_config, full_res_path, infra_deps,
814
+ config_gen_resources, resource_manifests, runtime_flags, all_services_map,
815
+ ctx.get('project_root', ''),
816
+ )
817
+ # A focused run still registers disabled siblings before Tilt applies
818
+ # set_enabled_resources. Do not leave their edge pointing at a Postgres
819
+ # resource that this evaluation did not register.
820
+ if not should_enable('database-management') and not ctx.get('_shared_platform_postgres_force_started', False):
821
+ built_config['res_deps'] = [dep for dep in built_config['res_deps'] if dep != 'postgres']
822
+ resource_configs.append(built_config)
823
+
824
+ debug_log("COMPOSE: Calling Docker.app_compose for '{}' with write_fn={}".format(resource_name, write_file))
825
+ Docker.app_compose(resource_path, resource_entries, write_file)
826
+
827
+ debug_log("COMPOSE: {} resource_entries count = {}".format(resource_name, len(resource_entries)))
828
+
829
+ # Prepend project root to make path absolute from project root
830
+ project_root = ctx.get('project_root', '')
831
+
832
+ # Only register docker_compose if we have actual services (not just libraries)
833
+ if resource_entries:
834
+ compose_file_rel = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.app.autogenerated.yml'
835
+ compose_file = project_root + '/' + compose_file_rel if project_root else compose_file_rel
836
+ # Load env file from project root for docker-compose variables (DB_PASSWORD, etc.)
837
+ env_file = project_root + '/.env' if project_root else '.env'
838
+ debug_log("COMPOSE: Calling docker_compose for '{}' with {} env_file={}".format(resource_name, compose_file, env_file))
839
+ _docker_compose_app(compose_file, compose_project_name, env_file)
840
+ port_override_rel = resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER + '/docker-compose.port-override.yml'
841
+ port_override = project_root + '/' + port_override_rel if project_root else port_override_rel
842
+ if str(local("test -f '" + port_override + "' && echo yes || echo no", quiet=True, echo_off=True)).strip() == 'yes':
843
+ debug_log("COMPOSE: Applying port override {}".format(port_override))
844
+ _docker_compose_app(port_override, compose_project_name, env_file)
845
+ else:
846
+ debug_log("COMPOSE: SKIPPING docker_compose for '{}' - no resource_entries".format(resource_name))
847
+
848
+ for compose_file in resource_config.get('compose_files', []):
849
+ if compose_file != '.autogenerated/docker-compose.app.autogenerated.yml':
850
+ compose_file_full = project_root + '/' + resource_path + '/' + compose_file if project_root else resource_path + '/' + compose_file
851
+ env_file = project_root + '/.env' if project_root else '.env'
852
+ _docker_compose_app(compose_file_full, compose_project_name, env_file)
853
+
854
+ debug_log("COMPOSE: Calling _register_dc_resources for '{}' with {} configs, auto_init={}".format(resource_name, len(resource_configs), runtime_flags['auto_init_apps']))
855
+ _register_dc_resources(resource_configs, resource_path, compose_project_name, runtime_flags['auto_init_apps'])
856
+
857
+ return {'compose_project_name': compose_project_name}
858
+
859
+
860
+ ComposeResourceRegistration = struct(
861
+ register = register_compose_resources,
862
+ )
863
+
864
+ DEBUG = {}