@tdk-landscape/tdk-cli-core 1.3.53 → 1.3.55
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.
- package/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/cli/dist/commands/doctor.js +21 -3
- package/cli/dist/commands/upgrade.js +7 -7
- package/cli/dist/generator/extension-fetch.js +16 -9
- package/cli/dist/utils/spinner.js +39 -0
- package/cli/package.json +1 -2
- package/package.json +16 -2
- package/.claude/skills/layer-autoresearch/SKILL.md +0 -48
- package/.claude/skills/tdk-troubleshoot/SKILL.md +0 -222
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -40
- package/.github/ISSUE_TEMPLATE/config.yml +0 -11
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -18
- package/.github/ISSUE_TEMPLATE/premium_license.yml +0 -43
- package/.github/dependabot.yml +0 -33
- package/.github/pull_request_template.md +0 -5
- package/.github/workflows/ci.yml +0 -200
- package/.github/workflows/release-binaries.yml +0 -139
- package/.github/zizmor.yml +0 -9
- package/.pre-commit-config.yaml +0 -57
- package/CODE_OF_CONDUCT.md +0 -9
- package/CONTRIBUTING.md +0 -42
- package/Makefile +0 -92
- package/SECURITY.md +0 -17
- package/benchmarks/results/container-scale-2026-09-25T20-54-49-736Z.json +0 -45
- package/benchmarks/results/container-scale-2026-09-25T21-01-20-540Z.json +0 -150
- package/benchmarks/results/container-scale-2026-09-25T21-15-01-441Z.json +0 -73
- package/benchmarks/results/container-scale-2026-09-25T22-09-01-630Z.json +0 -77
- package/benchmarks/results/container-scale-2026-09-25T22-18-28-371Z.json +0 -202
- package/cli/AGENTS.md +0 -390
- package/cli/DESIGN.md +0 -735
- package/cli/README.md +0 -292
- package/cli/biome.json +0 -40
- package/cli/dependency-graph.svg +0 -1135
- package/cli/dist/cli.d.ts +0 -3
- package/cli/dist/cli.d.ts.map +0 -1
- package/cli/dist/cli.js.map +0 -1
- package/cli/dist/commands/completion.d.ts +0 -3
- package/cli/dist/commands/completion.d.ts.map +0 -1
- package/cli/dist/commands/completion.js.map +0 -1
- package/cli/dist/commands/config.d.ts +0 -3
- package/cli/dist/commands/config.d.ts.map +0 -1
- package/cli/dist/commands/config.js.map +0 -1
- package/cli/dist/commands/doctor.d.ts +0 -19
- package/cli/dist/commands/doctor.d.ts.map +0 -1
- package/cli/dist/commands/doctor.js.map +0 -1
- package/cli/dist/commands/down.d.ts +0 -3
- package/cli/dist/commands/down.d.ts.map +0 -1
- package/cli/dist/commands/down.js.map +0 -1
- package/cli/dist/commands/help.d.ts +0 -2
- package/cli/dist/commands/help.d.ts.map +0 -1
- package/cli/dist/commands/help.js.map +0 -1
- package/cli/dist/commands/networks.d.ts +0 -3
- package/cli/dist/commands/networks.d.ts.map +0 -1
- package/cli/dist/commands/networks.js.map +0 -1
- package/cli/dist/commands/project.d.ts +0 -9
- package/cli/dist/commands/project.d.ts.map +0 -1
- package/cli/dist/commands/project.js.map +0 -1
- package/cli/dist/commands/projects.d.ts +0 -3
- package/cli/dist/commands/projects.d.ts.map +0 -1
- package/cli/dist/commands/projects.js.map +0 -1
- package/cli/dist/commands/resource.d.ts +0 -69
- package/cli/dist/commands/resource.d.ts.map +0 -1
- package/cli/dist/commands/resource.js.map +0 -1
- package/cli/dist/commands/resources.d.ts +0 -3
- package/cli/dist/commands/resources.d.ts.map +0 -1
- package/cli/dist/commands/resources.js.map +0 -1
- package/cli/dist/commands/stack.d.ts +0 -3
- package/cli/dist/commands/stack.d.ts.map +0 -1
- package/cli/dist/commands/stack.js.map +0 -1
- package/cli/dist/commands/stacks.d.ts +0 -3
- package/cli/dist/commands/stacks.d.ts.map +0 -1
- package/cli/dist/commands/stacks.js.map +0 -1
- package/cli/dist/commands/status.d.ts +0 -3
- package/cli/dist/commands/status.d.ts.map +0 -1
- package/cli/dist/commands/status.js.map +0 -1
- package/cli/dist/commands/ui.d.ts +0 -3
- package/cli/dist/commands/ui.d.ts.map +0 -1
- package/cli/dist/commands/ui.js.map +0 -1
- package/cli/dist/commands/up.d.ts +0 -3
- package/cli/dist/commands/up.d.ts.map +0 -1
- package/cli/dist/commands/up.js.map +0 -1
- package/cli/dist/commands/upgrade.d.ts +0 -14
- package/cli/dist/commands/upgrade.d.ts.map +0 -1
- package/cli/dist/commands/upgrade.js.map +0 -1
- package/cli/dist/commands/version.d.ts +0 -3
- package/cli/dist/commands/version.d.ts.map +0 -1
- package/cli/dist/commands/version.js.map +0 -1
- package/cli/dist/components/Accessible.d.ts +0 -8
- package/cli/dist/components/Accessible.d.ts.map +0 -1
- package/cli/dist/components/Accessible.js.map +0 -1
- package/cli/dist/components/BaseTooltip.d.ts +0 -4
- package/cli/dist/components/BaseTooltip.d.ts.map +0 -1
- package/cli/dist/components/BaseTooltip.js.map +0 -1
- package/cli/dist/components/DetailPanel.d.ts +0 -4
- package/cli/dist/components/DetailPanel.d.ts.map +0 -1
- package/cli/dist/components/DetailPanel.js.map +0 -1
- package/cli/dist/components/FileTree.d.ts +0 -4
- package/cli/dist/components/FileTree.d.ts.map +0 -1
- package/cli/dist/components/FileTree.js.map +0 -1
- package/cli/dist/components/ResourceSelectInput.d.ts +0 -4
- package/cli/dist/components/ResourceSelectInput.d.ts.map +0 -1
- package/cli/dist/components/ResourceSelectInput.js.map +0 -1
- package/cli/dist/components/ResourceTable.d.ts +0 -4
- package/cli/dist/components/ResourceTable.d.ts.map +0 -1
- package/cli/dist/components/ResourceTable.js.map +0 -1
- package/cli/dist/components/TabBar.d.ts +0 -4
- package/cli/dist/components/TabBar.d.ts.map +0 -1
- package/cli/dist/components/TabBar.js.map +0 -1
- package/cli/dist/components/Tooltip.d.ts +0 -12
- package/cli/dist/components/Tooltip.d.ts.map +0 -1
- package/cli/dist/components/Tooltip.js.map +0 -1
- package/cli/dist/components/index.d.ts +0 -8
- package/cli/dist/components/index.d.ts.map +0 -1
- package/cli/dist/components/index.js.map +0 -1
- package/cli/dist/config/platform-standards.d.ts +0 -159
- package/cli/dist/config/platform-standards.d.ts.map +0 -1
- package/cli/dist/config/platform-standards.js.map +0 -1
- package/cli/dist/generator/extension-fetch.d.ts +0 -25
- package/cli/dist/generator/extension-fetch.d.ts.map +0 -1
- package/cli/dist/generator/extension-fetch.js.map +0 -1
- package/cli/dist/generator/template-engine.d.ts +0 -62
- package/cli/dist/generator/template-engine.d.ts.map +0 -1
- package/cli/dist/generator/template-engine.js.map +0 -1
- package/cli/dist/index.d.ts +0 -11
- package/cli/dist/index.d.ts.map +0 -1
- package/cli/dist/index.js.map +0 -1
- package/cli/dist/types/index.d.ts +0 -257
- package/cli/dist/types/index.d.ts.map +0 -1
- package/cli/dist/types/index.js.map +0 -1
- package/cli/dist/utils/cache.d.ts +0 -19
- package/cli/dist/utils/cache.d.ts.map +0 -1
- package/cli/dist/utils/cache.js.map +0 -1
- package/cli/dist/utils/command-helpers.d.ts +0 -17
- package/cli/dist/utils/command-helpers.d.ts.map +0 -1
- package/cli/dist/utils/command-helpers.js.map +0 -1
- package/cli/dist/utils/constants.d.ts +0 -53
- package/cli/dist/utils/constants.d.ts.map +0 -1
- package/cli/dist/utils/constants.js.map +0 -1
- package/cli/dist/utils/discovery-context.d.ts +0 -4
- package/cli/dist/utils/discovery-context.d.ts.map +0 -1
- package/cli/dist/utils/discovery-context.js.map +0 -1
- package/cli/dist/utils/docker.d.ts +0 -4
- package/cli/dist/utils/docker.d.ts.map +0 -1
- package/cli/dist/utils/docker.js.map +0 -1
- package/cli/dist/utils/doctor-runtime.d.ts +0 -81
- package/cli/dist/utils/doctor-runtime.d.ts.map +0 -1
- package/cli/dist/utils/doctor-runtime.js.map +0 -1
- package/cli/dist/utils/env-validator.d.ts +0 -15
- package/cli/dist/utils/env-validator.d.ts.map +0 -1
- package/cli/dist/utils/env-validator.js.map +0 -1
- package/cli/dist/utils/errors.d.ts +0 -31
- package/cli/dist/utils/errors.d.ts.map +0 -1
- package/cli/dist/utils/errors.js.map +0 -1
- package/cli/dist/utils/file-helpers.d.ts +0 -14
- package/cli/dist/utils/file-helpers.d.ts.map +0 -1
- package/cli/dist/utils/file-helpers.js.map +0 -1
- package/cli/dist/utils/formatting.d.ts +0 -30
- package/cli/dist/utils/formatting.d.ts.map +0 -1
- package/cli/dist/utils/formatting.js.map +0 -1
- package/cli/dist/utils/paths.d.ts +0 -3
- package/cli/dist/utils/paths.d.ts.map +0 -1
- package/cli/dist/utils/paths.js.map +0 -1
- package/cli/dist/utils/port-assignment.d.ts +0 -6
- package/cli/dist/utils/port-assignment.d.ts.map +0 -1
- package/cli/dist/utils/port-assignment.js.map +0 -1
- package/cli/dist/utils/project-features.d.ts +0 -23
- package/cli/dist/utils/project-features.d.ts.map +0 -1
- package/cli/dist/utils/project-features.js.map +0 -1
- package/cli/dist/utils/project-templates.d.ts +0 -7
- package/cli/dist/utils/project-templates.d.ts.map +0 -1
- package/cli/dist/utils/project-templates.js.map +0 -1
- package/cli/dist/utils/prompt.d.ts +0 -28
- package/cli/dist/utils/prompt.d.ts.map +0 -1
- package/cli/dist/utils/prompt.js.map +0 -1
- package/cli/dist/utils/resource-features.d.ts +0 -29
- package/cli/dist/utils/resource-features.d.ts.map +0 -1
- package/cli/dist/utils/resource-features.js.map +0 -1
- package/cli/dist/utils/service-urls.d.ts +0 -30
- package/cli/dist/utils/service-urls.d.ts.map +0 -1
- package/cli/dist/utils/service-urls.js.map +0 -1
- package/cli/dist/utils/services.d.ts +0 -18
- package/cli/dist/utils/services.d.ts.map +0 -1
- package/cli/dist/utils/services.js.map +0 -1
- package/cli/dist/utils/stack-features.d.ts +0 -22
- package/cli/dist/utils/stack-features.d.ts.map +0 -1
- package/cli/dist/utils/stack-features.js.map +0 -1
- package/cli/dist/utils/tar.d.ts +0 -7
- package/cli/dist/utils/tar.d.ts.map +0 -1
- package/cli/dist/utils/tar.js.map +0 -1
- package/cli/dist/utils/tilt.d.ts +0 -20
- package/cli/dist/utils/tilt.d.ts.map +0 -1
- package/cli/dist/utils/tilt.js.map +0 -1
- package/cli/dist/utils/validation.d.ts +0 -16
- package/cli/dist/utils/validation.d.ts.map +0 -1
- package/cli/dist/utils/validation.js.map +0 -1
- package/cli/knip.json +0 -6
- package/cli/pnpm-lock.yaml +0 -2305
- package/cli/pnpm-workspace.yaml +0 -2
- package/cli/src/cli.ts +0 -72
- package/cli/src/commands/__tests__/always-enabled-infra.test.ts +0 -109
- package/cli/src/commands/__tests__/config.test.ts +0 -146
- package/cli/src/commands/__tests__/doctor.test.ts +0 -730
- package/cli/src/commands/__tests__/error-handling.test.ts +0 -78
- package/cli/src/commands/__tests__/phases-model.test.ts +0 -161
- package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +0 -187
- package/cli/src/commands/__tests__/project.test.ts +0 -68
- package/cli/src/commands/__tests__/resource.test.ts +0 -226
- package/cli/src/commands/__tests__/saas-starter-integration.test.ts +0 -194
- package/cli/src/commands/__tests__/stack-features-e2e.test.ts +0 -135
- package/cli/src/commands/__tests__/upgrade.test.ts +0 -198
- package/cli/src/commands/completion.ts +0 -300
- package/cli/src/commands/config.ts +0 -299
- package/cli/src/commands/doctor.ts +0 -926
- package/cli/src/commands/down.ts +0 -37
- package/cli/src/commands/help.ts +0 -143
- package/cli/src/commands/networks-design.md +0 -80
- package/cli/src/commands/networks.ts +0 -332
- package/cli/src/commands/project.ts +0 -456
- package/cli/src/commands/projects.ts +0 -82
- package/cli/src/commands/resource.ts +0 -652
- package/cli/src/commands/resources.ts +0 -95
- package/cli/src/commands/stack.ts +0 -128
- package/cli/src/commands/stacks.ts +0 -52
- package/cli/src/commands/status.ts +0 -88
- package/cli/src/commands/ui.tsx +0 -843
- package/cli/src/commands/up.ts +0 -169
- package/cli/src/commands/upgrade.ts +0 -628
- package/cli/src/commands/version.ts +0 -9
- package/cli/src/components/Accessible.tsx +0 -21
- package/cli/src/components/BaseTooltip.tsx +0 -66
- package/cli/src/components/DetailPanel.tsx +0 -146
- package/cli/src/components/FileTree.tsx +0 -89
- package/cli/src/components/ResourceSelectInput.tsx +0 -30
- package/cli/src/components/ResourceTable.tsx +0 -78
- package/cli/src/components/TabBar.tsx +0 -53
- package/cli/src/components/Tooltip.tsx +0 -11
- package/cli/src/components/index.ts +0 -7
- package/cli/src/config/platform-standards.test.ts +0 -11
- package/cli/src/config/platform-standards.ts +0 -196
- package/cli/src/generator/__tests__/extension-fetch.test.ts +0 -242
- package/cli/src/generator/__tests__/template-engine.test.ts +0 -70
- package/cli/src/generator/extension-fetch.ts +0 -286
- package/cli/src/generator/template-engine.ts +0 -752
- package/cli/src/index.ts +0 -86
- package/cli/src/templates.d.ts +0 -4
- package/cli/src/types/index.ts +0 -353
- package/cli/src/utils/__tests__/cache.test.ts +0 -98
- package/cli/src/utils/__tests__/formatting.test.ts +0 -170
- package/cli/src/utils/__tests__/paths.test.ts +0 -180
- package/cli/src/utils/__tests__/port-assignment.test.ts +0 -121
- package/cli/src/utils/__tests__/service-urls.test.ts +0 -174
- package/cli/src/utils/__tests__/services.test.ts +0 -531
- package/cli/src/utils/__tests__/tilt.test.ts +0 -172
- package/cli/src/utils/__tests__/validation.test.ts +0 -148
- package/cli/src/utils/cache.ts +0 -76
- package/cli/src/utils/command-helpers.ts +0 -54
- package/cli/src/utils/constants.ts +0 -130
- package/cli/src/utils/discovery-context.ts +0 -49
- package/cli/src/utils/docker.ts +0 -20
- package/cli/src/utils/doctor-runtime.ts +0 -644
- package/cli/src/utils/env-validator.ts +0 -139
- package/cli/src/utils/errors.ts +0 -168
- package/cli/src/utils/file-helpers.ts +0 -62
- package/cli/src/utils/formatting.ts +0 -215
- package/cli/src/utils/paths.ts +0 -53
- package/cli/src/utils/port-assignment.ts +0 -106
- package/cli/src/utils/project-features.ts +0 -118
- package/cli/src/utils/project-templates.ts +0 -29
- package/cli/src/utils/prompt.ts +0 -128
- package/cli/src/utils/resource-features.ts +0 -215
- package/cli/src/utils/service-urls.ts +0 -124
- package/cli/src/utils/services.ts +0 -364
- package/cli/src/utils/stack-features.ts +0 -30
- package/cli/src/utils/tar.ts +0 -24
- package/cli/src/utils/tilt.ts +0 -133
- package/cli/src/utils/validation.ts +0 -67
- package/cli/tsconfig.json +0 -25
- package/cli/tsconfig.typecheck.json +0 -8
- package/docs/FEATURES.md +0 -281
- package/docs/demo.svg +0 -217
- package/engine/docs/AUTODISCOVERY_TEST.md +0 -182
- package/engine/docs/C4-ARCHITECTURE-operations.md +0 -396
- package/engine/docs/C4-ARCHITECTURE-overview.md +0 -284
- package/engine/docs/C4-ARCHITECTURE.md +0 -17
- package/engine/docs/GOLDEN_IMAGE_INTEGRATION.md +0 -349
- package/engine/docs/MANIFEST_DRIVEN_ARCHITECTURE.md +0 -357
- package/engine/docs/README.md +0 -284
- package/install.sh +0 -19
- package/knip.json +0 -10
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/.openspec.yaml +0 -2
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/design.md +0 -102
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/proposal.md +0 -31
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-notifications/spec.md +0 -48
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-orchestration/spec.md +0 -63
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-troubleshooting/spec.md +0 -56
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/tasks.md +0 -61
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/design.md +0 -114
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/proposal.md +0 -32
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/manifest-field-migration/spec.md +0 -20
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/resource-terminology-standard/spec.md +0 -20
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/stack-terminology-standard/spec.md +0 -20
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/tasks.md +0 -194
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/design.md +0 -111
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/proposal.md +0 -33
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/function-naming-alignment/spec.md +0 -12
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/optional-parameter-patterns/spec.md +0 -18
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-documentation/spec.md +0 -16
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-naming-consistency/spec.md +0 -12
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-ordering-standard/spec.md +0 -12
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/tasks.md +0 -194
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/design.md +0 -84
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/proposal.md +0 -31
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/codebase-audit/spec.md +0 -27
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/dead-code-cleanup/spec.md +0 -27
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/test-gap-fill/spec.md +0 -23
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/todo-resolution/spec.md +0 -27
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/tasks.md +0 -39
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/design.md +0 -80
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/proposal.md +0 -40
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/spec.md +0 -52
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/tasks.md +0 -51
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/design.md +0 -43
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/proposal.md +0 -29
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/specs/self-contained-generated-projects/spec.md +0 -67
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/tasks.md +0 -27
- package/openspec/changes/optimize-runtime-docker-layers/.openspec.yaml +0 -3
- package/openspec/changes/optimize-runtime-docker-layers/design.md +0 -81
- package/openspec/changes/optimize-runtime-docker-layers/proposal.md +0 -44
- package/openspec/changes/optimize-runtime-docker-layers/specs/runtime-container-footprint/spec.md +0 -79
- package/openspec/changes/optimize-runtime-docker-layers/tasks.md +0 -36
- package/openspec/changes/prioritized-cold-start/.openspec.yaml +0 -4
- package/openspec/changes/prioritized-cold-start/design.md +0 -137
- package/openspec/changes/prioritized-cold-start/proposal.md +0 -41
- package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +0 -98
- package/openspec/changes/prioritized-cold-start/tasks.md +0 -69
- package/openspec/config.yaml +0 -1
- package/openspec/specs/manifest-field-migration/spec.md +0 -24
- package/openspec/specs/resource-terminology-standard/spec.md +0 -24
- package/openspec/specs/self-contained-generated-projects/spec.md +0 -67
- package/openspec/specs/stack-terminology-standard/spec.md +0 -24
- package/platform/services/platform/proxy/service.yaml +0 -14
- package/scripts/audit-codebase.sh +0 -213
- package/scripts/autoresearch/layer-eval.sh +0 -65
- package/scripts/benchmark/README.md +0 -25
- package/scripts/benchmark/container-scale.ts +0 -503
- package/scripts/benchmark/pre-release-gate.sh +0 -9
- package/scripts/install-git-hooks.sh +0 -14
- package/scripts/measure-idle-footprint.sh +0 -58
- package/scripts/record-demo.sh +0 -43
- package/scripts/release-binaries.sh +0 -97
- package/scripts/setup-pre-commit.sh +0 -33
- package/scripts/stage-npm-engine.sh +0 -36
- package/tests/tilt-engine/__init__.py +0 -5
- package/tests/tilt-engine/conftest.py +0 -182
- package/tests/tilt-engine/fixtures/appointment-frontend-service.json +0 -11
- package/tests/tilt-engine/fixtures/identity-backend-service.json +0 -12
- package/tests/tilt-engine/fixtures/invalid-service.json +0 -4
- package/tests/tilt-engine/test_agents_md_generator.py +0 -341
- package/tests/tilt-engine/test_agents_md_integration.py +0 -378
- package/tests/tilt-engine/test_cache_operations.py +0 -181
- package/tests/tilt-engine/test_cache_persistence.py +0 -142
- package/tests/tilt-engine/test_code_executor.py +0 -152
- package/tests/tilt-engine/test_code_viewer.py +0 -127
- package/tests/tilt-engine/test_compose_port_anchors.py +0 -310
- package/tests/tilt-engine/test_config_inspector.py +0 -162
- package/tests/tilt-engine/test_daemon_focus_mode.py +0 -89
- package/tests/tilt-engine/test_daemon_polling.py +0 -122
- package/tests/tilt-engine/test_daemon_registration.py +0 -115
- package/tests/tilt-engine/test_daemon_validation.py +0 -107
- package/tests/tilt-engine/test_docker_generator_bugs.py +0 -493
- package/tests/tilt-engine/test_docker_prune.py +0 -119
- package/tests/tilt-engine/test_dockerignore_path_bug.py +0 -82
- package/tests/tilt-engine/test_file_browser.py +0 -193
- package/tests/tilt-engine/test_frontend_basepath_manifest.py +0 -27
- package/tests/tilt-engine/test_health_dependencies.py +0 -130
- package/tests/tilt-engine/test_health_endpoints.py +0 -118
- package/tests/tilt-engine/test_health_tilt_ui.py +0 -85
- package/tests/tilt-engine/test_runtime_container_footprint.py +0 -162
- package/tests/tilt-engine/test_sablier_defer_start.py +0 -237
- package/tests/tilt-engine/test_safety_aliases.py +0 -84
- package/tests/tilt-engine/test_snapshot_diff.py +0 -136
- package/tests/tilt-engine/test_snapshot_persistence.py +0 -163
- package/tests/tilt-engine/test_snapshot_scanning.py +0 -123
- package/tests/tilt-engine/test_standalone_project_boot.py +0 -61
- package/tests/tilt-engine/test_standalone_traefik.py +0 -160
- 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
|
-
});
|