@tdk-landscape/tdk-cli-core 1.3.145 → 1.3.147

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/CHANGELOG.md +1 -0
  2. package/README.md +4 -2
  3. package/Tiltfile +2 -0
  4. package/cli/dist/commands/doctor.js +49 -2
  5. package/cli/dist/utils/doctor-runtime.js +60 -0
  6. package/cli/dist/utils/host-port-config.js +11 -2
  7. package/cli/dist/utils/host-port-plan.js +25 -3
  8. package/cli/dist/utils/service-urls.js +16 -2
  9. package/cli/dist/utils/smoke.js +28 -0
  10. package/cli/dist-bundle/chunk-LNZN426S.js +321 -0
  11. package/cli/dist-bundle/cli.js +3 -3
  12. package/cli/dist-bundle/{cold-preflight-F2FM46HK.js → cold-preflight-D7CAIHND.js} +1 -1
  13. package/cli/package.json +1 -1
  14. package/cli/templates/Tiltfile.hbs +12 -0
  15. package/discovery/config.star +1 -1
  16. package/engine/Tiltfile +2 -0
  17. package/engine/assets/docker/golden-layers.Dockerfile +8 -25
  18. package/engine/assets/scripts/cleanup-tilt-images.sh +2 -2
  19. package/engine/topologies/platform/docker/build/frontend_build_plan.star +65 -0
  20. package/engine/topologies/platform/docker/build/golden_image_build.star +110 -48
  21. package/engine/topologies/platform/docker/build/golden_image_constants.star +13 -6
  22. package/engine/topologies/platform/docker/build/golden_image_dockerfile.star +8 -27
  23. package/engine/topologies/platform/docker/layers/l3_builder_layers.star +3 -1
  24. package/engine/topologies/platform/docker/layers/prisma/constants.star +2 -1
  25. package/engine/topologies/tilt/resources/build_concurrency.star +56 -0
  26. package/engine/topologies/tilt/resources/infra-loader.star +4 -0
  27. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +24 -2
  28. package/engine/topologies/tilt/resources/orchestrator/generators/manifest_resource.star +5 -1
  29. package/engine/topologies/tilt/resources/watchers.star +7 -4
  30. package/package.json +1 -1
  31. package/cli/dist-bundle/chunk-47CDYJ5E.js +0 -316
@@ -38,13 +38,16 @@ def generate_golden_dockerfile():
38
38
  # This Dockerfile builds 8 golden images:
39
39
  # - """ + prefix + """-l1:latest - OS base + Bun runtime
40
40
  # - """ + prefix + """-l2:latest - Dependencies installed
41
- # - """ + prefix + """-l3-backend:latest - Backend build tools (Prisma, no Infisical CLI)
41
+ # - """ + prefix + """-l3-backend:latest - Backend and migrator build tools (Prisma, no Infisical CLI)
42
42
  # - """ + prefix + """-l3-frontend:latest - Frontend build tools (no Prisma)
43
- # - """ + prefix + """-l3-migrator:latest - Migrator build tools (Prisma, no Infisical CLI)
44
- # - """ + prefix + """-l4-backend:latest - Backend production runtime
43
+ # - """ + prefix + """-l4-backend:latest - Backend production runtime (Bun)
44
+ # - """ + prefix + """-l4-backend-node:latest - Backend production runtime (Node.js)
45
45
  # - """ + prefix + """-l4-frontend:latest - Frontend production runtime (Nginx)
46
46
  # - """ + prefix + """-l4-migrator:latest - Migrator production runtime
47
47
  #
48
+ # Migrators build on l3-backend: a separate l3-migrator stage installed the same Prisma
49
+ # and produced identical layers under a second image name.
50
+ #
48
51
  # Services use these as base images to skip heavy dependency installation.
49
52
  #
50
53
  # ⚠️ SKIP_INFISICAL_SETUP Support:
@@ -139,28 +142,6 @@ LABEL layer="l3-frontend" \
139
142
  RUN echo "Bun version: $(bun --version)"
140
143
 
141
144
 
