@tdk-landscape/tdk-cli-core 1.3.45 → 1.3.48

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 (431) hide show
  1. package/.github/workflows/release-binaries.yml +54 -0
  2. package/.pre-commit-config.yaml +57 -0
  3. package/Makefile +92 -0
  4. package/bun.lock +538 -0
  5. package/cli/AGENTS.md +390 -0
  6. package/cli/DESIGN.md +735 -0
  7. package/cli/biome.json +44 -0
  8. package/cli/dependency-graph.svg +1135 -0
  9. package/cli/knip.json +6 -0
  10. package/cli/package.json +77 -0
  11. package/cli/pnpm-lock.yaml +2305 -0
  12. package/cli/pnpm-workspace.yaml +2 -0
  13. package/cli/shared-platform-engineering/docker-templates/bun-hoisted-symlink-fix.sh +23 -0
  14. package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +464 -0
  15. package/cli/shared-platform-engineering/docker-templates/install-deps.sh +152 -0
  16. package/cli/shared-platform-engineering/docker-templates/prisma-bun-client-link-fix.sh +12 -0
  17. package/cli/shared-platform-engineering/docker-templates/prisma-normalize-client.sh +56 -0
  18. package/{dist/cli.js → cli/src/cli.ts} +21 -13
  19. package/cli/src/commands/__tests__/always-enabled-infra.test.ts +115 -0
  20. package/cli/src/commands/__tests__/config.test.ts +146 -0
  21. package/cli/src/commands/__tests__/doctor.test.ts +557 -0
  22. package/cli/src/commands/__tests__/error-handling.test.ts +78 -0
  23. package/cli/src/commands/__tests__/phases-model.test.ts +163 -0
  24. package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +207 -0
  25. package/cli/src/commands/__tests__/project.test.ts +68 -0
  26. package/cli/src/commands/__tests__/resource.test.ts +226 -0
  27. package/cli/src/commands/__tests__/saas-starter-integration.test.ts +196 -0
  28. package/cli/src/commands/__tests__/stack-features-e2e.test.ts +129 -0
  29. package/cli/src/commands/__tests__/upgrade.test.ts +101 -0
  30. package/{dist/commands/completion.js → cli/src/commands/completion.ts} +78 -72
  31. package/cli/src/commands/config.ts +299 -0
  32. package/cli/src/commands/doctor.ts +790 -0
  33. package/cli/src/commands/down.ts +37 -0
  34. package/cli/src/commands/help.ts +150 -0
  35. package/cli/src/commands/networks-design.md +80 -0
  36. package/cli/src/commands/networks.ts +332 -0
  37. package/cli/src/commands/project.ts +439 -0
  38. package/cli/src/commands/projects.ts +82 -0
  39. package/cli/src/commands/resource.ts +652 -0
  40. package/cli/src/commands/resources.ts +95 -0
  41. package/cli/src/commands/stack.ts +128 -0
  42. package/cli/src/commands/stacks.ts +52 -0
  43. package/cli/src/commands/status.ts +88 -0
  44. package/cli/src/commands/ui.tsx +843 -0
  45. package/cli/src/commands/up.ts +150 -0
  46. package/cli/src/commands/upgrade.ts +570 -0
  47. package/{dist/commands/version.js → cli/src/commands/version.ts} +5 -5
  48. package/cli/src/components/Accessible.tsx +21 -0
  49. package/cli/src/components/BaseTooltip.tsx +66 -0
  50. package/cli/src/components/DetailPanel.tsx +146 -0
  51. package/cli/src/components/FileTree.tsx +89 -0
  52. package/cli/src/components/ResourceSelectInput.tsx +30 -0
  53. package/cli/src/components/ResourceTable.tsx +78 -0
  54. package/cli/src/components/TabBar.tsx +53 -0
  55. package/cli/src/components/Tooltip.tsx +11 -0
  56. package/{dist/components/index.js → cli/src/components/index.ts} +0 -1
  57. package/cli/src/config/platform-standards.test.ts +11 -0
  58. package/cli/src/config/platform-standards.ts +196 -0
  59. package/cli/src/generator/__tests__/extension-fetch.test.ts +220 -0
  60. package/cli/src/generator/__tests__/template-engine.test.ts +70 -0
  61. package/cli/src/generator/extension-fetch.ts +279 -0
  62. package/cli/src/generator/template-engine.ts +754 -0
  63. package/cli/src/index.ts +86 -0
  64. package/cli/src/templates.d.ts +4 -0
  65. package/cli/src/types/index.ts +351 -0
  66. package/cli/src/utils/__tests__/cache.test.ts +98 -0
  67. package/cli/src/utils/__tests__/formatting.test.ts +170 -0
  68. package/cli/src/utils/__tests__/paths.test.ts +180 -0
  69. package/cli/src/utils/__tests__/port-assignment.test.ts +121 -0
  70. package/cli/src/utils/__tests__/service-urls.test.ts +174 -0
  71. package/cli/src/utils/__tests__/services.test.ts +531 -0
  72. package/cli/src/utils/__tests__/tilt.test.ts +143 -0
  73. package/cli/src/utils/__tests__/validation.test.ts +148 -0
  74. package/cli/src/utils/cache.ts +76 -0
  75. package/cli/src/utils/command-helpers.ts +54 -0
  76. package/cli/src/utils/constants.ts +126 -0
  77. package/cli/src/utils/discovery-context.ts +49 -0
  78. package/cli/src/utils/docker.ts +20 -0
  79. package/cli/src/utils/doctor-runtime.ts +604 -0
  80. package/cli/src/utils/env-validator.ts +139 -0
  81. package/cli/src/utils/errors.ts +168 -0
  82. package/cli/src/utils/file-helpers.ts +62 -0
  83. package/cli/src/utils/formatting.ts +215 -0
  84. package/cli/src/utils/paths.ts +53 -0
  85. package/cli/src/utils/port-assignment.ts +106 -0
  86. package/cli/src/utils/project-features.ts +118 -0
  87. package/cli/src/utils/project-templates.ts +28 -0
  88. package/cli/src/utils/prompt.ts +123 -0
  89. package/cli/src/utils/resource-features.ts +209 -0
  90. package/cli/src/utils/service-urls.ts +124 -0
  91. package/cli/src/utils/services.ts +363 -0
  92. package/cli/src/utils/stack-features.ts +30 -0
  93. package/cli/src/utils/tar.ts +24 -0
  94. package/cli/src/utils/tilt.ts +113 -0
  95. package/cli/src/utils/validation.ts +67 -0
  96. package/{templates → cli/templates}/Tiltfile.hbs +1 -1
  97. package/cli/tsconfig.json +25 -0
  98. package/cli/tsconfig.typecheck.json +8 -0
  99. package/docs/FEATURES.md +279 -0
  100. package/engine/topologies/platform/docker/dockerfile/dockerfile.star +3 -3
  101. package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +1 -1
  102. package/engine/topologies/platform/docker/layers/l2_dependency_layers.star +0 -3
  103. package/engine/topologies/platform/docker/layers/l3_builder_layers.star +1 -1
  104. package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +1 -1
  105. package/engine/topologies/platform/docker/secrets/infisical.star +19 -47
  106. package/engine/topologies/tilt/resources/orchestrator/apply_migrator_orchestration.star +1 -1
  107. package/install.sh +242 -0
  108. package/knip.json +10 -0
  109. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/.openspec.yaml +2 -0
  110. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/design.md +102 -0
  111. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/proposal.md +31 -0
  112. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-notifications/spec.md +48 -0
  113. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-orchestration/spec.md +63 -0
  114. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-troubleshooting/spec.md +56 -0
  115. package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/tasks.md +61 -0
  116. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/.openspec.yaml +2 -0
  117. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/design.md +114 -0
  118. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/proposal.md +32 -0
  119. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/manifest-field-migration/spec.md +20 -0
  120. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/resource-terminology-standard/spec.md +20 -0
  121. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/stack-terminology-standard/spec.md +20 -0
  122. package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/tasks.md +194 -0
  123. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/.openspec.yaml +2 -0
  124. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/design.md +111 -0
  125. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/proposal.md +33 -0
  126. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/function-naming-alignment/spec.md +12 -0
  127. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/optional-parameter-patterns/spec.md +18 -0
  128. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-documentation/spec.md +16 -0
  129. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-naming-consistency/spec.md +12 -0
  130. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-ordering-standard/spec.md +12 -0
  131. package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/tasks.md +194 -0
  132. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/.openspec.yaml +2 -0
  133. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/codebase-audit-report.md +62 -0
  134. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/design.md +84 -0
  135. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/proposal.md +31 -0
  136. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/codebase-audit/spec.md +27 -0
  137. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/dead-code-cleanup/spec.md +27 -0
  138. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/test-gap-fill/spec.md +23 -0
  139. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/todo-resolution/spec.md +27 -0
  140. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/tasks.md +39 -0
  141. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/.openspec.yaml +5 -0
  142. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/design.md +94 -0
  143. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/proposal.md +46 -0
  144. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CLEANUP_REPORT_8.md +174 -0
  145. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CRITICAL_ASSESSMENT_8.md +160 -0
  146. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/circular-deps/CRITICAL_ASSESSMENT_4.md +381 -0
  147. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/dead-code/CRITICAL_ASSESSMENT_3.md +316 -0
  148. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/CRITICAL_ASSESSMENT_1.md +290 -0
  149. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/IMPLEMENTATION_SUMMARY_1.md +233 -0
  150. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/defensive-cleanup/CRITICAL_ASSESSMENT_6.md +835 -0
  151. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/CRITICAL_ASSESSMENT_7.md +254 -0
  152. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/IMPLEMENTATION_SUMMARY_7.md +187 -0
  153. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/strong-typing/CRITICAL_ASSESSMENT_5.md +269 -0
  154. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/CRITICAL_ASSESSMENT_2.md +312 -0
  155. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/IMPLEMENTATION_SUMMARY.md +170 -0
  156. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/tasks.md +137 -0
  157. package/openspec/changes/archive/2026-06-25-landscape-consolidation/.openspec.yaml +2 -0
  158. package/openspec/changes/archive/2026-06-25-landscape-consolidation/design.md +80 -0
  159. package/openspec/changes/archive/2026-06-25-landscape-consolidation/proposal.md +40 -0
  160. package/openspec/changes/archive/2026-06-25-landscape-consolidation/spec.md +52 -0
  161. package/openspec/changes/archive/2026-06-25-landscape-consolidation/tasks.md +51 -0
  162. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/.openspec.yaml +2 -0
  163. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/design.md +43 -0
  164. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/proposal.md +29 -0
  165. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/specs/self-contained-generated-projects/spec.md +67 -0
  166. package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/tasks.md +27 -0
  167. package/openspec/specs/manifest-field-migration/spec.md +24 -0
  168. package/openspec/specs/resource-terminology-standard/spec.md +24 -0
  169. package/openspec/specs/self-contained-generated-projects/spec.md +67 -0
  170. package/openspec/specs/stack-terminology-standard/spec.md +24 -0
  171. package/package.json +27 -64
  172. package/platform/services/platform/proxy/service.yaml +14 -0
  173. package/scripts/audit-codebase.sh +213 -0
  174. package/scripts/install-git-hooks.sh +14 -0
  175. package/scripts/release-binaries.sh +94 -0
  176. package/scripts/setup-pre-commit.sh +33 -0
  177. package/scripts/stage-npm-engine.sh +36 -0
  178. package/shared-platform-engineering/docker-templates/bun-hoisted-symlink-fix.sh +23 -0
  179. package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +464 -0
  180. package/shared-platform-engineering/docker-templates/install-deps.sh +152 -0
  181. package/shared-platform-engineering/docker-templates/prisma-bun-client-link-fix.sh +12 -0
  182. package/shared-platform-engineering/docker-templates/prisma-normalize-client.sh +56 -0
  183. package/tests/tilt-engine/__init__.py +5 -0
  184. package/tests/tilt-engine/conftest.py +182 -0
  185. package/tests/tilt-engine/fixtures/appointment-frontend-service.json +11 -0
  186. package/tests/tilt-engine/fixtures/identity-backend-service.json +12 -0
  187. package/tests/tilt-engine/fixtures/invalid-service.json +4 -0
  188. package/tests/tilt-engine/test_agents_md_generator.py +341 -0
  189. package/tests/tilt-engine/test_agents_md_integration.py +378 -0
  190. package/tests/tilt-engine/test_cache_operations.py +181 -0
  191. package/tests/tilt-engine/test_cache_persistence.py +142 -0
  192. package/tests/tilt-engine/test_code_executor.py +152 -0
  193. package/tests/tilt-engine/test_code_viewer.py +127 -0
  194. package/tests/tilt-engine/test_compose_port_anchors.py +310 -0
  195. package/tests/tilt-engine/test_config_inspector.py +162 -0
  196. package/tests/tilt-engine/test_daemon_focus_mode.py +89 -0
  197. package/tests/tilt-engine/test_daemon_polling.py +122 -0
  198. package/tests/tilt-engine/test_daemon_registration.py +115 -0
  199. package/tests/tilt-engine/test_daemon_validation.py +107 -0
  200. package/tests/tilt-engine/test_docker_generator_bugs.py +493 -0
  201. package/tests/tilt-engine/test_docker_prune.py +119 -0
  202. package/tests/tilt-engine/test_dockerignore_path_bug.py +82 -0
  203. package/tests/tilt-engine/test_file_browser.py +193 -0
  204. package/tests/tilt-engine/test_frontend_basepath_manifest.py +27 -0
  205. package/tests/tilt-engine/test_health_dependencies.py +130 -0
  206. package/tests/tilt-engine/test_health_endpoints.py +118 -0
  207. package/tests/tilt-engine/test_health_tilt_ui.py +85 -0
  208. package/tests/tilt-engine/test_safety_aliases.py +84 -0
  209. package/tests/tilt-engine/test_snapshot_diff.py +136 -0
  210. package/tests/tilt-engine/test_snapshot_persistence.py +163 -0
  211. package/tests/tilt-engine/test_snapshot_scanning.py +123 -0
  212. package/tests/tilt-engine/test_standalone_project_boot.py +61 -0
  213. package/tests/tilt-engine/test_standalone_traefik.py +108 -0
  214. package/dist/cli.d.ts +0 -3
  215. package/dist/cli.d.ts.map +0 -1
  216. package/dist/cli.js.map +0 -1
  217. package/dist/commands/completion.d.ts +0 -3
  218. package/dist/commands/completion.d.ts.map +0 -1
  219. package/dist/commands/completion.js.map +0 -1
  220. package/dist/commands/config.d.ts +0 -3
  221. package/dist/commands/config.d.ts.map +0 -1
  222. package/dist/commands/config.js +0 -231
  223. package/dist/commands/config.js.map +0 -1
  224. package/dist/commands/doctor.d.ts +0 -7
  225. package/dist/commands/doctor.d.ts.map +0 -1
  226. package/dist/commands/doctor.js +0 -597
  227. package/dist/commands/doctor.js.map +0 -1
  228. package/dist/commands/down.d.ts +0 -3
  229. package/dist/commands/down.d.ts.map +0 -1
  230. package/dist/commands/down.js +0 -32
  231. package/dist/commands/down.js.map +0 -1
  232. package/dist/commands/help.d.ts +0 -2
  233. package/dist/commands/help.d.ts.map +0 -1
  234. package/dist/commands/help.js +0 -130
  235. package/dist/commands/help.js.map +0 -1
  236. package/dist/commands/networks.d.ts +0 -3
  237. package/dist/commands/networks.d.ts.map +0 -1
  238. package/dist/commands/networks.js +0 -260
  239. package/dist/commands/networks.js.map +0 -1
  240. package/dist/commands/project.d.ts +0 -3
  241. package/dist/commands/project.d.ts.map +0 -1
  242. package/dist/commands/project.js +0 -373
  243. package/dist/commands/project.js.map +0 -1
  244. package/dist/commands/projects.d.ts +0 -3
  245. package/dist/commands/projects.d.ts.map +0 -1
  246. package/dist/commands/projects.js +0 -71
  247. package/dist/commands/projects.js.map +0 -1
  248. package/dist/commands/resource.d.ts +0 -69
  249. package/dist/commands/resource.d.ts.map +0 -1
  250. package/dist/commands/resource.js +0 -579
  251. package/dist/commands/resource.js.map +0 -1
  252. package/dist/commands/resources.d.ts +0 -3
  253. package/dist/commands/resources.d.ts.map +0 -1
  254. package/dist/commands/resources.js +0 -73
  255. package/dist/commands/resources.js.map +0 -1
  256. package/dist/commands/stack.d.ts +0 -3
  257. package/dist/commands/stack.d.ts.map +0 -1
  258. package/dist/commands/stack.js +0 -97
  259. package/dist/commands/stack.js.map +0 -1
  260. package/dist/commands/stacks.d.ts +0 -3
  261. package/dist/commands/stacks.d.ts.map +0 -1
  262. package/dist/commands/stacks.js +0 -43
  263. package/dist/commands/stacks.js.map +0 -1
  264. package/dist/commands/status.d.ts +0 -3
  265. package/dist/commands/status.d.ts.map +0 -1
  266. package/dist/commands/status.js +0 -71
  267. package/dist/commands/status.js.map +0 -1
  268. package/dist/commands/ui.d.ts +0 -3
  269. package/dist/commands/ui.d.ts.map +0 -1
  270. package/dist/commands/ui.js +0 -445
  271. package/dist/commands/ui.js.map +0 -1
  272. package/dist/commands/up.d.ts +0 -3
  273. package/dist/commands/up.d.ts.map +0 -1
  274. package/dist/commands/up.js +0 -110
  275. package/dist/commands/up.js.map +0 -1
  276. package/dist/commands/upgrade.d.ts +0 -11
  277. package/dist/commands/upgrade.d.ts.map +0 -1
  278. package/dist/commands/upgrade.js +0 -496
  279. package/dist/commands/upgrade.js.map +0 -1
  280. package/dist/commands/version.d.ts +0 -3
  281. package/dist/commands/version.d.ts.map +0 -1
  282. package/dist/commands/version.js.map +0 -1
  283. package/dist/components/Accessible.d.ts +0 -8
  284. package/dist/components/Accessible.d.ts.map +0 -1
  285. package/dist/components/Accessible.js +0 -10
  286. package/dist/components/Accessible.js.map +0 -1
  287. package/dist/components/BaseTooltip.d.ts +0 -4
  288. package/dist/components/BaseTooltip.d.ts.map +0 -1
  289. package/dist/components/BaseTooltip.js +0 -28
  290. package/dist/components/BaseTooltip.js.map +0 -1
  291. package/dist/components/DetailPanel.d.ts +0 -4
  292. package/dist/components/DetailPanel.d.ts.map +0 -1
  293. package/dist/components/DetailPanel.js +0 -18
  294. package/dist/components/DetailPanel.js.map +0 -1
  295. package/dist/components/FileTree.d.ts +0 -4
  296. package/dist/components/FileTree.d.ts.map +0 -1
  297. package/dist/components/FileTree.js +0 -47
  298. package/dist/components/FileTree.js.map +0 -1
  299. package/dist/components/ResourceSelectInput.d.ts +0 -4
  300. package/dist/components/ResourceSelectInput.d.ts.map +0 -1
  301. package/dist/components/ResourceSelectInput.js +0 -7
  302. package/dist/components/ResourceSelectInput.js.map +0 -1
  303. package/dist/components/ResourceTable.d.ts +0 -4
  304. package/dist/components/ResourceTable.d.ts.map +0 -1
  305. package/dist/components/ResourceTable.js +0 -18
  306. package/dist/components/ResourceTable.js.map +0 -1
  307. package/dist/components/TabBar.d.ts +0 -4
  308. package/dist/components/TabBar.d.ts.map +0 -1
  309. package/dist/components/TabBar.js +0 -17
  310. package/dist/components/TabBar.js.map +0 -1
  311. package/dist/components/Tooltip.d.ts +0 -12
  312. package/dist/components/Tooltip.d.ts.map +0 -1
  313. package/dist/components/Tooltip.js +0 -12
  314. package/dist/components/Tooltip.js.map +0 -1
  315. package/dist/components/index.d.ts +0 -8
  316. package/dist/components/index.d.ts.map +0 -1
  317. package/dist/components/index.js.map +0 -1
  318. package/dist/config/platform-standards.d.ts +0 -159
  319. package/dist/config/platform-standards.d.ts.map +0 -1
  320. package/dist/config/platform-standards.js +0 -181
  321. package/dist/config/platform-standards.js.map +0 -1
  322. package/dist/generator/extension-fetch.d.ts +0 -25
  323. package/dist/generator/extension-fetch.d.ts.map +0 -1
  324. package/dist/generator/extension-fetch.js +0 -252
  325. package/dist/generator/extension-fetch.js.map +0 -1
  326. package/dist/generator/template-engine.d.ts +0 -61
  327. package/dist/generator/template-engine.d.ts.map +0 -1
  328. package/dist/generator/template-engine.js +0 -557
  329. package/dist/generator/template-engine.js.map +0 -1
  330. package/dist/index.d.ts +0 -11
  331. package/dist/index.d.ts.map +0 -1
  332. package/dist/index.js +0 -11
  333. package/dist/index.js.map +0 -1
  334. package/dist/types/index.d.ts +0 -255
  335. package/dist/types/index.d.ts.map +0 -1
  336. package/dist/types/index.js +0 -17
  337. package/dist/types/index.js.map +0 -1
  338. package/dist/utils/cache.d.ts +0 -19
  339. package/dist/utils/cache.d.ts.map +0 -1
  340. package/dist/utils/cache.js +0 -64
  341. package/dist/utils/cache.js.map +0 -1
  342. package/dist/utils/command-helpers.d.ts +0 -17
  343. package/dist/utils/command-helpers.d.ts.map +0 -1
  344. package/dist/utils/command-helpers.js +0 -41
  345. package/dist/utils/command-helpers.js.map +0 -1
  346. package/dist/utils/constants.d.ts +0 -52
  347. package/dist/utils/constants.d.ts.map +0 -1
  348. package/dist/utils/constants.js +0 -112
  349. package/dist/utils/constants.js.map +0 -1
  350. package/dist/utils/discovery-context.d.ts +0 -4
  351. package/dist/utils/discovery-context.d.ts.map +0 -1
  352. package/dist/utils/discovery-context.js +0 -39
  353. package/dist/utils/discovery-context.js.map +0 -1
  354. package/dist/utils/docker.d.ts +0 -4
  355. package/dist/utils/docker.d.ts.map +0 -1
  356. package/dist/utils/docker.js +0 -19
  357. package/dist/utils/docker.js.map +0 -1
  358. package/dist/utils/doctor-runtime.d.ts +0 -66
  359. package/dist/utils/doctor-runtime.d.ts.map +0 -1
  360. package/dist/utils/doctor-runtime.js +0 -469
  361. package/dist/utils/doctor-runtime.js.map +0 -1
  362. package/dist/utils/env-validator.d.ts +0 -15
  363. package/dist/utils/env-validator.d.ts.map +0 -1
  364. package/dist/utils/env-validator.js +0 -109
  365. package/dist/utils/env-validator.js.map +0 -1
  366. package/dist/utils/errors.d.ts +0 -31
  367. package/dist/utils/errors.d.ts.map +0 -1
  368. package/dist/utils/errors.js +0 -140
  369. package/dist/utils/errors.js.map +0 -1
  370. package/dist/utils/file-helpers.d.ts +0 -14
  371. package/dist/utils/file-helpers.d.ts.map +0 -1
  372. package/dist/utils/file-helpers.js +0 -45
  373. package/dist/utils/file-helpers.js.map +0 -1
  374. package/dist/utils/formatting.d.ts +0 -30
  375. package/dist/utils/formatting.d.ts.map +0 -1
  376. package/dist/utils/formatting.js +0 -164
  377. package/dist/utils/formatting.js.map +0 -1
  378. package/dist/utils/paths.d.ts +0 -3
  379. package/dist/utils/paths.d.ts.map +0 -1
  380. package/dist/utils/paths.js +0 -41
  381. package/dist/utils/paths.js.map +0 -1
  382. package/dist/utils/port-assignment.d.ts +0 -6
  383. package/dist/utils/port-assignment.d.ts.map +0 -1
  384. package/dist/utils/port-assignment.js +0 -81
  385. package/dist/utils/port-assignment.js.map +0 -1
  386. package/dist/utils/project-features.d.ts +0 -23
  387. package/dist/utils/project-features.d.ts.map +0 -1
  388. package/dist/utils/project-features.js +0 -98
  389. package/dist/utils/project-features.js.map +0 -1
  390. package/dist/utils/project-templates.d.ts +0 -7
  391. package/dist/utils/project-templates.d.ts.map +0 -1
  392. package/dist/utils/project-templates.js +0 -24
  393. package/dist/utils/project-templates.js.map +0 -1
  394. package/dist/utils/prompt.d.ts +0 -28
  395. package/dist/utils/prompt.d.ts.map +0 -1
  396. package/dist/utils/prompt.js +0 -79
  397. package/dist/utils/prompt.js.map +0 -1
  398. package/dist/utils/resource-features.d.ts +0 -29
  399. package/dist/utils/resource-features.d.ts.map +0 -1
  400. package/dist/utils/resource-features.js +0 -171
  401. package/dist/utils/resource-features.js.map +0 -1
  402. package/dist/utils/service-urls.d.ts +0 -30
  403. package/dist/utils/service-urls.d.ts.map +0 -1
  404. package/dist/utils/service-urls.js +0 -93
  405. package/dist/utils/service-urls.js.map +0 -1
  406. package/dist/utils/services.d.ts +0 -18
  407. package/dist/utils/services.d.ts.map +0 -1
  408. package/dist/utils/services.js +0 -291
  409. package/dist/utils/services.js.map +0 -1
  410. package/dist/utils/stack-features.d.ts +0 -22
  411. package/dist/utils/stack-features.d.ts.map +0 -1
  412. package/dist/utils/stack-features.js +0 -13
  413. package/dist/utils/stack-features.js.map +0 -1
  414. package/dist/utils/tar.d.ts +0 -7
  415. package/dist/utils/tar.d.ts.map +0 -1
  416. package/dist/utils/tar.js +0 -21
  417. package/dist/utils/tar.js.map +0 -1
  418. package/dist/utils/tilt.d.ts +0 -19
  419. package/dist/utils/tilt.d.ts.map +0 -1
  420. package/dist/utils/tilt.js +0 -78
  421. package/dist/utils/tilt.js.map +0 -1
  422. package/dist/utils/validation.d.ts +0 -16
  423. package/dist/utils/validation.d.ts.map +0 -1
  424. package/dist/utils/validation.js +0 -58
  425. package/dist/utils/validation.js.map +0 -1
  426. /package/{README.md → cli/README.md} +0 -0
  427. /package/{bin → cli/bin}/tdk.js +0 -0
  428. /package/{templates → cli/templates}/.tiltignore.hbs +0 -0
  429. /package/{templates → cli/templates}/TILT_RESOURCE_DEFAULTS.star.hbs +0 -0
  430. /package/{templates → cli/templates}/TILT_TECH_STACK.star.hbs +0 -0
  431. /package/{templates → cli/templates}/spec.master.hbs +0 -0
