@tdk-landscape/tdk-cli-core 1.3.44 → 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.
- package/.github/workflows/release-binaries.yml +54 -0
- package/.pre-commit-config.yaml +57 -0
- package/Makefile +92 -0
- package/bun.lock +538 -0
- package/cli/AGENTS.md +390 -0
- package/cli/DESIGN.md +735 -0
- package/cli/biome.json +44 -0
- package/cli/dependency-graph.svg +1135 -0
- package/cli/knip.json +6 -0
- package/cli/package.json +77 -0
- package/cli/pnpm-lock.yaml +2305 -0
- package/cli/pnpm-workspace.yaml +2 -0
- package/cli/shared-platform-engineering/docker-templates/bun-hoisted-symlink-fix.sh +23 -0
- package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +464 -0
- package/cli/shared-platform-engineering/docker-templates/install-deps.sh +152 -0
- package/cli/shared-platform-engineering/docker-templates/prisma-bun-client-link-fix.sh +12 -0
- package/cli/shared-platform-engineering/docker-templates/prisma-normalize-client.sh +56 -0
- package/{dist/cli.js → cli/src/cli.ts} +21 -13
- package/cli/src/commands/__tests__/always-enabled-infra.test.ts +115 -0
- package/cli/src/commands/__tests__/config.test.ts +146 -0
- package/cli/src/commands/__tests__/doctor.test.ts +557 -0
- package/cli/src/commands/__tests__/error-handling.test.ts +78 -0
- package/cli/src/commands/__tests__/phases-model.test.ts +163 -0
- package/cli/src/commands/__tests__/project-resource-features-e2e.test.ts +207 -0
- package/cli/src/commands/__tests__/project.test.ts +68 -0
- package/cli/src/commands/__tests__/resource.test.ts +226 -0
- package/cli/src/commands/__tests__/saas-starter-integration.test.ts +196 -0
- package/cli/src/commands/__tests__/stack-features-e2e.test.ts +129 -0
- package/cli/src/commands/__tests__/upgrade.test.ts +101 -0
- package/{dist/commands/completion.js → cli/src/commands/completion.ts} +78 -72
- package/cli/src/commands/config.ts +299 -0
- package/cli/src/commands/doctor.ts +790 -0
- package/cli/src/commands/down.ts +37 -0
- package/cli/src/commands/help.ts +150 -0
- package/cli/src/commands/networks-design.md +80 -0
- package/cli/src/commands/networks.ts +332 -0
- package/cli/src/commands/project.ts +439 -0
- package/cli/src/commands/projects.ts +82 -0
- package/cli/src/commands/resource.ts +652 -0
- package/cli/src/commands/resources.ts +95 -0
- package/cli/src/commands/stack.ts +128 -0
- package/cli/src/commands/stacks.ts +52 -0
- package/cli/src/commands/status.ts +88 -0
- package/cli/src/commands/ui.tsx +843 -0
- package/cli/src/commands/up.ts +150 -0
- package/cli/src/commands/upgrade.ts +570 -0
- package/{dist/commands/version.js → cli/src/commands/version.ts} +5 -5
- package/cli/src/components/Accessible.tsx +21 -0
- package/cli/src/components/BaseTooltip.tsx +66 -0
- package/cli/src/components/DetailPanel.tsx +146 -0
- package/cli/src/components/FileTree.tsx +89 -0
- package/cli/src/components/ResourceSelectInput.tsx +30 -0
- package/cli/src/components/ResourceTable.tsx +78 -0
- package/cli/src/components/TabBar.tsx +53 -0
- package/cli/src/components/Tooltip.tsx +11 -0
- package/{dist/components/index.js → cli/src/components/index.ts} +0 -1
- package/cli/src/config/platform-standards.test.ts +11 -0
- package/cli/src/config/platform-standards.ts +196 -0
- package/cli/src/generator/__tests__/extension-fetch.test.ts +220 -0
- package/cli/src/generator/__tests__/template-engine.test.ts +70 -0
- package/cli/src/generator/extension-fetch.ts +279 -0
- package/cli/src/generator/template-engine.ts +754 -0
- package/cli/src/index.ts +86 -0
- package/cli/src/templates.d.ts +4 -0
- package/cli/src/types/index.ts +351 -0
- package/cli/src/utils/__tests__/cache.test.ts +98 -0
- package/cli/src/utils/__tests__/formatting.test.ts +170 -0
- package/cli/src/utils/__tests__/paths.test.ts +180 -0
- package/cli/src/utils/__tests__/port-assignment.test.ts +121 -0
- package/cli/src/utils/__tests__/service-urls.test.ts +174 -0
- package/cli/src/utils/__tests__/services.test.ts +531 -0
- package/cli/src/utils/__tests__/tilt.test.ts +143 -0
- package/cli/src/utils/__tests__/validation.test.ts +148 -0
- package/cli/src/utils/cache.ts +76 -0
- package/cli/src/utils/command-helpers.ts +54 -0
- package/cli/src/utils/constants.ts +126 -0
- package/cli/src/utils/discovery-context.ts +49 -0
- package/cli/src/utils/docker.ts +20 -0
- package/cli/src/utils/doctor-runtime.ts +604 -0
- package/cli/src/utils/env-validator.ts +139 -0
- package/cli/src/utils/errors.ts +168 -0
- package/cli/src/utils/file-helpers.ts +62 -0
- package/cli/src/utils/formatting.ts +215 -0
- package/cli/src/utils/paths.ts +53 -0
- package/cli/src/utils/port-assignment.ts +106 -0
- package/cli/src/utils/project-features.ts +118 -0
- package/cli/src/utils/project-templates.ts +28 -0
- package/cli/src/utils/prompt.ts +123 -0
- package/cli/src/utils/resource-features.ts +209 -0
- package/cli/src/utils/service-urls.ts +124 -0
- package/cli/src/utils/services.ts +363 -0
- package/cli/src/utils/stack-features.ts +30 -0
- package/cli/src/utils/tar.ts +24 -0
- package/cli/src/utils/tilt.ts +113 -0
- package/cli/src/utils/validation.ts +67 -0
- package/{templates → cli/templates}/Tiltfile.hbs +1 -1
- package/cli/tsconfig.json +25 -0
- package/cli/tsconfig.typecheck.json +8 -0
- package/docs/FEATURES.md +279 -0
- package/engine/topologies/platform/docker/dockerfile/dockerfile.star +3 -3
- package/engine/topologies/platform/docker/generators/golden_docker_generator_v2.star +1 -1
- package/engine/topologies/platform/docker/layers/l2_dependency_layers.star +0 -3
- package/engine/topologies/platform/docker/layers/l3_builder_layers.star +1 -1
- package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +1 -1
- package/engine/topologies/platform/docker/secrets/infisical.star +19 -47
- package/engine/topologies/tilt/resources/orchestrator/apply_migrator_orchestration.star +1 -1
- package/install.sh +242 -0
- package/knip.json +10 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/.openspec.yaml +2 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/design.md +102 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/proposal.md +31 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-notifications/spec.md +48 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-orchestration/spec.md +63 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/specs/vscode-tdk-troubleshooting/spec.md +56 -0
- package/openspec/changes/add-vscode-tdk-troubleshooter-plugin/tasks.md +61 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/design.md +114 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/proposal.md +32 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/manifest-field-migration/spec.md +20 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/resource-terminology-standard/spec.md +20 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/specs/stack-terminology-standard/spec.md +20 -0
- package/openspec/changes/archive/2026-04-28-rename-domain-to-stack-service-to-resource/tasks.md +194 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/design.md +111 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/proposal.md +33 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/function-naming-alignment/spec.md +12 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/optional-parameter-patterns/spec.md +18 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-documentation/spec.md +16 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-naming-consistency/spec.md +12 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/specs/parameter-ordering-standard/spec.md +12 -0
- package/openspec/changes/archive/2026-04-28-star-files-parameter-fixes/tasks.md +194 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/codebase-audit-report.md +62 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/design.md +84 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/proposal.md +31 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/codebase-audit/spec.md +27 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/dead-code-cleanup/spec.md +27 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/test-gap-fill/spec.md +23 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/specs/todo-resolution/spec.md +27 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/tasks.md +39 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/.openspec.yaml +5 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/design.md +94 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/proposal.md +46 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CLEANUP_REPORT_8.md +174 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CRITICAL_ASSESSMENT_8.md +160 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/circular-deps/CRITICAL_ASSESSMENT_4.md +381 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/dead-code/CRITICAL_ASSESSMENT_3.md +316 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/CRITICAL_ASSESSMENT_1.md +290 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/IMPLEMENTATION_SUMMARY_1.md +233 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/defensive-cleanup/CRITICAL_ASSESSMENT_6.md +835 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/CRITICAL_ASSESSMENT_7.md +254 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/IMPLEMENTATION_SUMMARY_7.md +187 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/strong-typing/CRITICAL_ASSESSMENT_5.md +269 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/CRITICAL_ASSESSMENT_2.md +312 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/IMPLEMENTATION_SUMMARY.md +170 -0
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/tasks.md +137 -0
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/design.md +80 -0
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/proposal.md +40 -0
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/spec.md +52 -0
- package/openspec/changes/archive/2026-06-25-landscape-consolidation/tasks.md +51 -0
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/.openspec.yaml +2 -0
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/design.md +43 -0
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/proposal.md +29 -0
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/specs/self-contained-generated-projects/spec.md +67 -0
- package/openspec/changes/archive/2026-09-17-fix-generated-stack-boot/tasks.md +27 -0
- package/openspec/specs/manifest-field-migration/spec.md +24 -0
- package/openspec/specs/resource-terminology-standard/spec.md +24 -0
- package/openspec/specs/self-contained-generated-projects/spec.md +67 -0
- package/openspec/specs/stack-terminology-standard/spec.md +24 -0
- package/package.json +27 -64
- package/platform/services/platform/proxy/service.yaml +14 -0
- package/scripts/audit-codebase.sh +213 -0
- package/scripts/install-git-hooks.sh +14 -0
- package/scripts/release-binaries.sh +94 -0
- package/scripts/setup-pre-commit.sh +33 -0
- package/scripts/stage-npm-engine.sh +36 -0
- package/shared-platform-engineering/docker-templates/bun-hoisted-symlink-fix.sh +23 -0
- package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +464 -0
- package/shared-platform-engineering/docker-templates/install-deps.sh +152 -0
- package/shared-platform-engineering/docker-templates/prisma-bun-client-link-fix.sh +12 -0
- package/shared-platform-engineering/docker-templates/prisma-normalize-client.sh +56 -0
- package/tests/tilt-engine/__init__.py +5 -0
- package/tests/tilt-engine/conftest.py +182 -0
- package/tests/tilt-engine/fixtures/appointment-frontend-service.json +11 -0
- package/tests/tilt-engine/fixtures/identity-backend-service.json +12 -0
- package/tests/tilt-engine/fixtures/invalid-service.json +4 -0
- package/tests/tilt-engine/test_agents_md_generator.py +341 -0
- package/tests/tilt-engine/test_agents_md_integration.py +378 -0
- package/tests/tilt-engine/test_cache_operations.py +181 -0
- package/tests/tilt-engine/test_cache_persistence.py +142 -0
- package/tests/tilt-engine/test_code_executor.py +152 -0
- package/tests/tilt-engine/test_code_viewer.py +127 -0
- package/tests/tilt-engine/test_compose_port_anchors.py +310 -0
- package/tests/tilt-engine/test_config_inspector.py +162 -0
- package/tests/tilt-engine/test_daemon_focus_mode.py +89 -0
- package/tests/tilt-engine/test_daemon_polling.py +122 -0
- package/tests/tilt-engine/test_daemon_registration.py +115 -0
- package/tests/tilt-engine/test_daemon_validation.py +107 -0
- package/tests/tilt-engine/test_docker_generator_bugs.py +493 -0
- package/tests/tilt-engine/test_docker_prune.py +119 -0
- package/tests/tilt-engine/test_dockerignore_path_bug.py +82 -0
- package/tests/tilt-engine/test_file_browser.py +193 -0
- package/tests/tilt-engine/test_frontend_basepath_manifest.py +27 -0
- package/tests/tilt-engine/test_health_dependencies.py +130 -0
- package/tests/tilt-engine/test_health_endpoints.py +118 -0
- package/tests/tilt-engine/test_health_tilt_ui.py +85 -0
- package/tests/tilt-engine/test_safety_aliases.py +84 -0
- package/tests/tilt-engine/test_snapshot_diff.py +136 -0
- package/tests/tilt-engine/test_snapshot_persistence.py +163 -0
- package/tests/tilt-engine/test_snapshot_scanning.py +123 -0
- package/tests/tilt-engine/test_standalone_project_boot.py +61 -0
- package/tests/tilt-engine/test_standalone_traefik.py +108 -0
- package/dist/cli.d.ts +0 -3
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/completion.d.ts +0 -3
- package/dist/commands/completion.d.ts.map +0 -1
- package/dist/commands/completion.js.map +0 -1
- package/dist/commands/config.d.ts +0 -3
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js +0 -231
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/doctor.d.ts +0 -7
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js +0 -597
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/down.d.ts +0 -3
- package/dist/commands/down.d.ts.map +0 -1
- package/dist/commands/down.js +0 -32
- package/dist/commands/down.js.map +0 -1
- package/dist/commands/help.d.ts +0 -2
- package/dist/commands/help.d.ts.map +0 -1
- package/dist/commands/help.js +0 -130
- package/dist/commands/help.js.map +0 -1
- package/dist/commands/networks.d.ts +0 -3
- package/dist/commands/networks.d.ts.map +0 -1
- package/dist/commands/networks.js +0 -260
- package/dist/commands/networks.js.map +0 -1
- package/dist/commands/project.d.ts +0 -3
- package/dist/commands/project.d.ts.map +0 -1
- package/dist/commands/project.js +0 -373
- package/dist/commands/project.js.map +0 -1
- package/dist/commands/projects.d.ts +0 -3
- package/dist/commands/projects.d.ts.map +0 -1
- package/dist/commands/projects.js +0 -71
- package/dist/commands/projects.js.map +0 -1
- package/dist/commands/resource.d.ts +0 -69
- package/dist/commands/resource.d.ts.map +0 -1
- package/dist/commands/resource.js +0 -579
- package/dist/commands/resource.js.map +0 -1
- package/dist/commands/resources.d.ts +0 -3
- package/dist/commands/resources.d.ts.map +0 -1
- package/dist/commands/resources.js +0 -73
- package/dist/commands/resources.js.map +0 -1
- package/dist/commands/stack.d.ts +0 -3
- package/dist/commands/stack.d.ts.map +0 -1
- package/dist/commands/stack.js +0 -97
- package/dist/commands/stack.js.map +0 -1
- package/dist/commands/stacks.d.ts +0 -3
- package/dist/commands/stacks.d.ts.map +0 -1
- package/dist/commands/stacks.js +0 -43
- package/dist/commands/stacks.js.map +0 -1
- package/dist/commands/status.d.ts +0 -3
- package/dist/commands/status.d.ts.map +0 -1
- package/dist/commands/status.js +0 -71
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/ui.d.ts +0 -3
- package/dist/commands/ui.d.ts.map +0 -1
- package/dist/commands/ui.js +0 -445
- package/dist/commands/ui.js.map +0 -1
- package/dist/commands/up.d.ts +0 -3
- package/dist/commands/up.d.ts.map +0 -1
- package/dist/commands/up.js +0 -110
- package/dist/commands/up.js.map +0 -1
- package/dist/commands/upgrade.d.ts +0 -11
- package/dist/commands/upgrade.d.ts.map +0 -1
- package/dist/commands/upgrade.js +0 -496
- package/dist/commands/upgrade.js.map +0 -1
- package/dist/commands/version.d.ts +0 -3
- package/dist/commands/version.d.ts.map +0 -1
- package/dist/commands/version.js.map +0 -1
- package/dist/components/Accessible.d.ts +0 -8
- package/dist/components/Accessible.d.ts.map +0 -1
- package/dist/components/Accessible.js +0 -10
- package/dist/components/Accessible.js.map +0 -1
- package/dist/components/BaseTooltip.d.ts +0 -4
- package/dist/components/BaseTooltip.d.ts.map +0 -1
- package/dist/components/BaseTooltip.js +0 -28
- package/dist/components/BaseTooltip.js.map +0 -1
- package/dist/components/DetailPanel.d.ts +0 -4
- package/dist/components/DetailPanel.d.ts.map +0 -1
- package/dist/components/DetailPanel.js +0 -18
- package/dist/components/DetailPanel.js.map +0 -1
- package/dist/components/FileTree.d.ts +0 -4
- package/dist/components/FileTree.d.ts.map +0 -1
- package/dist/components/FileTree.js +0 -47
- package/dist/components/FileTree.js.map +0 -1
- package/dist/components/ResourceSelectInput.d.ts +0 -4
- package/dist/components/ResourceSelectInput.d.ts.map +0 -1
- package/dist/components/ResourceSelectInput.js +0 -7
- package/dist/components/ResourceSelectInput.js.map +0 -1
- package/dist/components/ResourceTable.d.ts +0 -4
- package/dist/components/ResourceTable.d.ts.map +0 -1
- package/dist/components/ResourceTable.js +0 -18
- package/dist/components/ResourceTable.js.map +0 -1
- package/dist/components/TabBar.d.ts +0 -4
- package/dist/components/TabBar.d.ts.map +0 -1
- package/dist/components/TabBar.js +0 -17
- package/dist/components/TabBar.js.map +0 -1
- package/dist/components/Tooltip.d.ts +0 -12
- package/dist/components/Tooltip.d.ts.map +0 -1
- package/dist/components/Tooltip.js +0 -12
- package/dist/components/Tooltip.js.map +0 -1
- package/dist/components/index.d.ts +0 -8
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/index.js.map +0 -1
- package/dist/config/platform-standards.d.ts +0 -159
- package/dist/config/platform-standards.d.ts.map +0 -1
- package/dist/config/platform-standards.js +0 -181
- package/dist/config/platform-standards.js.map +0 -1
- package/dist/generator/extension-fetch.d.ts +0 -25
- package/dist/generator/extension-fetch.d.ts.map +0 -1
- package/dist/generator/extension-fetch.js +0 -252
- package/dist/generator/extension-fetch.js.map +0 -1
- package/dist/generator/template-engine.d.ts +0 -61
- package/dist/generator/template-engine.d.ts.map +0 -1
- package/dist/generator/template-engine.js +0 -557
- package/dist/generator/template-engine.js.map +0 -1
- package/dist/index.d.ts +0 -11
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -11
- package/dist/index.js.map +0 -1
- package/dist/types/index.d.ts +0 -255
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -17
- package/dist/types/index.js.map +0 -1
- package/dist/utils/cache.d.ts +0 -19
- package/dist/utils/cache.d.ts.map +0 -1
- package/dist/utils/cache.js +0 -64
- package/dist/utils/cache.js.map +0 -1
- package/dist/utils/command-helpers.d.ts +0 -17
- package/dist/utils/command-helpers.d.ts.map +0 -1
- package/dist/utils/command-helpers.js +0 -41
- package/dist/utils/command-helpers.js.map +0 -1
- package/dist/utils/constants.d.ts +0 -52
- package/dist/utils/constants.d.ts.map +0 -1
- package/dist/utils/constants.js +0 -112
- package/dist/utils/constants.js.map +0 -1
- package/dist/utils/discovery-context.d.ts +0 -4
- package/dist/utils/discovery-context.d.ts.map +0 -1
- package/dist/utils/discovery-context.js +0 -39
- package/dist/utils/discovery-context.js.map +0 -1
- package/dist/utils/docker.d.ts +0 -4
- package/dist/utils/docker.d.ts.map +0 -1
- package/dist/utils/docker.js +0 -19
- package/dist/utils/docker.js.map +0 -1
- package/dist/utils/doctor-runtime.d.ts +0 -66
- package/dist/utils/doctor-runtime.d.ts.map +0 -1
- package/dist/utils/doctor-runtime.js +0 -469
- package/dist/utils/doctor-runtime.js.map +0 -1
- package/dist/utils/env-validator.d.ts +0 -15
- package/dist/utils/env-validator.d.ts.map +0 -1
- package/dist/utils/env-validator.js +0 -109
- package/dist/utils/env-validator.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -31
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -140
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/file-helpers.d.ts +0 -14
- package/dist/utils/file-helpers.d.ts.map +0 -1
- package/dist/utils/file-helpers.js +0 -45
- package/dist/utils/file-helpers.js.map +0 -1
- package/dist/utils/formatting.d.ts +0 -30
- package/dist/utils/formatting.d.ts.map +0 -1
- package/dist/utils/formatting.js +0 -164
- package/dist/utils/formatting.js.map +0 -1
- package/dist/utils/paths.d.ts +0 -3
- package/dist/utils/paths.d.ts.map +0 -1
- package/dist/utils/paths.js +0 -41
- package/dist/utils/paths.js.map +0 -1
- package/dist/utils/port-assignment.d.ts +0 -6
- package/dist/utils/port-assignment.d.ts.map +0 -1
- package/dist/utils/port-assignment.js +0 -81
- package/dist/utils/port-assignment.js.map +0 -1
- package/dist/utils/project-features.d.ts +0 -23
- package/dist/utils/project-features.d.ts.map +0 -1
- package/dist/utils/project-features.js +0 -98
- package/dist/utils/project-features.js.map +0 -1
- package/dist/utils/project-templates.d.ts +0 -7
- package/dist/utils/project-templates.d.ts.map +0 -1
- package/dist/utils/project-templates.js +0 -24
- package/dist/utils/project-templates.js.map +0 -1
- package/dist/utils/prompt.d.ts +0 -28
- package/dist/utils/prompt.d.ts.map +0 -1
- package/dist/utils/prompt.js +0 -79
- package/dist/utils/prompt.js.map +0 -1
- package/dist/utils/resource-features.d.ts +0 -29
- package/dist/utils/resource-features.d.ts.map +0 -1
- package/dist/utils/resource-features.js +0 -171
- package/dist/utils/resource-features.js.map +0 -1
- package/dist/utils/service-urls.d.ts +0 -30
- package/dist/utils/service-urls.d.ts.map +0 -1
- package/dist/utils/service-urls.js +0 -93
- package/dist/utils/service-urls.js.map +0 -1
- package/dist/utils/services.d.ts +0 -18
- package/dist/utils/services.d.ts.map +0 -1
- package/dist/utils/services.js +0 -291
- package/dist/utils/services.js.map +0 -1
- package/dist/utils/stack-features.d.ts +0 -22
- package/dist/utils/stack-features.d.ts.map +0 -1
- package/dist/utils/stack-features.js +0 -13
- package/dist/utils/stack-features.js.map +0 -1
- package/dist/utils/tar.d.ts +0 -7
- package/dist/utils/tar.d.ts.map +0 -1
- package/dist/utils/tar.js +0 -21
- package/dist/utils/tar.js.map +0 -1
- package/dist/utils/tilt.d.ts +0 -19
- package/dist/utils/tilt.d.ts.map +0 -1
- package/dist/utils/tilt.js +0 -78
- package/dist/utils/tilt.js.map +0 -1
- package/dist/utils/validation.d.ts +0 -16
- package/dist/utils/validation.d.ts.map +0 -1
- package/dist/utils/validation.js +0 -58
- package/dist/utils/validation.js.map +0 -1
- /package/{README.md → cli/README.md} +0 -0
- /package/{bin → cli/bin}/tdk.js +0 -0
- /package/{templates → cli/templates}/.tiltignore.hbs +0 -0
- /package/{templates → cli/templates}/TILT_RESOURCE_DEFAULTS.star.hbs +0 -0
- /package/{templates → cli/templates}/TILT_TECH_STACK.star.hbs +0 -0
- /package/{templates → cli/templates}/spec.master.hbs +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { DiscoveredResource } from "../types/index.js";
|
|
4
|
+
import { findProjectRoot } from "./paths.js";
|
|
5
|
+
|
|
6
|
+
export interface HealthTarget {
|
|
7
|
+
name: string;
|
|
8
|
+
appType: "frontend" | "backend";
|
|
9
|
+
url: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface HealthProbe extends HealthTarget {
|
|
13
|
+
ok: boolean;
|
|
14
|
+
/** HTTP status code, or undefined when the request never completed. */
|
|
15
|
+
status?: number;
|
|
16
|
+
/** Failure reason when the request never completed (DNS, refused, timeout). */
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getProjectName(): string {
|
|
21
|
+
const root = findProjectRoot();
|
|
22
|
+
if (root) {
|
|
23
|
+
try {
|
|
24
|
+
const content = readFileSync(join(root, ".tdk", "project.json"), "utf-8");
|
|
25
|
+
const parsed = JSON.parse(content);
|
|
26
|
+
if (parsed?.project?.name) {
|
|
27
|
+
return parsed.project.name;
|
|
28
|
+
}
|
|
29
|
+
} catch {}
|
|
30
|
+
}
|
|
31
|
+
return "beauty-crm";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function resolveSubdomainBases(): { appBase: string; apiBase: string } {
|
|
35
|
+
const projectName = getProjectName();
|
|
36
|
+
const raw = process.env.TDK_SERVICE_BASE_URL ?? `http://${projectName}.localhost`;
|
|
37
|
+
try {
|
|
38
|
+
const u = new URL(raw.includes("://") ? raw : `http://${raw}`);
|
|
39
|
+
const host = u.hostname;
|
|
40
|
+
if (host === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(host)) {
|
|
41
|
+
return {
|
|
42
|
+
appBase: `${u.protocol}//${host}${u.port ? `:${u.port}` : ""}`,
|
|
43
|
+
apiBase: `${u.protocol}//${host}${u.port ? `:${u.port}` : ""}`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
const bare = host.replace(/^(app|api)\./, "");
|
|
47
|
+
return {
|
|
48
|
+
appBase: `${u.protocol}//app.${bare}${u.port ? `:${u.port}` : ""}`,
|
|
49
|
+
apiBase: `${u.protocol}//api.${bare}${u.port ? `:${u.port}` : ""}`,
|
|
50
|
+
};
|
|
51
|
+
} catch {
|
|
52
|
+
return {
|
|
53
|
+
appBase: `http://app.${projectName}.localhost`,
|
|
54
|
+
apiBase: `http://api.${projectName}.localhost`,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function appendHealthPath(path: string): string {
|
|
60
|
+
return `${path.replace(/\/+$/, "")}/health`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** The route `tdk up` advertises for a service, without the /health suffix. */
|
|
64
|
+
export function resolveServicePath(resource: DiscoveredResource): string {
|
|
65
|
+
if (resource.config?.appType === "backend") {
|
|
66
|
+
const servicePathName = resource.name.replace(/-api$/, "");
|
|
67
|
+
return resource.config?.apiPath ?? `/api/${servicePathName}`;
|
|
68
|
+
}
|
|
69
|
+
return resource.config?.basePath ?? `/${resource.name}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Health URLs for every routable service, matching what `tdk up` prints.
|
|
74
|
+
* Workers, libraries, SDKs and migrators have no Traefik route, so they are
|
|
75
|
+
* skipped rather than reported as unreachable.
|
|
76
|
+
*/
|
|
77
|
+
export function buildHealthTargets(resources: DiscoveredResource[]): HealthTarget[] {
|
|
78
|
+
const { appBase, apiBase } = resolveSubdomainBases();
|
|
79
|
+
|
|
80
|
+
return resources
|
|
81
|
+
.filter(
|
|
82
|
+
(
|
|
83
|
+
resource,
|
|
84
|
+
): resource is DiscoveredResource & { config: { appType: "frontend" | "backend" } } =>
|
|
85
|
+
resource.config?.appType === "frontend" || resource.config?.appType === "backend",
|
|
86
|
+
)
|
|
87
|
+
.map((resource) => {
|
|
88
|
+
const base = resource.config.appType === "backend" ? apiBase : appBase;
|
|
89
|
+
return {
|
|
90
|
+
name: resource.name,
|
|
91
|
+
appType: resource.config.appType,
|
|
92
|
+
url: `${base}${appendHealthPath(resolveServicePath(resource))}`,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export async function pingHealthTarget(
|
|
98
|
+
target: HealthTarget,
|
|
99
|
+
timeoutMs: number,
|
|
100
|
+
): Promise<HealthProbe> {
|
|
101
|
+
try {
|
|
102
|
+
const response = await fetch(target.url, {
|
|
103
|
+
method: "GET",
|
|
104
|
+
redirect: "manual",
|
|
105
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
106
|
+
});
|
|
107
|
+
return { ...target, ok: response.ok, status: response.status };
|
|
108
|
+
} catch (err: unknown) {
|
|
109
|
+
const error =
|
|
110
|
+
err instanceof Error && err.name === "TimeoutError"
|
|
111
|
+
? `no response within ${timeoutMs}ms`
|
|
112
|
+
: err instanceof Error
|
|
113
|
+
? err.message
|
|
114
|
+
: String(err);
|
|
115
|
+
return { ...target, ok: false, error };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export async function pingHealthTargets(
|
|
120
|
+
targets: HealthTarget[],
|
|
121
|
+
timeoutMs: number,
|
|
122
|
+
): Promise<HealthProbe[]> {
|
|
123
|
+
return Promise.all(targets.map((target) => pingHealthTarget(target, timeoutMs)));
|
|
124
|
+
}
|
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import type {
|
|
4
|
+
AutogeneratedFile,
|
|
5
|
+
DiscoveredResource,
|
|
6
|
+
DiscoveredStack,
|
|
7
|
+
FileType,
|
|
8
|
+
ResourceConfig,
|
|
9
|
+
ResourceMetadata,
|
|
10
|
+
ResourceType,
|
|
11
|
+
StackMetadata,
|
|
12
|
+
} from "../types/index.js";
|
|
13
|
+
import { Cache, createCacheValidator } from "./cache.js";
|
|
14
|
+
import { AUTOGENERATED_FILE_PATTERNS, SKIP_DIRECTORIES } from "./constants.js";
|
|
15
|
+
import { formatCount } from "./formatting.js";
|
|
16
|
+
import { findProjectRoot } from "./paths.js";
|
|
17
|
+
import { includes } from "./validation.js";
|
|
18
|
+
|
|
19
|
+
const RESOURCE_JSON_FILENAME = "service.json";
|
|
20
|
+
|
|
21
|
+
function findServiceJsonFiles(
|
|
22
|
+
dir: string,
|
|
23
|
+
maxDepth: number = 5,
|
|
24
|
+
currentDepth: number = 0,
|
|
25
|
+
): string[] {
|
|
26
|
+
const results: string[] = [];
|
|
27
|
+
|
|
28
|
+
if (currentDepth > maxDepth) {
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
33
|
+
|
|
34
|
+
for (const entry of entries) {
|
|
35
|
+
const fullPath = join(dir, entry.name);
|
|
36
|
+
|
|
37
|
+
if (entry.isDirectory()) {
|
|
38
|
+
if (shouldSkipDirectory(entry.name)) continue;
|
|
39
|
+
results.push(...findServiceJsonFiles(fullPath, maxDepth, currentDepth + 1));
|
|
40
|
+
} else if (entry.isFile() && entry.name === RESOURCE_JSON_FILENAME) {
|
|
41
|
+
results.push(fullPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function shouldSkipDirectory(name: string): boolean {
|
|
49
|
+
return includes(SKIP_DIRECTORIES, name) || name.startsWith(".");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function isValidResourceConfig(value: unknown): value is ResourceConfig {
|
|
53
|
+
if (!value || typeof value !== "object") return false;
|
|
54
|
+
const config = value as Record<string, unknown>;
|
|
55
|
+
// Accept runtime, appType, or type (for backward compatibility with existing service.json files)
|
|
56
|
+
const hasRuntimeOrAppType =
|
|
57
|
+
typeof config.runtime === "string" ||
|
|
58
|
+
typeof config.appType === "string" ||
|
|
59
|
+
typeof config.type === "string";
|
|
60
|
+
return typeof config.appName === "string" && hasRuntimeOrAppType;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function parseResource(serviceJsonPath: string): DiscoveredResource {
|
|
64
|
+
const content = readFileSync(serviceJsonPath, "utf-8");
|
|
65
|
+
const parsed: unknown = JSON.parse(content);
|
|
66
|
+
|
|
67
|
+
if (!isValidResourceConfig(parsed)) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Invalid service.json at ${serviceJsonPath}: missing required fields (appName, runtime or appType)`,
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const parsedConfig = parsed as unknown as ResourceConfig;
|
|
74
|
+
const config: ResourceConfig = {
|
|
75
|
+
...parsedConfig,
|
|
76
|
+
appType: (parsedConfig.appType || (parsedConfig as any).type) as ResourceConfig["appType"],
|
|
77
|
+
};
|
|
78
|
+
const resourceDir = dirname(serviceJsonPath);
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
name: config.appName,
|
|
82
|
+
path: resourceDir,
|
|
83
|
+
configPath: serviceJsonPath,
|
|
84
|
+
config,
|
|
85
|
+
stack: config.stack,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function discoverResourcesFromRoot(projectRoot: string): DiscoveredResource[] {
|
|
90
|
+
const serviceJsonPaths = findServiceJsonFiles(projectRoot);
|
|
91
|
+
const resources: DiscoveredResource[] = [];
|
|
92
|
+
|
|
93
|
+
for (const path of serviceJsonPaths) {
|
|
94
|
+
resources.push(parseResource(path));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return resources;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function discoverResources(): DiscoveredResource[] {
|
|
101
|
+
const projectRoot = findProjectRoot();
|
|
102
|
+
|
|
103
|
+
if (!projectRoot) {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"Could not find project root (no Tiltfile found). Make sure you're in a root project.",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return discoverResourcesFromRoot(projectRoot);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Unique, sorted `stack` values across discovered service.json files under `projectRoot`.
|
|
114
|
+
* Tilt's discovery groups services by this same field (see tdk-cli-extensions
|
|
115
|
+
* discovery_orchestrator.star), so these are the names that must appear in a
|
|
116
|
+
* stack's `services` list in .tdk/project.json for that group to be enabled.
|
|
117
|
+
*/
|
|
118
|
+
export function discoverStackNames(projectRoot: string): string[] {
|
|
119
|
+
const resources = discoverResourcesFromRoot(projectRoot);
|
|
120
|
+
const stacks = new Set<string>();
|
|
121
|
+
|
|
122
|
+
for (const resource of resources) {
|
|
123
|
+
if (resource.stack) {
|
|
124
|
+
stacks.add(resource.stack);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return Array.from(stacks).sort();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export function getAllStacks(resources?: DiscoveredResource[]): string[] {
|
|
132
|
+
const resourcesToScan = resources || discoverResources();
|
|
133
|
+
const stacks = new Set<string>();
|
|
134
|
+
|
|
135
|
+
for (const resource of resourcesToScan) {
|
|
136
|
+
if (resource.stack) {
|
|
137
|
+
stacks.add(resource.stack);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return Array.from(stacks).sort();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function discoverStacks(): DiscoveredStack[] {
|
|
145
|
+
const resources = discoverResources();
|
|
146
|
+
const stackMap = new Map<string, DiscoveredResource[]>();
|
|
147
|
+
|
|
148
|
+
for (const resource of resources) {
|
|
149
|
+
if (resource.stack) {
|
|
150
|
+
const stackResources = stackMap.get(resource.stack);
|
|
151
|
+
if (stackResources) {
|
|
152
|
+
stackResources.push(resource);
|
|
153
|
+
} else {
|
|
154
|
+
stackMap.set(resource.stack, [resource]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const stacks: DiscoveredStack[] = [];
|
|
160
|
+
for (const [name, stackResources] of stackMap) {
|
|
161
|
+
stacks.push({
|
|
162
|
+
name,
|
|
163
|
+
description: formatCount(stackResources.length, "resource"),
|
|
164
|
+
resources: stackResources,
|
|
165
|
+
resourceCount: stackResources.length,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return stacks.sort((a, b) => a.name.localeCompare(b.name));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function getResourcesForStack(stackName: string): DiscoveredResource[] {
|
|
173
|
+
const allResources = discoverResources();
|
|
174
|
+
return allResources.filter((r) => r.stack === stackName);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function stackExists(stackName: string): boolean {
|
|
178
|
+
const resources = getResourcesForStack(stackName);
|
|
179
|
+
return resources.length > 0;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Cache TTL in milliseconds
|
|
184
|
+
*/
|
|
185
|
+
const CACHE_TTL_MS = 5000;
|
|
186
|
+
|
|
187
|
+
const resourcesCache = new Cache<ResourceMetadata>({ ttlMs: CACHE_TTL_MS });
|
|
188
|
+
const stacksCache = new Cache<StackMetadata>({ ttlMs: CACHE_TTL_MS });
|
|
189
|
+
const cacheValidator = createCacheValidator(CACHE_TTL_MS);
|
|
190
|
+
|
|
191
|
+
export function clearMetadataCache(): void {
|
|
192
|
+
resourcesCache.clear();
|
|
193
|
+
stacksCache.clear();
|
|
194
|
+
cacheValidator.reset();
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function detectFileType(filename: string, content?: string): FileType {
|
|
198
|
+
if (filename === "Dockerfile" || filename.startsWith("docker-compose")) {
|
|
199
|
+
return "docker";
|
|
200
|
+
}
|
|
201
|
+
if (filename === "Tiltfile" || filename.endsWith(".star")) {
|
|
202
|
+
return "tilt";
|
|
203
|
+
}
|
|
204
|
+
if (
|
|
205
|
+
filename === "vite.config.ts" ||
|
|
206
|
+
filename === "tsconfig.json" ||
|
|
207
|
+
filename === "package.json"
|
|
208
|
+
) {
|
|
209
|
+
return "config";
|
|
210
|
+
}
|
|
211
|
+
if (filename === "schema.prisma" || filename.includes("migration")) {
|
|
212
|
+
return "prisma";
|
|
213
|
+
}
|
|
214
|
+
if (content) {
|
|
215
|
+
const firstLines = content.split("\n").slice(0, 10).join("\n");
|
|
216
|
+
if (firstLines.includes("GENERATED BY TDK") || firstLines.includes("AUTOGENERATED")) {
|
|
217
|
+
return "generated";
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return "unknown";
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function getResourceMetadata(resource: DiscoveredResource): ResourceMetadata {
|
|
224
|
+
const cacheKey = resource.configPath;
|
|
225
|
+
|
|
226
|
+
if (cacheValidator.isValid()) {
|
|
227
|
+
const cached = resourcesCache.get(cacheKey);
|
|
228
|
+
if (cached) {
|
|
229
|
+
return cached;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const resourceDir = resource.path;
|
|
234
|
+
|
|
235
|
+
const stats = statSync(resource.configPath);
|
|
236
|
+
const createdAt = stats.mtime.toISOString();
|
|
237
|
+
const lastModified = stats.mtime.toISOString();
|
|
238
|
+
|
|
239
|
+
const autogeneratedFiles = discoverAutogeneratedFiles(resourceDir);
|
|
240
|
+
const hasDockerfile = existsSync(join(resourceDir, "Dockerfile"));
|
|
241
|
+
const hasTiltfile = existsSync(join(resourceDir, "Tiltfile"));
|
|
242
|
+
const hasDockerCompose =
|
|
243
|
+
existsSync(join(resourceDir, "docker-compose.yml")) ||
|
|
244
|
+
existsSync(join(resourceDir, "docker-compose.yaml"));
|
|
245
|
+
|
|
246
|
+
const configType = resource.config?.appType;
|
|
247
|
+
let type: ResourceType = configType || "backend";
|
|
248
|
+
if (!configType) {
|
|
249
|
+
if (resource.name.includes("frontend")) {
|
|
250
|
+
type = "frontend";
|
|
251
|
+
} else if (
|
|
252
|
+
resource.name.includes("sdk") ||
|
|
253
|
+
resource.name.includes("lib") ||
|
|
254
|
+
resource.name.includes("infra")
|
|
255
|
+
) {
|
|
256
|
+
type = "library";
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const metadata: ResourceMetadata = {
|
|
261
|
+
name: resource.name,
|
|
262
|
+
stack: resource.stack,
|
|
263
|
+
type,
|
|
264
|
+
port: resource.config?.port,
|
|
265
|
+
createdAt,
|
|
266
|
+
lastModified,
|
|
267
|
+
dependencies: resource.config?.dependsOn ?? [],
|
|
268
|
+
hasDockerfile,
|
|
269
|
+
hasTiltfile,
|
|
270
|
+
hasDockerCompose,
|
|
271
|
+
autogeneratedFiles,
|
|
272
|
+
status: "unknown",
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
resourcesCache.set(cacheKey, metadata);
|
|
276
|
+
cacheValidator.markUpdated();
|
|
277
|
+
|
|
278
|
+
return metadata;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function discoverAutogeneratedFiles(resourceDir: string): AutogeneratedFile[] {
|
|
282
|
+
const files: AutogeneratedFile[] = [];
|
|
283
|
+
|
|
284
|
+
for (const pattern of AUTOGENERATED_FILE_PATTERNS) {
|
|
285
|
+
const filePath = join(resourceDir, pattern);
|
|
286
|
+
if (existsSync(filePath)) {
|
|
287
|
+
const stats = statSync(filePath);
|
|
288
|
+
const content = readFileSync(filePath, "utf-8");
|
|
289
|
+
|
|
290
|
+
files.push({
|
|
291
|
+
name: pattern,
|
|
292
|
+
path: filePath,
|
|
293
|
+
type: detectFileType(pattern, content),
|
|
294
|
+
size: stats.size,
|
|
295
|
+
lastModified: stats.mtime.toISOString(),
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const prismaDir = join(resourceDir, "prisma");
|
|
301
|
+
if (existsSync(prismaDir)) {
|
|
302
|
+
const entries = readdirSync(prismaDir);
|
|
303
|
+
for (const entry of entries) {
|
|
304
|
+
if (entry === "schema.prisma" || entry.includes("migration")) {
|
|
305
|
+
const filePath = join(prismaDir, entry);
|
|
306
|
+
const stats = statSync(filePath);
|
|
307
|
+
files.push({
|
|
308
|
+
name: `prisma/${entry}`,
|
|
309
|
+
path: filePath,
|
|
310
|
+
type: "prisma",
|
|
311
|
+
size: stats.size,
|
|
312
|
+
lastModified: stats.mtime.toISOString(),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return files.sort((a, b) => a.name.localeCompare(b.name));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function getStackMetadata(stack: DiscoveredStack): StackMetadata {
|
|
322
|
+
const cacheKey = stack.name;
|
|
323
|
+
|
|
324
|
+
if (cacheValidator.isValid()) {
|
|
325
|
+
const cached = stacksCache.get(cacheKey);
|
|
326
|
+
if (cached) {
|
|
327
|
+
return cached;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const resourcesMetadata = stack.resources.map((r) => getResourceMetadata(r));
|
|
332
|
+
const timestamps = resourcesMetadata.map((r) => new Date(r.createdAt).getTime());
|
|
333
|
+
const earliestTimestamp = Math.min(...timestamps);
|
|
334
|
+
const latestTimestamp = Math.max(...timestamps);
|
|
335
|
+
const totalResources = resourcesMetadata.length;
|
|
336
|
+
|
|
337
|
+
let overallStatus: StackMetadata["overallStatus"] = "unknown";
|
|
338
|
+
if (totalResources > 0) {
|
|
339
|
+
const readyCount = resourcesMetadata.filter((r) => r.status === "ready").length;
|
|
340
|
+
const ratio = readyCount / totalResources;
|
|
341
|
+
if (ratio > 0.9) {
|
|
342
|
+
overallStatus = "healthy";
|
|
343
|
+
} else if (ratio > 0.5) {
|
|
344
|
+
overallStatus = "degraded";
|
|
345
|
+
} else {
|
|
346
|
+
overallStatus = "error";
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const metadata: StackMetadata = {
|
|
351
|
+
name: stack.name,
|
|
352
|
+
resourceCount: resourcesMetadata.length,
|
|
353
|
+
createdAt: new Date(earliestTimestamp).toISOString(),
|
|
354
|
+
lastModified: new Date(latestTimestamp).toISOString(),
|
|
355
|
+
resources: resourcesMetadata,
|
|
356
|
+
overallStatus,
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
stacksCache.set(cacheKey, metadata);
|
|
360
|
+
cacheValidator.markUpdated();
|
|
361
|
+
|
|
362
|
+
return metadata;
|
|
363
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface StackFeature {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
generatedFiles: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const STACK_FEATURES: Record<string, StackFeature> = {
|
|
8
|
+
"database-management": {
|
|
9
|
+
name: "database-management",
|
|
10
|
+
description: "Generate and load the stack-level PostgreSQL docker-compose file",
|
|
11
|
+
generatedFiles: ["services/platform/database-management/docker-compose.yml"],
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export interface StackFeaturePhaseConfig {
|
|
16
|
+
pre_alpha?: { enabledStacks?: string[] };
|
|
17
|
+
alpha?: { enabledStacks?: string[] };
|
|
18
|
+
beta?: { enabledStacks?: string[] };
|
|
19
|
+
out_of_scope?: { enabledStacks?: string[] };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isStackFeatureEnabledInStacks(
|
|
23
|
+
stacks: StackFeaturePhaseConfig,
|
|
24
|
+
featureName: string,
|
|
25
|
+
): boolean {
|
|
26
|
+
if (!STACK_FEATURES[featureName]) return false;
|
|
27
|
+
return ["pre_alpha", "alpha", "beta"].some((phase) =>
|
|
28
|
+
stacks[phase as keyof StackFeaturePhaseConfig]?.enabledStacks?.includes(featureName),
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Extracts a gzipped tarball (as an in-memory buffer) into destDir.
|
|
8
|
+
* Shells out to the system `tar` binary rather than pulling in a JS tar
|
|
9
|
+
* implementation - available by default on macOS and Linux.
|
|
10
|
+
*/
|
|
11
|
+
export function extractTarball(data: Buffer, destDir: string): void {
|
|
12
|
+
const tmpFile = join(mkdtempSync(join(tmpdir(), "tdk-ext-")), "bundle.tar.gz");
|
|
13
|
+
writeFileSync(tmpFile, data);
|
|
14
|
+
|
|
15
|
+
const result = spawnSync("tar", ["xzf", tmpFile, "-C", destDir, "--strip-components=1"], {
|
|
16
|
+
stdio: "pipe",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
rmSync(join(tmpFile, ".."), { recursive: true, force: true });
|
|
20
|
+
|
|
21
|
+
if (result.status !== 0) {
|
|
22
|
+
throw new Error(`tar extraction failed: ${result.stderr?.toString() || "unknown error"}`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import type { TiltCommandResult } from "../types/index.js";
|
|
4
|
+
import { findProjectRoot } from "./paths.js";
|
|
5
|
+
|
|
6
|
+
export function runTilt(
|
|
7
|
+
command: string,
|
|
8
|
+
args: string[] = [],
|
|
9
|
+
options: {
|
|
10
|
+
verbose?: boolean;
|
|
11
|
+
quiet?: boolean;
|
|
12
|
+
inheritStdio?: boolean;
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
} = {},
|
|
15
|
+
): Promise<TiltCommandResult> {
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
const tiltArgs = [command, ...args];
|
|
18
|
+
|
|
19
|
+
if (options.verbose) {
|
|
20
|
+
console.log(`Executing: tilt ${tiltArgs.join(" ")}`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const child = spawn("tilt", tiltArgs, {
|
|
24
|
+
stdio: options.inheritStdio ? "inherit" : "pipe",
|
|
25
|
+
shell: false,
|
|
26
|
+
timeout: options.timeoutMs,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
let stdout = "";
|
|
30
|
+
let stderr = "";
|
|
31
|
+
|
|
32
|
+
if (!options.inheritStdio) {
|
|
33
|
+
child.stdout?.on("data", (data: Buffer) => {
|
|
34
|
+
stdout += data.toString();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
child.stderr?.on("data", (data: Buffer) => {
|
|
38
|
+
stderr += data.toString();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
child.on("close", (code) => {
|
|
43
|
+
resolve({
|
|
44
|
+
exitCode: code ?? 1,
|
|
45
|
+
stdout,
|
|
46
|
+
stderr,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
child.on("error", (err) => {
|
|
51
|
+
reject(new Error(`Failed to spawn tilt: ${err.message}`));
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function isTiltAvailable(): Promise<boolean> {
|
|
57
|
+
try {
|
|
58
|
+
const result = await runTilt("version", [], { inheritStdio: false, timeoutMs: 10_000 });
|
|
59
|
+
return result.exitCode === 0;
|
|
60
|
+
} catch {
|
|
61
|
+
// tilt binary not found (or not spawnable) - treat as unavailable
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function getTiltfilePath(): string {
|
|
67
|
+
const projectRoot = findProjectRoot();
|
|
68
|
+
if (!projectRoot) {
|
|
69
|
+
throw new Error("Not in a TDK project (no .tdk/project.json found)");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return join(projectRoot, ".tdk", ".tdk-out", "Tiltfile");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function addTiltfilePath(args: string[]): void {
|
|
76
|
+
const tiltfilePath = getTiltfilePath();
|
|
77
|
+
args.push("-f", tiltfilePath);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function buildTiltUpArgs(
|
|
81
|
+
serviceNames: string[],
|
|
82
|
+
options: {
|
|
83
|
+
verbose?: boolean;
|
|
84
|
+
quiet?: boolean;
|
|
85
|
+
force?: boolean;
|
|
86
|
+
watch?: boolean;
|
|
87
|
+
} = {},
|
|
88
|
+
): string[] {
|
|
89
|
+
const args: string[] = [];
|
|
90
|
+
addTiltfilePath(args);
|
|
91
|
+
args.push(...serviceNames);
|
|
92
|
+
|
|
93
|
+
if (options.verbose && !options.quiet) {
|
|
94
|
+
args.push("--verbose");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (options.watch) {
|
|
98
|
+
args.push("--watch");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return args;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function buildTiltDownArgs(options: { force?: boolean } = {}): string[] {
|
|
105
|
+
const args: string[] = [];
|
|
106
|
+
addTiltfilePath(args);
|
|
107
|
+
|
|
108
|
+
if (options.force) {
|
|
109
|
+
args.push("--force");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return args;
|
|
113
|
+
}
|