142
- # =============================================================================
143
- # L3-MIGRATOR: MIGRATOR BUILD TOOLS (PRISMA)
144
- # =============================================================================
145
- FROM l2_golden AS l3_migrator_golden
146
-
147
- LABEL layer="l3-migrator" \
148
- description="Migrator build tools with Prisma" \
149
- maintainer="{prefix}"
150
-
151
- # Install Prisma CLI globally (required for migrations, pinned)
152
- RUN bun add -g prisma@7.5.0 @prisma/client@7.5.0
153
-
154
- # Verify Prisma installation
155
- RUN echo "Prisma version: $(bunx prisma --version | head -1)"
156
-
157
- # ⚠️ CRITICAL: Infisical CLI is NOT installed in golden L3 images
158
- # Reason: curl to dl.cloudsmith.io hangs during Docker builds when CDN is slow
159
- # Solution: Use SKIP_INFISICAL_SETUP=1 build arg or runtime env var injection
160
- # Services read secrets from environment variables at runtime (no CLI needed)
161
- # See: .tilt/topologies/platform/docker/layers/l3_builder_layers.star
162
-
163
-
164
145
  # =============================================================================
165
146
  # L4-BACKEND-BUN: BACKEND PRODUCTION RUNTIME (BUN)
166
147
  # =============================================================================
@@ -256,8 +237,8 @@ LABEL layer="l4-migrator" \
256
237
 
257
238
  ENV NODE_ENV=production
258
239
 
259
- # Copy global Prisma installation from L3
260
- COPY --from=l3_migrator_golden /root/.bun/install/global /root/.bun/install/global
240
+ # Copy global Prisma installation from L3 (l3-backend carries the same pinned Prisma)
241
+ COPY --from=l3_backend_golden /root/.bun/install/global /root/.bun/install/global
261
242
 
262
243
  # ⚠️ Infisical CLI is NOT included in golden L4 images
263
244
  # The migrator reads secrets directly from environment variables at runtime
