@tdk-landscape/tdk-cli-core 1.3.53 → 1.3.54

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 (388) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/cli/dist/generator/extension-fetch.js +16 -9
  3. package/cli/package.json +1 -1
  4. package/package.json +16 -1
  5. package/.claude/skills/layer-autoresearch/SKILL.md +0 -48
  6. package/.claude/skills/tdk-troubleshoot/SKILL.md +0 -222
  7. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -40
  8. package/.github/ISSUE_TEMPLATE/config.yml +0 -11
  9. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -18
  10. package/.github/ISSUE_TEMPLATE/premium_license.yml +0 -43
  11. package/.github/dependabot.yml +0 -33
  12. package/.github/pull_request_template.md +0 -5
  13. package/.github/workflows/ci.yml +0 -200
  14. package/.github/workflows/release-binaries.yml +0 -139
  15. package/.github/zizmor.yml +0 -9
  16. package/.pre-commit-config.yaml +0 -57
  17. package/CODE_OF_CONDUCT.md +0 -9
  18. package/CONTRIBUTING.md +0 -42
  19. package/Makefile +0 -92
  20. package/SECURITY.md +0 -17
  21. package/benchmarks/results/container-scale-2026-09-25T20-54-49-736Z.json +0 -45
  22. package/benchmarks/results/container-scale-2026-09-25T21-01-20-540Z.json +0 -150
  23. package/benchmarks/results/container-scale-2026-09-25T21-15-01-441Z.json +0 -73
  24. package/benchmarks/results/container-scale-2026-09-25T22-09-01-630Z.json +0 -77
  25. package/benchmarks/results/container-scale-2026-09-25T22-18-28-371Z.json +0 -202
  26. package/cli/AGENTS.md +0 -390
  27. package/cli/DESIGN.md +0 -735
  28. package/cli/README.md +0 -292
  29. package/cli/biome.json +0 -40
  30. package/cli/dependency-graph.svg +0 -1135
  31. package/cli/dist/cli.d.ts +0 -3
  32. package/cli/dist/cli.d.ts.map +0 -1
  33. package/cli/dist/cli.js.map +0 -1
  34. package/cli/dist/commands/completion.d.ts +0 -3
  35. package/cli/dist/commands/completion.d.ts.map +0 -1
  36. package/cli/dist/commands/completion.js.map +0 -1
  37. package/cli/dist/commands/config.d.ts +0 -3
  38. package/cli/dist/commands/config.d.ts.map +0 -1
  39. package/cli/dist/commands/config.js.map +0 -1
  40. package/cli/dist/commands/doctor.d.ts +0 -19
  41. package/cli/dist/commands/doctor.d.ts.map +0 -1
  42. package/cli/dist/commands/doctor.js.map +0 -1
  43. package/cli/dist/commands/down.d.ts +0 -3
  44. package/cli/dist/commands/down.d.ts.map +0 -1
  45. package/cli/dist/commands/down.js.map +0 -1
  46. package/cli/dist/commands/help.d.ts +0 -2
  47. package/cli/dist/commands/help.d.ts.map +0 -1
  48. package/cli/dist/commands/help.js.map +0 -1
  49. package/cli/dist/commands/networks.d.ts +0 -3
  50. package/cli/dist/commands/networks.d.ts.map +0 -1
  51. package/cli/dist/commands/networks.js.map +0 -1
  52. package/cli/dist/commands/project.d.ts +0 -9
  53. package/cli/dist/commands/project.d.ts.map +0 -1
  54. package/cli/dist/commands/project.js.map +0 -1
  55. package/cli/dist/commands/projects.d.ts +0 -3
  56. package/cli/dist/commands/projects.d.ts.map +0 -1
  57. package/cli/dist/commands/projects.js.map +0 -1
  58. package/cli/dist/commands/resource.d.ts +0 -69
  59. package/cli/dist/commands/resource.d.ts.map +0 -1
  60. package/cli/dist/commands/resource.js.map +0 -1
  61. package/cli/dist/commands/resources.d.ts +0 -3
  62. package/cli/dist/commands/resources.d.ts.map +0 -1
  63. package/cli/dist/commands/resources.js.map +0 -1
  64. package/cli/dist/commands/stack.d.ts +0 -3
  65. package/cli/dist/commands/stack.d.ts.map +0 -1
  66. package/cli/dist/commands/stack.js.map +0 -1
  67. package/cli/dist/commands/stacks.d.ts +0 -3
  68. package/cli/dist/commands/stacks.d.ts.map +0 -1
  69. package/cli/dist/commands/stacks.js.map +0 -1
  70. package/cli/dist/commands/status.d.ts +0 -3
  71. package/cli/dist/commands/status.d.ts.map +0 -1
  72. package/cli/dist/commands/status.js.map +0 -1
  73. package/cli/dist/commands/ui.d.ts +0 -3
  74. package/cli/dist/commands/ui.d.ts.map +0 -1
  75. package/cli/dist/commands/ui.js.map +0 -1
  76. package/cli/dist/commands/up.d.ts +0 -3
  77. package/cli/dist/commands/up.d.ts.map +0 -1
  78. package/cli/dist/commands/up.js.map +0 -1
  79. package/cli/dist/commands/upgrade.d.ts +0 -14
  80. package/cli/dist/commands/upgrade.d.ts.map +0 -1
  81. package/cli/dist/commands/upgrade.js.map +0 -1
  82. package/cli/dist/commands/version.d.ts +0 -3
  83. package/cli/dist/commands/version.d.ts.map +0 -1
  84. package/cli/dist/commands/version.js.map +0 -1
  85. package/cli/dist/components/Accessible.d.ts +0 -8
  86. package/cli/dist/components/Accessible.d.ts.map +0 -1
  87. package/cli/dist/components/Accessible.js.map +0 -1
  88. package/cli/dist/components/BaseTooltip.d.ts +0 -4
  89. package/cli/dist/components/BaseTooltip.d.ts.map +0 -1
  90. package/cli/dist/components/BaseTooltip.js.map +0 -1
  91. package/cli/dist/components/DetailPanel.d.ts +0 -4
  92. package/cli/dist/components/DetailPanel.d.ts.map +0 -1
  93. package/cli/dist/components/DetailPanel.js.map +0 -1
  94. package/cli/dist/components/FileTree.d.ts +0 -4
  95. package/cli/dist/components/FileTree.d.ts.map +0 -1
  96. package/cli/dist/components/FileTree.js.map +0 -1
  97. package/cli/dist/components/ResourceSelectInput.d.ts +0 -4
  98. package/cli/dist/components/ResourceSelectInput.d.ts.map +0 -1
  99. package/cli/dist/components/ResourceSelectInput.js.map +0 -1
  100. package/cli/dist/components/ResourceTable.d.ts +0 -4
  101. package/cli/dist/components/ResourceTable.d.ts.map +0 -1
  102. package/cli/dist/components/ResourceTable.js.map +0 -1
  103. package/cli/dist/components/TabBar.d.ts +0 -4
  104. package/cli/dist/components/TabBar.d.ts.map +0 -1
  105. package/cli/dist/components/TabBar.js.map +0 -1
  106. package/cli/dist/components/Tooltip.d.ts +0 -12
  107. package/cli/dist/components/Tooltip.d.ts.map +0 -1
  108. package/cli/dist/components/Tooltip.js.map +0 -1
  109. package/cli/dist/components/index.d.ts +0 -8
  110. package/cli/dist/components/index.d.ts.map +0 -1
  111. package/cli/dist/components/index.js.map +0 -1
  112. package/cli/dist/config/platform-standards.d.ts +0 -159
  113. package/cli/dist/config/platform-standards.d.ts.map +0 -1
  114. package/cli/dist/config/platform-standards.js.map +0 -1
  115. package/cli/dist/generator/extension-fetch.d.ts +0 -25
  116. package/cli/dist/generator/extension-fetch.d.ts.map +0 -1
  117. package/cli/dist/generator/extension-fetch.js.map +0 -1
  118. package/cli/dist/generator/template-engine.d.ts +0 -62
  119. package/cli/dist/generator/template-engine.d.ts.map +0 -1
  120. package/cli/dist/generator/template-engine.js.map +0 -1
  121. package/cli/dist/index.d.ts +0 -11
  122. package/cli/dist/index.d.ts.map +0 -1
  123. package/cli/dist/index.js.map +0 -1
  124. package/cli/dist/types/index.d.ts +0 -257
  125. package/cli/dist/types/index.d.ts.map +0 -1
  126. package/cli/dist/types/index.js.map +0 -1
  127. package/cli/dist/utils/cache.d.ts +0 -19
  128. package/cli/dist/utils/cache.d.ts.map +0 -1
  129. package/cli/dist/utils/cache.js.map +0 -1
  130. package/cli/dist/utils/command-helpers.d.ts +0 -17
  131. package/cli/dist/utils/command-helpers.d.ts.map +0 -1
  132. package/cli/dist/utils/command-helpers.js.map +0 -1
  133. package/cli/dist/utils/constants.d.ts +0 -53
  134. package/cli/dist/utils/constants.d.ts.map +0 -1
  135. package/cli/dist/utils/constants.js.map +0 -1
  136. package/cli/dist/utils/discovery-context.d.ts +0 -4
  137. package/cli/dist/utils/discovery-context.d.ts.map +0 -1
  138. package/cli/dist/utils/discovery-context.js.map +0 -1
  139. package/cli/dist/utils/docker.d.ts +0 -4
  140. package/cli/dist/utils/docker.d.ts.map +0 -1
  141. package/cli/dist/utils/docker.js.map +0 -1
  142. package/cli/dist/utils/doctor-runtime.d.ts +0 -81
  143. package/cli/dist/utils/doctor-runtime.d.ts.map +0 -1
  144. package/cli/dist/utils/doctor-runtime.js.map +0 -1
  145. package/cli/dist/utils/env-validator.d.ts +0 -15
  146. package/cli/dist/utils/env-validator.d.ts.map +0 -1
  147. package/cli/dist/utils/env-validator.js.map +0 -1
  148. package/cli/dist/utils/errors.d.ts +0 -31
  149. package/cli/dist/utils/errors.d.ts.map +0 -1
  150. package/cli/dist/utils/errors.js.map +0 -1
  151. package/cli/dist/utils/file-helpers.d.ts +0 -14
  152. package/cli/dist/utils/file-helpers.d.ts.map +0 -1
  153. package/cli/dist/utils/file-helpers.js.map +0 -1
  154. package/cli/dist/utils/formatting.d.ts +0 -30
  155. package/cli/dist/utils/formatting.d.ts.map +0 -1
  156. package/cli/dist/utils/formatting.js.map +0 -1
  157. package/cli/dist/utils/paths.d.ts +0 -3
  158. package/cli/dist/utils/paths.d.ts.map +0 -1
  159. package/cli/dist/utils/paths.js.map +0 -1
  160. package/cli/dist/utils/port-assignment.d.ts +0 -6
  161. package/cli/dist/utils/port-assignment.d.ts.map +0 -1
  162. package/cli/dist/utils/port-assignment.js.map +0 -1
  163. package/cli/dist/utils/project-features.d.ts +0 -23
  164. package/cli/dist/utils/project-features.d.ts.map +0 -1
  165. package/cli/dist/utils/project-features.js.map +0 -1
  166. package/cli/dist/utils/project-templates.d.ts +0 -7
  167. package/cli/dist/utils/project-templates.d.ts.map +0 -1
  168. package/cli/dist/utils/project-templates.js.map +0 -1
  169. package/cli/dist/utils/prompt.d.ts +0 -28
  170. package/cli/dist/utils/prompt.d.ts.map +0 -1
  171. package/cli/dist/utils/prompt.js.map +0 -1
  172. package/cli/dist/utils/resource-features.d.ts +0 -29
  173. package/cli/dist/utils/resource-features.d.ts.map +0 -1
  174. package/cli/dist/utils/resource-features.js.map +0 -1
  175. package/cli/dist/utils/service-urls.d.ts +0 -30
  176. package/cli/dist/utils/service-urls.d.ts.map +0 -1
  177. package/cli/dist/utils/service-urls.js.map +0 -1
  178. package/cli/dist/utils/services.d.ts +0 -18
  179. package/cli/dist/utils/services.d.ts.map +0 -1
  180. package/cli/dist/utils/services.js.map +0 -1
  181. package/cli/dist/utils/stack-features.d.ts +0 -22
  182. package/cli/dist/utils/stack-features.d.ts.map +0 -1
  183. package/cli/dist/utils/stack-features.js.map +0 -1
  184. package/cli/dist/utils/tar.d.ts +0 -7
  185. package/cli/dist/utils/tar.d.ts.map +0 -1
  186. package/cli/dist/utils/tar.js.map +0 -1
  187. package/cli/dist/utils/tilt.d.ts +0 -20
  188. package/cli/dist/utils/tilt.d.ts.map +0 -1
  189. package/cli/dist/utils/tilt.js.map +0 -1
  190. package/cli/dist/utils/validation.d.ts +0 -16
  191. package/cli/dist/utils/validation.d.ts.map +0 -1
  192. package/cli/dist/utils/validation.js.map +0 -1
  193. package/cli/knip.json +0 -6
  194. package/cli/pnpm-lock.yaml +0 -2305
  195. package/cli/pnpm-workspace.yaml +0 -2
  196. package/cli/src/cli.ts +0 -72
  197. package/cli/src/commands/__tests__/always-enabled-infra.test.ts +0 -109
  198. package/cli/src/commands/__tests__/config.test.ts +0 -146
  199. package/cli/src/commands/__tests__/doctor.test.ts +0 -730
  200. package/cli/src/commands/__tests__/error-handling.test.ts +0 -78
  201. package/cli/src/commands/__tests__/phases-model.test.ts +0 -161
  202. package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +0 -187
  203. package/cli/src/commands/__tests__/project.test.ts +0 -68
  204. package/cli/src/commands/__tests__/resource.test.ts +0 -226
  205. package/cli/src/commands/__tests__/saas-starter-integration.test.ts +0 -194
  206. package/cli/src/commands/__tests__/stack-features-e2e.test.ts +0 -135
  207. package/cli/src/commands/__tests__/upgrade.test.ts +0 -198
  208. package/cli/src/commands/completion.ts +0 -300
  209. package/cli/src/commands/config.ts +0 -299
  210. package/cli/src/commands/doctor.ts +0 -926
  211. package/cli/src/commands/down.ts +0 -37
  212. package/cli/src/commands/help.ts +0 -143
  213. package/cli/src/commands/networks-design.md +0 -80
  214. package/cli/src/commands/networks.ts +0 -332
  215. package/cli/src/commands/project.ts +0 -456
  216. package/cli/src/commands/projects.ts +0 -82
  217. package/cli/src/commands/resource.ts +0 -652
  218. package/cli/src/commands/resources.ts +0 -95
  219. package/cli/src/commands/stack.ts +0 -128
  220. package/cli/src/commands/stacks.ts +0 -52
  221. package/cli/src/commands/status.ts +0 -88
  222. package/cli/src/commands/ui.tsx +0 -843
  223. package/cli/src/commands/up.ts +0 -169
  224. package/cli/src/commands/upgrade.ts +0 -628
  225. package/cli/src/commands/version.ts +0 -9
  226. package/cli/src/components/Accessible.tsx +0 -21
  227. package/cli/src/components/BaseTooltip.tsx +0 -66
  228. package/cli/src/components/DetailPanel.tsx +0 -146
  229. package/cli/src/components/FileTree.tsx +0 -89
  230. package/cli/src/components/ResourceSelectInput.tsx +0 -30
  231. package/cli/src/components/ResourceTable.tsx +0 -78
  232. package/cli/src/components/TabBar.tsx +0 -53
  233. package/cli/src/components/Tooltip.tsx +0 -11
  234. package/cli/src/components/index.ts +0 -7
  235. package/cli/src/config/platform-standards.test.ts +0 -11
  236. package/cli/src/config/platform-standards.ts +0 -196
  237. package/cli/src/generator/__tests__/extension-fetch.test.ts +0 -242
  238. package/cli/src/generator/__tests__/template-engine.test.ts +0 -70
  239. package/cli/src/generator/extension-fetch.ts +0 -286
  240. package/cli/src/generator/template-engine.ts +0 -752
  241. package/cli/src/index.ts +0 -86
  242. package/cli/src/templates.d.ts +0 -4
  243. package/cli/src/types/index.ts +0 -353
  244. package/cli/src/utils/__tests__/cache.test.ts +0 -98
  245. package/cli/src/utils/__tests__/formatting.test.ts +0 -170
  246. package/cli/src/utils/__tests__/paths.test.ts +0 -180
  247. package/cli/src/utils/__tests__/port-assignment.test.ts +0 -121
  248. package/cli/src/utils/__tests__/service-urls.test.ts +0 -174
  249. package/cli/src/utils/__tests__/services.test.ts +0 -531
  250. package/cli/src/utils/__tests__/tilt.test.ts +0 -172
  251. package/cli/src/utils/__tests__/validation.test.ts +0 -148
  252. package/cli/src/utils/cache.ts +0 -76
  253. package/cli/src/utils/command-helpers.ts +0 -54
  254. package/cli/src/utils/constants.ts +0 -130
  255. package/cli/src/utils/discovery-context.ts +0 -49
  256. package/cli/src/utils/docker.ts +0 -20
  257. package/cli/src/utils/doctor-runtime.ts +0 -644
  258. package/cli/src/utils/env-validator.ts +0 -139
  259. package/cli/src/utils/errors.ts +0 -168
  260. package/cli/src/utils/file-helpers.ts +0 -62
  261. package/cli/src/utils/formatting.ts +0 -215
  262. package/cli/src/utils/paths.ts +0 -53
  263. package/cli/src/utils/port-assignment.ts +0 -106
  264. package/cli/src/utils/project-features.ts +0 -118
  265. package/cli/src/utils/project-templates.ts +0 -29
  266. package/cli/src/utils/prompt.ts +0 -128
  267. package/cli/src/utils/resource-features.ts +0 -215
  268. package/cli/src/utils/service-urls.ts +0 -124
  269. package/cli/src/utils/services.ts +0 -364
  270. package/cli/src/utils/stack-features.ts +0 -30
  271. package/cli/src/utils/tar.ts +0 -24
  272. package/cli/src/utils/tilt.ts +0 -133
  273. package/cli/src/utils/validation.ts +0 -67
  274. package/cli/tsconfig.json +0 -25
  275. package/cli/tsconfig.typecheck.json +0 -8
  276. package/docs/FEATURES.md +0 -281
  277. package/docs/demo.svg +0 -217
  278. package/engine/docs/AUTODISCOVERY_TEST.md +0 -182
  279. package/engine/docs/C4-ARCHITECTURE-operations.md +0 -396
  280. package/engine/docs/C4-ARCHITECTURE-overview.md +0 -284
  281. package/engine/docs/C4-ARCHITECTURE.md +0 -17
  282. package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +0 -349
  283. package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +0 -357
  284. package/engine/docs/README.md +0 -284
  285. package/install.sh +0 -19
  286. package/knip.json +0 -10
  287. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/.openspec.yaml +0 -2
  288. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/design.md +0 -102
  289. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/proposal.md +0 -31
  290. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-notifications/spec.md +0 -48
  291. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-orchestration/spec.md +0 -63
  292. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-troubleshooting/spec.md +0 -56
  293. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/tasks.md +0 -61
  294. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/.openspec.yaml +0 -2
  295. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/design.md +0 -114
  296. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/proposal.md +0 -32
  297. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/manifest-field-migration/spec.md +0 -20
  298. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/resource-terminology-standard/spec.md +0 -20
  299. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/stack-terminology-standard/spec.md +0 -20
  300. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/tasks.md +0 -194
  301. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/.openspec.yaml +0 -2
  302. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/design.md +0 -111
  303. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/proposal.md +0 -33
  304. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/function-naming-alignment/spec.md +0 -12
  305. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/optional-parameter-patterns/spec.md +0 -18
  306. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-documentation/spec.md +0 -16
  307. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-naming-consistency/spec.md +0 -12
  308. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-ordering-standard/spec.md +0 -12
  309. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/tasks.md +0 -194
  310. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/.openspec.yaml +0 -2
  311. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/design.md +0 -84
  312. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/proposal.md +0 -31
  313. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/codebase-audit/spec.md +0 -27
  314. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/dead-code-cleanup/spec.md +0 -27
  315. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/test-gap-fill/spec.md +0 -23
  316. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/todo-resolution/spec.md +0 -27
  317. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/tasks.md +0 -39
  318. package/openspec/changes/archive/2026-06-25-landscape-consolidation/.openspec.yaml +0 -2
  319. package/openspec/changes/archive/2026-06-25-landscape-consolidation/design.md +0 -80
  320. package/openspec/changes/archive/2026-06-25-landscape-consolidation/proposal.md +0 -40
  321. package/openspec/changes/archive/2026-06-25-landscape-consolidation/spec.md +0 -52
  322. package/openspec/changes/archive/2026-06-25-landscape-consolidation/tasks.md +0 -51
  323. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/.openspec.yaml +0 -2
  324. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/design.md +0 -43
  325. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/proposal.md +0 -29
  326. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/specs/self-contained-generated-projects/spec.md +0 -67
  327. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/tasks.md +0 -27
  328. package/openspec/changes/optimize-runtime-docker-layers/.openspec.yaml +0 -3
  329. package/openspec/changes/optimize-runtime-docker-layers/design.md +0 -81
  330. package/openspec/changes/optimize-runtime-docker-layers/proposal.md +0 -44
  331. package/openspec/changes/optimize-runtime-docker-layers/specs/runtime-container-footprint/spec.md +0 -79
  332. package/openspec/changes/optimize-runtime-docker-layers/tasks.md +0 -36
  333. package/openspec/changes/prioritized-cold-start/.openspec.yaml +0 -4
  334. package/openspec/changes/prioritized-cold-start/design.md +0 -137
  335. package/openspec/changes/prioritized-cold-start/proposal.md +0 -41
  336. package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +0 -98
  337. package/openspec/changes/prioritized-cold-start/tasks.md +0 -69
  338. package/openspec/config.yaml +0 -1
  339. package/openspec/specs/manifest-field-migration/spec.md +0 -24
  340. package/openspec/specs/resource-terminology-standard/spec.md +0 -24
  341. package/openspec/specs/self-contained-generated-projects/spec.md +0 -67
  342. package/openspec/specs/stack-terminology-standard/spec.md +0 -24
  343. package/platform/services/platform/proxy/service.yaml +0 -14
  344. package/scripts/audit-codebase.sh +0 -213
  345. package/scripts/autoresearch/layer-eval.sh +0 -65
  346. package/scripts/benchmark/README.md +0 -25
  347. package/scripts/benchmark/container-scale.ts +0 -503
  348. package/scripts/benchmark/pre-release-gate.sh +0 -9
  349. package/scripts/install-git-hooks.sh +0 -14
  350. package/scripts/measure-idle-footprint.sh +0 -58
  351. package/scripts/record-demo.sh +0 -43
  352. package/scripts/release-binaries.sh +0 -97
  353. package/scripts/setup-pre-commit.sh +0 -33
  354. package/scripts/stage-npm-engine.sh +0 -36
  355. package/tests/tilt-engine/__init__.py +0 -5
  356. package/tests/tilt-engine/conftest.py +0 -182
  357. package/tests/tilt-engine/fixtures/appointment-frontend-service.json +0 -11
  358. package/tests/tilt-engine/fixtures/identity-backend-service.json +0 -12
  359. package/tests/tilt-engine/fixtures/invalid-service.json +0 -4
  360. package/tests/tilt-engine/test_agents_md_generator.py +0 -341
  361. package/tests/tilt-engine/test_agents_md_integration.py +0 -378
  362. package/tests/tilt-engine/test_cache_operations.py +0 -181
  363. package/tests/tilt-engine/test_cache_persistence.py +0 -142
  364. package/tests/tilt-engine/test_code_executor.py +0 -152
  365. package/tests/tilt-engine/test_code_viewer.py +0 -127
  366. package/tests/tilt-engine/test_compose_port_anchors.py +0 -310
  367. package/tests/tilt-engine/test_config_inspector.py +0 -162
  368. package/tests/tilt-engine/test_daemon_focus_mode.py +0 -89
  369. package/tests/tilt-engine/test_daemon_polling.py +0 -122
  370. package/tests/tilt-engine/test_daemon_registration.py +0 -115
  371. package/tests/tilt-engine/test_daemon_validation.py +0 -107
  372. package/tests/tilt-engine/test_docker_generator_bugs.py +0 -493
  373. package/tests/tilt-engine/test_docker_prune.py +0 -119
  374. package/tests/tilt-engine/test_dockerignore_path_bug.py +0 -82
  375. package/tests/tilt-engine/test_file_browser.py +0 -193
  376. package/tests/tilt-engine/test_frontend_basepath_manifest.py +0 -27
  377. package/tests/tilt-engine/test_health_dependencies.py +0 -130
  378. package/tests/tilt-engine/test_health_endpoints.py +0 -118
  379. package/tests/tilt-engine/test_health_tilt_ui.py +0 -85
  380. package/tests/tilt-engine/test_runtime_container_footprint.py +0 -162
  381. package/tests/tilt-engine/test_sablier_defer_start.py +0 -237
  382. package/tests/tilt-engine/test_safety_aliases.py +0 -84
  383. package/tests/tilt-engine/test_snapshot_diff.py +0 -136
  384. package/tests/tilt-engine/test_snapshot_persistence.py +0 -163
  385. package/tests/tilt-engine/test_snapshot_scanning.py +0 -123
  386. package/tests/tilt-engine/test_standalone_project_boot.py +0 -61
  387. package/tests/tilt-engine/test_standalone_traefik.py +0 -160
  388. package/tests/tilt-engine/test_traefik_static_wake_route.py +0 -187
