@tdk-landscape/tdk-cli-core 1.3.49 → 1.3.51

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 (311) hide show
  1. package/.claude/skills/layer-autoresearch/SKILL.md +48 -0
  2. package/.claude/skills/tdk-troubleshoot/SKILL.md +222 -0
  3. package/.github/ISSUE_TEMPLATE/bug_report.yml +40 -0
  4. package/.github/ISSUE_TEMPLATE/config.yml +8 -0
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +18 -0
  6. package/.github/dependabot.yml +33 -0
  7. package/.github/pull_request_template.md +5 -0
  8. package/.github/workflows/ci.yml +187 -0
  9. package/.github/workflows/release-binaries.yml +19 -9
  10. package/.github/zizmor.yml +9 -0
  11. package/CODE_OF_CONDUCT.md +9 -0
  12. package/CONTRIBUTING.md +42 -0
  13. package/LICENSE +21 -0
  14. package/README.md +151 -0
  15. package/SECURITY.md +17 -0
  16. package/benchmarks/results/container-scale-2026-09-25T20-54-49-736Z.json +45 -0
  17. package/benchmarks/results/container-scale-2026-09-25T21-01-20-540Z.json +150 -0
  18. package/benchmarks/results/container-scale-2026-09-25T21-15-01-441Z.json +73 -0
  19. package/benchmarks/results/container-scale-2026-09-25T22-09-01-630Z.json +77 -0
  20. package/benchmarks/results/container-scale-2026-09-25T22-18-28-371Z.json +202 -0
  21. package/cli/README.md +25 -0
  22. package/cli/biome.json +1 -1
  23. package/cli/dist/cli.d.ts +3 -0
  24. package/cli/dist/cli.d.ts.map +1 -0
  25. package/cli/dist/cli.js +64 -0
  26. package/cli/dist/cli.js.map +1 -0
  27. package/cli/dist/commands/completion.d.ts +3 -0
  28. package/cli/dist/commands/completion.d.ts.map +1 -0
  29. package/cli/dist/commands/completion.js +294 -0
  30. package/cli/dist/commands/completion.js.map +1 -0
  31. package/cli/dist/commands/config.d.ts +3 -0
  32. package/cli/dist/commands/config.d.ts.map +1 -0
  33. package/cli/dist/commands/config.js +231 -0
  34. package/cli/dist/commands/config.js.map +1 -0
  35. package/cli/dist/commands/doctor.d.ts +19 -0
  36. package/cli/dist/commands/doctor.d.ts.map +1 -0
  37. package/cli/dist/commands/doctor.js +745 -0
  38. package/cli/dist/commands/doctor.js.map +1 -0
  39. package/cli/dist/commands/down.d.ts +3 -0
  40. package/cli/dist/commands/down.d.ts.map +1 -0
  41. package/cli/dist/commands/down.js +32 -0
  42. package/cli/dist/commands/down.js.map +1 -0
  43. package/cli/dist/commands/help.d.ts +2 -0
  44. package/cli/dist/commands/help.d.ts.map +1 -0
  45. package/cli/dist/commands/help.js +138 -0
  46. package/cli/dist/commands/help.js.map +1 -0
  47. package/cli/dist/commands/networks.d.ts +3 -0
  48. package/cli/dist/commands/networks.d.ts.map +1 -0
  49. package/cli/dist/commands/networks.js +260 -0
  50. package/cli/dist/commands/networks.js.map +1 -0
  51. package/cli/dist/commands/project.d.ts +3 -0
  52. package/cli/dist/commands/project.d.ts.map +1 -0
  53. package/cli/dist/commands/project.js +370 -0
  54. package/cli/dist/commands/project.js.map +1 -0
  55. package/cli/dist/commands/projects.d.ts +3 -0
  56. package/cli/dist/commands/projects.d.ts.map +1 -0
  57. package/cli/dist/commands/projects.js +71 -0
  58. package/cli/dist/commands/projects.js.map +1 -0
  59. package/cli/dist/commands/resource.d.ts +69 -0
  60. package/cli/dist/commands/resource.d.ts.map +1 -0
  61. package/cli/dist/commands/resource.js +579 -0
  62. package/cli/dist/commands/resource.js.map +1 -0
  63. package/cli/dist/commands/resources.d.ts +3 -0
  64. package/cli/dist/commands/resources.d.ts.map +1 -0
  65. package/cli/dist/commands/resources.js +73 -0
  66. package/cli/dist/commands/resources.js.map +1 -0
  67. package/cli/dist/commands/stack.d.ts +3 -0
  68. package/cli/dist/commands/stack.d.ts.map +1 -0
  69. package/cli/dist/commands/stack.js +97 -0
  70. package/cli/dist/commands/stack.js.map +1 -0
  71. package/cli/dist/commands/stacks.d.ts +3 -0
  72. package/cli/dist/commands/stacks.d.ts.map +1 -0
  73. package/cli/dist/commands/stacks.js +43 -0
  74. package/cli/dist/commands/stacks.js.map +1 -0
  75. package/cli/dist/commands/status.d.ts +3 -0
  76. package/cli/dist/commands/status.d.ts.map +1 -0
  77. package/cli/dist/commands/status.js +71 -0
  78. package/cli/dist/commands/status.js.map +1 -0
  79. package/cli/dist/commands/ui.d.ts +3 -0
  80. package/cli/dist/commands/ui.d.ts.map +1 -0
  81. package/cli/dist/commands/ui.js +445 -0
  82. package/cli/dist/commands/ui.js.map +1 -0
  83. package/cli/dist/commands/up.d.ts +3 -0
  84. package/cli/dist/commands/up.d.ts.map +1 -0
  85. package/cli/dist/commands/up.js +124 -0
  86. package/cli/dist/commands/up.js.map +1 -0
  87. package/cli/dist/commands/upgrade.d.ts +11 -0
  88. package/cli/dist/commands/upgrade.d.ts.map +1 -0
  89. package/cli/dist/commands/upgrade.js +496 -0
  90. package/cli/dist/commands/upgrade.js.map +1 -0
  91. package/cli/dist/commands/version.d.ts +3 -0
  92. package/cli/dist/commands/version.d.ts.map +1 -0
  93. package/cli/dist/commands/version.js +9 -0
  94. package/cli/dist/commands/version.js.map +1 -0
  95. package/cli/dist/components/Accessible.d.ts +8 -0
  96. package/cli/dist/components/Accessible.d.ts.map +1 -0
  97. package/cli/dist/components/Accessible.js +10 -0
  98. package/cli/dist/components/Accessible.js.map +1 -0
  99. package/cli/dist/components/BaseTooltip.d.ts +4 -0
  100. package/cli/dist/components/BaseTooltip.d.ts.map +1 -0
  101. package/cli/dist/components/BaseTooltip.js +28 -0
  102. package/cli/dist/components/BaseTooltip.js.map +1 -0
  103. package/cli/dist/components/DetailPanel.d.ts +4 -0
  104. package/cli/dist/components/DetailPanel.d.ts.map +1 -0
  105. package/cli/dist/components/DetailPanel.js +18 -0
  106. package/cli/dist/components/DetailPanel.js.map +1 -0
  107. package/cli/dist/components/FileTree.d.ts +4 -0
  108. package/cli/dist/components/FileTree.d.ts.map +1 -0
  109. package/cli/dist/components/FileTree.js +47 -0
  110. package/cli/dist/components/FileTree.js.map +1 -0
  111. package/cli/dist/components/ResourceSelectInput.d.ts +4 -0
  112. package/cli/dist/components/ResourceSelectInput.d.ts.map +1 -0
  113. package/cli/dist/components/ResourceSelectInput.js +7 -0
  114. package/cli/dist/components/ResourceSelectInput.js.map +1 -0
  115. package/cli/dist/components/ResourceTable.d.ts +4 -0
  116. package/cli/dist/components/ResourceTable.d.ts.map +1 -0
  117. package/cli/dist/components/ResourceTable.js +18 -0
  118. package/cli/dist/components/ResourceTable.js.map +1 -0
  119. package/cli/dist/components/TabBar.d.ts +4 -0
  120. package/cli/dist/components/TabBar.d.ts.map +1 -0
  121. package/cli/dist/components/TabBar.js +17 -0
  122. package/cli/dist/components/TabBar.js.map +1 -0
  123. package/cli/dist/components/Tooltip.d.ts +12 -0
  124. package/cli/dist/components/Tooltip.d.ts.map +1 -0
  125. package/cli/dist/components/Tooltip.js +12 -0
  126. package/cli/dist/components/Tooltip.js.map +1 -0
  127. package/cli/dist/components/index.d.ts +8 -0
  128. package/cli/dist/components/index.d.ts.map +1 -0
  129. package/cli/dist/components/index.js +8 -0
  130. package/cli/dist/components/index.js.map +1 -0
  131. package/cli/dist/config/platform-standards.d.ts +159 -0
  132. package/cli/dist/config/platform-standards.d.ts.map +1 -0
  133. package/cli/dist/config/platform-standards.js +181 -0
  134. package/cli/dist/config/platform-standards.js.map +1 -0
  135. package/cli/dist/generator/extension-fetch.d.ts +25 -0
  136. package/cli/dist/generator/extension-fetch.d.ts.map +1 -0
  137. package/cli/dist/generator/extension-fetch.js +259 -0
  138. package/cli/dist/generator/extension-fetch.js.map +1 -0
  139. package/cli/dist/generator/template-engine.d.ts +62 -0
  140. package/cli/dist/generator/template-engine.d.ts.map +1 -0
  141. package/cli/dist/generator/template-engine.js +623 -0
  142. package/cli/dist/generator/template-engine.js.map +1 -0
  143. package/cli/dist/index.d.ts +11 -0
  144. package/cli/dist/index.d.ts.map +1 -0
  145. package/cli/dist/index.js +11 -0
  146. package/cli/dist/index.js.map +1 -0
  147. package/cli/dist/types/index.d.ts +257 -0
  148. package/cli/dist/types/index.d.ts.map +1 -0
  149. package/cli/dist/types/index.js +17 -0
  150. package/cli/dist/types/index.js.map +1 -0
  151. package/cli/dist/utils/cache.d.ts +19 -0
  152. package/cli/dist/utils/cache.d.ts.map +1 -0
  153. package/cli/dist/utils/cache.js +64 -0
  154. package/cli/dist/utils/cache.js.map +1 -0
  155. package/cli/dist/utils/command-helpers.d.ts +17 -0
  156. package/cli/dist/utils/command-helpers.d.ts.map +1 -0
  157. package/cli/dist/utils/command-helpers.js +41 -0
  158. package/cli/dist/utils/command-helpers.js.map +1 -0
  159. package/cli/dist/utils/constants.d.ts +53 -0
  160. package/cli/dist/utils/constants.d.ts.map +1 -0
  161. package/cli/dist/utils/constants.js +115 -0
  162. package/cli/dist/utils/constants.js.map +1 -0
  163. package/cli/dist/utils/discovery-context.d.ts +4 -0
  164. package/cli/dist/utils/discovery-context.d.ts.map +1 -0
  165. package/cli/dist/utils/discovery-context.js +39 -0
  166. package/cli/dist/utils/discovery-context.js.map +1 -0
  167. package/cli/dist/utils/docker.d.ts +4 -0
  168. package/cli/dist/utils/docker.d.ts.map +1 -0
  169. package/cli/dist/utils/docker.js +19 -0
  170. package/cli/dist/utils/docker.js.map +1 -0
  171. package/cli/dist/utils/doctor-runtime.d.ts +81 -0
  172. package/cli/dist/utils/doctor-runtime.d.ts.map +1 -0
  173. package/cli/dist/utils/doctor-runtime.js +498 -0
  174. package/cli/dist/utils/doctor-runtime.js.map +1 -0
  175. package/cli/dist/utils/env-validator.d.ts +15 -0
  176. package/cli/dist/utils/env-validator.d.ts.map +1 -0
  177. package/cli/dist/utils/env-validator.js +109 -0
  178. package/cli/dist/utils/env-validator.js.map +1 -0
  179. package/cli/dist/utils/errors.d.ts +31 -0
  180. package/cli/dist/utils/errors.d.ts.map +1 -0
  181. package/cli/dist/utils/errors.js +140 -0
  182. package/cli/dist/utils/errors.js.map +1 -0
  183. package/cli/dist/utils/file-helpers.d.ts +14 -0
  184. package/cli/dist/utils/file-helpers.d.ts.map +1 -0
  185. package/cli/dist/utils/file-helpers.js +45 -0
  186. package/cli/dist/utils/file-helpers.js.map +1 -0
  187. package/cli/dist/utils/formatting.d.ts +30 -0
  188. package/cli/dist/utils/formatting.d.ts.map +1 -0
  189. package/cli/dist/utils/formatting.js +164 -0
  190. package/cli/dist/utils/formatting.js.map +1 -0
  191. package/cli/dist/utils/paths.d.ts +3 -0
  192. package/cli/dist/utils/paths.d.ts.map +1 -0
  193. package/cli/dist/utils/paths.js +41 -0
  194. package/cli/dist/utils/paths.js.map +1 -0
  195. package/cli/dist/utils/port-assignment.d.ts +6 -0
  196. package/cli/dist/utils/port-assignment.d.ts.map +1 -0
  197. package/cli/dist/utils/port-assignment.js +81 -0
  198. package/cli/dist/utils/port-assignment.js.map +1 -0
  199. package/cli/dist/utils/project-features.d.ts +23 -0
  200. package/cli/dist/utils/project-features.d.ts.map +1 -0
  201. package/cli/dist/utils/project-features.js +98 -0
  202. package/cli/dist/utils/project-features.js.map +1 -0
  203. package/cli/dist/utils/project-templates.d.ts +7 -0
  204. package/cli/dist/utils/project-templates.d.ts.map +1 -0
  205. package/cli/dist/utils/project-templates.js +24 -0
  206. package/cli/dist/utils/project-templates.js.map +1 -0
  207. package/cli/dist/utils/prompt.d.ts +28 -0
  208. package/cli/dist/utils/prompt.d.ts.map +1 -0
  209. package/cli/dist/utils/prompt.js +79 -0
  210. package/cli/dist/utils/prompt.js.map +1 -0
  211. package/cli/dist/utils/resource-features.d.ts +29 -0
  212. package/cli/dist/utils/resource-features.d.ts.map +1 -0
  213. package/cli/dist/utils/resource-features.js +175 -0
  214. package/cli/dist/utils/resource-features.js.map +1 -0
  215. package/cli/dist/utils/service-urls.d.ts +30 -0
  216. package/cli/dist/utils/service-urls.d.ts.map +1 -0
  217. package/cli/dist/utils/service-urls.js +93 -0
  218. package/cli/dist/utils/service-urls.js.map +1 -0
  219. package/cli/dist/utils/services.d.ts +18 -0
  220. package/cli/dist/utils/services.d.ts.map +1 -0
  221. package/cli/dist/utils/services.js +292 -0
  222. package/cli/dist/utils/services.js.map +1 -0
  223. package/cli/dist/utils/stack-features.d.ts +22 -0
  224. package/cli/dist/utils/stack-features.d.ts.map +1 -0
  225. package/cli/dist/utils/stack-features.js +13 -0
  226. package/cli/dist/utils/stack-features.js.map +1 -0
  227. package/cli/dist/utils/tar.d.ts +7 -0
  228. package/cli/dist/utils/tar.d.ts.map +1 -0
  229. package/cli/dist/utils/tar.js +21 -0
  230. package/cli/dist/utils/tar.js.map +1 -0
  231. package/cli/dist/utils/tilt.d.ts +20 -0
  232. package/cli/dist/utils/tilt.d.ts.map +1 -0
  233. package/cli/dist/utils/tilt.js +95 -0
  234. package/cli/dist/utils/tilt.js.map +1 -0
  235. package/cli/dist/utils/validation.d.ts +16 -0
  236. package/cli/dist/utils/validation.d.ts.map +1 -0
  237. package/cli/dist/utils/validation.js +58 -0
  238. package/cli/dist/utils/validation.js.map +1 -0
  239. package/cli/package.json +11 -12
  240. package/cli/src/commands/__tests__/always-enabled-infra.test.ts +2 -8
  241. package/cli/src/commands/__tests__/doctor.test.ts +181 -8
  242. package/cli/src/commands/__tests__/phases-model.test.ts +2 -4
  243. package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +4 -24
  244. package/cli/src/commands/__tests__/saas-starter-integration.test.ts +8 -10
  245. package/cli/src/commands/__tests__/stack-features-e2e.test.ts +10 -4
  246. package/cli/src/commands/__tests__/upgrade.test.ts +23 -13
  247. package/cli/src/commands/doctor.ts +136 -0
  248. package/cli/src/commands/help.ts +13 -3
  249. package/cli/src/commands/project.ts +11 -14
  250. package/cli/src/commands/projects.ts +2 -2
  251. package/cli/src/commands/up.ts +13 -4
  252. package/cli/src/commands/upgrade.ts +11 -4
  253. package/cli/src/config/platform-standards.test.ts +6 -6
  254. package/cli/src/generator/__tests__/extension-fetch.test.ts +36 -14
  255. package/cli/src/generator/extension-fetch.ts +12 -5
  256. package/cli/src/generator/template-engine.ts +19 -21
  257. package/cli/src/types/index.ts +2 -0
  258. package/cli/src/utils/__tests__/tilt.test.ts +29 -0
  259. package/cli/src/utils/constants.ts +4 -0
  260. package/cli/src/utils/doctor-runtime.ts +67 -27
  261. package/cli/src/utils/env-validator.ts +2 -2
  262. package/cli/src/utils/project-templates.ts +2 -1
  263. package/cli/src/utils/prompt.ts +2 -4
  264. package/cli/src/utils/resource-features.ts +10 -4
  265. package/cli/src/utils/services.ts +2 -1
  266. package/cli/src/utils/tilt.ts +20 -0
  267. package/docs/demo.svg +217 -0
  268. package/engine/assets/docker/wake-gateway/Dockerfile +27 -0
  269. package/engine/assets/docker/wake-gateway/decide.test.ts +133 -0
  270. package/engine/assets/docker/wake-gateway/decide.ts +105 -0
  271. package/engine/assets/docker/wake-gateway/server.ts +311 -0
  272. package/engine/topologies/platform/docker/build/golden_image_dockerfile.star +13 -23
  273. package/engine/topologies/platform/docker/compose/compose.star +7 -14
  274. package/engine/topologies/platform/docker/compose/compose_helpers.star +1 -1
  275. package/engine/topologies/platform/docker/compose/traefik_standalone.star +66 -6
  276. package/engine/topologies/platform/docker/config/healthcheck.star +56 -0
  277. package/engine/topologies/platform/docker/constants.star +10 -0
  278. package/engine/topologies/platform/docker/layers/l1_base_layers.star +1 -1
  279. package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +55 -20
  280. package/engine/topologies/platform/docker/networking/traefik_static_routes.star +161 -0
  281. package/engine/topologies/tilt/generators/typescript/backend_tsconfig.star +2 -2
  282. package/engine/topologies/tilt/generators/typescript/frontend_tsconfig.star +1 -1
  283. package/engine/topologies/tilt/manifest/schema.star +6 -0
  284. package/engine/topologies/tilt/manifest/validator.star +16 -0
  285. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +143 -9
  286. package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +12 -6
  287. package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +2 -1
  288. package/knip.json +1 -1
  289. package/openspec/changes/optimize-runtime-docker-layers/.openspec.yaml +3 -0
  290. package/openspec/changes/optimize-runtime-docker-layers/design.md +81 -0
  291. package/openspec/changes/optimize-runtime-docker-layers/proposal.md +44 -0
  292. package/openspec/changes/optimize-runtime-docker-layers/specs/runtime-container-footprint/spec.md +79 -0
  293. package/openspec/changes/optimize-runtime-docker-layers/tasks.md +36 -0
  294. package/openspec/changes/prioritized-cold-start/.openspec.yaml +4 -0
  295. package/openspec/changes/prioritized-cold-start/design.md +133 -0
  296. package/openspec/changes/prioritized-cold-start/proposal.md +41 -0
  297. package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +92 -0
  298. package/openspec/changes/prioritized-cold-start/tasks.md +56 -0
  299. package/openspec/config.yaml +1 -0
  300. package/package.json +35 -5
  301. package/scripts/autoresearch/layer-eval.sh +65 -0
  302. package/scripts/benchmark/README.md +25 -0
  303. package/scripts/benchmark/container-scale.ts +503 -0
  304. package/scripts/benchmark/pre-release-gate.sh +9 -0
  305. package/scripts/measure-idle-footprint.sh +58 -0
  306. package/scripts/record-demo.sh +43 -0
  307. package/tests/tilt-engine/test_runtime_container_footprint.py +162 -0
  308. package/tests/tilt-engine/test_sablier_defer_start.py +196 -0
  309. package/tests/tilt-engine/test_standalone_traefik.py +52 -0
  310. package/tests/tilt-engine/test_traefik_static_wake_route.py +187 -0
  311. package/bun.lock +0 -538
