@tdk-landscape/tdk-cli-core 1.3.52 → 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 (390) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +1 -1
  3. package/cli/dist/commands/config.js +1 -1
  4. package/cli/dist/commands/resource.js +1 -1
  5. package/cli/dist/generator/extension-fetch.js +16 -9
  6. package/cli/package.json +1 -1
  7. package/package.json +16 -1
  8. package/.claude/skills/layer-autoresearch/SKILL.md +0 -48
  9. package/.claude/skills/tdk-troubleshoot/SKILL.md +0 -222
  10. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -40
  11. package/.github/ISSUE_TEMPLATE/config.yml +0 -8
  12. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -18
  13. package/.github/dependabot.yml +0 -33
  14. package/.github/pull_request_template.md +0 -5
  15. package/.github/workflows/ci.yml +0 -200
  16. package/.github/workflows/release-binaries.yml +0 -139
  17. package/.github/zizmor.yml +0 -9
  18. package/.pre-commit-config.yaml +0 -57
  19. package/CODE_OF_CONDUCT.md +0 -9
  20. package/CONTRIBUTING.md +0 -42
  21. package/Makefile +0 -92
  22. package/SECURITY.md +0 -17
  23. package/benchmarks/results/container-scale-2026-09-25T20-54-49-736Z.json +0 -45
  24. package/benchmarks/results/container-scale-2026-09-25T21-01-20-540Z.json +0 -150
  25. package/benchmarks/results/container-scale-2026-09-25T21-15-01-441Z.json +0 -73
  26. package/benchmarks/results/container-scale-2026-09-25T22-09-01-630Z.json +0 -77
  27. package/benchmarks/results/container-scale-2026-09-25T22-18-28-371Z.json +0 -202
  28. package/cli/AGENTS.md +0 -390
  29. package/cli/DESIGN.md +0 -735
  30. package/cli/README.md +0 -292
  31. package/cli/biome.json +0 -40
  32. package/cli/dependency-graph.svg +0 -1135
  33. package/cli/dist/cli.d.ts +0 -3
  34. package/cli/dist/cli.d.ts.map +0 -1
  35. package/cli/dist/cli.js.map +0 -1
  36. package/cli/dist/commands/completion.d.ts +0 -3
  37. package/cli/dist/commands/completion.d.ts.map +0 -1
  38. package/cli/dist/commands/completion.js.map +0 -1
  39. package/cli/dist/commands/config.d.ts +0 -3
  40. package/cli/dist/commands/config.d.ts.map +0 -1
  41. package/cli/dist/commands/config.js.map +0 -1
  42. package/cli/dist/commands/doctor.d.ts +0 -19
  43. package/cli/dist/commands/doctor.d.ts.map +0 -1
  44. package/cli/dist/commands/doctor.js.map +0 -1
  45. package/cli/dist/commands/down.d.ts +0 -3
  46. package/cli/dist/commands/down.d.ts.map +0 -1
  47. package/cli/dist/commands/down.js.map +0 -1
  48. package/cli/dist/commands/help.d.ts +0 -2
  49. package/cli/dist/commands/help.d.ts.map +0 -1
  50. package/cli/dist/commands/help.js.map +0 -1
  51. package/cli/dist/commands/networks.d.ts +0 -3
  52. package/cli/dist/commands/networks.d.ts.map +0 -1
  53. package/cli/dist/commands/networks.js.map +0 -1
  54. package/cli/dist/commands/project.d.ts +0 -9
  55. package/cli/dist/commands/project.d.ts.map +0 -1
  56. package/cli/dist/commands/project.js.map +0 -1
  57. package/cli/dist/commands/projects.d.ts +0 -3
  58. package/cli/dist/commands/projects.d.ts.map +0 -1
  59. package/cli/dist/commands/projects.js.map +0 -1
  60. package/cli/dist/commands/resource.d.ts +0 -69
  61. package/cli/dist/commands/resource.d.ts.map +0 -1
  62. package/cli/dist/commands/resource.js.map +0 -1
  63. package/cli/dist/commands/resources.d.ts +0 -3
  64. package/cli/dist/commands/resources.d.ts.map +0 -1
  65. package/cli/dist/commands/resources.js.map +0 -1
  66. package/cli/dist/commands/stack.d.ts +0 -3
  67. package/cli/dist/commands/stack.d.ts.map +0 -1
  68. package/cli/dist/commands/stack.js.map +0 -1
  69. package/cli/dist/commands/stacks.d.ts +0 -3
  70. package/cli/dist/commands/stacks.d.ts.map +0 -1
  71. package/cli/dist/commands/stacks.js.map +0 -1
  72. package/cli/dist/commands/status.d.ts +0 -3
  73. package/cli/dist/commands/status.d.ts.map +0 -1
  74. package/cli/dist/commands/status.js.map +0 -1
  75. package/cli/dist/commands/ui.d.ts +0 -3
  76. package/cli/dist/commands/ui.d.ts.map +0 -1
  77. package/cli/dist/commands/ui.js.map +0 -1
  78. package/cli/dist/commands/up.d.ts +0 -3
  79. package/cli/dist/commands/up.d.ts.map +0 -1
  80. package/cli/dist/commands/up.js.map +0 -1
  81. package/cli/dist/commands/upgrade.d.ts +0 -14
  82. package/cli/dist/commands/upgrade.d.ts.map +0 -1
  83. package/cli/dist/commands/upgrade.js.map +0 -1
  84. package/cli/dist/commands/version.d.ts +0 -3
  85. package/cli/dist/commands/version.d.ts.map +0 -1
  86. package/cli/dist/commands/version.js.map +0 -1
  87. package/cli/dist/components/Accessible.d.ts +0 -8
  88. package/cli/dist/components/Accessible.d.ts.map +0 -1
  89. package/cli/dist/components/Accessible.js.map +0 -1
  90. package/cli/dist/components/BaseTooltip.d.ts +0 -4
  91. package/cli/dist/components/BaseTooltip.d.ts.map +0 -1
  92. package/cli/dist/components/BaseTooltip.js.map +0 -1
  93. package/cli/dist/components/DetailPanel.d.ts +0 -4
  94. package/cli/dist/components/DetailPanel.d.ts.map +0 -1
  95. package/cli/dist/components/DetailPanel.js.map +0 -1
  96. package/cli/dist/components/FileTree.d.ts +0 -4
  97. package/cli/dist/components/FileTree.d.ts.map +0 -1
  98. package/cli/dist/components/FileTree.js.map +0 -1
  99. package/cli/dist/components/ResourceSelectInput.d.ts +0 -4
  100. package/cli/dist/components/ResourceSelectInput.d.ts.map +0 -1
  101. package/cli/dist/components/ResourceSelectInput.js.map +0 -1
  102. package/cli/dist/components/ResourceTable.d.ts +0 -4
  103. package/cli/dist/components/ResourceTable.d.ts.map +0 -1
  104. package/cli/dist/components/ResourceTable.js.map +0 -1
  105. package/cli/dist/components/TabBar.d.ts +0 -4
  106. package/cli/dist/components/TabBar.d.ts.map +0 -1
  107. package/cli/dist/components/TabBar.js.map +0 -1
  108. package/cli/dist/components/Tooltip.d.ts +0 -12
  109. package/cli/dist/components/Tooltip.d.ts.map +0 -1
  110. package/cli/dist/components/Tooltip.js.map +0 -1
  111. package/cli/dist/components/index.d.ts +0 -8
  112. package/cli/dist/components/index.d.ts.map +0 -1
  113. package/cli/dist/components/index.js.map +0 -1
  114. package/cli/dist/config/platform-standards.d.ts +0 -159
  115. package/cli/dist/config/platform-standards.d.ts.map +0 -1
  116. package/cli/dist/config/platform-standards.js.map +0 -1
  117. package/cli/dist/generator/extension-fetch.d.ts +0 -25
  118. package/cli/dist/generator/extension-fetch.d.ts.map +0 -1
  119. package/cli/dist/generator/extension-fetch.js.map +0 -1
  120. package/cli/dist/generator/template-engine.d.ts +0 -62
  121. package/cli/dist/generator/template-engine.d.ts.map +0 -1
  122. package/cli/dist/generator/template-engine.js.map +0 -1
  123. package/cli/dist/index.d.ts +0 -11
  124. package/cli/dist/index.d.ts.map +0 -1
  125. package/cli/dist/index.js.map +0 -1
  126. package/cli/dist/types/index.d.ts +0 -257
  127. package/cli/dist/types/index.d.ts.map +0 -1
  128. package/cli/dist/types/index.js.map +0 -1
  129. package/cli/dist/utils/cache.d.ts +0 -19
  130. package/cli/dist/utils/cache.d.ts.map +0 -1
  131. package/cli/dist/utils/cache.js.map +0 -1
  132. package/cli/dist/utils/command-helpers.d.ts +0 -17
  133. package/cli/dist/utils/command-helpers.d.ts.map +0 -1
  134. package/cli/dist/utils/command-helpers.js.map +0 -1
  135. package/cli/dist/utils/constants.d.ts +0 -53
  136. package/cli/dist/utils/constants.d.ts.map +0 -1
  137. package/cli/dist/utils/constants.js.map +0 -1
  138. package/cli/dist/utils/discovery-context.d.ts +0 -4
  139. package/cli/dist/utils/discovery-context.d.ts.map +0 -1
  140. package/cli/dist/utils/discovery-context.js.map +0 -1
  141. package/cli/dist/utils/docker.d.ts +0 -4
  142. package/cli/dist/utils/docker.d.ts.map +0 -1
  143. package/cli/dist/utils/docker.js.map +0 -1
  144. package/cli/dist/utils/doctor-runtime.d.ts +0 -81
  145. package/cli/dist/utils/doctor-runtime.d.ts.map +0 -1
  146. package/cli/dist/utils/doctor-runtime.js.map +0 -1
  147. package/cli/dist/utils/env-validator.d.ts +0 -15
  148. package/cli/dist/utils/env-validator.d.ts.map +0 -1
  149. package/cli/dist/utils/env-validator.js.map +0 -1
  150. package/cli/dist/utils/errors.d.ts +0 -31
  151. package/cli/dist/utils/errors.d.ts.map +0 -1
  152. package/cli/dist/utils/errors.js.map +0 -1
  153. package/cli/dist/utils/file-helpers.d.ts +0 -14
  154. package/cli/dist/utils/file-helpers.d.ts.map +0 -1
  155. package/cli/dist/utils/file-helpers.js.map +0 -1
  156. package/cli/dist/utils/formatting.d.ts +0 -30
  157. package/cli/dist/utils/formatting.d.ts.map +0 -1
  158. package/cli/dist/utils/formatting.js.map +0 -1
  159. package/cli/dist/utils/paths.d.ts +0 -3
  160. package/cli/dist/utils/paths.d.ts.map +0 -1
  161. package/cli/dist/utils/paths.js.map +0 -1
  162. package/cli/dist/utils/port-assignment.d.ts +0 -6
  163. package/cli/dist/utils/port-assignment.d.ts.map +0 -1
  164. package/cli/dist/utils/port-assignment.js.map +0 -1
  165. package/cli/dist/utils/project-features.d.ts +0 -23
  166. package/cli/dist/utils/project-features.d.ts.map +0 -1
  167. package/cli/dist/utils/project-features.js.map +0 -1
  168. package/cli/dist/utils/project-templates.d.ts +0 -7
  169. package/cli/dist/utils/project-templates.d.ts.map +0 -1
  170. package/cli/dist/utils/project-templates.js.map +0 -1
  171. package/cli/dist/utils/prompt.d.ts +0 -28
  172. package/cli/dist/utils/prompt.d.ts.map +0 -1
  173. package/cli/dist/utils/prompt.js.map +0 -1
  174. package/cli/dist/utils/resource-features.d.ts +0 -29
  175. package/cli/dist/utils/resource-features.d.ts.map +0 -1
  176. package/cli/dist/utils/resource-features.js.map +0 -1
  177. package/cli/dist/utils/service-urls.d.ts +0 -30
  178. package/cli/dist/utils/service-urls.d.ts.map +0 -1
  179. package/cli/dist/utils/service-urls.js.map +0 -1
  180. package/cli/dist/utils/services.d.ts +0 -18
  181. package/cli/dist/utils/services.d.ts.map +0 -1
  182. package/cli/dist/utils/services.js.map +0 -1
  183. package/cli/dist/utils/stack-features.d.ts +0 -22
  184. package/cli/dist/utils/stack-features.d.ts.map +0 -1
  185. package/cli/dist/utils/stack-features.js.map +0 -1
  186. package/cli/dist/utils/tar.d.ts +0 -7
  187. package/cli/dist/utils/tar.d.ts.map +0 -1
  188. package/cli/dist/utils/tar.js.map +0 -1
  189. package/cli/dist/utils/tilt.d.ts +0 -20
  190. package/cli/dist/utils/tilt.d.ts.map +0 -1
  191. package/cli/dist/utils/tilt.js.map +0 -1
  192. package/cli/dist/utils/validation.d.ts +0 -16
  193. package/cli/dist/utils/validation.d.ts.map +0 -1
  194. package/cli/dist/utils/validation.js.map +0 -1
  195. package/cli/knip.json +0 -6
  196. package/cli/pnpm-lock.yaml +0 -2305
  197. package/cli/pnpm-workspace.yaml +0 -2
  198. package/cli/src/cli.ts +0 -72
  199. package/cli/src/commands/__tests__/always-enabled-infra.test.ts +0 -109
  200. package/cli/src/commands/__tests__/config.test.ts +0 -146
  201. package/cli/src/commands/__tests__/doctor.test.ts +0 -730
  202. package/cli/src/commands/__tests__/error-handling.test.ts +0 -78
  203. package/cli/src/commands/__tests__/phases-model.test.ts +0 -161
  204. package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +0 -187
  205. package/cli/src/commands/__tests__/project.test.ts +0 -68
  206. package/cli/src/commands/__tests__/resource.test.ts +0 -226
  207. package/cli/src/commands/__tests__/saas-starter-integration.test.ts +0 -194
  208. package/cli/src/commands/__tests__/stack-features-e2e.test.ts +0 -135
  209. package/cli/src/commands/__tests__/upgrade.test.ts +0 -198
  210. package/cli/src/commands/completion.ts +0 -300
  211. package/cli/src/commands/config.ts +0 -299
  212. package/cli/src/commands/doctor.ts +0 -926
  213. package/cli/src/commands/down.ts +0 -37
  214. package/cli/src/commands/help.ts +0 -143
  215. package/cli/src/commands/networks-design.md +0 -80
  216. package/cli/src/commands/networks.ts +0 -332
  217. package/cli/src/commands/project.ts +0 -456
  218. package/cli/src/commands/projects.ts +0 -82
  219. package/cli/src/commands/resource.ts +0 -652
  220. package/cli/src/commands/resources.ts +0 -95
  221. package/cli/src/commands/stack.ts +0 -128
  222. package/cli/src/commands/stacks.ts +0 -52
  223. package/cli/src/commands/status.ts +0 -88
  224. package/cli/src/commands/ui.tsx +0 -843
  225. package/cli/src/commands/up.ts +0 -169
  226. package/cli/src/commands/upgrade.ts +0 -628
  227. package/cli/src/commands/version.ts +0 -9
  228. package/cli/src/components/Accessible.tsx +0 -21
  229. package/cli/src/components/BaseTooltip.tsx +0 -66
  230. package/cli/src/components/DetailPanel.tsx +0 -146
  231. package/cli/src/components/FileTree.tsx +0 -89
  232. package/cli/src/components/ResourceSelectInput.tsx +0 -30
  233. package/cli/src/components/ResourceTable.tsx +0 -78
  234. package/cli/src/components/TabBar.tsx +0 -53
  235. package/cli/src/components/Tooltip.tsx +0 -11
  236. package/cli/src/components/index.ts +0 -7
  237. package/cli/src/config/platform-standards.test.ts +0 -11
  238. package/cli/src/config/platform-standards.ts +0 -196
  239. package/cli/src/generator/__tests__/extension-fetch.test.ts +0 -242
  240. package/cli/src/generator/__tests__/template-engine.test.ts +0 -70
  241. package/cli/src/generator/extension-fetch.ts +0 -286
  242. package/cli/src/generator/template-engine.ts +0 -752
  243. package/cli/src/index.ts +0 -86
  244. package/cli/src/templates.d.ts +0 -4
  245. package/cli/src/types/index.ts +0 -353
  246. package/cli/src/utils/__tests__/cache.test.ts +0 -98
  247. package/cli/src/utils/__tests__/formatting.test.ts +0 -170
  248. package/cli/src/utils/__tests__/paths.test.ts +0 -180
  249. package/cli/src/utils/__tests__/port-assignment.test.ts +0 -121
  250. package/cli/src/utils/__tests__/service-urls.test.ts +0 -174
  251. package/cli/src/utils/__tests__/services.test.ts +0 -531
  252. package/cli/src/utils/__tests__/tilt.test.ts +0 -172
  253. package/cli/src/utils/__tests__/validation.test.ts +0 -148
  254. package/cli/src/utils/cache.ts +0 -76
  255. package/cli/src/utils/command-helpers.ts +0 -54
  256. package/cli/src/utils/constants.ts +0 -130
  257. package/cli/src/utils/discovery-context.ts +0 -49
  258. package/cli/src/utils/docker.ts +0 -20
  259. package/cli/src/utils/doctor-runtime.ts +0 -644
  260. package/cli/src/utils/env-validator.ts +0 -139
  261. package/cli/src/utils/errors.ts +0 -168
  262. package/cli/src/utils/file-helpers.ts +0 -62
  263. package/cli/src/utils/formatting.ts +0 -215
  264. package/cli/src/utils/paths.ts +0 -53
  265. package/cli/src/utils/port-assignment.ts +0 -106
  266. package/cli/src/utils/project-features.ts +0 -118
  267. package/cli/src/utils/project-templates.ts +0 -29
  268. package/cli/src/utils/prompt.ts +0 -128
  269. package/cli/src/utils/resource-features.ts +0 -215
  270. package/cli/src/utils/service-urls.ts +0 -124
  271. package/cli/src/utils/services.ts +0 -364
  272. package/cli/src/utils/stack-features.ts +0 -30
  273. package/cli/src/utils/tar.ts +0 -24
  274. package/cli/src/utils/tilt.ts +0 -133
  275. package/cli/src/utils/validation.ts +0 -67
  276. package/cli/tsconfig.json +0 -25
  277. package/cli/tsconfig.typecheck.json +0 -8
  278. package/docs/FEATURES.md +0 -279
  279. package/docs/demo.svg +0 -217
  280. package/engine/docs/AUTODISCOVERY_TEST.md +0 -182
  281. package/engine/docs/C4-ARCHITECTURE-operations.md +0 -396
  282. package/engine/docs/C4-ARCHITECTURE-overview.md +0 -284
  283. package/engine/docs/C4-ARCHITECTURE.md +0 -17
  284. package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +0 -349
  285. package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +0 -357
  286. package/engine/docs/README.md +0 -284
  287. package/install.sh +0 -19
  288. package/knip.json +0 -10
  289. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/.openspec.yaml +0 -2
  290. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/design.md +0 -102
  291. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/proposal.md +0 -31
  292. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-notifications/spec.md +0 -48
  293. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-orchestration/spec.md +0 -63
  294. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-troubleshooting/spec.md +0 -56
  295. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/tasks.md +0 -61
  296. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/.openspec.yaml +0 -2
  297. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/design.md +0 -114
  298. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/proposal.md +0 -32
  299. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/manifest-field-migration/spec.md +0 -20
  300. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/resource-terminology-standard/spec.md +0 -20
  301. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/stack-terminology-standard/spec.md +0 -20
  302. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/tasks.md +0 -194
  303. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/.openspec.yaml +0 -2
  304. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/design.md +0 -111
  305. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/proposal.md +0 -33
  306. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/function-naming-alignment/spec.md +0 -12
  307. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/optional-parameter-patterns/spec.md +0 -18
  308. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-documentation/spec.md +0 -16
  309. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-naming-consistency/spec.md +0 -12
  310. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-ordering-standard/spec.md +0 -12
  311. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/tasks.md +0 -194
  312. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/.openspec.yaml +0 -2
  313. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/design.md +0 -84
  314. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/proposal.md +0 -31
  315. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/codebase-audit/spec.md +0 -27
  316. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/dead-code-cleanup/spec.md +0 -27
  317. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/test-gap-fill/spec.md +0 -23
  318. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/todo-resolution/spec.md +0 -27
  319. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/tasks.md +0 -39
  320. package/openspec/changes/archive/2026-06-25-landscape-consolidation/.openspec.yaml +0 -2
  321. package/openspec/changes/archive/2026-06-25-landscape-consolidation/design.md +0 -80
  322. package/openspec/changes/archive/2026-06-25-landscape-consolidation/proposal.md +0 -40
  323. package/openspec/changes/archive/2026-06-25-landscape-consolidation/spec.md +0 -52
  324. package/openspec/changes/archive/2026-06-25-landscape-consolidation/tasks.md +0 -51
  325. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/.openspec.yaml +0 -2
  326. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/design.md +0 -43
  327. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/proposal.md +0 -29
  328. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/specs/self-contained-generated-projects/spec.md +0 -67
  329. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/tasks.md +0 -27
  330. package/openspec/changes/optimize-runtime-docker-layers/.openspec.yaml +0 -3
  331. package/openspec/changes/optimize-runtime-docker-layers/design.md +0 -81
  332. package/openspec/changes/optimize-runtime-docker-layers/proposal.md +0 -44
  333. package/openspec/changes/optimize-runtime-docker-layers/specs/runtime-container-footprint/spec.md +0 -79
  334. package/openspec/changes/optimize-runtime-docker-layers/tasks.md +0 -36
  335. package/openspec/changes/prioritized-cold-start/.openspec.yaml +0 -4
  336. package/openspec/changes/prioritized-cold-start/design.md +0 -137
  337. package/openspec/changes/prioritized-cold-start/proposal.md +0 -41
  338. package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +0 -98
  339. package/openspec/changes/prioritized-cold-start/tasks.md +0 -69
  340. package/openspec/config.yaml +0 -1
  341. package/openspec/specs/manifest-field-migration/spec.md +0 -24
  342. package/openspec/specs/resource-terminology-standard/spec.md +0 -24
  343. package/openspec/specs/self-contained-generated-projects/spec.md +0 -67
  344. package/openspec/specs/stack-terminology-standard/spec.md +0 -24
  345. package/platform/services/platform/proxy/service.yaml +0 -14
  346. package/scripts/audit-codebase.sh +0 -213
  347. package/scripts/autoresearch/layer-eval.sh +0 -65
  348. package/scripts/benchmark/README.md +0 -25
  349. package/scripts/benchmark/container-scale.ts +0 -503
  350. package/scripts/benchmark/pre-release-gate.sh +0 -9
  351. package/scripts/install-git-hooks.sh +0 -14
  352. package/scripts/measure-idle-footprint.sh +0 -58
  353. package/scripts/record-demo.sh +0 -43
  354. package/scripts/release-binaries.sh +0 -97
  355. package/scripts/setup-pre-commit.sh +0 -33
  356. package/scripts/stage-npm-engine.sh +0 -36
  357. package/tests/tilt-engine/__init__.py +0 -5
  358. package/tests/tilt-engine/conftest.py +0 -182
  359. package/tests/tilt-engine/fixtures/appointment-frontend-service.json +0 -11
  360. package/tests/tilt-engine/fixtures/identity-backend-service.json +0 -12
  361. package/tests/tilt-engine/fixtures/invalid-service.json +0 -4
  362. package/tests/tilt-engine/test_agents_md_generator.py +0 -341
  363. package/tests/tilt-engine/test_agents_md_integration.py +0 -378
  364. package/tests/tilt-engine/test_cache_operations.py +0 -181
  365. package/tests/tilt-engine/test_cache_persistence.py +0 -142
  366. package/tests/tilt-engine/test_code_executor.py +0 -152
  367. package/tests/tilt-engine/test_code_viewer.py +0 -127
  368. package/tests/tilt-engine/test_compose_port_anchors.py +0 -310
  369. package/tests/tilt-engine/test_config_inspector.py +0 -162
  370. package/tests/tilt-engine/test_daemon_focus_mode.py +0 -89
  371. package/tests/tilt-engine/test_daemon_polling.py +0 -122
  372. package/tests/tilt-engine/test_daemon_registration.py +0 -115
  373. package/tests/tilt-engine/test_daemon_validation.py +0 -107
  374. package/tests/tilt-engine/test_docker_generator_bugs.py +0 -493
  375. package/tests/tilt-engine/test_docker_prune.py +0 -119
  376. package/tests/tilt-engine/test_dockerignore_path_bug.py +0 -82
  377. package/tests/tilt-engine/test_file_browser.py +0 -193
  378. package/tests/tilt-engine/test_frontend_basepath_manifest.py +0 -27
  379. package/tests/tilt-engine/test_health_dependencies.py +0 -130
  380. package/tests/tilt-engine/test_health_endpoints.py +0 -118
  381. package/tests/tilt-engine/test_health_tilt_ui.py +0 -85
  382. package/tests/tilt-engine/test_runtime_container_footprint.py +0 -162
  383. package/tests/tilt-engine/test_sablier_defer_start.py +0 -237
  384. package/tests/tilt-engine/test_safety_aliases.py +0 -84
  385. package/tests/tilt-engine/test_snapshot_diff.py +0 -136
  386. package/tests/tilt-engine/test_snapshot_persistence.py +0 -163
  387. package/tests/tilt-engine/test_snapshot_scanning.py +0 -123
  388. package/tests/tilt-engine/test_standalone_project_boot.py +0 -61
  389. package/tests/tilt-engine/test_standalone_traefik.py +0 -160
  390. 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
- });