@@ -1,926 +0,0 @@
1
- import { execSync } from "node:child_process";
2
- import { existsSync, readFileSync } from "node:fs";
3
- import { dirname, join, normalize } from "node:path";
4
- import chalk from "chalk";
5
- import { Command } from "commander";
6
- import type { CheckResult } from "../types/index.js";
7
- import {
8
- MASTER_CONFIG_FILES,
9
- QUICKSTART_DOCS_URL,
10
- REQUIRED_PACKAGE_SCRIPTS,
11
- } from "../utils/constants.js";
12
- import {
13
- checkIngressPorts,
14
- checkPrivateNpmRegistry,
15
- checkTiltResourceHealth,
16
- } from "../utils/doctor-runtime.js";
17
- import { validateEnvFile } from "../utils/env-validator.js";
18
- import { formatCount } from "../utils/formatting.js";
19
- import { findProjectRoot } from "../utils/paths.js";
20
- import { buildHealthTargets, pingHealthTargets } from "../utils/service-urls.js";
21
- import { discoverResourcesFromRoot } from "../utils/services.js";
22
-
23
- export {
24
- checkIngressPorts,
25
- checkPrivateNpmRegistry,
26
- checkTiltResourceHealth,
27
- summarizeTiltBuildError,
28
- } from "../utils/doctor-runtime.js";
29
-
30
- // A wedged Docker daemon makes `docker ps` block forever instead of failing,
31
- // and doctor is exactly the tool people run when their environment is broken.
32
- const EXEC_TIMEOUT_MS = 10_000;
33
-
34
- function isTimeout(err: unknown): boolean {
35
- return (err as NodeJS.ErrnoException | undefined)?.code === "ETIMEDOUT";
36
- }
37
-
38
- function createExecCheck(
39
- name: string,
40
- command: string,
41
- successMessage: string,
42
- failureMessage: string,
43
- fixInstructions: string,
44
- ): () => CheckResult {
45
- return () => {
46
- try {
47
- execSync(command, { stdio: "pipe", timeout: EXEC_TIMEOUT_MS });
48
- return {
49
- name,
50
- didPass: true,
51
- message: successMessage,
52
- };
53
- } catch {
54
- // Error details not needed - failure message tells user what to fix
55
- return {
56
- name,
57
- didPass: false,
58
- message: failureMessage,
59
- fix: fixInstructions,
60
- };
61
- }
62
- };
63
- }
64
-
65
- function checkDockerRuntime(): CheckResult {
66
- // Check for Docker
67
- try {
68
- execSync("docker ps", { stdio: "pipe", timeout: EXEC_TIMEOUT_MS });
69
- return {
70
- name: "Container Runtime",
71
- didPass: true,
72
- message: "Docker daemon is running",
73
- };
74
- } catch (err) {
75
- if (isTimeout(err)) {
76
- return {
77
- name: "Container Runtime",
78
- didPass: false,
79
- message: `Docker daemon is not responding (\`docker ps\` hung for ${EXEC_TIMEOUT_MS / 1000}s)`,
80
- fix: "Restart the runtime: quit and reopen Docker Desktop, or run `colima restart`",
81
- };
82
- }
83
- // Docker not running, check for Colima
84
- try {
85
- execSync("colima status", { stdio: "pipe", timeout: EXEC_TIMEOUT_MS });
86
- // Colima is running
87
- return {
88
- name: "Container Runtime",
89
- didPass: true,
90
- message: "Colima (Docker runtime) is running",
91
- };
92
- } catch {
93
- // Check if Colima is installed but not running
94
- try {
95
- execSync("which colima", { stdio: "pipe", timeout: EXEC_TIMEOUT_MS });
96
- return {
97
- name: "Container Runtime",
98
- didPass: false,
99
- message: "Colima is installed but not running",
100
- fix: "Start Colima: colima start",
101
- };
102
- } catch {
103
- // Check for Podman
104
- try {
105
- execSync("podman ps", { stdio: "pipe", timeout: EXEC_TIMEOUT_MS });
106
- return {
107
- name: "Container Runtime",
108
- didPass: true,
109
- message: "Podman is running",
110
- };
111
- } catch {
112
- // No container runtime found
113
- return {
114
- name: "Container Runtime",
115
- didPass: false,
116
- message: "No container runtime (Docker/Colima/Podman) is running",
117
- fix: `Start: colima start (recommended) OR open -a Docker (macOS) OR sudo systemctl start docker (Linux). Setup guide: ${QUICKSTART_DOCS_URL}`,
118
- };
119
- }
120
- }
121
- }
122
- }
123
- }
124
-
125
- const checkDockerCompose = createExecCheck(
126
- "Docker Compose",
127
- "docker compose version",
128
- "Docker Compose plugin available",
129
- "Docker Compose plugin not found",
130
- "Install Docker Compose: https://docs.docker.com/compose/install/",
131
- );
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
-
208
- const checkTilt = createExecCheck(
209
- "Tilt CLI",
210
- "tilt version",
211
- "Tilt CLI installed",
212
- "Tilt CLI not found",
213
- `Install Tilt: brew install tilt (macOS) or see https://docs.tilt.dev/install.html. Setup guide: ${QUICKSTART_DOCS_URL}`,
214
- );
215
-
216
- function checkEnvironmentVariables(): CheckResult {
217
- const projectRoot = findProjectRoot() ?? process.cwd();
218
- const validation = validateEnvFile(projectRoot);
219
-
220
- if (validation.missing.length > 0) {
221
- return {
222
- name: "Environment Variables",
223
- didPass: false,
224
- message: `Missing required env variables: ${validation.missing.join(", ")}`,
225
- fix: `Edit .env and set these values:\n ${validation.missing.map((v) => `${v}=<value>`).join("\n ")}`,
226
- };
227
- }
228
-
229
- if (validation.invalid.length > 0) {
230
- return {
231
- name: "Environment Variables",
232
- didPass: false,
233
- message: `Invalid env variables: ${validation.invalid.join(", ")}`,
234
- fix: "Edit .env and provide values for empty variables",
235
- };
236
- }
237
-
238
- return {
239
- name: "Environment Variables",
240
- didPass: true,
241
- message: "All required environment variables are set",
242
- };
243
- }
244
-
245
- function checkMasterConfigs(): CheckResult {
246
- // `tdk project` writes generated master configs to .tdk/.tdk-out/, not the
247
- // project root, so look there (and walk up to find the project root, same
248
- // as every other command that reads project state).
249
- const projectRoot = findProjectRoot() ?? process.cwd();
250
- const outDir = join(projectRoot, ".tdk", ".tdk-out");
251
-
252
- const missing = MASTER_CONFIG_FILES.filter((file) => !existsSync(join(outDir, file)));
253
-
254
- if (missing.length === 0) {
255
- return {
256
- name: "Master Configs",
257
- didPass: true,
258
- message: `${MASTER_CONFIG_FILES.join(", ")} found`,
259
- };
260
- }
261
-
262
- return {
263
- name: "Master Configs",
264
- didPass: false,
265
- message: `Master configs missing: ${missing.join(", ")}`,
266
- fix: "Run: tdk project",
267
- };
268
- }
269
-
270
- const REQUIRED_DOCKER_TEMPLATE_FILES = [
271
- "install-deps.sh",
272
- "bun-hoisted-symlink-fix.sh",
273
- "prisma-bun-client-link-fix.sh",
274
- "prisma-normalize-client.sh",
275
- "prisma-runtime-relink.sh",
276
- "infisical-entrypoint.sh",
277
- "migrate.sh",
278
- ] as const;
279
-
280
- export function checkGeneratedProjectRuntimeAssets(): CheckResult {
281
- const projectRoot = findProjectRoot() ?? process.cwd();
282
- const problems: string[] = [];
283
-
284
- if (!existsSync(join(projectRoot, "package.json"))) {
285
- problems.push("package.json (workspace root manifest)");
286
- }
287
-
288
- const templateDir = join(projectRoot, "shared-platform-engineering", "docker-templates");
289
- for (const file of REQUIRED_DOCKER_TEMPLATE_FILES) {
290
- if (!existsSync(join(templateDir, file))) {
291
- problems.push(`shared-platform-engineering/docker-templates/${file}`);
292
- }
293
- }
294
-
295
- if (problems.length === 0) {
296
- return {
297
- name: "Generated Runtime Assets",
298
- didPass: true,
299
- message: "Generated Docker runtime assets are present",
300
- };
301
- }
302
-
303
- return {
304
- name: "Generated Runtime Assets",
305
- didPass: false,
306
- message: `Generated Dockerfiles reference missing project runtime assets:\n ${problems.join("\n ")}`,
307
- fix: "Run `tdk project --yes` (or `tdk config regenerate`) with an updated TDK. `tdk up` also refreshes these assets before starting Tilt.",
308
- };
309
- }
310
-
311
- function findPrivateStarlarkLoadExports(content: string): string[] {
312
- const privateExports = new Set<string>();
313
- const loadCallPattern = /^load\s*\(([\s\S]*?)\)/gm;
314
-
315
- for (const loadMatch of content.matchAll(loadCallPattern)) {
316
- const args = loadMatch[1] ?? "";
317
- const quotedValuePattern = /["']([^"']+)["']/g;
318
- const quotedValues = Array.from(args.matchAll(quotedValuePattern), (match) => match[1]);
319
-
320
- // First quoted arg is the module path. Later quoted args are exported names
321
- // or alias targets, and Starlark refuses to export names beginning with "_".
322
- for (const value of quotedValues.slice(1)) {
323
- if (value.startsWith("_")) {
324
- privateExports.add(value);
325
- }
326
- }
327
- }
328
-
329
- return Array.from(privateExports).sort();
330
- }
331
-
332
- function resolveStarlarkLoadTarget(
333
- file: string,
334
- modulePath: string,
335
- projectRoot: string,
336
- ): string | null {
337
- if (modulePath === "ext://tdk-cli") {
338
- return join(projectRoot, ".tdk", ".tdk-out", "tdk-cli-ext", "Tiltfile");
339
- }
340
-
341
- if (modulePath.startsWith(".") || (!modulePath.includes("://") && !modulePath.startsWith("@"))) {
342
- return normalize(join(dirname(file), modulePath));
343
- }
344
-
345
- return null;
346
- }
347
-
348
- function findMissingRelativeStarlarkLoads(
349
- file: string,
350
- content: string,
351
- projectRoot: string,
352
- ): string[] {
353
- const missing: string[] = [];
354
- const loadCallPattern = /^load\s*\(([\s\S]*?)\)/gm;
355
-
356
- for (const loadMatch of content.matchAll(loadCallPattern)) {
357
- const args = loadMatch[1] ?? "";
358
- const moduleMatch = args.match(/["']([^"']+)["']/);
359
- const modulePath = moduleMatch?.[1];
360
-
361
- if (!modulePath) {
362
- continue;
363
- }
364
-
365
- const resolved = resolveStarlarkLoadTarget(file, modulePath, projectRoot);
366
- if (!resolved) {
367
- continue;
368
- }
369
-
370
- if (!existsSync(resolved)) {
371
- missing.push(`${file}: ${modulePath} -> ${resolved}`);
372
- }
373
- }
374
-
375
- return missing;
376
- }
377
-
378
- function findRelativeStarlarkLoadTargets(
379
- file: string,
380
- content: string,
381
- projectRoot: string,
382
- ): string[] {
383
- const targets: string[] = [];
384
- const loadCallPattern = /^load\s*\(([\s\S]*?)\)/gm;
385
-
386
- for (const loadMatch of content.matchAll(loadCallPattern)) {
387
- const args = loadMatch[1] ?? "";
388
- const moduleMatch = args.match(/["']([^"']+)["']/);
389
- const modulePath = moduleMatch?.[1];
390
-
391
- if (modulePath) {
392
- const target = resolveStarlarkLoadTarget(file, modulePath, projectRoot);
393
- if (target) {
394
- targets.push(target);
395
- }
396
- }
397
- }
398
-
399
- return targets;
400
- }
401
-
402
- function collectReachableStarlarkFiles(entryFile: string, projectRoot: string): string[] {
403
- const visited = new Set<string>();
404
- const pending = [entryFile];
405
-
406
- while (pending.length > 0) {
407
- const file = pending.pop();
408
- if (!file || visited.has(file) || !existsSync(file)) {
409
- continue;
410
- }
411
-
412
- visited.add(file);
413
- const content = readFileSync(file, "utf-8");
414
- for (const target of findRelativeStarlarkLoadTargets(file, content, projectRoot)) {
415
- if (!visited.has(target)) {
416
- pending.push(target);
417
- }
418
- }
419
- }
420
-
421
- return Array.from(visited).sort();
422
- }
423
-
424
- export function checkStarlarkLoadExports(): CheckResult {
425
- const projectRoot = findProjectRoot() ?? process.cwd();
426
- const entryFile = join(projectRoot, ".tdk", ".tdk-out", "Tiltfile");
427
-
428
- if (!existsSync(entryFile)) {
429
- return {
430
- name: "Starlark Load Exports",
431
- didPass: true,
432
- isSkipped: true,
433
- message: "No generated Tiltfile to check",
434
- };
435
- }
436
-
437
- const privateExportProblems: string[] = [];
438
- const missingLoadProblems: string[] = [];
439
- const reachableFiles = collectReachableStarlarkFiles(entryFile, projectRoot);
440
-
441
- for (const file of reachableFiles) {
442
- const content = readFileSync(file, "utf-8");
443
- const privateExports = findPrivateStarlarkLoadExports(content);
444
- if (privateExports.length > 0) {
445
- privateExportProblems.push(`${file}: ${privateExports.join(", ")}`);
446
- }
447
-
448
- for (const missingLoad of findMissingRelativeStarlarkLoads(file, content, projectRoot)) {
449
- missingLoadProblems.push(missingLoad);
450
- }
451
- }
452
-
453
- if (privateExportProblems.length === 0 && missingLoadProblems.length === 0) {
454
- const fileCount = formatCount(reachableFiles.length, "reachable Starlark file");
455
- return {
456
- name: "Starlark Load Exports",
457
- didPass: true,
458
- message: `${fileCount} ${reachableFiles.length === 1 ? "has" : "have"} valid load exports and paths`,
459
- };
460
- }
461
-
462
- const sections: string[] = [];
463
- if (privateExportProblems.length > 0) {
464
- sections.push(`Private exported symbols:\n ${privateExportProblems.join("\n ")}`);
465
- }
466
- if (missingLoadProblems.length > 0) {
467
- sections.push(`Missing relative load targets:\n ${missingLoadProblems.join("\n ")}`);
468
- }
469
-
470
- return {
471
- name: "Starlark Load Exports",
472
- didPass: false,
473
- message: `Starlark load() issues will stop Tilt before services start:\n ${sections.join("\n\n ")}`,
474
- fix: "Regenerate with a current TDK (`tdk config regenerate`). If the issue remains, rename loaded symbols without leading underscores and update stale load paths.",
475
- };
476
- }
477
-
478
- function checkStartupScripts(): CheckResult {
479
- const projectRoot = findProjectRoot() ?? process.cwd();
480
- const resources = discoverResourcesFromRoot(projectRoot);
481
-
482
- const problems: string[] = [];
483
-
484
- for (const resource of resources) {
485
- const packageJsonPath = join(resource.path, "package.json");
486
- if (!existsSync(packageJsonPath)) {
487
- continue;
488
- }
489
-
490
- const appType = resource.config?.appType ?? "backend";
491
- const requiredScripts = REQUIRED_PACKAGE_SCRIPTS[appType] ?? REQUIRED_PACKAGE_SCRIPTS.backend;
492
-
493
- let scripts: Record<string, string>;
494
- try {
495
- scripts = JSON.parse(readFileSync(packageJsonPath, "utf-8")).scripts ?? {};
496
- } catch {
497
- problems.push(`${resource.name} (package.json is invalid JSON)`);
498
- continue;
499
- }
500
-
501
- const missing = requiredScripts.filter((script) => !scripts[script]);
502
- if (missing.length > 0) {
503
- problems.push(`${resource.name}: missing "${missing.join('", "')}"`);
504
- }
505
- }
506
-
507
- if (problems.length === 0) {
508
- return {
509
- name: "Startup Scripts",
510
- didPass: true,
511
- message: "All services have required package.json scripts",
512
- };
513
- }
514
-
515
- return {
516
- name: "Startup Scripts",
517
- didPass: false,
518
- message: `Services missing required package.json scripts:\n ${problems.join("\n ")}`,
519
- fix: 'Add the missing scripts to each service\'s package.json, e.g.:\n "dev": "bun run src/index.ts",\n "build": "tsc",\n "start": "bun run dist/index.js"',
520
- };
521
- }
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
-
579
- function readJsonFile(path: string): Record<string, unknown> | null {
580
- try {
581
- return JSON.parse(readFileSync(path, "utf-8")) as Record<string, unknown>;
582
- } catch {
583
- return null;
584
- }
585
- }
586
-
587
- function hasSyntheticDefaultImports(tsconfigPath: string): boolean {
588
- const config = readJsonFile(tsconfigPath);
589
- const compilerOptions = config?.compilerOptions as Record<string, unknown> | undefined;
590
- return (
591
- compilerOptions?.allowSyntheticDefaultImports === true ||
592
- compilerOptions?.esModuleInterop === true
593
- );
594
- }
595
-
596
- export function checkFrontendDockerPreflight(): CheckResult {
597
- const projectRoot = findProjectRoot() ?? process.cwd();
598
- const resources = discoverResourcesFromRoot(projectRoot).filter(
599
- (resource) => resource.config?.appType === "frontend",
600
- );
601
-
602
- if (resources.length === 0) {
603
- return {
604
- name: "Frontend Docker Preflight",
605
- didPass: true,
606
- isSkipped: true,
607
- message: "No frontend services to check",
608
- };
609
- }
610
-
611
- const problems: string[] = [];
612
-
613
- for (const resource of resources) {
614
- const dockerfilePath = join(resource.path, ".autogenerated", "Dockerfile.app.autogenerated");
615
- const dockerTsconfigPath = join(
616
- resource.path,
617
- ".autogenerated",
618
- "tsconfig.docker.autogenerated.json",
619
- );
620
-
621
- if (existsSync(dockerfilePath)) {
622
- const dockerfile = readFileSync(dockerfilePath, "utf-8");
623
- const exposesNginxPort = /\bEXPOSE\s+80\b/.test(dockerfile);
624
- const stack = resource.config?.stack;
625
- const composePath = stack
626
- ? join(
627
- projectRoot,
628
- "services",
629
- stack,
630
- ".autogenerated",
631
- "docker-compose.app.autogenerated.yml",
632
- )
633
- : "";
634
-
635
- if (exposesNginxPort && composePath && existsSync(composePath)) {
636
- const compose = readFileSync(composePath, "utf-8");
637
- const escapedName = resource.name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
638
- const portPattern = new RegExp(
639
- `traefik\\.http\\.services\\.${escapedName}\\.loadbalancer\\.server\\.port=(\\d+)`,
640
- );
641
- const match = compose.match(portPattern);
642
- const routedPort = match?.[1];
643
-
644
- if (routedPort && routedPort !== "80") {
645
- problems.push(
646
- `${resource.name}: nginx runtime exposes 80, but generated Traefik routes to ${routedPort}`,
647
- );
648
- }
649
- }
650
- }
651
-
652
- if (existsSync(dockerTsconfigPath) && !hasSyntheticDefaultImports(dockerTsconfigPath)) {
653
- const mainPath = join(resource.path, "src", "main.tsx");
654
- if (existsSync(mainPath)) {
655
- const main = readFileSync(mainPath, "utf-8");
656
- const defaultImports = [
657
- /import\s+\w+\s+from\s+["']react["']/,
658
- /import\s+\w+\s+from\s+["']react-dom\/client["']/,
659
- ]
660
- .filter((pattern) => pattern.test(main))
661
- .map((pattern) => (pattern.source.includes("react-dom") ? "react-dom/client" : "react"));
662
-
663
- if (defaultImports.length > 0) {
664
- problems.push(
665
- `${resource.name}: Docker tsconfig does not allow synthetic default imports, but src/main.tsx default-imports ${defaultImports.join(" and ")}`,
666
- );
667
- }
668
- }
669
- }
670
- }
671
-
672
- if (problems.length === 0) {
673
- const frontendCount = formatCount(resources.length, "frontend");
674
- return {
675
- name: "Frontend Docker Preflight",
676
- didPass: true,
677
- message: `${frontendCount} ${resources.length === 1 ? "has" : "have"} compatible Docker build/routing metadata`,
678
- };
679
- }
680
-
681
- return {
682
- name: "Frontend Docker Preflight",
683
- didPass: false,
684
- message: `Frontend Docker metadata has issues that will make \`tdk up\` fail or route 404:\n ${problems.join("\n ")}`,
685
- fix: 'Regenerate with a current TDK (`tdk config regenerate`) and ensure frontend nginx runtimes route to port 80. For React entrypoints, prefer named imports: `import { StrictMode } from "react"` and `import { createRoot } from "react-dom/client"`.',
686
- };
687
- }
688
-
689
- const MEM_NEAR_LIMIT_PCT = 90;
690
- const CPU_HANGING_PCT = 80;
691
-
692
- interface ContainerStat {
693
- name: string;
694
- memPct: number;
695
- cpuPct: number;
696
- }
697
-
698
- function parseDockerStats(raw: string): ContainerStat[] {
699
- return raw
700
- .split("\n")
701
- .map((line) => line.trim())
702
- .filter(Boolean)
703
- .map((line) => {
704
- const [name, memPctRaw, cpuPctRaw] = line.split(",");
705
- return {
706
- name: name ?? "unknown",
707
- memPct: Number.parseFloat((memPctRaw ?? "").replace("%", "")),
708
- cpuPct: Number.parseFloat((cpuPctRaw ?? "").replace("%", "")),
709
- };
710
- })
711
- .filter((stat) => Number.isFinite(stat.memPct) && Number.isFinite(stat.cpuPct));
712
- }
713
-
714
- /**
715
- * Flags containers pinned near their memory limit while also burning CPU --
716
- * the signature of a boot-time process stuck in a retry/fetch loop, not a
717
- * genuine crash (which would just exit, not sit at ~100% resource usage).
718
- *
719
- * Caught in this workspace: a backend runtime image missing the local Prisma
720
- * CLI fell back to `bunx prisma`, which re-fetched prisma@latest from npm on
721
- * every container start. That pinned a 512MB container at ~100% memory and
722
- * 100%+ CPU indefinitely, and it never became healthy. Neither `docker ps`
723
- * (just shows "unhealthy") nor the healthcheck's own retry loop surfaces
724
- * *why* -- only live resource stats catch this pattern before it's mistaken
725
- * for a slow migration or a flaky healthcheck.
726
- */
727
- function checkContainerResourceHealth(): CheckResult {
728
- let raw: string;
729
- try {
730
- raw = execSync('docker stats --no-stream --format "{{.Name}},{{.MemPerc}},{{.CPUPerc}}"', {
731
- stdio: "pipe",
732
- encoding: "utf-8",
733
- timeout: EXEC_TIMEOUT_MS,
734
- });
735
- } catch (err) {
736
- return {
737
- name: "Container Resource Health",
738
- didPass: true,
739
- isSkipped: true,
740
- message: isTimeout(err)
741
- ? "Docker not responding - skipped container resource check"
742
- : "Docker not running - skipped container resource check",
743
- };
744
- }
745
-
746
- const stats = parseDockerStats(raw);
747
- if (stats.length === 0) {
748
- return {
749
- name: "Container Resource Health",
750
- didPass: true,
751
- isSkipped: true,
752
- message: "No running containers to check",
753
- };
754
- }
755
-
756
- const hangers = stats.filter(
757
- (stat) => stat.memPct >= MEM_NEAR_LIMIT_PCT && stat.cpuPct >= CPU_HANGING_PCT,
758
- );
759
-
760
- if (hangers.length === 0) {
761
- return {
762
- name: "Container Resource Health",
763
- didPass: true,
764
- message: `${formatCount(stats.length, "container")} within normal resource usage`,
765
- };
766
- }
767
-
768
- const details = hangers
769
- .map((stat) => `${stat.name} (mem ${stat.memPct.toFixed(0)}%, cpu ${stat.cpuPct.toFixed(0)}%)`)
770
- .join("\n ");
771
-
772
- return {
773
- name: "Container Resource Health",
774
- didPass: false,
775
- message: `${formatCount(hangers.length, "container")} pinned near its memory limit while burning CPU -- likely stuck in a boot-time retry/fetch loop, not a normal crash:\n ${details}`,
776
- fix: "Check the container's boot logs for a network fetch loop (e.g. `bunx <pkg>` re-downloading a CLI on every start instead of using one already installed): docker logs <container>. If a Prisma auto-migration is the cause, set AUTO_MIGRATE=false in the project's .env as a temporary unblock.",
777
- };
778
- }
779
-
780
- const DEFAULT_PING_TIMEOUT_MS = 5000;
781
-
782
- /**
783
- * Pings every routable service on the same /health URLs `tdk up` advertises.
784
- *
785
- * This is a runtime check, not an environment one: before `tdk up` there is
786
- * nothing to ping, so a stopped stack is reported as skipped and doctor still
787
- * passes. Once services are up, an unreachable endpoint is a real failure --
788
- * it catches the case where a container is running but Traefik never routed
789
- * to it, which `docker ps` alone will not show.
790
- */
791
- async function checkServiceHealth(timeoutMs: number): Promise<CheckResult> {
792
- const projectRoot = findProjectRoot() ?? process.cwd();
793
- const targets = buildHealthTargets(discoverResourcesFromRoot(projectRoot));
794
-
795
- if (targets.length === 0) {
796
- return {
797
- name: "Service Health",
798
- didPass: true,
799
- isSkipped: true,
800
- message: "No routable services to ping",
801
- };
802
- }
803
-
804
- const probes = await pingHealthTargets(targets, timeoutMs);
805
- const reachable = probes.filter((probe) => probe.ok);
806
- const failed = probes.filter((probe) => !probe.ok);
807
-
808
- // Nothing answered at all: either the stack was never started, or ingress
809
- // never came up (Traefik port conflict). Prefer failing via
810
- // checkTiltResourceHealth / checkIngressPorts when Tilt is up; here we only
811
- // skip when there is truly nothing to probe yet.
812
- if (reachable.length === 0) {
813
- return {
814
- name: "Service Health",
815
- didPass: true,
816
- isSkipped: true,
817
- message: `No services responded - skipped ping of ${formatCount(targets.length, "service")} (stack may be down, or Traefik never bound :80)`,
818
- fix: "If `tdk up` is already running, check Traefik/port 80 in the Tilt UI. Otherwise start with: tdk up",
819
- };
820
- }
821
-
822
- if (failed.length === 0) {
823
- return {
824
- name: "Service Health",
825
- didPass: true,
826
- message: `All ${formatCount(targets.length, "service")} responding on /health`,
827
- };
828
- }
829
-
830
- const details = failed
831
- .map((probe) => {
832
- const reason = probe.status ? `HTTP ${probe.status}` : (probe.error ?? "no response");
833
- return `${probe.name} (${reason})\n ${probe.url}`;
834
- })
835
- .join("\n ");
836
-
837
- return {
838
- name: "Service Health",
839
- didPass: false,
840
- message: `${formatCount(failed.length, "service")} not responding (${reachable.length}/${probes.length} healthy):\n ${details}`,
841
- fix: "Check container state and routing: docker ps, then tdk networks to compare the advertised URLs against Traefik's routers",
842
- };
843
- }
844
-
845
- export const doctorCommand = new Command("doctor")
846
- .description("Check environment readiness for TDK")
847
- .option("--no-ping", "Skip pinging running services' /health endpoints")
848
- .option(
849
- "--ping-timeout <ms>",
850
- "Per-service ping timeout in milliseconds",
851
- String(DEFAULT_PING_TIMEOUT_MS),
852
- )
853
- .action(async (options) => {
854
- console.log(`\n${chalk.bold("🔍 TDK Doctor")}\n`);
855
- console.log("Checking environment...\n");
856
-
857
- const pingTimeout = Number.parseInt(options.pingTimeout, 10);
858
- if (!Number.isFinite(pingTimeout) || pingTimeout <= 0) {
859
- console.log(`${chalk.red("✗")} --ping-timeout must be a positive number of milliseconds`);
860
- process.exit(1);
861
- }
862
-
863
- const checks: Array<() => CheckResult | Promise<CheckResult>> = [
864
- checkDockerRuntime,
865
- checkTilt,
866
- checkDockerCompose,
867
- checkDockerVersions,
868
- checkMasterConfigs,
869
- checkGeneratedProjectRuntimeAssets,
870
- checkStarlarkLoadExports,
871
- checkStartupScripts,
872
- checkTypeScriptTypeDependencies,
873
- checkFrontendDockerPreflight,
874
- checkEnvironmentVariables,
875
- // Preflight: catch "port 80 already allocated" BEFORE claiming ready.
876
- checkIngressPorts,
877
- // Preflight: Verdaccio down causes ImageBuild bun install ConnectionRefused.
878
- checkPrivateNpmRegistry,
879
- // Runtime checks: skip gracefully if the stack isn't started yet.
880
- checkContainerResourceHealth,
881
- // When Tilt is up, surface red resources (Traefik/apps never started).
882
- checkTiltResourceHealth,
883
- ];
884
-
885
- // Runs last: needs routable services (and working Traefik) to mean anything.
886
- if (options.ping) {
887
- checks.push(() => checkServiceHealth(pingTimeout));
888
- }
889
-
890
- let allPassed = true;
891
-
892
- for (const checkFn of checks) {
893
- const result = await checkFn();
894
-
895
- if (result.isSkipped) {
896
- console.log(`${chalk.gray("○")} ${chalk.gray(result.message)}`);
897
- if (result.fix) {
898
- console.log(`${chalk.blue("ℹ")} ${result.fix}`);
899
- }
900
- } else if (result.didPass) {
901
- console.log(`${chalk.green("✓")} ${result.message}`);
902
- } else {
903
- console.log(`${chalk.red("✗")} ${result.message}`);
904
- if (result.fix) {
905
- console.log(`${chalk.blue("ℹ")} Fix: ${result.fix}`);
906
- }
907
- allPassed = false;
908
- break;
909
- }
910
- }
911
-
912
- console.log("");
913
-
914
- if (allPassed) {
915
- console.log(`${chalk.green(chalk.bold("✓"))} Environment ready for TDK`);
916
- console.log("");
917
- console.log("Next steps:");
918
- console.log(" 1. Run: tdk up");
919
- console.log(" 2. Open: http://localhost:10350");
920
- } else {
921
- console.log(`${chalk.red(chalk.bold("✗"))} Environment not ready`);
922
- console.log("");
923
- console.log("Fix the issues above, then run: tdk doctor");
924
- process.exit(1);
925
- }
926
- });