@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,193 @@
1
+ # Copyright (c) 2026 Flisk Landscape contributors
2
+ # SPDX-License-Identifier: MIT
3
+ # =============================================================================
4
+ # 👁️ DISCOVERY DAEMON - Continuous Service Monitoring
5
+ # =============================================================================
6
+ # Monitors filesystem for new resources and triggers incremental registration
7
+ # =============================================================================
8
+
9
+ load("./resource_snapshot.star", "ResourceSnapshot")
10
+ load("./registry.star", "CacheOps")
11
+ load("../engine/topologies/tilt/manifest/loader.star", "ManifestLoader")
12
+ # Discovery config - inlined for unified repo
13
+ def get_discovery_config():
14
+ return {
15
+ "scan_interval_seconds": 5,
16
+ "max_scan_timeout_ms": 5000,
17
+ "initial_scan_delay_seconds": 2,
18
+ "scan_debounce_ms": 100,
19
+ }
20
+
21
+ _DISCOVERY_CONFIG = get_discovery_config()
22
+
23
+ def run_discovery_daemon(
24
+ scan_interval_seconds=_DISCOVERY_CONFIG["scan_interval_seconds"],
25
+ focus_mode=False,
26
+ focus_stacks=[],
27
+ auto_init_new=True,
28
+ on_new_resource=None,
29
+ verbose=False
30
+ ):
31
+ """
32
+ Run the discovery daemon with continuous monitoring loop.
33
+
34
+ This function is designed to be called as a serve_cmd in a local_resource,
35
+ running continuously to monitor for new resources.
36
+
37
+ Args:
38
+ scan_interval_seconds: Seconds between scans (default: from get_discovery_config)
39
+ focus_mode: Whether focus mode is active
40
+ focus_stacks: List of domains to focus on (empty = all)
41
+ auto_init_new: Whether to auto-init new resources
42
+ on_new_resource: Callback function for new resource detection
43
+ verbose: Enable verbose logging
44
+ """
45
+ print("🔍 Discovery daemon starting...")
46
+ print(" └─ Scan interval: {}s".format(scan_interval_seconds))
47
+ print(" └─ Focus mode: {}".format("enabled" if focus_mode else "disabled"))
48
+ print(" └─ Auto-init: {}".format("enabled" if auto_init_new else "disabled"))
49
+
50
+ # Initialize snapshot if it doesn't exist
51
+ if not ResourceSnapshot.exists():
52
+ initial_services = ResourceSnapshot.scan()
53
+ ResourceSnapshot.save(initial_services)
54
+ print("✅ Initial snapshot created: {} services".format(len(initial_services)))
55
+
56
+ # Continuous monitoring loop
57
+ while True:
58
+ start_time = 0
59
+
60
+ # Load previous snapshot
61
+ old_snapshot = ResourceSnapshot.load_from_file()
62
+
63
+ # Scan for current services
64
+ current_services = ResourceSnapshot.scan()
65
+
66
+ # Compare to find changes
67
+ diff = ResourceSnapshot.diff(old_snapshot, current_services)
68
+
69
+ # Handle new resources
70
+ if diff.added_count > 0:
71
+ if verbose:
72
+ print("🔍 Detected {} new resource(s)".format(diff.added_count))
73
+
74
+ for resource_path in diff.added:
75
+ _handle_new_service(
76
+ resource_path,
77
+ focus_mode=focus_mode,
78
+ focus_stacks=focus_stacks,
79
+ auto_init=auto_init_new,
80
+ verbose=verbose,
81
+ on_new_resource=on_new_resource
82
+ )
83
+
84
+ # Handle removed services (optional - just log for now)
85
+ if diff.removed_count > 0 and verbose:
86
+ print("🗑️ Detected {} removed service(s)".format(diff.removed_count))
87
+ for resource_path in diff.removed:
88
+ print(" - {}".format(resource_path))
89
+
90
+ # Update snapshot if there were changes
91
+ if diff.added_count > 0 or diff.removed_count > 0:
92
+ ResourceSnapshot.save(current_services)
93
+ if verbose:
94
+ print("📸 Snapshot updated: {} services".format(len(current_services)))
95
+
96
+ # Calculate sleep time (account for scan duration)
97
+ elapsed = 0 - start_time
98
+ sleep_time = max(0, scan_interval_seconds - elapsed)
99
+
100
+ # Sleep before next scan
101
+ if sleep_time > 0:
102
+ sleep(sleep_time)
103
+
104
+ def _handle_new_service(
105
+ resource_path,
106
+ focus_mode=False,
107
+ focus_stacks=[],
108
+ auto_init=True,
109
+ verbose=False,
110
+ on_new_resource=None
111
+ ):
112
+ """
113
+ Process a newly detected service.
114
+
115
+ Args:
116
+ resource_path: Path to service.json
117
+ focus_mode: Whether to filter by stack
118
+ focus_stacks: Allowed domains
119
+ auto_init: Whether to auto-init the service
120
+ verbose: Verbose logging
121
+ on_new_resource: Optional callback
122
+ """
123
+ # Extract service directory
124
+ resource_dir = resource_path.rsplit("/", 1)[0] if "/" in resource_path else resource_path
125
+
126
+ # Check for package.json (complete service structure)
127
+ package_json_path = resource_dir + "/package.json"
128
+ if not _file_exists(package_json_path):
129
+ print("⏳ Waiting for package.json in {}".format(resource_dir))
130
+ return
131
+
132
+ # Load and validate manifest
133
+ load_result = ManifestLoader.load_from_file(resource_path)
134
+ if load_result.error:
135
+ print("❌ Invalid manifest: {}".format(resource_path))
136
+ print(" └─ Error: {}".format(load_result.error))
137
+ return
138
+
139
+ manifest = load_result.manifest
140
+ if not manifest:
141
+ print("❌ Empty manifest: {}".format(resource_path))
142
+ return
143
+
144
+ # Get service name
145
+ resource_name = manifest.get("appName", "")
146
+ if not resource_name:
147
+ print("❌ Missing appName in: {}".format(resource_path))
148
+ return
149
+
150
+ # Check for duplicates
151
+ if CacheOps.has(resource_name):
152
+ if verbose:
153
+ print("ℹ️ Service already registered: {}".format(resource_name))
154
+ return
155
+
156
+ # Check focus mode
157
+ stack = manifest.get("stack", "")
158
+ if focus_mode and focus_stacks and stack not in focus_stacks:
159
+ print("📋 Focus mode: Skipping {} (stack: {})".format(resource_name, stack))
160
+ return
161
+
162
+ # Log detection
163
+ print("🔍 New resource detected: {}".format(resource_name))
164
+ print(" └─ Path: {}".format(resource_path))
165
+ print(" └─ Stack: {}".format(stack))
166
+ print(" └─ Type: {}".format(manifest.get("appType", "unknown")))
167
+
168
+ # Call callback if provided
169
+ if on_new_resource:
170
+ on_new_resource(resource_name, resource_path, manifest, auto_init)
171
+
172
+ def _file_exists(path):
173
+ """Check if a file exists."""
174
+ result = local(
175
+ "test -f {} && echo 'yes' || echo 'no'".format(path),
176
+ quiet=True,
177
+ echo_off=True
178
+ )
179
+ return str(result).strip() == "yes"
180
+
181
+ def time_now():
182
+ """Get current time in seconds (for timing)."""
183
+ result = local("date +%s", quiet=True, echo_off=True)
184
+ return int(str(result).strip())
185
+
186
+ def sleep(seconds):
187
+ """Sleep for specified seconds."""
188
+ local("sleep {}".format(seconds), quiet=True, echo_off=True)
189
+
190
+ # Export daemon functions
191
+ DiscoveryDaemon = struct(
192
+ run=run_discovery_daemon,
193
+ )
@@ -0,0 +1,492 @@
1
+ # Copyright (c) 2026 Flisk contributors
2
+ # SPDX-License-Identifier: MIT
3
+ load("../engine/topologies/tilt/manifest/parser.star", "extract_stack_from_path")
4
+ load("../engine/topologies/tilt/manifest/loader.star", "ManifestLoader")
5
+ load("./manifest/loading.star", "get_default_syncs_for_type")
6
+
7
+ # Out of scope stacks - defined locally for unified repo
8
+ OUT_OF_SCOPE_STACKS = ["warehouse", "logistics", "accounting"]
9
+
10
+ load("./manifest/constants.star", "MANIFEST_FILENAME", "MANIFEST_FILENAME_YAML")
11
+
12
+ # Service defaults - inlined for unified repo
13
+ def get_default_port(app_type):
14
+ if app_type == "frontend":
15
+ return 3000
16
+ return 4000
17
+
18
+ BASE_PORT_FRONTEND = 3000
19
+ BASE_PORT_BACKEND = 4000
20
+
21
+ # Phase 1: Use json_manifest_scanner for manifest discovery (enables Phase 2 multi-source discovery)
22
+ load("./json_manifest_scanner.star", "discover_json_manifests")
23
+ load("./constants.star",
24
+ "RESOURCES_ROOT",
25
+ "DISCOVERY_SCAN_ROOTS",
26
+ "SCAN_ROOT_PATTERNS",
27
+ "MAX_SCAN_TIMEOUT_MS",
28
+ "MAX_MANIFESTS_PER_ROOT")
29
+
30
+ # Phase 1.5: Validation integration for stability
31
+ load("./validation.star", "validate")
32
+
33
+ # Phase 2: Root overlap validation (prevents duplicate scanning from misconfiguration)
34
+ def _validate_scan_roots(roots):
35
+ """Ensure no root is a subdirectory of another."""
36
+ sorted_roots = sorted(roots, key=len)
37
+ for i, root in enumerate(sorted_roots):
38
+ for other in sorted_roots[i+1:]:
39
+ root_normalized = root.rstrip("/") + "/"
40
+ other_normalized = other.rstrip("/") + "/"
41
+ if other_normalized.startswith(root_normalized):
42
+ print("⚠️ Warning: {} is subdirectory of {}".format(other, root))
43
+
44
+ def _to_project_relative_path(path, project_root):
45
+ """Return path relative to project_root (supports ../ out-of-tree siblings).
46
+
47
+ Absolute find() results used to be "normalized" by stripping a leading '/',
48
+ which turned `/private/var/.../platform/verdaccio` into a fake in-repo path
49
+ `private/var/.../platform/verdaccio` and broke Docker COPY checksums.
50
+ """
51
+ if not path:
52
+ return path
53
+ root = project_root if project_root else os.environ.get("TDK_PROJECT_ROOT", ".")
54
+ # Already project-relative (including ../sibling/...)
55
+ if not path.startswith("/"):
56
+ return path
57
+ cmd = (
58
+ "python3 -c \"import os; print(os.path.relpath(os.path.realpath('''" +
59
+ path +
60
+ "'''), os.path.realpath('''" +
61
+ root +
62
+ "''')))\""
63
+ )
64
+ relative = str(local(cmd, quiet=True, echo_off=True)).strip()
65
+ if relative:
66
+ return relative
67
+ # Fallback: strip project_root prefix if present
68
+ root_prefix = root.rstrip("/") + "/"
69
+ if path.startswith(root_prefix):
70
+ return path[len(root_prefix):]
71
+ return path.lstrip("/")
72
+
73
+ # Built-in functions available in Tilt (no load needed)
74
+ # read_json, local are built-in
75
+
76
+ # Define locally since parser.star exports this as private
77
+ def _determine_app_type(manifest, resource_path):
78
+ """
79
+ Determine app type from manifest or service path.
80
+ """
81
+ # Check if manifest has explicit appType
82
+ if manifest.get("appType") in ["frontend", "backend", "library", "migrator", "sdk", "worker", "infra", "bring-your-own"]:
83
+ return manifest["appType"]
84
+
85
+ # Extract from path
86
+ dir_name = resource_path.split("/")[-1] if resource_path else ""
87
+
88
+ if dir_name.endswith("-frontend"):
89
+ return "frontend"
90
+ if dir_name.endswith("-backend"):
91
+ return "backend"
92
+ if dir_name.endswith("-migrator"):
93
+ return "migrator"
94
+ if dir_name.endswith("-sdk"):
95
+ return "sdk"
96
+
97
+ # Default to backend
98
+ return "backend"
99
+
100
+ def normalize_manifest(manifest, resource_path):
101
+ """
102
+ Normalize manifest to discovery resource format.
103
+ Phase 5: Works with both legacy and new manifest system normalized manifests.
104
+ """
105
+ # If manifest is already normalized by new system, use it directly
106
+ if manifest.get("_normalized") or manifest.get("syncs"):
107
+ # Extract fields from normalized manifest
108
+ app_name = manifest.get("appName", resource_path.split("/")[-1])
109
+ app_type = manifest.get("appType", _determine_app_type(manifest, resource_path))
110
+ stack = manifest.get("stack", extract_stack_from_path(resource_path))
111
+ port = manifest.get("port", BASE_PORT_BACKEND if app_type == "backend" else BASE_PORT_FRONTEND)
112
+ else:
113
+ # Legacy path: compute fields
114
+ app_name = manifest.get("appName", resource_path.split("/")[-1])
115
+ app_type = _determine_app_type(manifest, resource_path)
116
+ stack = manifest.get("stack", extract_stack_from_path(resource_path))
117
+ port = manifest.get("port", BASE_PORT_BACKEND if app_type == "backend" else BASE_PORT_FRONTEND)
118
+
119
+ features = manifest.get("featuresEnabled", [])
120
+ syncs = manifest.get("syncs", get_default_syncs_for_type(app_type, features))
121
+ dockerfile = manifest.get("dockerfile", ".autogenerated/Dockerfile.app.autogenerated")
122
+
123
+ resource = {
124
+ "name": app_name,
125
+ "dockerfile": dockerfile if app_type == "bring-your-own" else app_name + "/" + dockerfile,
126
+ "syncs": syncs,
127
+ "port": port,
128
+ "stack": stack,
129
+ "_manifest": manifest.get("_manifest", manifest),
130
+ "_resource_path": resource_path,
131
+ }
132
+
133
+ if app_type == "frontend":
134
+ resource["frontend"] = True
135
+ resource["backendName"] = manifest.get("backendName", app_name.replace("-frontend", "-backend"))
136
+
137
+ if manifest.get("target_path"):
138
+ resource["target_path"] = manifest["target_path"]
139
+ if manifest.get("prisma_client_path"):
140
+ resource["prisma_client_path"] = manifest["prisma_client_path"]
141
+ if manifest.get("registry_host"):
142
+ resource["registry_host"] = manifest["registry_host"]
143
+ if manifest.get("start_command"):
144
+ resource["start_command"] = manifest["start_command"]
145
+
146
+ return resource
147
+
148
+
149
+ def _get_stack_path(stack):
150
+ return "services/product/" + stack
151
+
152
+
153
+ def initialize_discovery(cache, second_pass=False):
154
+ """
155
+ Initialize discovery cache by scanning for manifest files.
156
+
157
+ Args:
158
+ cache: Dictionary to populate with discovery data
159
+ second_pass: If True, this is the second initialization pass (for logging only)
160
+ """
161
+ if cache.get("initialized"):
162
+ return
163
+
164
+ # Scan for resources from JSON manifests (source of truth)
165
+ # YAML files are only for Tilt resource tracking, not data parsing
166
+ if second_pass:
167
+ print(" 1.2 Preparing Tilt resources...")
168
+ else:
169
+ print(" 1.1 Scanning service manifests...")
170
+
171
+ resources = _scan_resources()
172
+
173
+ # Build dependency graph and aliases
174
+ dependencies = {}
175
+ aliases = {}
176
+ path_map = {}
177
+
178
+ for resource in resources:
179
+ name = resource.get("name", "")
180
+ path = resource.get("path", "")
181
+
182
+ # Map name to path
183
+ if name:
184
+ aliases[name] = path
185
+ path_map[path] = name
186
+
187
+ # Extract dependencies from manifest
188
+ manifest = resource.get("_manifest", {})
189
+ deps = manifest.get("dependsOn", [])
190
+ if deps:
191
+ dependencies[name] = deps
192
+
193
+ # Populate cache
194
+ cache["app_resources"] = resources
195
+ cache["resource_dependencies"] = dependencies
196
+ cache["resource_aliases"] = aliases
197
+ cache["resource_path_map"] = path_map
198
+ cache["stack_configs"] = {}
199
+ cache["initialized"] = True
200
+ if second_pass:
201
+ cache["second_pass"] = True
202
+
203
+
204
+ def _scan_resources():
205
+ """
206
+ FIRST PASS: Scan for all resources with JSON manifest files from multiple roots.
207
+ Phase 2: Multi-root discovery with validation, deduplication, and explicit stack extraction.
208
+ Returns list of resource dictionaries.
209
+ """
210
+ resources = []
211
+
212
+ # Phase 1.5: Track validation stats and skipped stacks for discovery summary
213
+ validation_stats = {
214
+ "total_manifests": 0,
215
+ "valid_manifests": 0,
216
+ "manifests_with_warnings": 0,
217
+ "total_warnings": 0,
218
+ }
219
+ skipped_stacks = {} # Track skipped stacks for summary
220
+
221
+ # Phase 2: Validate scan roots don't overlap (prevents duplicate scanning)
222
+ _validate_scan_roots(DISCOVERY_SCAN_ROOTS)
223
+
224
+ # Phase 2: Scan all root directories and collect manifest paths
225
+ all_manifest_paths = [] # Collect from all roots
226
+
227
+ # Scan all root directories (quiet unless verbose)
228
+ total_roots = len(DISCOVERY_SCAN_ROOTS)
229
+
230
+ for root in DISCOVERY_SCAN_ROOTS:
231
+ # Use json_manifest_scanner.discover_json_manifests() to find all manifest files
232
+ paths = discover_json_manifests(root)
233
+
234
+ if paths:
235
+ # Phase 2: Performance guardrails - warn if root is too large
236
+ if len(paths) > MAX_MANIFESTS_PER_ROOT:
237
+ print(" ⚠️ Large root: {} has {} manifests (max: {})".format(
238
+ root, len(paths), MAX_MANIFESTS_PER_ROOT))
239
+
240
+ # Only show in verbose mode
241
+ if os.environ.get('TILT_LOG_LEVEL') == 'verbose':
242
+ print(" 📁 Scanned {} manifests from {}".format(len(paths), root))
243
+ all_manifest_paths.extend(paths)
244
+
245
+ # Phase 2: Deduplicate by path (in case of overlaps between roots)
246
+ seen_paths = {}
247
+ manifest_paths = []
248
+ for path in all_manifest_paths:
249
+ if path not in seen_paths:
250
+ seen_paths[path] = True
251
+ manifest_paths.append(path)
252
+
253
+ # CRITICAL FIX: Filter out tdk-cli internal paths to prevent self-scanning
254
+ # This prevents tdk-cli from discovering its own internal test stubs
255
+ def _is_tdk_cli_internal_path(path):
256
+ """Check if path is within tdk-cli's own directory structure."""
257
+ internal_markers = [
258
+ "tdk-cli/discovery/services/",
259
+ "tdk-cli/discovery/identity-",
260
+ ]
261
+ for marker in internal_markers:
262
+ if marker in path:
263
+ return True
264
+ return False
265
+
266
+ filtered_manifest_paths = []
267
+ for path in manifest_paths:
268
+ if _is_tdk_cli_internal_path(path):
269
+ print("⚠️ Skipping tdk-cli internal stub: {}".format(path))
270
+ continue
271
+ filtered_manifest_paths.append(path)
272
+
273
+ manifest_paths = filtered_manifest_paths
274
+
275
+ if not manifest_paths:
276
+ return resources
277
+
278
+ project_root = os.environ.get("TDK_PROJECT_ROOT", ".")
279
+
280
+ for manifest_path in manifest_paths:
281
+ # manifest_path may be absolute (legacy find) or project-relative.
282
+ # Always rewrite to a path relative to the Flisk project root first.
283
+ manifest_path = _to_project_relative_path(manifest_path, project_root)
284
+
285
+ # Parse manifest using proper loader (handles JSON and YAML)
286
+ # First, extract service path from manifest path
287
+ full_resource_path = manifest_path.rsplit("/", 1)[0]
288
+
289
+ # Use the loader which handles both JSON and YAML and normalizes format
290
+ # Loader needs a filesystem path: keep absolute for reads when needed.
291
+ load_path = manifest_path
292
+ if not load_path.startswith("/"):
293
+ load_path = project_root.rstrip("/") + "/" + load_path
294
+ load_result = ManifestLoader.load_from_file(load_path)
295
+ if load_result.error:
296
+ print("Error loading manifest: " + load_result.error)
297
+ continue
298
+
299
+ manifest = load_result.manifest
300
+ if not manifest:
301
+ continue
302
+
303
+ # Phase 1.5: Validate manifest structure and content
304
+ validation_stats["total_manifests"] += 1
305
+ validation_issues = validate(manifest)
306
+ if validation_issues:
307
+ validation_stats["manifests_with_warnings"] += 1
308
+ validation_stats["total_warnings"] += len(validation_issues)
309
+ # Log all validation issues with file path for context
310
+ for issue in validation_issues:
311
+ print("⚠️ Validation: " + manifest_path + ": " + issue)
312
+ # Lenient mode: log warnings but continue discovery
313
+ # (Strict mode could fail here with: continue)
314
+ else:
315
+ validation_stats["valid_manifests"] += 1
316
+
317
+ # Skip out-of-scope stacks for alpha (defined in spec.master)
318
+ stack = manifest.get("stack", "")
319
+ if stack in OUT_OF_SCOPE_STACKS:
320
+ # Track skipped stack for summary instead of printing immediately
321
+ if stack not in skipped_stacks:
322
+ skipped_stacks[stack] = 0
323
+ skipped_stacks[stack] += 1
324
+ continue
325
+
326
+ # Convert relative path to project-root-relative path
327
+ # manifest_path is like: ../../../../services/product/{domain}/{service}/manifest.json
328
+ # We want: services/product/{domain}/{service}
329
+ if manifest_path.startswith("../../../../"):
330
+ project_relative_path = manifest_path[12:] # Remove "../../../../" prefix
331
+ else:
332
+ project_relative_path = manifest_path
333
+
334
+ # Extract service info from the project-relative path
335
+ # Format: services/product/{domain}/{service}/" + MANIFEST_FILENAME,
336
+ path_parts = project_relative_path.split("/")
337
+ if len(path_parts) < 2:
338
+ continue
339
+
340
+ resource_dir = path_parts[-2] # e.g., "user-management-frontend"
341
+
342
+ # Phase 2: Use explicit stack extraction patterns
343
+ # Determine which root this manifest came from
344
+ matching_root = None
345
+ for root in DISCOVERY_SCAN_ROOTS:
346
+ if manifest_path.startswith(root):
347
+ matching_root = root
348
+ break
349
+
350
+ # Use configured pattern or default to parent folder
351
+ pattern = SCAN_ROOT_PATTERNS.get(matching_root, {"stack_depth": -2})
352
+ depth = pattern["stack_depth"]
353
+
354
+ # Extract stack based on configured depth
355
+ if abs(depth) <= len(path_parts):
356
+ stack_dir = path_parts[depth]
357
+ else:
358
+ stack_dir = path_parts[-2] if len(path_parts) >= 2 else "" # Fallback to parent
359
+
360
+ # Build paths relative to project root (for use by other modules)
361
+ # Handle both nested paths (services/product/stack/service) and flat paths (identity-*)
362
+ if len(path_parts) >= 3:
363
+ base_path = "/".join(path_parts[:-2]) # e.g., "services/product/users"
364
+ elif len(path_parts) == 2:
365
+ base_path = path_parts[0] # e.g., "identity-management-backend"
366
+ else:
367
+ base_path = path_parts[0] if path_parts else ""
368
+ resource_path = base_path # This is the DOMAIN path
369
+ full_resource_path = _to_project_relative_path(
370
+ project_relative_path.rsplit("/", 1)[0],
371
+ project_root,
372
+ ) # Full path to service
373
+
374
+ # BUG FIX: Normalize worktree paths to project-relative paths
375
+ # Worktrees create paths like .worktrees/task1-dry/services/platform/...
376
+ # These need to be converted to services/platform/... for correct Dockerfile resolution
377
+ if full_resource_path.startswith('.worktrees/'):
378
+ # Extract the part after the worktree name
379
+ parts = full_resource_path.split('/')
380
+ if len(parts) >= 3:
381
+ # Skip .worktrees/ and the worktree name
382
+ full_resource_path = '/'.join(parts[2:])
383
+ elif '.worktrees/' in full_resource_path:
384
+ # Handle paths that include worktree somewhere in the middle
385
+ worktree_idx = full_resource_path.find('.worktrees/')
386
+ after_worktree = full_resource_path[worktree_idx:]
387
+ parts = after_worktree.split('/')
388
+ if len(parts) >= 3:
389
+ full_resource_path = '/'.join(parts[2:])
390
+
391
+ # Also normalize resource_path (base_path) if it has worktree
392
+ if resource_path.startswith('.worktrees/'):
393
+ parts = resource_path.split('/')
394
+ if len(parts) >= 3:
395
+ resource_path = '/'.join(parts[2:])
396
+ elif '.worktrees/' in resource_path:
397
+ worktree_idx = resource_path.find('.worktrees/')
398
+ after_worktree = resource_path[worktree_idx:]
399
+ parts = after_worktree.split('/')
400
+ if len(parts) >= 3:
401
+ resource_path = '/'.join(parts[2:])
402
+
403
+ app_name = manifest.get("appName", resource_dir)
404
+ app_type = manifest.get("appType", "backend")
405
+ stack = manifest.get("stack", stack_dir)
406
+ port = manifest.get("port", get_default_port(app_type))
407
+ features = manifest.get("featuresEnabled", [])
408
+
409
+ # Build resource entry
410
+ # dockerfile path is relative to the resource directory (prepended with res_path by caller)
411
+ # Use custom dockerfile from manifest if specified, otherwise use autogenerated default
412
+ custom_dockerfile = manifest.get("dockerfile")
413
+ if custom_dockerfile:
414
+ dockerfile_path = custom_dockerfile
415
+ else:
416
+ dockerfile_path = ".autogenerated/Dockerfile.app.autogenerated"
417
+
418
+ resource = {
419
+ "name": app_name,
420
+ "dockerfile": dockerfile_path,
421
+ "syncs": get_default_syncs_for_type(app_type, features),
422
+ "port": port,
423
+ "stack": stack,
424
+ "_manifest": manifest,
425
+ "_resource_path": full_resource_path,
426
+ }
427
+
428
+ # Add frontend-specific fields
429
+ if app_type == "frontend":
430
+ resource["frontend"] = True
431
+ resource["backendName"] = manifest.get("backendName", app_name.replace("-frontend", "-backend"))
432
+
433
+ # Build resource entry
434
+ resource_key = stack if stack else app_name.replace("-" + app_type, "")
435
+
436
+ # Check if app resource already exists (merge resources for same stack)
437
+ existing_app_resource = None
438
+ for app_res in resources:
439
+ if app_res["name"] == resource_key:
440
+ existing_app_resource = app_res
441
+ break
442
+
443
+ if existing_app_resource:
444
+ # Check if resource with same name already exists (prevent duplicates from multiple scan roots)
445
+ resource_exists = False
446
+ for existing_res in existing_app_resource["resources"]:
447
+ if existing_res.get("name") == resource["name"]:
448
+ resource_exists = True
449
+ print(" ⚠️ Skipping duplicate resource: " + app_name + " (from " + resource_path + ")")
450
+ break
451
+
452
+ if not resource_exists:
453
+ # Add resource to existing app resource
454
+ existing_app_resource["resources"].append(resource)
455
+ existing_app_resource["labels"].append("app." + app_name)
456
+ pass # Service merged into existing domain
457
+ else:
458
+ # Create new app resource entry
459
+ # Use resource_path (domain path) for the app_resource - docker-compose goes here
460
+ # Individual resources have _resource_path for their specific paths
461
+ app_resource = {
462
+ "name": resource_key,
463
+ "appName": resource_key,
464
+ "path": resource_path,
465
+ "labels": ["app." + app_name] if app_name else [],
466
+ "resources": [resource],
467
+ }
468
+ pass # New domain group created
469
+ resources.append(app_resource)
470
+
471
+ # Phase 1.5: Print consolidated discovery summary
472
+ if validation_stats["total_manifests"] > 0:
473
+ # Calculate total skipped manually (sum() not available in Starlark)
474
+ total_skipped = 0
475
+ for count in skipped_stacks.values():
476
+ total_skipped += count
477
+ print("✅ {} resources loaded ({} valid, {} skipped)".format(
478
+ validation_stats["total_manifests"],
479
+ validation_stats["valid_manifests"],
480
+ total_skipped))
481
+
482
+ if validation_stats["manifests_with_warnings"] > 0:
483
+ print(" ⚠️ {} manifest(s) with {} validation warning(s)".format(
484
+ validation_stats["manifests_with_warnings"],
485
+ validation_stats["total_warnings"]))
486
+
487
+ if skipped_stacks and os.environ.get('TILT_LOG_LEVEL') == 'verbose':
488
+ skipped_list = ", ".join(["{} ({})".format(d, c) for d, c in skipped_stacks.items()])
489
+ print(" 📋 Focus mode skipped: {}".format(skipped_list))
490
+
491
+
492
+ return resources
@@ -0,0 +1,7 @@
1
+ # Copyright (c) 2026 Flisk Landscape contributors
2
+ # SPDX-License-Identifier: MIT
3
+ def by_app_type(manifests, app_type):
4
+ return [m for m in manifests if m.get("appType") == app_type]
5
+
6
+ def by_stack(manifests, stack):
7
+ return [m for m in manifests if m.get("stack") == stack]