@@ -0,0 +1,557 @@
1
+ import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
5
+ import {
6
+ checkFrontendDockerPreflight,
7
+ checkGeneratedProjectRuntimeAssets,
8
+ checkStarlarkLoadExports,
9
+ } from "../doctor.js";
10
+ import {
11
+ checkIngressPorts,
12
+ checkPrivateNpmRegistry,
13
+ checkTiltResourceHealth,
14
+ findForeignIngressHolders,
15
+ orderTiltFailures,
16
+ parsePublishedPortHolders,
17
+ parseTiltResourceFailures,
18
+ probeContainerRuntimeError,
19
+ summarizeTiltBuildError,
20
+ } from "../../utils/doctor-runtime.js";
21
+
22
+ describe("doctor frontend Docker preflight", () => {
23
+ let testDir: string;
24
+ let originalCwd: string;
25
+
26
+ beforeEach(() => {
27
+ originalCwd = process.cwd();
28
+ testDir = join(
29
+ tmpdir(),
30
+ `tdk-doctor-frontend-${Date.now()}-${Math.random().toString(16).slice(2)}`,
31
+ );
32
+ mkdirSync(testDir, { recursive: true });
33
+ process.chdir(testDir);
34
+ });
35
+
36
+ afterEach(() => {
37
+ process.chdir(originalCwd);
38
+ if (testDir && existsSync(testDir)) {
39
+ rmSync(testDir, { recursive: true, force: true });
40
+ }
41
+ });
42
+
43
+ function writeFrontendProject(options: {
44
+ composePort: number;
45
+ dockerTsconfig: Record<string, unknown>;
46
+ mainTsx: string;
47
+ }) {
48
+ const appDir = join(testDir, "services", "app", "dashboard-app");
49
+ const generatedDir = join(appDir, ".autogenerated");
50
+ const stackGeneratedDir = join(testDir, "services", "app", ".autogenerated");
51
+
52
+ mkdirSync(generatedDir, { recursive: true });
53
+ mkdirSync(stackGeneratedDir, { recursive: true });
54
+ mkdirSync(join(appDir, "src"), { recursive: true });
55
+
56
+ writeFileSync(
57
+ join(appDir, "service.json"),
58
+ JSON.stringify(
59
+ {
60
+ appName: "dashboard-app",
61
+ appType: "frontend",
62
+ stack: "app",
63
+ port: 3200,
64
+ basePath: "/dashboard-app",
65
+ },
66
+ null,
67
+ 2,
68
+ ),
69
+ );
70
+ writeFileSync(
71
+ join(generatedDir, "Dockerfile.app.autogenerated"),
72
+ "FROM nginx:alpine\nCOPY dist /usr/share/nginx/html\nEXPOSE 80\n",
73
+ );
74
+ writeFileSync(
75
+ join(stackGeneratedDir, "docker-compose.app.autogenerated.yml"),
76
+ [
77
+ "services:",
78
+ " dashboard-app:",
79
+ " labels:",
80
+ ` - "traefik.http.services.dashboard-app.loadbalancer.server.port=${options.composePort}"`,
81
+ ].join("\n"),
82
+ );
83
+ writeFileSync(
84
+ join(generatedDir, "tsconfig.docker.autogenerated.json"),
85
+ JSON.stringify(options.dockerTsconfig, null, 2),
86
+ );
87
+ writeFileSync(join(appDir, "src", "main.tsx"), options.mainTsx);
88
+ }
89
+
90
+ it("fails when generated Traefik routes an nginx frontend to the Vite dev port", () => {
91
+ writeFrontendProject({
92
+ composePort: 3200,
93
+ dockerTsconfig: { compilerOptions: { allowSyntheticDefaultImports: true } },
94
+ mainTsx: 'import { StrictMode } from "react";\n',
95
+ });
96
+
97
+ const result = checkFrontendDockerPreflight();
98
+
99
+ expect(result.didPass).toBe(false);
100
+ expect(result.message).toContain("nginx runtime exposes 80");
101
+ expect(result.message).toContain("routes to 3200");
102
+ });
103
+
104
+ it("fails when Docker tsconfig rejects default React imports used by the entrypoint", () => {
105
+ writeFrontendProject({
106
+ composePort: 80,
107
+ dockerTsconfig: { compilerOptions: { strict: true } },
108
+ mainTsx: ['import React from "react";', 'import ReactDOM from "react-dom/client";', ""].join(
109
+ "\n",
110
+ ),
111
+ });
112
+
113
+ const result = checkFrontendDockerPreflight();
114
+
115
+ expect(result.didPass).toBe(false);
116
+ expect(result.message).toContain("does not allow synthetic default imports");
117
+ expect(result.message).toContain("react-dom/client");
118
+ });
119
+
120
+ it("passes when generated frontend Docker metadata is internally consistent", () => {
121
+ writeFrontendProject({
122
+ composePort: 80,
123
+ dockerTsconfig: { compilerOptions: { strict: true } },
124
+ mainTsx: [
125
+ 'import { StrictMode } from "react";',
126
+ 'import { createRoot } from "react-dom/client";',
127
+ "",
128
+ ].join("\n"),
129
+ });
130
+
131
+ const result = checkFrontendDockerPreflight();
132
+
133
+ expect(result.didPass).toBe(true);
134
+ });
135
+
136
+ it("fails when generated Starlark loads a private exported symbol", () => {
137
+ const outDir = join(testDir, ".tdk", ".tdk-out");
138
+ const extDir = join(outDir, "tdk-cli-ext", "engine");
139
+ mkdirSync(extDir, { recursive: true });
140
+ writeFileSync(join(outDir, "Tiltfile"), 'load("./tdk-cli-ext/engine/bad.star", "Bad")\n');
141
+ writeFileSync(
142
+ join(extDir, "sablier_container_cycle.star"),
143
+ "_sablier_middleware_suffix = 'x'\n",
144
+ );
145
+ writeFileSync(join(extDir, "public.star"), "Docker = struct()\n");
146
+ writeFileSync(
147
+ join(extDir, "bad.star"),
148
+ [
149
+ "Bad = struct()",
150
+ 'load("./sablier_container_cycle.star", "_sablier_middleware_suffix")',
151
+ 'load("./public.star", _Docker = "Docker")',
152
+ "",
153
+ ].join("\n"),
154
+ );
155
+
156
+ const result = checkStarlarkLoadExports();
157
+
158
+ expect(result.didPass).toBe(false);
159
+ expect(result.message).toContain("_sablier_middleware_suffix");
160
+ expect(result.message).not.toContain("_Docker");
161
+ });
162
+
163
+ it("fails when generated Starlark loads a missing relative file", () => {
164
+ const outDir = join(testDir, ".tdk", ".tdk-out");
165
+ const extDir = join(outDir, "tdk-cli-ext", "discovery");
166
+ mkdirSync(extDir, { recursive: true });
167
+ writeFileSync(
168
+ join(outDir, "Tiltfile"),
169
+ 'load("./tdk-cli-ext/discovery/daemon.star", "Daemon")\n',
170
+ );
171
+ writeFileSync(join(extDir, "daemon.star"), 'load("./resource_registry.star", "CacheOps")\n');
172
+
173
+ const result = checkStarlarkLoadExports();
174
+
175
+ expect(result.didPass).toBe(false);
176
+ expect(result.message).toContain("Missing relative load targets");
177
+ expect(result.message).toContain("resource_registry.star");
178
+ });
179
+
180
+ it("passes when generated Starlark only uses private local aliases", () => {
181
+ const extDir = join(testDir, ".tdk", ".tdk-out", "tdk-cli-ext", "engine");
182
+ mkdirSync(extDir, { recursive: true });
183
+ writeFileSync(join(extDir, "public.star"), "Docker = struct()\n");
184
+ writeFileSync(join(extDir, "good.star"), 'load("./public.star", _Docker = "Docker")\n');
185
+
186
+ const result = checkStarlarkLoadExports();
187
+
188
+ expect(result.didPass).toBe(true);
189
+ });
190
+ });
191
+
192
+ describe("doctor generated runtime asset preflight", () => {
193
+ let testDir: string;
194
+ let originalCwd: string;
195
+
196
+ beforeEach(() => {
197
+ originalCwd = process.cwd();
198
+ testDir = join(
199
+ tmpdir(),
200
+ `tdk-doctor-runtime-assets-${Date.now()}-${Math.random().toString(16).slice(2)}`,
201
+ );
202
+ mkdirSync(join(testDir, ".tdk"), { recursive: true });
203
+ writeFileSync(
204
+ join(testDir, ".tdk", "project.json"),
205
+ JSON.stringify({
206
+ version: "1.0",
207
+ project: { name: "asset-check", version: "1.0.0" },
208
+ phases: {
209
+ pre_alpha: { name: "Pre-Alpha", description: "", enabledStacks: [] },
210
+ alpha: { name: "Alpha", description: "", enabledStacks: [] },
211
+ beta: { name: "Beta", description: "", enabledStacks: [] },
212
+ out_of_scope: { name: "Out of Scope", description: "", enabledStacks: [] },
213
+ },
214
+ optional_infra: {
215
+ monitoring: false,
216
+ elk: false,
217
+ debezium: false,
218
+ golden_image: true,
219
+ verdaccio: false,
220
+ },
221
+ discovery: { paths: ["services/*/*"] },
222
+ overrides: {},
223
+ }),
224
+ );
225
+ process.chdir(testDir);
226
+ });
227
+
228
+ afterEach(() => {
229
+ process.chdir(originalCwd);
230
+ if (testDir && existsSync(testDir)) {
231
+ rmSync(testDir, { recursive: true, force: true });
232
+ }
233
+ });
234
+
235
+ function writeRequiredRuntimeAssets() {
236
+ const templateDir = join(testDir, "shared-platform-engineering", "docker-templates");
237
+ mkdirSync(templateDir, { recursive: true });
238
+ for (const file of [
239
+ "install-deps.sh",
240
+ "bun-hoisted-symlink-fix.sh",
241
+ "prisma-bun-client-link-fix.sh",
242
+ "prisma-normalize-client.sh",
243
+ ]) {
244
+ writeFileSync(join(templateDir, file), "#!/bin/sh\n");
245
+ }
246
+ }
247
+
248
+ it("fails when the root workspace package.json and Docker template scripts are missing", () => {
249
+ const result = checkGeneratedProjectRuntimeAssets();
250
+
251
+ expect(result.didPass).toBe(false);
252
+ expect(result.message).toContain("package.json");
253
+ expect(result.message).toContain("install-deps.sh");
254
+ expect(result.fix).toContain("tdk project");
255
+ });
256
+
257
+ it("passes when generated Docker runtime assets are present", () => {
258
+ writeFileSync(
259
+ join(testDir, "package.json"),
260
+ JSON.stringify({ name: "asset-check", private: true, workspaces: ["services/*/*"] }),
261
+ );
262
+ writeRequiredRuntimeAssets();
263
+
264
+ const result = checkGeneratedProjectRuntimeAssets();
265
+
266
+ expect(result.didPass).toBe(true);
267
+ expect(result.message).toContain("runtime assets are present");
268
+ });
269
+ });
270
+
271
+ describe("doctor ingress + tilt runtime checks", () => {
272
+ it("detects a foreign Traefik holding host port 80", () => {
273
+ const dockerPs = [
274
+ "tdk_saas_starter_traefik\t0.0.0.0:80->80/tcp,:::80->80/tcp,0.0.0.0:8080->8080/tcp",
275
+ "beauty_crm_postgres\t0.0.0.0:5432->5432/tcp",
276
+ ].join("\n");
277
+
278
+ const holders = parsePublishedPortHolders(dockerPs, [80, 443]);
279
+ expect(holders).toHaveLength(1);
280
+ expect(holders[0]?.name).toBe("tdk_saas_starter_traefik");
281
+ expect(holders[0]?.publishedPorts).toContain(80);
282
+
283
+ const foreign = findForeignIngressHolders(holders, "beauty_crm");
284
+ expect(foreign).toHaveLength(1);
285
+
286
+ const result = checkIngressPorts((() => dockerPs) as never, "beauty-crm");
287
+ expect(result.didPass).toBe(false);
288
+ expect(result.message).toContain("tdk_saas_starter_traefik");
289
+ expect(result.fix).toContain("docker stop");
290
+ });
291
+
292
+ it("passes when this project's Traefik owns the ingress ports", () => {
293
+ const dockerPs =
294
+ "beauty_crm_traefik\t0.0.0.0:80->80/tcp,:::80->80/tcp,0.0.0.0:443->443/tcp";
295
+ const result = checkIngressPorts((() => dockerPs) as never, "beauty-crm");
296
+ expect(result.didPass).toBe(true);
297
+ expect(result.message).toContain("beauty_crm_traefik");
298
+ });
299
+
300
+ it("fails doctor when Tilt reports Traefik update errors that block apps", () => {
301
+ const payload = {
302
+ items: [
303
+ {
304
+ metadata: { name: "traefik" },
305
+ status: {
306
+ updateStatus: "error",
307
+ runtimeStatus: "unknown",
308
+ buildHistory: [
309
+ {
310
+ error:
311
+ 'Bind for 0.0.0.0:80 failed: port is already allocated\nerror: exit status 1',
312
+ },
313
+ ],
314
+ },
315
+ },
316
+ {
317
+ metadata: { name: "salon-management-frontend" },
318
+ status: { updateStatus: "pending", runtimeStatus: "pending" },
319
+ },
320
+ {
321
+ metadata: { name: "postgres" },
322
+ status: { updateStatus: "ok", runtimeStatus: "ok" },
323
+ },
324
+ ],
325
+ };
326
+
327
+ const parsed = parseTiltResourceFailures(JSON.stringify(payload));
328
+ expect(parsed.failures).toHaveLength(1);
329
+ expect(parsed.failures[0]?.name).toBe("traefik");
330
+ expect(parsed.pendingCount).toBe(1);
331
+
332
+ const result = checkTiltResourceHealth((() => JSON.stringify(payload)) as never);
333
+ expect(result.didPass).toBe(false);
334
+ expect(result.message).toContain("traefik");
335
+ expect(result.message).toContain("port 80");
336
+ expect(result.message).toContain("pending");
337
+ expect(result.fix).toMatch(/docker ps --filter publish=80|Free the conflicting/);
338
+ });
339
+
340
+ it("skips tilt resource check when tilt is not running", () => {
341
+ const result = checkTiltResourceHealth((() => {
342
+ throw new Error("tilt not running");
343
+ }) as never);
344
+ expect(result.isSkipped).toBe(true);
345
+ expect(result.didPass).toBe(true);
346
+ });
347
+
348
+ it("summarizes ConnectionRefused package manifest errors from build logs", () => {
349
+ const raw = [
350
+ "error: ConnectionRefused downloading package manifest @tdk-landscape/eventing",
351
+ "error: ConnectionRefused downloading package manifest @beauty-crm/identity-js-sdk",
352
+ "error: ConnectionRefused downloading package manifest @tdk-landscape/observability",
353
+ 'ImageBuild: process "/bin/sh -c bun install --production --cache-dir=/cache/bun" did not complete successfully: exit code: 1',
354
+ ].join("\n");
355
+
356
+ const summary = summarizeTiltBuildError(raw);
357
+ expect(summary).toContain("ConnectionRefused");
358
+ expect(summary).toContain("@tdk-landscape/eventing");
359
+ expect(summary).toContain("Verdaccio");
360
+ });
361
+
362
+ it("summarizes truncated bun install ImageBuild exits as registry failures", () => {
363
+ const summary = summarizeTiltBuildError(
364
+ 'ImageBuild: process "/bin/sh -c bun install --production --cache-dir=/cache/bun" did not complete successfully: exit code: 1',
365
+ );
366
+ expect(summary).toMatch(/dependency install failed|Verdaccio|ConnectionRefused/i);
367
+ });
368
+
369
+ it("summarizes missing compose images for run-only resources", () => {
370
+ const summary = summarizeTiltBuildError(
371
+ 'Command "docker compose -p appointment-planner-autogenerated -f .../docker-compose.app.autogenerated.yml up -d --no-build appointment-planner-builder-backend" failed: exit status 1',
372
+ );
373
+ expect(summary).toContain("appointment-planner-builder-backend");
374
+ expect(summary).toMatch(/image is missing|ImageBuild|run-only/i);
375
+ });
376
+
377
+ it("lists every failed resource even when an infra resource also failed", () => {
378
+ const payload = {
379
+ items: [
380
+ {
381
+ metadata: { name: "nats-http-bridge" },
382
+ status: { updateStatus: "ok", runtimeStatus: "error" },
383
+ },
384
+ {
385
+ metadata: { name: "appointment-management-backend" },
386
+ status: {
387
+ updateStatus: "error",
388
+ runtimeStatus: "unknown",
389
+ buildHistory: [
390
+ {
391
+ error:
392
+ 'ImageBuild: process "/bin/sh -c bun run build" did not complete successfully: exit code: 1',
393
+ },
394
+ ],
395
+ },
396
+ },
397
+ {
398
+ metadata: { name: "appointment-management-backend-run-only" },
399
+ status: {
400
+ updateStatus: "error",
401
+ runtimeStatus: "not_applicable",
402
+ buildHistory: [
403
+ {
404
+ error:
405
+ 'Command "docker compose -p appointment-autogenerated -f x.yml up -d --no-build appointment-management-backend" failed: exit status 1',
406
+ },
407
+ ],
408
+ },
409
+ },
410
+ ],
411
+ };
412
+
413
+ const result = checkTiltResourceHealth(((command: string) => {
414
+ if (command.includes("tilt get uiresources")) {
415
+ return JSON.stringify(payload);
416
+ }
417
+ if (command.startsWith("docker ps")) {
418
+ return "platform-autogenerated-nats-http-bridge-1\n";
419
+ }
420
+ if (command.includes("docker logs")) {
421
+ return 'error: Failed to start NATS HTTP Bridge {"error":"Connection error: getaddrinfo ENOTFOUND"}\nInitializing Kafka consumer... {"brokers":["kafka:9092"]}';
422
+ }
423
+ throw new Error(`unexpected exec: ${command}`);
424
+ }) as typeof import("node:child_process").execSync);
425
+
426
+ expect(result.didPass).toBe(false);
427
+ expect(result.message).toContain("3 failed resources");
428
+ expect(result.message).toContain("nats-http-bridge");
429
+ expect(result.message).toContain("appointment-management-backend");
430
+ expect(result.message).toContain("appointment-management-backend-run-only");
431
+ expect(result.message).toMatch(/Kafka broker unreachable|kafka:9092/i);
432
+ expect(result.message).toMatch(/bun run build/i);
433
+ expect(result.fix).toMatch(/Kafka/i);
434
+ expect(
435
+ orderTiltFailures(parseTiltResourceFailures(JSON.stringify(payload)).failures)[0]?.name,
436
+ ).toBe("nats-http-bridge");
437
+ });
438
+
439
+ it("probes docker logs for Kafka ENOTFOUND runtime crashes", () => {
440
+ const exec = ((command: string) => {
441
+ if (command.startsWith("docker ps")) {
442
+ return "platform-autogenerated-nats-http-bridge-1\n";
443
+ }
444
+ if (command.includes("docker logs")) {
445
+ return "getaddrinfo ENOTFOUND\nbroker kafka:9092\nFailed to start NATS HTTP Bridge";
446
+ }
447
+ return "";
448
+ }) as typeof import("node:child_process").execSync;
449
+
450
+ const summary = probeContainerRuntimeError("nats-http-bridge", exec);
451
+ expect(summary).toMatch(/Kafka broker unreachable/);
452
+ });
453
+
454
+ it("summarizes bun run build ImageBuild failures", () => {
455
+ const summary = summarizeTiltBuildError(
456
+ 'ImageBuild: process "/bin/sh -c bun run build" did not complete successfully: exit code: 1',
457
+ );
458
+ expect(summary).toMatch(/bun run build|TypeScript|Tilt/i);
459
+ });
460
+
461
+ it("surfaces registry-oriented fix when ImageBuild dependency installs fail", () => {
462
+ const payload = {
463
+ items: [
464
+ {
465
+ metadata: { name: "appointment-management-backend" },
466
+ status: {
467
+ updateStatus: "error",
468
+ runtimeStatus: "unknown",
469
+ buildHistory: [
470
+ {
471
+ error:
472
+ 'ImageBuild: process "/bin/sh -c bun install --production --cache-dir=/cache/bun" did not complete successfully: exit code: 1',
473
+ },
474
+ ],
475
+ },
476
+ },
477
+ {
478
+ metadata: { name: "salon-management-frontend" },
479
+ status: { updateStatus: "pending", runtimeStatus: "pending" },
480
+ },
481
+ ],
482
+ };
483
+
484
+ const result = checkTiltResourceHealth((() => JSON.stringify(payload)) as never);
485
+ expect(result.didPass).toBe(false);
486
+ expect(result.message).toContain("appointment-management-backend");
487
+ expect(result.message).toMatch(/dependency install failed|Verdaccio|ConnectionRefused/i);
488
+ expect(result.fix).toMatch(/verdaccio:start|publish/i);
489
+ });
490
+
491
+ it("fails private registry check when Verdaccio is enabled but unreachable", () => {
492
+ const projectRoot = join(
493
+ tmpdir(),
494
+ `tdk-doctor-registry-${Date.now()}-${Math.random().toString(16).slice(2)}`,
495
+ );
496
+ mkdirSync(join(projectRoot, ".tdk"), { recursive: true });
497
+ writeFileSync(
498
+ join(projectRoot, ".tdk", "project.json"),
499
+ JSON.stringify({
500
+ project: { name: "demo" },
501
+ optional_infra: { verdaccio: true },
502
+ phases: {},
503
+ }),
504
+ );
505
+
506
+ const execDown = ((command: string) => {
507
+ if (command.startsWith("docker ps")) {
508
+ return "";
509
+ }
510
+ if (command.includes("curl")) {
511
+ throw new Error("Failed to connect to localhost port 4873");
512
+ }
513
+ return "";
514
+ }) as typeof import("node:child_process").execSync;
515
+
516
+ const result = checkPrivateNpmRegistry(execDown, projectRoot, "http://localhost:4873");
517
+
518
+ expect(result.didPass).toBe(false);
519
+ expect(result.message).toContain("ConnectionRefused");
520
+ expect(result.fix).toMatch(/verdaccio:start/);
521
+
522
+ rmSync(projectRoot, { recursive: true, force: true });
523
+ });
524
+
525
+ it("passes private registry check when Verdaccio responds", () => {
526
+ const projectRoot = join(
527
+ tmpdir(),
528
+ `tdk-doctor-registry-ok-${Date.now()}-${Math.random().toString(16).slice(2)}`,
529
+ );
530
+ mkdirSync(join(projectRoot, ".tdk"), { recursive: true });
531
+ writeFileSync(
532
+ join(projectRoot, ".tdk", "project.json"),
533
+ JSON.stringify({
534
+ project: { name: "demo" },
535
+ optional_infra: { verdaccio: true },
536
+ phases: {},
537
+ }),
538
+ );
539
+
540
+ const execUp = ((command: string) => {
541
+ if (command.startsWith("docker ps")) {
542
+ return "beauty-crm-verdaccio\n";
543
+ }
544
+ if (command.includes("curl")) {
545
+ return "200";
546
+ }
547
+ return "";
548
+ }) as typeof import("node:child_process").execSync;
549
+
550
+ const result = checkPrivateNpmRegistry(execUp, projectRoot, "http://localhost:4873");
551
+
552
+ expect(result.didPass).toBe(true);
553
+ expect(result.message).toContain("reachable");
554
+
555
+ rmSync(projectRoot, { recursive: true, force: true });
556
+ });
557
+ });
@@ -0,0 +1,78 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ createKebabCaseValidator,
4
+ isValidPort,
5
+ validateResourceName,
6
+ } from "../../utils/validation.js";
7
+
8
+ describe("error handling", () => {
9
+ describe("resource name validation", () => {
10
+ it("should validate resource names using actual validation utility", () => {
11
+ expect(validateResourceName("my-service")).toEqual({ valid: true });
12
+ expect(validateResourceName("service123")).toEqual({ valid: true });
13
+ expect(validateResourceName("api-gateway")).toEqual({ valid: true });
14
+
15
+ expect(validateResourceName("")).toEqual({
16
+ valid: false,
17
+ error: "Resource name is required",
18
+ });
19
+ expect(validateResourceName("MyService")).toEqual({
20
+ valid: false,
21
+ error: "Use lowercase letters, numbers, and hyphens only",
22
+ });
23
+ expect(validateResourceName("my_service")).toEqual({
24
+ valid: false,
25
+ error: "Use lowercase letters, numbers, and hyphens only",
26
+ });
27
+ });
28
+
29
+ it("should create kebab-case validators for different contexts", () => {
30
+ const resourceValidator = createKebabCaseValidator("resource");
31
+ const stackValidator = createKebabCaseValidator("stack");
32
+
33
+ expect(resourceValidator("my-resource")).toBe(true);
34
+ expect(resourceValidator("")).toBe("Resource name is required");
35
+ expect(resourceValidator("MyResource")).toBe(
36
+ "Use lowercase letters, numbers, and hyphens only",
37
+ );
38
+
39
+ expect(stackValidator("my-stack")).toBe(true);
40
+ expect(stackValidator("")).toBe("Stack name is required");
41
+ expect(stackValidator("MyStack")).toBe("Use kebab-case (lowercase, numbers, hyphens only)");
42
+ });
43
+ });
44
+
45
+ describe("port assignment", () => {
46
+ it("should validate port is within valid range using isValidPort", () => {
47
+ // Valid ports (isValidPort allows ports 1-65535, not just 1024+)
48
+ expect(isValidPort(3000)).toBe(true);
49
+ expect(isValidPort(8080)).toBe(true);
50
+ expect(isValidPort(1024)).toBe(true);
51
+ expect(isValidPort(1)).toBe(true); // Valid per isValidPort (just > 0)
52
+ expect(isValidPort(65535)).toBe(true);
53
+
54
+ // Invalid ports
55
+ expect(isValidPort(65536)).toBe(false);
56
+ expect(isValidPort(0)).toBe(false);
57
+ expect(isValidPort(-1)).toBe(false);
58
+ });
59
+ });
60
+
61
+ describe("stack name validation", () => {
62
+ it("should validate stack name format using createKebabCaseValidator", () => {
63
+ const validNames = ["main", "api-services", "v1-stack", "test123"];
64
+
65
+ const invalidNames = ["My Stack", "my_stack", "MyStack", ""];
66
+
67
+ const stackValidator = createKebabCaseValidator("stack");
68
+
69
+ for (const name of validNames) {
70
+ expect(stackValidator(name)).toBe(true);
71
+ }
72
+
73
+ for (const name of invalidNames) {
74
+ expect(typeof stackValidator(name)).toBe("string");
75
+ }
76
+ });
77
+ });
78
+ });