@@ -130,6 +130,81 @@ const checkDockerCompose = createExecCheck(
130
130
  "Install Docker Compose: https://docs.docker.com/compose/install/",
131
131
  );
132
132
 
133
+ // Generated healthchecks use `start_interval`, which older engines/compose reject.
134
+ const MIN_DOCKER_ENGINE_VERSION = [25, 0, 0] as const;
135
+ const MIN_DOCKER_COMPOSE_VERSION = [2, 20, 2] as const;
136
+
137
+ function parseVersion(raw: string): number[] | null {
138
+ const match = raw.trim().match(/(\d+)\.(\d+)(?:\.(\d+))?/);
139
+ if (!match) {
140
+ return null;
141
+ }
142
+ return [Number(match[1]), Number(match[2]), Number(match[3] ?? 0)];
143
+ }
144
+
145
+ function isAtLeast(version: number[], minimum: readonly number[]): boolean {
146
+ for (const [index, required] of minimum.entries()) {
147
+ const actual = version[index] ?? 0;
148
+ if (actual !== required) {
149
+ return actual > required;
150
+ }
151
+ }
152
+ return true;
153
+ }
154
+
155
+ export function checkDockerVersions(exec: typeof execSync = execSync): CheckResult {
156
+ const run = (command: string): string =>
157
+ String(exec(command, { stdio: "pipe", encoding: "utf-8", timeout: EXEC_TIMEOUT_MS })).trim();
158
+
159
+ let engineRaw: string;
160
+ let composeRaw: string;
161
+ try {
162
+ engineRaw = run("docker version --format '{{.Server.Version}}'");
163
+ composeRaw = run("docker compose version --short");
164
+ } catch {
165
+ return {
166
+ name: "Docker Versions",
167
+ didPass: true,
168
+ isSkipped: true,
169
+ message: "Could not read Docker Engine/Compose versions - skipped version check",
170
+ };
171
+ }
172
+
173
+ const engine = parseVersion(engineRaw);
174
+ const compose = parseVersion(composeRaw);
175
+ if (!engine || !compose) {
176
+ return {
177
+ name: "Docker Versions",
178
+ didPass: true,
179
+ isSkipped: true,
180
+ message: `Unrecognized Docker version output (engine "${engineRaw}", compose "${composeRaw}") - skipped version check`,
181
+ };
182
+ }
183
+
184
+ const problems: string[] = [];
185
+ if (!isAtLeast(engine, MIN_DOCKER_ENGINE_VERSION)) {
186
+ problems.push(`Docker Engine ${engineRaw} (need 25.0+)`);
187
+ }
188
+ if (!isAtLeast(compose, MIN_DOCKER_COMPOSE_VERSION)) {
189
+ problems.push(`Docker Compose ${composeRaw} (need 2.20.2+)`);
190
+ }
191
+
192
+ if (problems.length === 0) {
193
+ return {
194
+ name: "Docker Versions",
195
+ didPass: true,
196
+ message: `Docker Engine ${engineRaw} and Compose ${composeRaw} support generated healthchecks`,
197
+ };
198
+ }
199
+
200
+ return {
201
+ name: "Docker Versions",
202
+ didPass: false,
203
+ message: `Docker is too old for generated healthchecks (they use start_interval):\n ${problems.join("\n ")}`,
204
+ fix: "Update Docker Desktop, or on Linux update docker-ce and the docker-compose-plugin package",
205
+ };
206
+ }
207
+
133
208
  const checkTilt = createExecCheck(
134
209
  "Tilt CLI",
135
210
  "tilt version",
@@ -197,6 +272,9 @@ const REQUIRED_DOCKER_TEMPLATE_FILES = [
197
272
  "bun-hoisted-symlink-fix.sh",
198
273
  "prisma-bun-client-link-fix.sh",
199
274
  "prisma-normalize-client.sh",
275
+ "prisma-runtime-relink.sh",
276
+ "infisical-entrypoint.sh",
277
+ "migrate.sh",
200
278
  ] as const;
201
279
 
202
280
  export function checkGeneratedProjectRuntimeAssets(): CheckResult {
@@ -442,6 +520,62 @@ function checkStartupScripts(): CheckResult {
442
520
  };
443
521
  }
444
522
 
523
+ /**
524
+ * Backend/frontend tsconfig generators set `"types": ["bun"]` on the
525
+ * assumption that `@types/bun` is a direct devDependency (`tdk resource`
526
+ * adds it for new services). Nothing re-adds it if a service's package.json
527
+ * loses that entry -- e.g. a checkout missing it entirely, or a manual edit
528
+ * -- and the failure only surfaces later as `tsc: TS2688: Cannot find type
529
+ * definition file for 'bun'` inside `bun run build`, mid Docker image build.
530
+ */
531
+ export function checkTypeScriptTypeDependencies(): CheckResult {
532
+ const projectRoot = findProjectRoot() ?? process.cwd();
533
+ const resources = discoverResourcesFromRoot(projectRoot);
534
+
535
+ const problems: string[] = [];
536
+
537
+ for (const resource of resources) {
538
+ const packageJsonPath = join(resource.path, "package.json");
539
+ const dockerTsconfigPath = join(
540
+ resource.path,
541
+ ".autogenerated",
542
+ "tsconfig.docker.autogenerated.json",
543
+ );
544
+
545
+ if (!existsSync(packageJsonPath) || !existsSync(dockerTsconfigPath)) {
546
+ continue;
547
+ }
548
+
549
+ const tsconfig = readJsonFile(dockerTsconfigPath);
550
+ const compilerOptions = tsconfig?.compilerOptions as Record<string, unknown> | undefined;
551
+ const types = compilerOptions?.types;
552
+ if (!Array.isArray(types) || !types.includes("bun")) {
553
+ continue;
554
+ }
555
+
556
+ const pkg = readJsonFile(packageJsonPath);
557
+ const devDependencies = (pkg?.devDependencies as Record<string, string> | undefined) ?? {};
558
+ if (!devDependencies["@types/bun"]) {
559
+ problems.push(resource.name);
560
+ }
561
+ }
562
+
563
+ if (problems.length === 0) {
564
+ return {
565
+ name: "TypeScript Type Dependencies",
566
+ didPass: true,
567
+ message: "All services with a bun-typed tsconfig have @types/bun installed",
568
+ };
569
+ }
570
+
571
+ return {
572
+ name: "TypeScript Type Dependencies",
573
+ didPass: false,
574
+ message: `Services set "types": ["bun"] in their Docker tsconfig but are missing the "@types/bun" devDependency, so \`bun run build\` fails with TS2688:\n ${problems.join("\n ")}`,
575
+ fix: 'Add to each service\'s package.json devDependencies: "@types/bun": "^1.4.2"',
576
+ };
577
+ }
578
+
445
579
  function readJsonFile(path: string): Record<string, unknown> | null {
446
580
  try {
447
581
  return JSON.parse(readFileSync(path, "utf-8")) as Record<string, unknown>;
@@ -730,10 +864,12 @@ export const doctorCommand = new Command("doctor")
730
864
  checkDockerRuntime,
731
865
  checkTilt,
732
866
  checkDockerCompose,
867
+ checkDockerVersions,
733
868
  checkMasterConfigs,
734
869
  checkGeneratedProjectRuntimeAssets,
735
870
  checkStarlarkLoadExports,
736
871
  checkStartupScripts,
872
+ checkTypeScriptTypeDependencies,
737
873
  checkFrontendDockerPreflight,
738
874
  checkEnvironmentVariables,
739
875
  // Preflight: catch "port 80 already allocated" BEFORE claiming ready.
@@ -62,7 +62,11 @@ const COMMAND_GROUPS = [
62
62
  emoji: "🌐",
63
63
  color: chalk.blueBright,
64
64
  commands: [
65
- { name: "networks, traefik", desc: "Show Traefik-routed URLs for all services", alias: "--stack, --json" },
65
+ {
66
+ name: "networks, traefik",
67
+ desc: "Show Traefik-routed URLs for all services",
68
+ alias: "--stack, --json",
69
+ },
66
70
  ],
67
71
  },
68
72
  {
@@ -71,7 +75,11 @@ const COMMAND_GROUPS = [
71
75
  color: chalk.cyan,
72
76
  commands: [
73
77
  { name: "ui, interactive", desc: "Interactive TUI for managing services", alias: "" },
74
- { name: "config", desc: "Manage project configuration and regenerate master files", alias: "regenerate, verify, edit" },
78
+ {
79
+ name: "config",
80
+ desc: "Manage project configuration and regenerate master files",
81
+ alias: "regenerate, verify, edit",
82
+ },
75
83
  { name: "doctor", desc: "Check environment readiness", alias: "" },
76
84
  { name: "completion", desc: "Generate shell completions", alias: "--install --shell zsh" },
77
85
  { name: "upgrade, update", desc: "Self-update to latest version", alias: "--force" },
@@ -144,7 +152,9 @@ export function showHelp(): void {
144
152
  );
145
153
  console.log(chalk.gray(` ${"═".repeat(50)}`));
146
154
  console.log(chalk.gray(` For more help: ${chalk.cyan("tdk help [command]}")}`));
147
- console.log(chalk.gray(` GitHub: ${chalk.cyan("https://github.com/tdk-landscape/tdk-cli-core")}`));
155
+ console.log(
156
+ chalk.gray(` GitHub: ${chalk.cyan("https://github.com/tdk-landscape/tdk-cli-core")}`),
157
+ );
148
158
  console.log();
149
159
  console.log(chalk.green.bold(" Happy coding! 🚀\n"));
150
160
  }
@@ -1,11 +1,13 @@
1
1
  import { execFileSync } from "node:child_process";
2
- import { existsSync, readFileSync, readdirSync } from "node:fs";
2
+ import { existsSync, readdirSync, readFileSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
4
  import { cwd } from "node:process";
5
5
  import chalk from "chalk";
6
6
  import { Command } from "commander";
7
7
  import { generateMasterConfigs, readProjectConfig } from "../generator/template-engine.js";
8
+ import type { ProjectConfig } from "../types/index.js";
8
9
  import { MASTER_CONFIG_FILES } from "../utils/constants.js";
10
+ import { ensureEnvFile, validateEnvFile } from "../utils/env-validator.js";
9
11
  import { errorFactories, runCommand, showErrorAndExit } from "../utils/errors.js";
10
12
  import { ensureDirectory, writeJsonFile } from "../utils/file-helpers.js";
11
13
  import {
@@ -16,13 +18,11 @@ import {
16
18
  showSuccess,
17
19
  } from "../utils/formatting.js";
18
20
  import { findProjectRoot } from "../utils/paths.js";
21
+ import { PROJECT_FEATURES } from "../utils/project-features.js";
19
22
  import { PROJECT_TEMPLATES } from "../utils/project-templates.js";
23
+ import { promptConfirm, promptMultiSelect, promptText } from "../utils/prompt.js";
20
24
  import { discoverStackNames } from "../utils/services.js";
21
25
  import { isPathSafe } from "../utils/validation.js";
22
- import { ensureEnvFile, validateEnvFile } from "../utils/env-validator.js";
23
- import { PROJECT_FEATURES } from "../utils/project-features.js";
24
- import { promptConfirm, promptMultiSelect, promptText } from "../utils/prompt.js";
25
- import type { ProjectConfig } from "../types/index.js";
26
26
 
27
27
  /**
28
28
  * Stack names discovered from service.json files already in the repo (e.g. a
@@ -63,10 +63,7 @@ function syncDiscoveredStacksToPreAlpha(
63
63
  }
64
64
 
65
65
  projectConfig.phases.pre_alpha.enabledStacks = Array.from(
66
- new Set([
67
- ...projectConfig.phases.pre_alpha.enabledStacks,
68
- ...missingStacks,
69
- ]),
66
+ new Set([...projectConfig.phases.pre_alpha.enabledStacks, ...missingStacks]),
70
67
  );
71
68
 
72
69
  return missingStacks;
@@ -240,7 +237,10 @@ export const projectCommand = new Command("project")
240
237
 
241
238
  if (projectJsonExists && !options.force) {
242
239
  showSuccess(".tdk/project.json exists");
243
- const rawProjectConfig = JSON.parse(readFileSync(projectJsonPath, "utf-8")) as Record<string, unknown>;
240
+ const rawProjectConfig = JSON.parse(readFileSync(projectJsonPath, "utf-8")) as Record<
241
+ string,
242
+ unknown
243
+ >;
244
244
  const projectConfig = readProjectConfig(projectRoot);
245
245
  const discoveredStacks = discoverExistingServiceStacks(projectRoot);
246
246
  const autoEnabledStacks = syncDiscoveredStacksToPreAlpha(projectConfig, discoveredStacks);
@@ -251,10 +251,7 @@ export const projectCommand = new Command("project")
251
251
  }
252
252
 
253
253
  if (autoEnabledStacks.length > 0) {
254
- showDetail(
255
- `Auto-enabled discovered service stacks: ${autoEnabledStacks.join(", ")}`,
256
- 0,
257
- );
254
+ showDetail(`Auto-enabled discovered service stacks: ${autoEnabledStacks.join(", ")}`, 0);
258
255
  }
259
256
 
260
257
  showStep("\n📋 Regenerating master configuration files...\n");
@@ -1,11 +1,11 @@
1
1
  import { existsSync } from "node:fs";
2
- import { join, resolve } from "node:path";
2
+ import { join } from "node:path";
3
3
  import chalk from "chalk";
4
4
  import { Command } from "commander";
5
+ import { MASTER_CONFIG_FILES } from "../utils/constants.js";
5
6
  import { createDiscoveryContext } from "../utils/discovery-context.js";
6
7
  import { requireProjectRoot, runCommand } from "../utils/errors.js";
7
8
  import { formatCount } from "../utils/formatting.js";
8
- import { MASTER_CONFIG_FILES } from "../utils/constants.js";
9
9
 
10
10
  export const projectsCommand = new Command("projects")
11
11
  .description("Show project information and configuration status")
@@ -5,8 +5,8 @@ import { ensureProjectRuntimeAssets } from "../generator/template-engine.js";
5
5
  import { handleDryRun } from "../utils/command-helpers.js";
6
6
  import { errorFactories, handleTiltFailure, withTiltCheck } from "../utils/errors.js";
7
7
  import { formatCount } from "../utils/formatting.js";
8
- import { findAvailablePort } from "../utils/port-assignment.js";
9
8
  import { findProjectRoot } from "../utils/paths.js";
9
+ import { findAvailablePort } from "../utils/port-assignment.js";
10
10
  import { appendHealthPath, resolveSubdomainBases } from "../utils/service-urls.js";
11
11
  import {
12
12
  discoverResources,
@@ -89,15 +89,23 @@ export const upCommand = new Command("up")
89
89
  backends.forEach((svc) => {
90
90
  const servicePathName = svc.name.replace(/-api$/, "");
91
91
  const apiPath = svc.config?.apiPath ?? `/api/${servicePathName}`;
92
+ const sablier = svc.config?.sablier;
93
+ const deferredTag =
94
+ sablier?.enable && sablier?.deferStart
95
+ ? chalk.dim(" (deferred — starts on first request)")
96
+ : "";
92
97
  console.log(
93
- chalk.gray(` - ${svc.name}: ${apiBase}${chalk.cyan(appendHealthPath(apiPath))}`),
98
+ chalk.gray(
99
+ ` - ${svc.name}: ${apiBase}${chalk.cyan(appendHealthPath(apiPath))}${deferredTag}`,
100
+ ),
94
101
  );
95
102
  });
96
103
  }
97
104
  }
98
105
 
99
- const dryRunCommand =
100
- focusServiceNames.length > 0 ? `tilt up ${focusServiceNames.join(" ")}` : "tilt up";
106
+ const dryRunCommand = stackName
107
+ ? `tilt up -- --focus=${stackName} ${focusServiceNames.join(" ")}`
108
+ : "tilt up";
101
109
  if (handleDryRun(options, "not starting services", dryRunCommand)) {
102
110
  return;
103
111
  }
@@ -130,6 +138,7 @@ export const upCommand = new Command("up")
130
138
  verbose: options.verbose,
131
139
  quiet: options.quiet,
132
140
  force: options.force,
141
+ focusTargets: stackName ? [stackName] : undefined,
133
142
  });
134
143
 
135
144
  if (!options.quiet) {
@@ -70,7 +70,8 @@ function detectInstallation(): InstallInfo {
70
70
  const BINARY_RELEASE_REPO = "tdk-landscape/tdk-cli-releases";
71
71
 
72
72
  function binaryAssetName(): string | null {
73
- const osName = process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : null;
73
+ const osName =
74
+ process.platform === "darwin" ? "darwin" : process.platform === "linux" ? "linux" : null;
74
75
  const archName = process.arch === "arm64" ? "arm64" : process.arch === "x64" ? "amd64" : null;
75
76
  if (!osName || !archName) return null;
76
77
  return `tdk-${osName}-${archName}`;
@@ -174,7 +175,9 @@ export async function upgradeViaBinary(tdkPath: string, release: BinaryRelease):
174
175
  console.log(chalk.cyan(` chmod +x ${tdkPath}`));
175
176
  console.log(chalk.cyan(` rm -rf ${engineDir} && mkdir -p ${engineDir}`));
176
177
  console.log(
177
- chalk.cyan(` curl -fsSL ${release.engineDownloadUrl} | tar -xzf - -C ${engineDir} --strip-components=1`),
178
+ chalk.cyan(
179
+ ` curl -fsSL ${release.engineDownloadUrl} | tar -xzf - -C ${engineDir} --strip-components=1`,
180
+ ),
178
181
  );
179
182
  return false;
180
183
  } finally {
@@ -442,8 +445,12 @@ export const upgradeCommand = new Command("upgrade")
442
445
  chalk.gray(" Action: git pull origin main && bun install && bun link --force"),
443
446
  );
444
447
  } else if (installInfo.method === "binary" && binaryRelease) {
445
- console.log(chalk.gray(` Action: Download and replace with ${binaryRelease.downloadUrl}`));
446
- console.log(chalk.gray(` Action: Refresh bundled engine from ${binaryRelease.engineDownloadUrl}`));
448
+ console.log(
449
+ chalk.gray(` Action: Download and replace with ${binaryRelease.downloadUrl}`),
450
+ );
451
+ console.log(
452
+ chalk.gray(` Action: Refresh bundled engine from ${binaryRelease.engineDownloadUrl}`),
453
+ );
447
454
  } else {
448
455
  console.log(chalk.gray(` Action: Upgrade to ${latestVersion}`));
449
456
  }
@@ -2,10 +2,10 @@ import { describe, expect, it } from "vitest";
2
2
  import { PLATFORM_STANDARDS } from "./platform-standards.js";
3
3
 
4
4
  describe("platform standards", () => {
5
- it("keeps the low-level Traefik host generic and uses a non-privileged port", () => {
6
- expect(PLATFORM_STANDARDS.traefik.defaultHost).toBe("localhost");
7
- expect(PLATFORM_STANDARDS.traefik.appHost).toBe("app.localhost");
8
- expect(PLATFORM_STANDARDS.traefik.apiHost).toBe("api.localhost");
9
- expect(PLATFORM_STANDARDS.traefik.defaultPort).toBe(8080);
10
- });
5
+ it("keeps the low-level Traefik host generic and uses a non-privileged port", () => {
6
+ expect(PLATFORM_STANDARDS.traefik.defaultHost).toBe("localhost");
7
+ expect(PLATFORM_STANDARDS.traefik.appHost).toBe("app.localhost");
8
+ expect(PLATFORM_STANDARDS.traefik.apiHost).toBe("api.localhost");
9
+ expect(PLATFORM_STANDARDS.traefik.defaultPort).toBe(8080);
10
+ });
11
11
  });
@@ -8,7 +8,15 @@
8
8
  // so this exercises the same code path `tdk project` actually runs.
9
9
 
10
10
  import { execFileSync } from "node:child_process";
11
- import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, utimesSync, writeFileSync } from "node:fs";
11
+ import {
12
+ existsSync,
13
+ mkdirSync,
14
+ mkdtempSync,
15
+ readFileSync,
16
+ rmSync,
17
+ utimesSync,
18
+ writeFileSync,
19
+ } from "node:fs";
12
20
  import { tmpdir } from "node:os";
13
21
  import { join } from "node:path";
14
22
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
@@ -23,7 +31,7 @@ function buildFixtureTarball(): Buffer {
23
31
  mkdirSync(join(src, "typescript"), { recursive: true });
24
32
  writeFileSync(
25
33
  join(src, "typescript", "playwright_config.star"),
26
- "# REAL premium playwright config\ndef generate_playwright_config(): pass\n"
34
+ "# REAL premium playwright config\ndef generate_playwright_config(): pass\n",
27
35
  );
28
36
  writeFileSync(join(src, "c4_diagram.star"), "# REAL premium c4 diagram generator\n");
29
37
 
@@ -49,7 +57,7 @@ beforeEach(() => {
49
57
  mkdirSync(join(destDir, "engine/topologies/tilt/generators/typescript"), { recursive: true });
50
58
  writeFileSync(
51
59
  join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
52
- "# unlicensed stub\n"
60
+ "# unlicensed stub\n",
53
61
  );
54
62
 
55
63
  process.env.HOME = fakeHome;
@@ -79,15 +87,17 @@ describe("applyPremiumOverlay", () => {
79
87
  expect(
80
88
  readFileSync(
81
89
  join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
82
- "utf-8"
83
- )
90
+ "utf-8",
91
+ ),
84
92
  ).toBe("# unlicensed stub\n");
85
93
  });
86
94
 
87
95
  it("scenario 2: invalid/ungranted key -> tries every known resource, then falls back to free tier", async () => {
88
96
  process.env.TDK_LICENSE_KEY = "tdk-fa411b"; // the mistyped key from the real session
89
97
 
90
- const fetchSpy = vi.fn().mockResolvedValue(new Response("key does not grant resource", { status: 403 }));
98
+ const fetchSpy = vi
99
+ .fn()
100
+ .mockResolvedValue(new Response("key does not grant resource", { status: 403 }));
91
101
  vi.stubGlobal("fetch", fetchSpy);
92
102
 
93
103
  const { applyPremiumOverlay } = await import("../extension-fetch.js");
@@ -103,8 +113,8 @@ describe("applyPremiumOverlay", () => {
103
113
  expect(
104
114
  readFileSync(
105
115
  join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
106
- "utf-8"
107
- )
116
+ "utf-8",
117
+ ),
108
118
  ).toBe("# unlicensed stub\n");
109
119
  });
110
120
 
@@ -129,12 +139,15 @@ describe("applyPremiumOverlay", () => {
129
139
 
130
140
  const playwrightOut = readFileSync(
131
141
  join(destDir, "engine/topologies/tilt/generators/typescript/playwright_config.star"),
132
- "utf-8"
142
+ "utf-8",
133
143
  );
134
144
  expect(playwrightOut).toContain("REAL premium playwright config");
135
145
  expect(playwrightOut).not.toContain("unlicensed stub");
136
146
 
137
- const c4Out = readFileSync(join(destDir, "engine/topologies/tilt/generators/c4_diagram.star"), "utf-8");
147
+ const c4Out = readFileSync(
148
+ join(destDir, "engine/topologies/tilt/generators/c4_diagram.star"),
149
+ "utf-8",
150
+ );
138
151
  expect(c4Out).toContain("REAL premium c4 diagram generator");
139
152
  });
140
153
 
@@ -142,7 +155,7 @@ describe("applyPremiumOverlay", () => {
142
155
  process.env.TDK_LICENSE_KEY = "tdk-fa411b";
143
156
  const seenProjectIds: string[] = [];
144
157
  const fetchSpy = vi.fn().mockImplementation((url: string) => {
145
- seenProjectIds.push(new URL(url).searchParams.get("projectId")!);
158
+ seenProjectIds.push(new URL(url).searchParams.get("projectId") ?? "");
146
159
  return Promise.resolve(new Response("not granted", { status: 403 }));
147
160
  });
148
161
  vi.stubGlobal("fetch", fetchSpy);
@@ -161,7 +174,9 @@ describe("applyPremiumOverlay", () => {
161
174
  process.env.TDK_LICENSE_KEY = "tdk-fa411a";
162
175
  fixtureTarball ??= buildFixtureTarball();
163
176
 
164
- const fetchSpy = vi.fn().mockResolvedValue(new Response(new Uint8Array(fixtureTarball), { status: 200 }));
177
+ const fetchSpy = vi
178
+ .fn()
179
+ .mockResolvedValue(new Response(new Uint8Array(fixtureTarball), { status: 200 }));
165
180
  vi.stubGlobal("fetch", fetchSpy);
166
181
 
167
182
  const { applyPremiumOverlay } = await import("../extension-fetch.js");
@@ -178,7 +193,11 @@ describe("applyPremiumOverlay", () => {
178
193
  // A Response body can only be read once - mockResolvedValue would
179
194
  // reuse the same instance across both calls in this test, so build a
180
195
  // fresh Response per invocation instead.
181
- const fetchSpy = vi.fn().mockImplementation(() => Promise.resolve(new Response(new Uint8Array(fixtureTarball), { status: 200 })));
196
+ const fetchSpy = vi
197
+ .fn()
198
+ .mockImplementation(() =>
199
+ Promise.resolve(new Response(new Uint8Array(fixtureTarball), { status: 200 })),
200
+ );
182
201
  vi.stubGlobal("fetch", fetchSpy);
183
202
 
184
203
  const { applyPremiumOverlay } = await import("../extension-fetch.js");
@@ -197,7 +216,10 @@ describe("applyPremiumOverlay", () => {
197
216
  fixtureTarball ??= buildFixtureTarball();
198
217
 
199
218
  process.env.TDK_LICENSE_KEY = "tdk-fa411a";
200
- vi.stubGlobal("fetch", vi.fn().mockResolvedValue(new Response(new Uint8Array(fixtureTarball), { status: 200 })));
219
+ vi.stubGlobal(
220
+ "fetch",
221
+ vi.fn().mockResolvedValue(new Response(new Uint8Array(fixtureTarball), { status: 200 })),
222
+ );
201
223
  const { applyPremiumOverlay } = await import("../extension-fetch.js");
202
224
  await applyPremiumOverlay(projectRoot, destDir);
203
225
 
@@ -30,13 +30,21 @@ import { homedir } from "node:os";
30
30
  import { join } from "node:path";
31
31
  import { extractTarball } from "../utils/tar.js";
32
32
 
33
- const DEFAULT_ENDPOINT = "https://tdk-extension-dist.oranguman.workers.dev/v1/premium/bundle.tar.gz";
33
+ const DEFAULT_ENDPOINT =
34
+ "https://tdk-extension-dist.oranguman.workers.dev/v1/premium/bundle.tar.gz";
34
35
 
35
36
  // Tried in order until one is granted - the worker unlocks the whole
36
37
  // bundle on the first resource name a key is found to grant, since
37
38
  // premium.tar.gz ships all paid resources together. Keep in sync with
38
39
  // what issue-key.yml/update-key.yml accept as `resources` entries.
39
- const KNOWN_RESOURCES = ["playwright", "c4-diagram", "logging", "agents-md", "sablier", "verdaccio"];
40
+ const KNOWN_RESOURCES = [
41
+ "playwright",
42
+ "c4-diagram",
43
+ "logging",
44
+ "agents-md",
45
+ "sablier",
46
+ "verdaccio",
47
+ ];
40
48
 
41
49
  // Re-check the license periodically rather than trusting a local cache
42
50
  // forever - an expired or revoked key shouldn't keep unlocking premium
@@ -61,8 +69,7 @@ const PREMIUM_PATH_MAP: Record<string, string> = {
61
69
  "engine/topologies/tilt/generators/typescript/fixed_frontend_tsconfig.star",
62
70
  "synthetic_monitor.star": "engine/resources/synthetic_monitor.star",
63
71
  "synthetic-monitor-topology.star": "engine/topologies/platform/services/synthetic-monitor.star",
64
- "database-management-service.yaml":
65
- "platform/services/platform/database-management/service.yaml",
72
+ "database-management-service.yaml": "platform/services/platform/database-management/service.yaml",
66
73
  "networking/sablier_container_cycle.star":
67
74
  "engine/topologies/platform/docker/networking/sablier_container_cycle.star",
68
75
  "registries/verdaccio_loader.star": "engine/topologies/platform/registries/verdaccio_loader.star",
@@ -86,7 +93,7 @@ function getOrCreateProjectId(projectRoot: string): string {
86
93
  }
87
94
  const id = randomUUID();
88
95
  mkdirSync(join(projectRoot, ".tdk"), { recursive: true });
89
- writeFileSync(idPath, id + "\n");
96
+ writeFileSync(idPath, `${id}\n`);
90
97
  return id;
91
98
  }
92
99
 
@@ -33,13 +33,12 @@ export function loadTemplate(filename: string): string {
33
33
  triedPaths.push(templatePath);
34
34
  try {
35
35
  return fs.readFileSync(templatePath, "utf-8");
36
- } catch (error) {
37
- // Try next path
38
- continue;
39
- }
36
+ } catch (_error) {}
40
37
  }
41
38
 
42
- throw new Error(`Failed to load template ${filename} from any of these paths: ${triedPaths.join(", ")}`);
39
+ throw new Error(
40
+ `Failed to load template ${filename} from any of these paths: ${triedPaths.join(", ")}`,
41
+ );
43
42
  }
44
43
 
45
44
  // Templates used to be loaded eagerly here, at module initialization. That
@@ -192,10 +191,7 @@ export class TemplateEngine {
192
191
  runtime: PLATFORM_STANDARDS.runtime,
193
192
  project: projectConfig.project,
194
193
  phases: dedupePhaseEnabledStacks(projectConfig.phases),
195
- alwaysEnabledInfra: projectConfig.always_enabled_infra ?? [
196
- "database-management",
197
- "proxy",
198
- ],
194
+ alwaysEnabledInfra: projectConfig.always_enabled_infra ?? ["database-management", "proxy"],
199
195
  optionalInfra: projectConfig.optional_infra,
200
196
  serviceDescriptions: RESOURCE_DESCRIPTIONS,
201
197
  infraDescriptions: INFRA_DESCRIPTIONS,
@@ -538,10 +534,7 @@ export async function generateMasterConfigs(projectRoot: string): Promise<void>
538
534
  if (isStackFeatureEnabledInStacks(projectConfig.phases, "database-management")) {
539
535
  const composeDir = path.join(projectRoot, "services", "platform", "database-management");
540
536
  fs.mkdirSync(composeDir, { recursive: true });
541
- const composePath = path.join(
542
- composeDir,
543
- "docker-compose.yml",
544
- );
537
+ const composePath = path.join(composeDir, "docker-compose.yml");
545
538
  writeTextFile(composePath, generateDatabaseManagementCompose(projectConfig));
546
539
  console.log("✓ Generated: services/platform/database-management/docker-compose.yml");
547
540
  }
@@ -571,9 +564,7 @@ export async function generateMasterConfigs(projectRoot: string): Promise<void>
571
564
  // This makes `tdk up` work offline and on any machine - no hardcoded paths,
572
565
  // no dependency on a private GitHub repo.
573
566
  const TDK_EXTENSION_DIRS = ["engine", "discovery", "specs", "ext"] as string[];
574
- const PROJECT_RUNTIME_ASSET_DIRS = [
575
- ["shared-platform-engineering", "docker-templates"],
576
- ] as const;
567
+ const PROJECT_RUNTIME_ASSET_DIRS = [["shared-platform-engineering", "docker-templates"]] as const;
577
568
  const REQUIRED_DOCKER_TEMPLATE_FILES = [
578
569
  "install-deps.sh",
579
570
  "bun-hoisted-symlink-fix.sh",
@@ -615,9 +606,11 @@ function findCliAssetRoot(): string | null {
615
606
  path.join(process.cwd(), "node_modules", "@tdk-landscape", "tdk-cli-core"),
616
607
  ];
617
608
 
618
- return candidates.find((candidate) =>
619
- fs.existsSync(path.join(candidate, "shared-platform-engineering", "docker-templates")),
620
- ) ?? null;
609
+ return (
610
+ candidates.find((candidate) =>
611
+ fs.existsSync(path.join(candidate, "shared-platform-engineering", "docker-templates")),
612
+ ) ?? null
613
+ );
621
614
  }
622
615
 
623
616
  export function ensureProjectRuntimeAssets(projectRoot: string): string[] {
@@ -645,7 +638,12 @@ export function ensureProjectRuntimeAssets(projectRoot: string): string[] {
645
638
  }
646
639
 
647
640
  for (const file of REQUIRED_DOCKER_TEMPLATE_FILES) {
648
- const filePath = path.join(projectRoot, "shared-platform-engineering", "docker-templates", file);
641
+ const filePath = path.join(
642
+ projectRoot,
643
+ "shared-platform-engineering",
644
+ "docker-templates",
645
+ file,
646
+ );
649
647
  if (!fs.existsSync(filePath)) {
650
648
  console.warn(`⚠️ Missing runtime asset after copy: ${filePath}`);
651
649
  }
@@ -663,7 +661,7 @@ async function vendorTdkExtension(projectRoot: string): Promise<void> {
663
661
  // 2. Self-contained repo (engine/ ships next to cli/ - public tdk-cli-core)
664
662
  // 3. Executable-adjacent checkout (bundled installs)
665
663
  // 4. Relative ../tdk-cli sibling (monorepo maintainer layout)
666
- let sources: string[] = [];
664
+ const sources: string[] = [];
667
665
  if (process.env.TDK_EXTENSION_SOURCE) {
668
666
  sources.push(process.env.TDK_EXTENSION_SOURCE);
669
667
  }
@@ -26,6 +26,8 @@ export interface ResourceConfig {
26
26
  enable?: boolean;
27
27
  group?: string;
28
28
  sessionDuration?: string;
29
+ /** Skip this resource during `tdk up` entirely; a Traefik static route wakes it on first request. Requires enable: true. */
30
+ deferStart?: boolean;
29
31
  };
30
32
  }
31
33