@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,125 @@
1
+ // Copyright (c) 2026 Flisk Landscape contributors
2
+ // SPDX-License-Identifier: MIT
3
+ import { execFileSync } from "node:child_process";
4
+ const run = (command, args) => execFileSync(command, args, { encoding: "utf-8", stdio: "pipe", windowsHide: true });
5
+ /** Network names the engine creates per project (see engine/.../docker/constants.star and init-networks). */
6
+ const PROJECT_NETWORK_SUFFIXES = [
7
+ "traefik-public",
8
+ "traefik-private",
9
+ "backend",
10
+ "database",
11
+ "infisical-network",
12
+ "verdaccio-network",
13
+ "proxy",
14
+ ];
15
+ /** The engine prefixes networks with the project name, hyphens turned into underscores. */
16
+ export function projectNetworkNames(projectName) {
17
+ const prefix = projectName.replace(/-/g, "_");
18
+ return PROJECT_NETWORK_SUFFIXES.map((suffix) => `${prefix}_${suffix}`);
19
+ }
20
+ /**
21
+ * Prefixes of Flisk projects among `networkNames`, from the networks the engine creates. Generic suffixes such as
22
+ * `backend` also occur in non-Flisk compose projects, so a prefix counts only if it has a Traefik network, which
23
+ * only Flisk creates.
24
+ */
25
+ export function tdkNetworkPrefixes(networkNames) {
26
+ const prefixes = new Set();
27
+ for (const name of networkNames) {
28
+ for (const marker of ["traefik-public", "traefik-private"]) {
29
+ if (name.endsWith(`_${marker}`))
30
+ prefixes.add(name.slice(0, -(marker.length + 1)));
31
+ }
32
+ }
33
+ return prefixes;
34
+ }
35
+ /** The Flisk project prefix a network belongs to (`umami` for `umami_backend`), or null. */
36
+ export function tdkNetworkOwner(name, prefixes) {
37
+ for (const suffix of PROJECT_NETWORK_SUFFIXES) {
38
+ if (name.endsWith(`_${suffix}`)) {
39
+ const prefix = name.slice(0, -(suffix.length + 1));
40
+ if (prefixes.has(prefix))
41
+ return prefix;
42
+ }
43
+ }
44
+ return null;
45
+ }
46
+ /**
47
+ * Remove this project's own networks. Only the exact names the engine creates are touched, and `docker network rm`
48
+ * itself refuses a network that still has containers attached, so another project's networks and in-use networks
49
+ * are never removed.
50
+ */
51
+ export function pruneProjectNetworks(projectName, commandRunner = run) {
52
+ const existing = new Set(commandRunner("docker", ["network", "ls", "--format", "{{.Name}}"])
53
+ .split(/\r?\n/)
54
+ .map((line) => line.trim())
55
+ .filter(Boolean));
56
+ const result = { removed: [], kept: [] };
57
+ for (const name of projectNetworkNames(projectName)) {
58
+ if (!existing.has(name))
59
+ continue;
60
+ try {
61
+ commandRunner("docker", ["network", "rm", name]);
62
+ result.removed.push(name);
63
+ }
64
+ catch (err) {
65
+ const stderr = String(err.stderr ?? err).trim();
66
+ result.kept.push({ name, reason: stderr.split(/\r?\n/)[0] ?? "" });
67
+ }
68
+ }
69
+ return result;
70
+ }
71
+ /**
72
+ * PIDs of `tilt up` processes started for this project's Tiltfile. Matching on the Tiltfile path keeps another
73
+ * project's Tilt (or a Tilt the user started by hand) untouched.
74
+ */
75
+ export function findProjectTiltUpPids(tiltfilePath, platform = process.platform, commandRunner = run) {
76
+ if (platform === "win32")
77
+ return [];
78
+ let output;
79
+ try {
80
+ output = commandRunner("ps", ["-axo", "pid=,command="]);
81
+ }
82
+ catch {
83
+ return [];
84
+ }
85
+ const pids = [];
86
+ for (const line of output.split(/\r?\n/)) {
87
+ const match = /^\s*(\d+)\s+(.*)$/.exec(line);
88
+ if (!match)
89
+ continue;
90
+ const command = match[2] ?? "";
91
+ const exe = (command.split(/\s+/)[0] ?? "").split("/").at(-1);
92
+ const target = ` -f ${tiltfilePath}`;
93
+ const at = command.indexOf(target);
94
+ const boundary = command[at + target.length];
95
+ if (exe === "tilt" &&
96
+ /^\S+\s+up\s/.test(command) &&
97
+ at > 0 &&
98
+ (boundary === undefined || boundary === " ")) {
99
+ pids.push(Number(match[1]));
100
+ }
101
+ }
102
+ return pids;
103
+ }
104
+ export function stopProjectTiltUp(tiltfilePath, platform = process.platform, commandRunner = run) {
105
+ const pids = findProjectTiltUpPids(tiltfilePath, platform, commandRunner);
106
+ for (const pid of pids) {
107
+ try {
108
+ commandRunner("kill", ["-TERM", String(pid)]);
109
+ }
110
+ catch {
111
+ // Already gone.
112
+ }
113
+ }
114
+ return pids;
115
+ }
116
+ /** Wait (up to `timeoutMs`) for the `tilt up` processes to exit after TERM, so `tilt down` does not race a live Tilt. */
117
+ export async function waitForTiltUpExit(tiltfilePath, timeoutMs = 8000, findPids = findProjectTiltUpPids) {
118
+ const deadline = Date.now() + timeoutMs;
119
+ while (findPids(tiltfilePath).length > 0) {
120
+ if (Date.now() >= deadline)
121
+ return false;
122
+ await new Promise((resolve) => setTimeout(resolve, 250));
123
+ }
124
+ return true;
125
+ }
@@ -0,0 +1,266 @@
1
+ // Copyright (c) 2026 Flisk Landscape contributors
2
+ // SPDX-License-Identifier: MIT
3
+ import { randomBytes } from "node:crypto";
4
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { join } from "node:path";
6
+ import { writeTextFileAtomic } from "./atomic-write.js";
7
+ const REQUIRED_ENV_VARS = [
8
+ {
9
+ name: "VERDACCIO_URL_DOCKER",
10
+ description: "Docker-internal URL of the private npm registry (Verdaccio, a paid feature)",
11
+ // Verdaccio is a premium, off-by-default service, so a free project must not need its URL.
12
+ required: false,
13
+ default: "http://verdaccio:4873",
14
+ example: "http://verdaccio:4873",
15
+ },
16
+ {
17
+ name: "VERDACCIO_URL",
18
+ description: "Local URL of the private npm registry (Verdaccio, a paid feature)",
19
+ required: false,
20
+ default: "http://localhost:4873",
21
+ },
22
+ {
23
+ name: "TILT_ENV",
24
+ description: "Tilt environment name",
25
+ required: true,
26
+ default: "dev",
27
+ example: "dev",
28
+ complete: true,
29
+ },
30
+ {
31
+ name: "DATABASE_URL",
32
+ description: "PostgreSQL connection string (uses the generated DB_PASSWORD below)",
33
+ required: false,
34
+ // Built from DB_PASSWORD in generateEnvFile(); there is no shared literal password.
35
+ },
36
+ {
37
+ name: "DB_PASSWORD",
38
+ description: "PostgreSQL superuser password (docker-compose POSTGRES_PASSWORD)",
39
+ required: true,
40
+ // No static default: a shared password across every generated project is a
41
+ // credential leak waiting to happen. generateEnvFile() fills this one in with
42
+ // a fresh random value per project instead.
43
+ example: "postgres",
44
+ complete: true,
45
+ },
46
+ {
47
+ name: "JWT_SECRET",
48
+ description: "Secret that signs local-jwt tokens (generated once per project; never shared between projects)",
49
+ // Not required for `flisk doctor`: `flisk up` adds it to an older project's .env before starting anything.
50
+ required: false,
51
+ complete: true,
52
+ },
53
+ ];
54
+ const generateDbPassword = () => randomBytes(16).toString("hex");
55
+ const generateJwtSecret = () => randomBytes(32).toString("hex");
56
+ function generatedValue(name, password) {
57
+ if (name === "DB_PASSWORD")
58
+ return password;
59
+ if (name === "JWT_SECRET")
60
+ return generateJwtSecret();
61
+ if (name === "DATABASE_URL")
62
+ return `postgresql://postgres:${password}@postgres:5432/app_dev`;
63
+ return REQUIRED_ENV_VARS.find((v) => v.name === name)?.default ?? "";
64
+ }
65
+ function parseEnvValue(raw) {
66
+ const value = raw.trim();
67
+ const quote = value[0];
68
+ if (quote === '"' || quote === "'") {
69
+ let escaped = false;
70
+ for (let index = 1; index < value.length; index += 1) {
71
+ const char = value[index];
72
+ if (escaped) {
73
+ escaped = false;
74
+ continue;
75
+ }
76
+ if (char === "\\") {
77
+ escaped = true;
78
+ continue;
79
+ }
80
+ if (char === quote) {
81
+ const quoted = value.slice(1, index);
82
+ if (quote === '"') {
83
+ const escapes = {
84
+ n: "\n",
85
+ r: "\r",
86
+ t: "\t",
87
+ '"': '"',
88
+ "\\": "\\",
89
+ $: "$",
90
+ };
91
+ return quoted.replace(/\\([nrt"\\$])/g, (_match, escapedChar) => escapes[escapedChar] ?? escapedChar);
92
+ }
93
+ return quoted.replace(/\\'/g, "'");
94
+ }
95
+ }
96
+ return value;
97
+ }
98
+ const commentIndex = raw.search(/\s#/);
99
+ return (commentIndex === -1 ? raw : raw.slice(0, commentIndex)).trim();
100
+ }
101
+ /** Parses the Compose-compatible subset used by Flisk for project environment files. */
102
+ export function parseEnv(content) {
103
+ const result = new Map();
104
+ const normalized = content.startsWith("\uFEFF") ? content.slice(1) : content;
105
+ for (const rawLine of normalized.split(/\r?\n/)) {
106
+ const line = rawLine.trim();
107
+ if (!line || line.startsWith("#"))
108
+ continue;
109
+ const assignment = line.startsWith("export ") ? line.slice("export ".length).trim() : line;
110
+ const equals = assignment.indexOf("=");
111
+ if (equals <= 0)
112
+ continue;
113
+ const name = assignment.slice(0, equals).trim();
114
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))
115
+ continue;
116
+ result.set(name, parseEnvValue(assignment.slice(equals + 1)));
117
+ }
118
+ return result;
119
+ }
120
+ function describe(envVar) {
121
+ const lines = [`# ${envVar.description}`];
122
+ if (envVar.required)
123
+ lines.push("# Required (the value below is a working default)");
124
+ if (envVar.example)
125
+ lines.push(`# Example: ${envVar.example}`);
126
+ return lines;
127
+ }
128
+ export function generateEnvFile() {
129
+ const password = generateDbPassword();
130
+ const lines = [
131
+ "# šŸ”§ Flisk Environment Configuration",
132
+ "# Generated by `flisk project`. The defaults work as-is; edit only to change them.",
133
+ "# Keep this file out of git: it holds a generated database password and JWT secret.",
134
+ "#",
135
+ "# After editing, run: flisk config regenerate && flisk up",
136
+ "",
137
+ ];
138
+ for (const envVar of REQUIRED_ENV_VARS) {
139
+ lines.push(...describe(envVar));
140
+ lines.push(`${envVar.name}=${generatedValue(envVar.name, password)}`);
141
+ lines.push("");
142
+ }
143
+ return lines.join("\n");
144
+ }
145
+ /** The password a postgres-style URL carries, or undefined when there is none or it is a variable reference. */
146
+ function urlPassword(url) {
147
+ const match = url.match(/^[a-z][a-z0-9+.-]*:\/\/[^:/@\s]+:([^@\s]*)@/i);
148
+ if (!match || match[1].includes("$"))
149
+ return undefined;
150
+ return match[1];
151
+ }
152
+ export function validateEnvFile(projectRoot) {
153
+ const envPath = join(projectRoot, ".env");
154
+ const result = {
155
+ missing: [],
156
+ invalid: [],
157
+ warnings: [],
158
+ };
159
+ if (!existsSync(envPath)) {
160
+ return {
161
+ missing: REQUIRED_ENV_VARS.filter((v) => v.required).map((v) => v.name),
162
+ invalid: [],
163
+ warnings: [".env file not found - will be auto-generated"],
164
+ };
165
+ }
166
+ const env = parseEnv(readFileSync(envPath, "utf-8"));
167
+ for (const envVar of REQUIRED_ENV_VARS) {
168
+ if (envVar.required && !env.has(envVar.name)) {
169
+ result.missing.push(envVar.name);
170
+ }
171
+ if (env.has(envVar.name) && !(env.get(envVar.name) ?? "").trim()) {
172
+ result.invalid.push(`${envVar.name} is set but empty`);
173
+ }
174
+ }
175
+ const databaseUrl = env.get("DATABASE_URL");
176
+ const dbPassword = env.get("DB_PASSWORD");
177
+ if (databaseUrl && dbPassword) {
178
+ const inUrl = urlPassword(databaseUrl);
179
+ if (inUrl !== undefined && inUrl !== dbPassword) {
180
+ result.warnings.push("DATABASE_URL carries a different password than DB_PASSWORD; the database container uses DB_PASSWORD");
181
+ }
182
+ }
183
+ return result;
184
+ }
185
+ /**
186
+ * Replaces the value in one parsed assignment while preserving its prefix, inline comment, and line ending.
187
+ * The caller only uses this for assignments whose parsed value is empty or whitespace.
188
+ */
189
+ function replaceEmptyEnvValue(line, name, value) {
190
+ const parsed = parseEnv(line);
191
+ if (!parsed.has(name))
192
+ return line;
193
+ const equalsIndex = line.indexOf("=");
194
+ if (equalsIndex < 0)
195
+ return line;
196
+ const rawValue = line.slice(equalsIndex + 1);
197
+ const commentIndex = rawValue.search(/\s#/);
198
+ const comment = commentIndex < 0 ? "" : rawValue.slice(commentIndex);
199
+ return line.slice(0, equalsIndex + 1) + value + comment;
200
+ }
201
+ /**
202
+ * Appends missing keys a newer CLI expects and fills empty generated keys in place.
203
+ * Non-empty values are not changed. Creates the file when it is missing.
204
+ *
205
+ * @returns the names that were added or filled in, empty when the file was already complete
206
+ */
207
+ export function completeEnvFile(projectRoot) {
208
+ const envPath = join(projectRoot, ".env");
209
+ if (!existsSync(envPath)) {
210
+ writeFileSync(envPath, generateEnvFile(), { mode: 0o600 });
211
+ return REQUIRED_ENV_VARS.map((v) => v.name);
212
+ }
213
+ const existing = readFileSync(envPath, "utf-8");
214
+ const env = parseEnv(existing);
215
+ const toComplete = REQUIRED_ENV_VARS.filter((v) => {
216
+ if (!v.complete)
217
+ return false;
218
+ if (!env.has(v.name))
219
+ return true;
220
+ return !(env.get(v.name) ?? "").trim();
221
+ });
222
+ if (toComplete.length === 0)
223
+ return [];
224
+ const toAdd = toComplete.filter((v) => !env.has(v.name));
225
+ const toRepair = toComplete.filter((v) => env.has(v.name));
226
+ // Anything generated from the password must use the project's existing non-empty value.
227
+ const existingPassword = env.get("DB_PASSWORD");
228
+ const password = existingPassword?.trim() ? existingPassword : generateDbPassword();
229
+ const lines = existing.split(/(\r\n|\n|\r)/);
230
+ for (const envVar of toRepair) {
231
+ let lineIndex = -1;
232
+ for (let index = 0; index < lines.length; index += 2) {
233
+ if (parseEnv(lines[index]).has(envVar.name))
234
+ lineIndex = index;
235
+ }
236
+ if (lineIndex < 0) {
237
+ throw new Error(`Could not locate empty .env assignment for ${envVar.name}`);
238
+ }
239
+ lines[lineIndex] = replaceEmptyEnvValue(lines[lineIndex], envVar.name, generatedValue(envVar.name, password));
240
+ }
241
+ let updated = lines.join("");
242
+ if (toAdd.length > 0) {
243
+ const addedLines = [
244
+ "",
245
+ "# Added by Flisk: keys this version expects. Existing values above were not changed.",
246
+ "",
247
+ ];
248
+ for (const envVar of toAdd) {
249
+ addedLines.push(...describe(envVar));
250
+ addedLines.push(`${envVar.name}=${generatedValue(envVar.name, password)}`);
251
+ addedLines.push("");
252
+ }
253
+ const separator = updated.endsWith("\n") || updated.endsWith("\r") ? "" : "\n";
254
+ updated += separator + addedLines.join("\n");
255
+ }
256
+ writeTextFileAtomic(envPath, updated);
257
+ return toComplete.map((v) => v.name);
258
+ }
259
+ export function ensureEnvFile(projectRoot) {
260
+ const envPath = join(projectRoot, ".env");
261
+ if (!existsSync(envPath)) {
262
+ writeFileSync(envPath, generateEnvFile(), { mode: 0o600 });
263
+ return true;
264
+ }
265
+ return false;
266
+ }
@@ -0,0 +1,175 @@
1
+ // Copyright (c) 2026 Flisk Landscape contributors
2
+ // SPDX-License-Identifier: MIT
3
+ import chalk from "chalk";
4
+ import { QUICKSTART_DOCS_URL } from "./constants.js";
5
+ import { getContainerRuntimeStatus } from "./docker.js";
6
+ import { findProjectRoot } from "./paths.js";
7
+ import { suggestClosest } from "./suggestions.js";
8
+ import { isTiltAvailable } from "./tilt.js";
9
+ export function getErrorMessage(err) {
10
+ return err instanceof Error ? err.message : String(err);
11
+ }
12
+ export function logVerbose(message, err) {
13
+ if (process.env.TDK_VERBOSE) {
14
+ const errMsg = err !== undefined ? `: ${getErrorMessage(err)}` : "";
15
+ console.warn(chalk.gray(`${message}${errMsg}`));
16
+ }
17
+ }
18
+ export class TdkError extends Error {
19
+ suggestions;
20
+ exitCode;
21
+ constructor(message, suggestions = [], exitCode = 1) {
22
+ super(message);
23
+ this.name = "TdkError";
24
+ this.suggestions = suggestions;
25
+ this.exitCode = exitCode;
26
+ }
27
+ display() {
28
+ showError(this.message, undefined, this.suggestions);
29
+ }
30
+ /** Display this error and exit the process with its exit code. */
31
+ exit() {
32
+ this.display();
33
+ process.exit(this.exitCode);
34
+ }
35
+ }
36
+ /**
37
+ * Thrown by the `process.exit` test double so the stack unwinds at an intentional exit.
38
+ * `runCommand` rethrows it instead of formatting it as a command failure.
39
+ */
40
+ export class ProcessExitError extends Error {
41
+ code;
42
+ constructor(code = 1) {
43
+ super(`process.exit(${code})`);
44
+ this.name = "ProcessExitError";
45
+ this.code = code;
46
+ }
47
+ }
48
+ function closestNameSuggestions(names, candidates, includeInput = false) {
49
+ const suggestions = new Set();
50
+ for (const name of names) {
51
+ const closest = suggestClosest(name, candidates);
52
+ if (closest) {
53
+ suggestions.add(includeInput ? `Did you mean "${closest}" for "${name}"?` : `Did you mean "${closest}"?`);
54
+ }
55
+ }
56
+ return [...suggestions];
57
+ }
58
+ export const errorFactories = {
59
+ tiltNotInstalled: () => new TdkError("Tilt CLI is not installed", [
60
+ "Install Tilt: `brew install tilt` (macOS)",
61
+ "Or download from: https://docs.tilt.dev/install.html",
62
+ "Verify with: `tilt version`",
63
+ `Setup guide: ${QUICKSTART_DOCS_URL}`,
64
+ ]),
65
+ dockerNotAvailable: () => new TdkError("Docker (or a compatible container runtime) is not running", [
66
+ "Start Docker Desktop, then verify with: `docker ps`",
67
+ "Or start Colima: `colima start`",
68
+ "Or start the Docker service on Linux: `sudo systemctl start docker`",
69
+ `Setup guide: ${QUICKSTART_DOCS_URL}`,
70
+ ]),
71
+ dockerNotResponding: () => new TdkError("Docker is running but not responding (`docker ps` hung for 10s)", [
72
+ "Quit and reopen Docker Desktop, or run `colima restart`",
73
+ "Then verify with: `docker ps`",
74
+ ]),
75
+ stackNotFound: (name, stackNames = []) => new TdkError(`Stack "${name}" not found`, [
76
+ ...closestNameSuggestions([name], stackNames),
77
+ "Run `flisk stacks` to see available stacks",
78
+ "Run `flisk stack` to assign resources to a stack",
79
+ ]),
80
+ resourceNotFound: (name, resourceNames = []) => new TdkError(`Resource "${name}" not found`, [
81
+ ...closestNameSuggestions([name], resourceNames),
82
+ "Run `flisk resources` to list all resources",
83
+ "Check the resource name spelling",
84
+ ]),
85
+ unknownServices: (names, validNames) => {
86
+ // Service selectors are Tilt resource names, so share the resource suggestion path.
87
+ const suggestions = closestNameSuggestions(names, validNames, names.length > 1);
88
+ return new TdkError(`Unknown service ${names.join(", ")}. Valid names: ${validNames.join(", ")}`, suggestions, 2);
89
+ },
90
+ directoryExists: (path) => new TdkError(`Directory already exists: ${path}`, [
91
+ "Use `--path` to specify a different location",
92
+ "Remove the existing directory if no longer needed",
93
+ ]),
94
+ invalidPath: (path) => new TdkError(`Invalid path: ${path}`, [
95
+ "Path must be within the project directory",
96
+ 'Path cannot contain special characters like <>:"|?*',
97
+ ]),
98
+ notInProject: () => new TdkError("Could not find project root (no .tdk/project.json found)", [
99
+ "Run this from within a Flisk project",
100
+ "Run `flisk project --yes` to initialize a new project",
101
+ ]),
102
+ };
103
+ export function requireProjectRoot() {
104
+ const projectRoot = findProjectRoot();
105
+ if (!projectRoot) {
106
+ return errorFactories.notInProject().exit();
107
+ }
108
+ return projectRoot;
109
+ }
110
+ function handleCommandError(err) {
111
+ if (err instanceof TdkError) {
112
+ err.exit();
113
+ }
114
+ showError(getErrorMessage(err));
115
+ process.exit(1);
116
+ }
117
+ export async function runCommand(action, options) {
118
+ try {
119
+ return await action();
120
+ }
121
+ catch (err) {
122
+ if (err instanceof ProcessExitError) {
123
+ throw err;
124
+ }
125
+ if (options?.verbose && err instanceof Error && err.stack) {
126
+ console.error(chalk.gray(err.stack));
127
+ }
128
+ return handleCommandError(err);
129
+ }
130
+ }
131
+ export async function withTiltCheck(action, options) {
132
+ const problems = [];
133
+ const runtime = getContainerRuntimeStatus();
134
+ if (runtime === "unresponsive") {
135
+ problems.push(errorFactories.dockerNotResponding());
136
+ }
137
+ else if (runtime === "missing") {
138
+ problems.push(errorFactories.dockerNotAvailable());
139
+ }
140
+ if (!(await isTiltAvailable())) {
141
+ problems.push(errorFactories.tiltNotInstalled());
142
+ }
143
+ if (problems.length > 0) {
144
+ console.error(chalk.red(`\nFlisk can't start - missing prerequisites:\n`));
145
+ problems.forEach((problem, i) => {
146
+ if (i > 0)
147
+ console.error("");
148
+ problem.display();
149
+ });
150
+ console.error(chalk.gray(`\nRun \`flisk doctor\` for a full environment check.`));
151
+ process.exit(1);
152
+ }
153
+ return runCommand(action, options);
154
+ }
155
+ export function showErrorAndExit(message, exitCode = 1, suggestions) {
156
+ showError(message, undefined, suggestions);
157
+ process.exit(exitCode);
158
+ }
159
+ /** Display a formatted error message. Does NOT exit. */
160
+ export function showError(message, context, suggestions) {
161
+ console.error(chalk.red(`āŒ ${message}`));
162
+ if (context) {
163
+ console.error(chalk.gray(` ${context}`));
164
+ }
165
+ if (suggestions && suggestions.length > 0) {
166
+ console.error(chalk.yellow("\nšŸ’” Suggestions:"));
167
+ for (const s of suggestions) {
168
+ console.error(chalk.cyan(` → ${s}`));
169
+ }
170
+ }
171
+ }
172
+ export function handleTiltFailure(command, exitCode) {
173
+ console.error(chalk.red(`\ntilt ${command} failed with exit code ${exitCode}`));
174
+ process.exit(exitCode);
175
+ }
@@ -0,0 +1,31 @@
1
+ // Copyright (c) 2026 Flisk Landscape contributors
2
+ // SPDX-License-Identifier: MIT
3
+ import { exec, execFile } from "node:child_process";
4
+ import { promisify } from "node:util";
5
+ import { findOnPath } from "./which.js";
6
+ const execPromise = promisify(exec);
7
+ export const execAsync = async (command, timeoutMs) => {
8
+ if (process.platform === "win32") {
9
+ // Doctor commands are simple executable/argument invocations. Tokenize
10
+ // their quoted arguments and bypass cmd.exe/PowerShell entirely.
11
+ const parts = command.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) ?? [];
12
+ const [parsedFile, ...args] = parts.map((part) => part.startsWith('"') || part.startsWith("'") ? part.slice(1, -1) : part);
13
+ if (!parsedFile)
14
+ throw new Error("Command is empty");
15
+ const file = findOnPath(parsedFile) ?? parsedFile;
16
+ const { stdout } = await promisify(execFile)(file, args, {
17
+ encoding: "utf-8",
18
+ timeout: timeoutMs,
19
+ windowsHide: true,
20
+ shell: false,
21
+ });
22
+ return stdout;
23
+ }
24
+ const { stdout } = await execPromise(command, { encoding: "utf-8", timeout: timeoutMs });
25
+ return stdout;
26
+ };
27
+ /** `exec` kills a timed-out child and sets `killed`; `execSync` reports ETIMEDOUT. */
28
+ export function isExecTimeout(err) {
29
+ const e = err;
30
+ return e?.code === "ETIMEDOUT" || e?.killed === true;
31
+ }