@@ -172,8 +172,10 @@ def L3_generate_frontend_builder(res_path, build_cmd = RUNTIME_CONFIG["bun"]["ba
172
172
  # Args passed after the script name are appended to the end of the script
173
173
  # command, so they reach `vite build` while any preceding steps in the
174
174
  # script (e.g. `tsc --noEmit &&`) still run.
175
+ # A build script that already names a config (the CLI scaffold does) keeps its own; a second --config is not added.
176
+ config_flag = "" if "--config" in build_cmd else " --config " + AUTOGENERATED_CONFIG_PATHS['vite_build']
175
177
  parts.append(
176
- "RUN " + build_cmd + " --config " + AUTOGENERATED_CONFIG_PATHS['vite_build'] + "\n"
178
+ "RUN " + build_cmd + config_flag + "\n"
177
179
  )
178
180
  return "".join(parts)
179
181
 
@@ -83,7 +83,8 @@ def _load_golden_prefix():
83
83
 
84
84
  _GOLDEN_PREFIX = _load_golden_prefix()
85
85
 
86
- DEFAULT_GOLDEN_L3_MIGRATOR_IMAGE = _GOLDEN_PREFIX + "-l3-migrator:latest"
86
+ # Migrators build on l3-backend; the golden build no longer makes a separate l3-migrator image.
87
+ DEFAULT_GOLDEN_L3_MIGRATOR_IMAGE = _GOLDEN_PREFIX + "-l3-backend:latest"
87
88
  DEFAULT_GOLDEN_L4_MIGRATOR_IMAGE = _GOLDEN_PREFIX + "-l4-migrator:latest"
88
89
 
89
90
  DEFAULT_DB_PORT = "5432"
@@ -0,0 +1,56 @@
1
+ # =============================================================================
2
+ # 🏗️ TILT SDK - BUILD CONCURRENCY
3
+ # =============================================================================
4
+ # Sets Tilt's maximum parallel updates from the Docker engine's CPU count and
5
+ # memory, instead of Tilt's default, so a warm `tdk up` on a machine with spare
6
+ # capacity builds more than three images at once.
7
+ #
8
+ # Override with TDK_MAX_PARALLEL_BUILDS=<positive integer>.
9
+ # =============================================================================
10
+
11
+ MIN_PARALLEL_BUILDS = 3
12
+ MAX_PARALLEL_BUILDS = 8
13
+ # CPUs kept free for Tilt, the Traefik/Postgres containers and the host.
14
+ RESERVED_CPUS = 2
15
+ # Rough peak memory per concurrent image build (Vite and tsc dominate).
16
+ BUILD_MEMORY_BUDGET_BYTES = 1610612736 # 1.5 GiB
17
+
18
+
19
+ def _is_positive_int(text):
20
+ return len(text) > 0 and text.isdigit() and int(text) > 0
21
+
22
+
23
+ def _engine_resources():
24
+ """Returns (cpus, memory_bytes) from `docker info`, or None when unavailable."""
25
+ out = str(local(
26
+ "docker info --format '{{.NCPU}} {{.MemTotal}}' 2>/dev/null || true",
27
+ quiet=True,
28
+ echo_off=True,
29
+ )).strip()
30
+ parts = out.split(' ')
31
+ if len(parts) != 2 or not parts[0].isdigit() or not parts[1].isdigit():
32
+ return None
33
+ return (int(parts[0]), int(parts[1]))
34
+
35
+
36
+ def compute_max_parallel_builds(cpus, memory_bytes):
37
+ """The concurrency for an engine with `cpus` CPUs and `memory_bytes` of memory."""
38
+ by_cpu = cpus - RESERVED_CPUS
39
+ by_memory = memory_bytes // BUILD_MEMORY_BUDGET_BYTES
40
+ return max(MIN_PARALLEL_BUILDS, min(MAX_PARALLEL_BUILDS, min(by_cpu, by_memory)))
41
+
42
+
43
+ def configure_build_concurrency():
44
+ """Calls update_settings once with the chosen max_parallel_updates. Call at Tiltfile load."""
45
+ override = os.environ.get('TDK_MAX_PARALLEL_BUILDS', '').strip()
46
+ if _is_positive_int(override):
47
+ value = int(override)
48
+ print("🧮 Parallel builds: " + str(value) + " (TDK_MAX_PARALLEL_BUILDS)")
49
+ else:
50
+ resources = _engine_resources()
51
+ if resources == None:
52
+ print("🧮 Parallel builds: Tilt default (docker info unavailable, so the engine's CPU and memory could not be read)")
53
+ return
54
+ value = compute_max_parallel_builds(resources[0], resources[1])
55
+ print("🧮 Parallel builds: " + str(value) + " (from Docker engine: " + str(resources[0]) + " CPUs)")
56
+ update_settings(max_parallel_updates=value)
@@ -21,6 +21,7 @@
21
21
  # =============================================================================
22
22
 
23
23
  load("../common/utils_debug.star", "debug_log")
24
+ load("./build_concurrency.star", "configure_build_concurrency")
24
25
  load("../../platform/docker/constants.star", "PlatformDockerConstants")
25
26
  load("../../platform/docker/compose/traefik_standalone.star", "generate_standalone_traefik_compose")
26
27
  load("../../platform/docker/networking/sablier_container_cycle.star", "sablier_middleware_suffix")
@@ -442,6 +443,9 @@ def load_all_infrastructure(should_enable, fix_docker_networks_fn=None, docker_p
442
443
  if should_enable('monitoring') and should_enable('elk'):
443
444
  fail("Incompatible flags: 'monitoring' and 'elk' cannot both be enabled at the same time. Disable one of them.")
444
445
 
446
+ # Size Tilt's parallel image builds to the Docker engine before any build is queued
447
+ configure_build_concurrency()
448
+
445
449
  # Build golden image before other infrastructure (if enabled)
446
450
  golden_image_resource = None
447
451
  if docker_provider and write_fn:
@@ -11,6 +11,7 @@ OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
11
11
 
12
12
  load("../../common/utils_debug.star", "debug_log")
13
13
  load('../../../platform/docker/index.star', 'Docker')
14
+ load('../../../platform/docker/build/frontend_build_plan.star', 'frontend_build_plan')
14
15
  load('../../../platform/docker/constants.star', 'PlatformDockerConstants')
15
16
  load('../../../tilt/manifest/constants.star', 'BASE_PORT_FRONTEND', 'BASE_PORT_BACKEND')
16
17
  load('../../../platform/docker/networking/traefik_static_routes.star', 'generate_static_wake_route', 'normalize_abs_path')
@@ -575,11 +576,29 @@ def _should_skip_frontend(res, should_enable):
575
576
  return res.get('frontend', False) and should_enable('backends-only')
576
577
 
577
578
 
578
- def _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable):
579
+ def _register_frontend_typecheck(res, service_dir, typecheck_cmd):
580
+ """Non-blocking `<service>-typecheck` resource: runs the planned tsc command so type errors show in Tilt without gating the image.
581
+
582
+ The command runs on the host, so TypeScript must resolve from the service directory (`bun install`, at the
583
+ service or workspace root). Without it the resource fails with that instruction instead of a bare module error.
584
+ """
585
+ local_resource(
586
+ name=res['name'] + '-typecheck',
587
+ cmd="cd '" + service_dir + "' && { bunx tsc --version >/dev/null 2>&1 || { echo 'typecheck needs host dependencies: run bun install in " + service_dir + "'; exit 1; }; } && " + typecheck_cmd,
588
+ deps=[service_dir + '/src', service_dir + '/tsconfig.json'],
589
+ labels=['app.' + res['name'], 'typecheck'],
590
+ # tsc --noEmit writes no files, so it can run alongside the image builds.
591
+ allow_parallel=True,
592
+ )
593
+
594
+
595
+ def _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable, project_root=''):
579
596
  """Process a frontend resource and return compose entry."""
580
597
  target_path = res.get('target_path', manifest.get('target_path', '/usr/share/nginx/html'))
581
598
  use_nginx = 'nginx' in target_path or target_path == '/usr/share/nginx/html'
582
599
  port = res.get('port', manifest.get('port', BASE_PORT_FRONTEND))
600
+ service_dir = (project_root.rstrip('/') + '/' if project_root else '') + full_res_path
601
+ plan = frontend_build_plan(service_dir + '/package.json')
583
602
  Docker.frontend(
584
603
  res_path=full_res_path,
585
604
  resource_name=res['name'],
@@ -587,7 +606,10 @@ def _process_frontend_resource(res, manifest, full_res_path, resource_path, reso
587
606
  target_path=target_path,
588
607
  use_nginx=use_nginx,
589
608
  use_golden=should_enable('golden-image'),
609
+ build_cmd=plan['build_cmd'],
590
610
  )
611
+ if plan['typecheck']:
612
+ _register_frontend_typecheck(res, service_dir, plan['typecheck_cmd'])
591
613
  return Docker.frontend_compose(resource_path=resource_path, resource_name=resource_name, res=res, manifest=manifest)
592
614
 
593
615
 
@@ -735,7 +757,7 @@ def register_compose_resources(resource_config, ctx, runtime_flags, manifest_sta
735
757
  continue
736
758
 
737
759
  if res.get('frontend', False):
738
- entry = _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable)
760
+ entry = _process_frontend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable, ctx.get('project_root', ''))
739
761
  else:
740
762
  entry = _process_backend_resource(res, manifest, full_res_path, resource_path, resource_name, should_enable)
741
763
  # A deferStart resource has no container Traefik can discover via
@@ -32,6 +32,7 @@ load('../../../generators/nginx_conf.star', 'Nginx')
32
32
  load('../../../generators/api_gateway.star', 'ApiGateway')
33
33
  load('../../../generators/tsconfig.star', 'TSConfig')
34
34
  load('../../../../platform/docker/index.star', 'Docker')
35
+ load('../../../../platform/docker/build/frontend_build_plan.star', 'frontend_build_plan')
35
36
  load('../../../generators/npmrc.star', 'PackageConfig')
36
37
  load('../../libs.star', 'Libs')
37
38
  load('./env.star', 'EnvGenerators')
@@ -371,13 +372,16 @@ def _generate_all_configs_for_resource(
371
372
  target_path = resource_config.get('target_path', '/usr/share/nginx/html')
372
373
  use_nginx = 'nginx' in target_path or target_path == '/usr/share/nginx/html'
373
374
  port = resource_config.get('port', manifest.get('port', BASE_PORT_FRONTEND))
375
+ root = ctx.get('project_root', '')
376
+ plan = frontend_build_plan((root.rstrip('/') + '/' if root else '') + resource_path + '/package.json')
374
377
  dockerfile_content = Docker.frontend(
375
378
  res_path=resource_path,
376
379
  resource_name=resource_config['name'],
377
380
  port=port,
378
381
  target_path=target_path,
379
382
  use_nginx=use_nginx,
380
- use_golden=should_enable('golden-image')
383
+ use_golden=should_enable('golden-image'),
384
+ build_cmd=plan['build_cmd'],
381
385
  )
382
386
  elif provider_owned:
383
387
  dockerfile_content = Docker.backend_language(
@@ -89,14 +89,14 @@ def setup_utility_resources():
89
89
  )
90
90
 
91
91
  local_resource('prune-images',
92
- cmd='./.tdk/.tdk-out/ext/assets/scripts/cleanup-tilt-images.sh --keep 0 --force && docker image prune -f',
92
+ cmd='./.tdk/.tdk-out/tdk-cli-ext/engine/assets/scripts/cleanup-tilt-images.sh --keep 0 --force && docker image prune -f',
93
93
  resource_deps=[],
94
94
  labels=['dev.maintenance'],
95
95
  auto_init=False
96
96
  )
97
97
 
98
98
  local_resource('memory-optimizer',
99
- cmd='./.tdk/.tdk-out/ext/assets/scripts/mac-m1-resource-monitor.sh && ./.tdk/.tdk-out/ext/assets/scripts/cleanup-tilt-images.sh --keep 0 --force && docker image prune -f && docker builder prune -af --filter "until=24h"',
99
+ cmd='./.tdk/.tdk-out/tdk-cli-ext/engine/assets/scripts/mac-m1-resource-monitor.sh && ./.tdk/.tdk-out/tdk-cli-ext/engine/assets/scripts/cleanup-tilt-images.sh --keep 0 --force && docker image prune -f && docker builder prune -af --filter "until=24h"',
100
100
  resource_deps=[],
101
101
  labels=['dev.maintenance', 'mac-m1'],
102
102
  auto_init=False
@@ -121,12 +121,15 @@ def setup_utility_resources():
121
121
  else
122
122
  echo "$(date +%H:%M:%S) ✓ $count dangling images (threshold: 5)"
123
123
  fi
124
+ # Tilt tags every build as tilt-<hash>, so superseded builds stay tagged
125
+ # and are never dangling. Keep the newest 2 per service; running images are skipped.
126
+ ./.tdk/.tdk-out/tdk-cli-ext/engine/assets/scripts/cleanup-tilt-images.sh --keep 2 --force >/dev/null 2>&1 || true
124
127
  sleep 300
125
128
  done
126
129
  ''',
127
130
  resource_deps=[],
128
131
  labels=['dev.maintenance', 'mac-m1'],
129
- auto_init=False,
132
+ auto_init=True,
130
133
  )
131
134
 
132
135
  # Continuously reclaim heavyweight migrator images once migration succeeds.
@@ -134,7 +137,7 @@ def setup_utility_resources():
134
137
  serve_cmd='''
135
138
  echo "🧹 Migrator image cleanup started (every 45s)"
136
139
  while true; do
137
- ./.tdk/.tdk-out/ext/assets/scripts/cleanup-completed-migrator-images.sh || true
140
+ ./.tdk/.tdk-out/tdk-cli-ext/engine/assets/scripts/cleanup-completed-migrator-images.sh || true
138
141
  sleep 45
139
142
  done
140
143
  ''',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tdk-landscape/tdk-cli-core",
3
- "version": "1.3.145",
3
+ "version": "1.3.147",
4
4
  "description": "TDK CLI — start services on your machine.",
5
5
  "homepage": "https://tdk-landscape.github.io/tdk-website",
6
6
  "repository": {