@tdk-landscape/tdk-cli-core 1.3.50 → 1.3.52

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 (92) hide show
  1. package/.github/workflows/ci.yml +13 -0
  2. package/.github/workflows/release-binaries.yml +76 -1
  3. package/CHANGELOG.md +50 -0
  4. package/README.md +54 -17
  5. package/cli/README.md +16 -43
  6. package/cli/biome.json +0 -4
  7. package/cli/dist/commands/help.d.ts.map +1 -1
  8. package/cli/dist/commands/help.js +22 -39
  9. package/cli/dist/commands/help.js.map +1 -1
  10. package/cli/dist/commands/project.d.ts +6 -0
  11. package/cli/dist/commands/project.d.ts.map +1 -1
  12. package/cli/dist/commands/project.js +16 -0
  13. package/cli/dist/commands/project.js.map +1 -1
  14. package/cli/dist/commands/up.d.ts.map +1 -1
  15. package/cli/dist/commands/up.js +5 -0
  16. package/cli/dist/commands/up.js.map +1 -1
  17. package/cli/dist/commands/upgrade.d.ts +3 -0
  18. package/cli/dist/commands/upgrade.d.ts.map +1 -1
  19. package/cli/dist/commands/upgrade.js +43 -1
  20. package/cli/dist/commands/upgrade.js.map +1 -1
  21. package/cli/dist/utils/constants.d.ts +1 -1
  22. package/cli/dist/utils/constants.d.ts.map +1 -1
  23. package/cli/dist/utils/constants.js +1 -1
  24. package/cli/dist/utils/constants.js.map +1 -1
  25. package/cli/dist/utils/doctor-runtime.js +5 -5
  26. package/cli/dist/utils/doctor-runtime.js.map +1 -1
  27. package/cli/dist/utils/prompt.d.ts.map +1 -1
  28. package/cli/dist/utils/prompt.js +6 -1
  29. package/cli/dist/utils/prompt.js.map +1 -1
  30. package/cli/dist/utils/service-urls.js +1 -1
  31. package/cli/dist/utils/service-urls.js.map +1 -1
  32. package/cli/package.json +2 -1
  33. package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
  34. package/cli/src/commands/__tests__/doctor.test.ts +8 -8
  35. package/cli/src/commands/__tests__/upgrade.test.ts +90 -3
  36. package/cli/src/commands/help.ts +22 -39
  37. package/cli/src/commands/project.ts +20 -0
  38. package/cli/src/commands/up.ts +10 -0
  39. package/cli/src/commands/upgrade.ts +52 -1
  40. package/cli/src/utils/constants.ts +1 -1
  41. package/cli/src/utils/doctor-runtime.ts +5 -5
  42. package/cli/src/utils/prompt.ts +8 -1
  43. package/cli/src/utils/service-urls.ts +1 -1
  44. package/discovery/identity-management-backend/service.yaml +2 -2
  45. package/discovery/identity-management-frontend/service.yaml +1 -1
  46. package/discovery/registry.star +3 -1
  47. package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +2 -2
  48. package/docs/demo.svg +217 -0
  49. package/engine/assets/docker/golden-layers.Dockerfile +18 -18
  50. package/engine/assets/docker/wake-gateway/Dockerfile +4 -3
  51. package/engine/assets/docker/wake-gateway/decide.test.ts +72 -1
  52. package/engine/assets/docker/wake-gateway/decide.ts +51 -2
  53. package/engine/assets/docker/wake-gateway/server.ts +165 -28
  54. package/engine/assets/scripts/mac-m1-resource-monitor.sh +1 -1
  55. package/engine/scripts/debug-container.sh +8 -3
  56. package/engine/spec.master +2 -2
  57. package/engine/topologies/platform/docker/compose/traefik_standalone.star +23 -1
  58. package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +1 -1
  59. package/engine/topologies/platform/docker/networking/traefik_static_routes.star +62 -8
  60. package/engine/topologies/tilt/common/utils.star +1 -1
  61. package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +89 -12
  62. package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +20 -0
  63. package/install.sh +19 -242
  64. package/openspec/changes/prioritized-cold-start/design.md +27 -3
  65. package/openspec/changes/prioritized-cold-start/proposal.md +1 -0
  66. package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +9 -3
  67. package/openspec/changes/prioritized-cold-start/tasks.md +24 -1
  68. package/package.json +1 -1
  69. package/platform/services/platform/proxy/service.yaml +1 -1
  70. package/scripts/record-demo.sh +43 -0
  71. package/scripts/release-binaries.sh +8 -5
  72. package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
  73. package/tests/tilt-engine/test_sablier_defer_start.py +41 -0
  74. package/tests/tilt-engine/test_standalone_traefik.py +14 -0
  75. package/tests/tilt-engine/test_traefik_static_wake_route.py +68 -0
  76. package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/codebase-audit-report.md +0 -62
  77. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/.openspec.yaml +0 -5
  78. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/design.md +0 -94
  79. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/proposal.md +0 -46
  80. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CLEANUP_REPORT_8.md +0 -174
  81. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CRITICAL_ASSESSMENT_8.md +0 -160
  82. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/circular-deps/CRITICAL_ASSESSMENT_4.md +0 -381
  83. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/dead-code/CRITICAL_ASSESSMENT_3.md +0 -316
  84. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/CRITICAL_ASSESSMENT_1.md +0 -290
  85. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/IMPLEMENTATION_SUMMARY_1.md +0 -233
  86. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/defensive-cleanup/CRITICAL_ASSESSMENT_6.md +0 -835
  87. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/CRITICAL_ASSESSMENT_7.md +0 -254
  88. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/IMPLEMENTATION_SUMMARY_7.md +0 -187
  89. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/strong-typing/CRITICAL_ASSESSMENT_5.md +0 -269
  90. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/CRITICAL_ASSESSMENT_2.md +0 -312
  91. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/IMPLEMENTATION_SUMMARY.md +0 -170
  92. package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/tasks.md +0 -137
@@ -7,6 +7,7 @@
7
7
 
8
8
  load("../constants.star", "PlatformDockerConstants")
9
9
  load("../config/healthcheck.star", "compose_healthcheck_timing")
10
+ load("../networking/traefik_static_routes.star", "normalize_abs_path")
10
11
 
11
12
 
12
13
  def generate_standalone_traefik_compose():
@@ -91,7 +92,7 @@ services:
91
92
  - PORT={gateway_port}
92
93
  volumes:
93
94
  - /var/run/docker.sock:/var/run/docker.sock
94
- - {tilt_dev_dir}:/root/.tilt-dev:ro
95
+ - {tilt_dev_dir}:/root/.tilt-dev:ro{project_root_mount}
95
96
  networks:
96
97
  - traefik-public
97
98
 
@@ -108,4 +109,25 @@ networks:
108
109
  gateway_container=PlatformDockerConstants.TRAEFIK_WAKE_GATEWAY_CONTAINER,
109
110
  gateway_port=PlatformDockerConstants.TRAEFIK_WAKE_GATEWAY_PORT,
110
111
  tilt_dev_dir=os.environ.get("HOME", "") + "/.tilt-dev",
112
+ project_root_mount=_project_root_mount(),
111
113
  )
114
+
115
+
116
+ def _project_root_mount():
117
+ """Read-only mount of the project at its own absolute host path.
118
+
119
+ The gateway runs `docker compose up --no-build` for a deferred resource
120
+ itself (bypassing Tilt's build queue), using the compose files Tilt uses.
121
+ Compose resolves relative paths in them (env_file etc.) client-side, so
122
+ they must exist at the same absolute paths inside the gateway container.
123
+ Empty when TDK_PROJECT_ROOT is unset (the generated Tiltfile sets it).
124
+ """
125
+ root = project_root_abspath()
126
+ if not root:
127
+ return ""
128
+ return "\n - " + root + ":" + root + ":ro"
129
+
130
+
131
+ def project_root_abspath():
132
+ """Absolute, normalized project root (TDK_PROJECT_ROOT), or "" when unset."""
133
+ return normalize_abs_path(os.environ.get("TDK_PROJECT_ROOT", ""))
@@ -110,7 +110,7 @@ def L3_generate_migration_engine(res_path, use_golden = True):
110
110
  + "COPY " + res_path_rel + "/" + OUTPUT.AUTOGENERATED_FOLDER + "/bunfig.docker.autogenerated.toml ./bunfig.toml\n"
111
111
  + "COPY bun.lock* ./\n"
112
112
  + "# Install runtime deps only for migrator image (skip test/dev toolchain)\n"
113
- + "# NOTE: keep bunfig.toml (it carries the @beauty-crm/@tdk-landscape registry\n"
113
+ + "# NOTE: keep bunfig.toml (it carries the project/@tdk-landscape registry\n"
114
114
  + "# scopes pointing at Verdaccio) - deleting it forces scoped packages to fall\n"
115
115
  + "# back to the public npm registry and fail with ConnectionRefused/404.\n"
116
116
  + "RUN --mount=type=cache,target=/cache/bun,sharing=shared rm -f bun.lock bun.lockb && env -u CI BUN_CONFIG_FROZEN_LOCKFILE=false BUN_TMPDIR=/tmp BUN_INSTALL=/tmp/bun-install bun install --production --no-frozen-lockfile --concurrent-scripts --cache-dir=/cache/bun\n"
@@ -13,10 +13,15 @@
13
13
  # backend was healthy).
14
14
  #
15
15
  # Config for a request travels to the gateway via headers (X-Wake-*), not
16
- # the path/query, so the original request path reaches the real backend
17
- # unchanged once the resource is ready (see wake-gateway/server.ts).
16
+ # the path/query. The route still strips the same `apiPath` prefix the real
17
+ # Docker-label `-project` router strips (get_backend_traefik_labels) before
18
+ # forwarding -- confirmed live against tdk-erp-system (task 7.2) that a
19
+ # backend's app only serves its bare health path (e.g. `/health`), not the
20
+ # full `/api/{name}/health` the public route is matched on; without this, the
21
+ # gateway's own proxy-through would forward the unstripped path once healthy
22
+ # and the app would 404 on it, even though the wake itself succeeded.
18
23
 
19
- load("./traefik_helpers.star", "project_backend_rule", "build_entrypoints")
24
+ load("./traefik_helpers.star", "project_backend_rule", "cli_api_path", "build_entrypoints")
20
25
  load("./traefik_constants.star",
21
26
  "TRAEFIK_BACKEND_ENABLE_HTTP",
22
27
  "TRAEFIK_BACKEND_ENABLE_HTTPS",
@@ -25,6 +30,29 @@ load("./traefik_constants.star",
25
30
  STATIC_ROUTE_PRIORITY = 1
26
31
 
27
32
 
33
+ def normalize_abs_path(path):
34
+ """Absolute path with `.`/`..` segments collapsed, or "" for "".
35
+
36
+ Tilt's os.path.abspath does not collapse `..` (confirmed:
37
+ abspath("/a/.tdk/.tdk-out/../..") comes back unchanged), and the
38
+ generated Tiltfile's project root is exactly that shape
39
+ (config.main_dir + "/../.."). The gateway's project mount and the compose
40
+ paths in its route headers must match byte-for-byte, so both go through here.
41
+ """
42
+ if not path:
43
+ return ""
44
+ parts = []
45
+ for segment in os.path.abspath(path).split("/"):
46
+ if segment == "" or segment == ".":
47
+ continue
48
+ if segment == "..":
49
+ if parts:
50
+ parts.pop()
51
+ continue
52
+ parts.append(segment)
53
+ return "/" + "/".join(parts)
54
+
55
+
28
56
  def _container_name(compose_project_name, res_name):
29
57
  """Docker Compose's own naming convention: <project>-<service>-<replica>.
30
58
 
@@ -43,6 +71,9 @@ def generate_static_wake_route(
43
71
  gateway_host,
44
72
  gateway_port,
45
73
  dependencies=None,
74
+ compose_files=None,
75
+ env_file="",
76
+ image="",
46
77
  ):
47
78
  """YAML for one resource's Traefik file-provider dynamic-config entry.
48
79
 
@@ -51,21 +82,36 @@ def generate_static_wake_route(
51
82
  different compose project than the resource itself, so the project name
52
83
  travels alongside the resource name rather than being assumed shared.
53
84
 
85
+ `compose_files` (absolute paths), `env_file` and `image` let the gateway
86
+ create the container itself with `docker compose up --no-build` when the
87
+ image already exists, instead of waiting in Tilt's build queue behind
88
+ `tilt trigger`. Omitted headers make the gateway use `tilt trigger` only.
89
+
54
90
  Written to the directory PlatformDockerConstants.TRAEFIK_DYNAMIC_DIR_REL
55
91
  mounts into the standalone Traefik container (traefik_standalone.star).
56
92
  """
57
93
  dependencies = dependencies or []
58
94
 
59
95
  rule = project_backend_rule(manifest, resource_entry_name)
96
+ api_path = cli_api_path(resource_entry_name, manifest)
60
97
  entrypoints = build_entrypoints(TRAEFIK_BACKEND_ENABLE_HTTP, TRAEFIK_BACKEND_ENABLE_HTTPS)
61
98
  router_name = resource_entry_name + "-wake"
62
- middleware_name = resource_entry_name + "-wake-headers"
99
+ headers_middleware_name = resource_entry_name + "-wake-headers"
100
+ strip_middleware_name = resource_entry_name + "-wake-strip"
63
101
  service_name = resource_entry_name + "-wake-gateway"
64
102
  container_name = _container_name(compose_project_name, resource_entry_name)
65
103
  deps_header = ",".join([
66
104
  dep_res_name + "=" + _container_name(dep_project_name, dep_res_name)
67
105
  for dep_res_name, dep_project_name in dependencies
68
106
  ])
107
+ compose_headers = ""
108
+ if compose_files and image:
109
+ compose_headers = (
110
+ '\n X-Wake-Compose-Project: "' + compose_project_name + '"'
111
+ + '\n X-Wake-Compose-Files: "' + ",".join(compose_files) + '"'
112
+ + '\n X-Wake-Env-File: "' + env_file + '"'
113
+ + '\n X-Wake-Image: "' + image + '"'
114
+ )
69
115
 
70
116
  return """# SYSTEM-GENERATED - DO NOT EDIT (sablier.deferStart static wake route)
71
117
  http:
@@ -76,16 +122,21 @@ http:
76
122
  - {entrypoint}
77
123
  service: {service_name}
78
124
  middlewares:
79
- - {middleware_name}
125
+ - {strip_middleware_name}
126
+ - {headers_middleware_name}
80
127
  priority: {priority}
81
128
  middlewares:
82
- {middleware_name}:
129
+ {strip_middleware_name}:
130
+ stripPrefix:
131
+ prefixes:
132
+ - "{api_path}"
133
+ {headers_middleware_name}:
83
134
  headers:
84
135
  customRequestHeaders:
85
136
  X-Wake-Resource: "{resource_entry_name}"
86
137
  X-Wake-Container: "{container_name}"
87
138
  X-Wake-Deps: "{deps_header}"
88
- X-Wake-Proxy-Port: "{internal_port}"
139
+ X-Wake-Proxy-Port: "{internal_port}"{compose_headers}
89
140
  services:
90
141
  {service_name}:
91
142
  loadBalancer:
@@ -96,12 +147,15 @@ http:
96
147
  rule=rule,
97
148
  entrypoint=entrypoints.split(",")[0],
98
149
  service_name=service_name,
99
- middleware_name=middleware_name,
150
+ strip_middleware_name=strip_middleware_name,
151
+ headers_middleware_name=headers_middleware_name,
152
+ api_path=api_path,
100
153
  priority=STATIC_ROUTE_PRIORITY,
101
154
  resource_entry_name=resource_entry_name,
102
155
  container_name=container_name,
103
156
  deps_header=deps_header,
104
157
  internal_port=internal_port,
158
+ compose_headers=compose_headers,
105
159
  gateway_host=gateway_host,
106
160
  gateway_port=gateway_port,
107
161
  )
@@ -60,7 +60,7 @@ MIGRATED_PACKAGES = {
60
60
  load("../manifest/constants.star", "MANIFEST_FILENAME")
61
61
 
62
62
  # List of all shared platform networks
63
- # All networks use PROJECT_NAME format (e.g., beauty_crm_*)
63
+ # All networks use PROJECT_NAME format (e.g., tdk_project_*)
64
64
  PLATFORM_NETWORKS = [
65
65
  PlatformDockerConstants.NETWORK_TRAEFIK_PUBLIC,
66
66
  PlatformDockerConstants.PROJECT_NAME + "_traefik-private",
@@ -10,7 +10,7 @@ OUTPUT = struct(AUTOGENERATED_FOLDER = ".autogenerated")
10
10
  load('../../../platform/docker/index.star', 'Docker')
11
11
  load('../../../platform/docker/constants.star', 'PlatformDockerConstants')
12
12
  load('../../../tilt/manifest/constants.star', 'BASE_PORT_FRONTEND', 'BASE_PORT_BACKEND')
13
- load('../../../platform/docker/networking/traefik_static_routes.star', 'generate_static_wake_route')
13
+ load('../../../platform/docker/networking/traefik_static_routes.star', 'generate_static_wake_route', 'normalize_abs_path')
14
14
  load('../../../platform/docker/networking/sablier_container_cycle.star', 'sablier_middleware_suffix')
15
15
 
16
16
  load('./builders/typescript.star', 'TypescriptBuilders')
@@ -213,9 +213,82 @@ def _build_live_update_rules(res_path, full_res_path, syncs):
213
213
  return live_update_rules
214
214
 
215
215
 
216
+ def _app_image_name(resource_name, res_name):
217
+ """The image ref docker_build builds and the app compose service declares."""
218
+ return resource_name + '_' + res_name + ':dev'
219
+
220
+
221
+ def _wake_compose_invocation(project_root, resource_path, res_name, resource_name):
222
+ """Compose files, env file and image for the wake gateway's direct start.
223
+
224
+ The same files/--env-file the `-run-only` resource passes, as absolute
225
+ normalized paths: the gateway mounts the project at the same normalized
226
+ root (traefik_standalone.star), so these resolve identically there.
227
+ Returns None without a project root (paths would be relative to Tilt's cwd).
228
+ """
229
+ if not project_root:
230
+ return None
231
+ root = normalize_abs_path(project_root)
232
+ compose_dir = root + '/' + resource_path + '/' + OUTPUT.AUTOGENERATED_FOLDER
233
+ files = [compose_dir + '/docker-compose.app.autogenerated.yml']
234
+ port_override = compose_dir + '/docker-compose.port-override.yml'
235
+ if os.path.exists(port_override):
236
+ files.append(port_override)
237
+ env_file = root + '/.env'
238
+ return {
239
+ 'compose_files': files,
240
+ 'env_file': env_file if os.path.exists(env_file) else '',
241
+ 'image': _app_image_name(resource_name, res_name),
242
+ }
243
+
244
+
216
245
  def _register_docker_build(config, live_update_rules):
217
246
  """Register docker_build with live_update for hot-reload support."""
218
- image_name = config['resource_name'] + '_' + config['res_name'] + ':dev'
247
+ TypescriptBuilders.build_typescript_service(
248
+ _app_image_name(config['resource_name'], config['res_name']),
249
+ config.get('project_root', '') or '.',
250
+ _resolve_dockerfile(config),
251
+ live_update_rules,
252
+ config['res_deps'],
253
+ )
254
+
255
+
256
+ def _register_deferred_image_prebuild(config, auto_init_apps):
257
+ """Build a deferStart resource's image during `tdk up` without creating its container.
258
+
259
+ `auto_init=False` on the dc_resource skips its docker_build too (confirmed
260
+ live on tdk-erp-system, task 7.2), so a fresh project's first request would
261
+ find no image and the wake gateway would fall back to `tilt trigger`, which
262
+ queues behind every other build. This local_resource builds the same image
263
+ (same Dockerfile, `production` target, host network, and an allowlist
264
+ .dockerignore equivalent to docker_build's only=/ignore=) under the tag the
265
+ compose service declares, so the gateway can start it directly.
266
+ """
267
+ project_root = config.get('project_root', '')
268
+ dockerfile = _resolve_dockerfile(config)
269
+ prebuild_dockerfile = dockerfile + '.prebuild'
270
+ ignore_content = TypescriptBuilders.prebuild_dockerignore(dockerfile, project_root, config['res_path'])
271
+ # BuildKit reads `<dockerfile>.dockerignore` for `-f <dockerfile>`; the
272
+ # original Dockerfile already has a (denylist) one, hence the copy.
273
+ cmd = (
274
+ "cp '" + dockerfile + "' '" + prebuild_dockerfile + "'"
275
+ + " && printf '%s' '" + ignore_content + "' > '" + prebuild_dockerfile + ".dockerignore'"
276
+ + " && docker build --network host --target production"
277
+ + " -f '" + prebuild_dockerfile + "'"
278
+ + " -t '" + _app_image_name(config['resource_name'], config['res_name']) + "'"
279
+ + " '" + (project_root or '.') + "'"
280
+ )
281
+ local_resource(
282
+ name=config['res_name'] + '-image',
283
+ cmd=cmd,
284
+ labels=config['labels'],
285
+ resource_deps=config['res_deps'],
286
+ auto_init=auto_init_apps,
287
+ )
288
+
289
+
290
+ def _resolve_dockerfile(config):
291
+ """Absolute (when project_root is set) path of a resource's Dockerfile."""
219
292
  project_root = config.get('project_root', '')
220
293
  # Use custom dockerfile from config if specified, otherwise use autogenerated default
221
294
  # The res_path is relative to project_root (e.g., 'services/product/...')
@@ -234,13 +307,7 @@ def _register_docker_build(config, live_update_rules):
234
307
  dockerfile = project_root + dockerfile
235
308
  else:
236
309
  dockerfile = project_root + '/' + dockerfile
237
- TypescriptBuilders.build_typescript_service(
238
- image_name,
239
- project_root or '.',
240
- dockerfile,
241
- live_update_rules,
242
- config['res_deps'],
243
- )
310
+ return dockerfile
244
311
 
245
312
 
246
313
  def _register_run_only_resource(config, resource_path, compose_project_name, auto_init_apps=True):
@@ -289,9 +356,11 @@ def _register_single_resource(config, resource_path, compose_project_name, auto_
289
356
 
290
357
  # A sablier.enable + sablier.deferStart resource is held back from tdk up's
291
358
  # normal bring-up: its container is never created or started here, only via
292
- # the Traefik wake path on first request. docker_build below is unaffected
293
- # (it has no auto_init gate), so the image still builds either way.
294
- effective_auto_init = auto_init_apps and not resource_defers_start(config.get('manifest', {}))
359
+ # the Traefik wake path on first request. auto_init=False also skips the
360
+ # dc_resource's docker_build, so its image is built by a separate
361
+ # `<name>-image` resource instead (_register_deferred_image_prebuild).
362
+ defers_start = resource_defers_start(config.get('manifest', {}))
363
+ effective_auto_init = auto_init_apps and not defers_start
295
364
 
296
365
  print("DEBUG REGISTER: Registering '{}' app_type='{}' auto_init={}".format(res_name, app_type, effective_auto_init))
297
366
 
@@ -304,6 +373,8 @@ def _register_single_resource(config, resource_path, compose_project_name, auto_
304
373
  config['syncs']
305
374
  )
306
375
  _register_docker_build(config, live_update_rules)
376
+ if defers_start:
377
+ _register_deferred_image_prebuild(config, auto_init_apps)
307
378
  else:
308
379
  print("DEBUG REGISTER: '{}' skipping docker_build (app_type='{}', syncs={})".format(res_name, app_type, config.get('syncs')))
309
380
 
@@ -478,6 +549,9 @@ def register_compose_resources(resource_config, ctx, runtime_flags, manifest_sta
478
549
  if resource_defers_start(manifest) and write_file:
479
550
  internal_port = res.get('port', manifest.get('port', BASE_PORT_BACKEND))
480
551
  static_route_path = PlatformDockerConstants.TRAEFIK_DYNAMIC_DIR_REL + '/' + res['name'] + '.yml'
552
+ compose_invocation = _wake_compose_invocation(
553
+ ctx.get('project_root', ''), resource_path, res['name'], resource_name,
554
+ ) or {}
481
555
  write_file(static_route_path, generate_static_wake_route(
482
556
  resource_entry_name=res['name'],
483
557
  compose_project_name=compose_project_name,
@@ -486,6 +560,9 @@ def register_compose_resources(resource_config, ctx, runtime_flags, manifest_sta
486
560
  gateway_host=PlatformDockerConstants.TRAEFIK_WAKE_GATEWAY_CONTAINER,
487
561
  gateway_port=PlatformDockerConstants.TRAEFIK_WAKE_GATEWAY_PORT,
488
562
  dependencies=resolve_defer_start_dependencies(manifest, resource_manifests, all_services_map),
563
+ compose_files=compose_invocation.get('compose_files'),
564
+ env_file=compose_invocation.get('env_file', ''),
565
+ image=compose_invocation.get('image', ''),
489
566
  ))
490
567
 
491
568
  resource_entries.append(entry)
@@ -162,9 +162,29 @@ def _build_typescript_service(name, context, dockerfile, live_update_rules, deps
162
162
  )
163
163
 
164
164
 
165
+ def prebuild_dockerignore(dockerfile, project_root, res_path):
166
+ """Allowlist .dockerignore matching _build_typescript_service's only=/ignore=.
167
+
168
+ A plain `docker build` has no only= filter, so without this it would send
169
+ the whole project root as context. `res_path` is relative to the project
170
+ root (the build context); `dockerfile` may be absolute.
171
+ """
172
+ abs_res = project_root + '/' + res_path if project_root else res_path
173
+ lines = ['*']
174
+ for path in _get_resource_only_paths(abs_res):
175
+ lines.append('!' + (res_path if path == abs_res else path))
176
+ ignores = _load_autogenerated_dockerignore_patterns(dockerfile, res_path)
177
+ for pattern in get_filewatch_ignore_patterns(res_path):
178
+ if pattern not in ignores:
179
+ ignores.append(pattern)
180
+ lines.extend(ignores)
181
+ return '\n'.join(lines) + '\n'
182
+
183
+
165
184
  TypescriptBuilders = struct(
166
185
  build_typescript_service = _build_typescript_service,
167
186
  load_dockerignore_patterns = _load_autogenerated_dockerignore_patterns,
187
+ prebuild_dockerignore = prebuild_dockerignore,
168
188
  )
169
189
 
170
190
  DEBUG = {}
package/install.sh CHANGED
@@ -1,242 +1,19 @@
1
- #!/bin/bash
2
- # TDK CLI Install Script
3
- # Install the Tilt Development Kit CLI
4
- # Usage: curl -fsSL https://raw.githubusercontent.com/tdk-landscape/tdk-cli-core/main/install.sh | bash
5
-
6
- set -e
7
-
8
- # Colors
9
- RED='\033[0;31m'
10
- GREEN='\033[0;32m'
11
- YELLOW='\033[1;33m'
12
- BLUE='\033[0;34m'
13
- NC='\033[0m' # No Color
14
-
15
- # Configuration
16
- REPO_URL="https://github.com/tdk-landscape/tdk-cli-core.git"
17
- INSTALL_DIR="${HOME}/.tdk"
18
- BIN_DIR="${HOME}/.bun/bin"
19
-
20
- # Print functions
21
- print_info() {
22
- echo -e "${BLUE}ℹ️ $1${NC}"
23
- }
24
-
25
- print_success() {
26
- echo -e "${GREEN}✅ $1${NC}"
27
- }
28
-
29
- print_warning() {
30
- echo -e "${YELLOW}⚠️ $1${NC}"
31
- }
32
-
33
- print_error() {
34
- echo -e "${RED}❌ $1${NC}"
35
- }
36
-
37
- # Check if command exists
38
- command_exists() {
39
- command -v "$1" >/dev/null 2>&1
40
- }
41
-
42
- # Detect OS
43
- detect_os() {
44
- case "$(uname -s)" in
45
- Linux*) echo "linux";;
46
- Darwin*) echo "macos";;
47
- CYGWIN*) echo "windows";;
48
- MINGW*) echo "windows";;
49
- MSYS*) echo "windows";;
50
- *) echo "unknown";;
51
- esac
52
- }
53
-
54
- # Check prerequisites
55
- check_prerequisites() {
56
- print_info "Checking prerequisites..."
57
-
58
- OS=$(detect_os)
59
- print_info "Detected OS: $OS"
60
-
61
- # Check for git
62
- if ! command_exists git; then
63
- print_error "git is required but not installed."
64
- echo "Please install git first:"
65
- echo " macOS: brew install git"
66
- echo " Linux: sudo apt-get install git (or your package manager)"
67
- exit 1
68
- fi
69
-
70
- # Check for a JavaScript runtime (bun or node)
71
- if command_exists bun; then
72
- RUNTIME="bun"
73
- print_success "Found bun runtime"
74
- elif command_exists node; then
75
- RUNTIME="node"
76
- print_success "Found node runtime"
77
-
78
- # Check for npm
79
- if ! command_exists npm; then
80
- print_error "npm is required with node but not found"
81
- exit 1
82
- fi
83
- else
84
- print_warning "No JavaScript runtime found (bun or node)"
85
- echo ""
86
- echo "Would you like to install Bun? (Recommended - much faster)"
87
- echo " curl -fsSL https://bun.sh/install | bash"
88
- echo ""
89
- read -p "Install Bun now? [Y/n] " -n 1 -r
90
- echo
91
- if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then
92
- print_info "Installing Bun..."
93
- curl -fsSL https://bun.sh/install | bash
94
-
95
- # Source bun setup
96
- if [ -f "${HOME}/.bashrc" ]; then
97
- export BUN_INSTALL="${HOME}/.bun"
98
- export PATH="${BUN_INSTALL}/bin:$PATH"
99
- fi
100
-
101
- if command_exists bun; then
102
- RUNTIME="bun"
103
- print_success "Bun installed successfully"
104
- else
105
- print_error "Bun installation failed or not in PATH"
106
- print_info "Please restart your terminal and run this script again"
107
- exit 1
108
- fi
109
- else
110
- print_error "Bun or Node.js is required to install TDK"
111
- exit 1
112
- fi
113
- fi
114
- }
115
-
116
- # Setup directories
117
- setup_directories() {
118
- print_info "Setting up directories..."
119
-
120
- mkdir -p "$INSTALL_DIR"
121
- mkdir -p "$BIN_DIR"
122
-
123
- print_success "Directories created"
124
- }
125
-
126
- # Clone or update repository
127
- clone_repository() {
128
- print_info "Cloning TDK CLI repository..."
129
-
130
- if [ -d "${INSTALL_DIR}/tdk-cli" ]; then
131
- print_warning "Existing installation found, updating..."
132
- cd "${INSTALL_DIR}/tdk-cli"
133
- git fetch origin
134
- git reset --hard origin/main
135
- else
136
- git clone --depth 1 "$REPO_URL" "${INSTALL_DIR}/tdk-cli"
137
- cd "${INSTALL_DIR}/tdk-cli"
138
- fi
139
-
140
- print_success "Repository cloned/updated"
141
- }
142
-
143
- # Install dependencies and link
144
- install_and_link() {
145
- print_info "Installing dependencies..."
146
-
147
- cd "${INSTALL_DIR}/tdk-cli/cli"
148
-
149
- if [ "$RUNTIME" = "bun" ]; then
150
- bun install
151
- print_success "Dependencies installed with bun"
152
-
153
- print_info "Linking TDK CLI..."
154
- bun link --force
155
- print_success "TDK CLI linked globally"
156
- else
157
- npm install
158
- print_success "Dependencies installed with npm"
159
-
160
- print_info "Linking TDK CLI..."
161
- npm link --force
162
- print_success "TDK CLI linked globally"
163
- fi
164
- }
165
-
166
- # Setup PATH
167
- setup_path() {
168
- print_info "Setting up PATH..."
169
-
170
- SHELL_CONFIG=""
171
- if [ -f "${HOME}/.zshrc" ]; then
172
- SHELL_CONFIG="${HOME}/.zshrc"
173
- elif [ -f "${HOME}/.bashrc" ]; then
174
- SHELL_CONFIG="${HOME}/.bashrc"
175
- elif [ -f "${HOME}/.bash_profile" ]; then
176
- SHELL_CONFIG="${HOME}/.bash_profile"
177
- fi
178
-
179
- if [ -n "$SHELL_CONFIG" ]; then
180
- if ! grep -q "\.bun/bin" "$SHELL_CONFIG" 2>/dev/null; then
181
- echo "" >> "$SHELL_CONFIG"
182
- echo "# TDK CLI (installed via install.sh)" >> "$SHELL_CONFIG"
183
- echo 'export PATH="${HOME}/.bun/bin:${PATH}"' >> "$SHELL_CONFIG"
184
- print_success "Added ~/.bun/bin to PATH in $(basename "$SHELL_CONFIG")"
185
- print_warning "Please restart your terminal or run: source $SHELL_CONFIG"
186
- else
187
- print_info "PATH already configured in $(basename "$SHELL_CONFIG")"
188
- fi
189
- else
190
- print_warning "Could not detect shell config file"
191
- print_info "Please manually add to your shell config:"
192
- echo 'export PATH="${HOME}/.bun/bin:${PATH}"'
193
- fi
194
- }
195
-
196
- # Verify installation
197
- verify_installation() {
198
- print_info "Verifying installation..."
199
-
200
- export PATH="${BIN_DIR}:${PATH}"
201
-
202
- if command_exists tdk; then
203
- VERSION=$(tdk -v 2>/dev/null || echo "unknown")
204
- print_success "TDK CLI installed successfully!"
205
- echo ""
206
- echo "Version: $VERSION"
207
- echo "Location: $(which tdk)"
208
- echo ""
209
- echo "Quick start:"
210
- echo " tdk --help # Show all commands"
211
- echo " tdk project # Initialize a new project"
212
- echo " tdk resource api # Create a new resource"
213
- echo ""
214
- print_info "Happy coding! 🚀"
215
- else
216
- print_error "Installation verification failed"
217
- print_info "tdk command not found in PATH"
218
- print_info "You may need to restart your terminal or run:"
219
- echo " export PATH=\"${HOME}/.bun/bin:\${PATH}\""
220
- exit 1
221
- fi
222
- }
223
-
224
- # Main installation flow
225
- main() {
226
- echo ""
227
- echo "╔════════════════════════════════════════════════════════════╗"
228
- echo "║ 🚀 TDK CLI Installer ║"
229
- echo "║ Tilt Development Kit - Install Script ║"
230
- echo "╚════════════════════════════════════════════════════════════╝"
231
- echo ""
232
-
233
- check_prerequisites
234
- setup_directories
235
- clone_repository
236
- install_and_link
237
- setup_path
238
- verify_installation
239
- }
240
-
241
- # Run main function
242
- main "$@"
1
+ #!/usr/bin/env bash
2
+ # Legacy installer URL for the TDK CLI.
3
+ #
4
+ # The official installer is https://tdk-landscape.github.io/install.sh. It
5
+ # installs the prebuilt `tdk` binary plus its bundled engine, verified
6
+ # against the release checksums, with no Node or Bun required. This script
7
+ # used to clone this repo and `bun link` it instead; it now hands off to the
8
+ # official installer so old
9
+ # curl -fsSL https://raw.githubusercontent.com/tdk-landscape/tdk-cli-core/main/install.sh | bash
10
+ # commands keep working and every install method gets the same result.
11
+ #
12
+ # To work on TDK itself, clone the repo instead (see CONTRIBUTING.md).
13
+
14
+ set -euo pipefail
15
+
16
+ readonly OFFICIAL_INSTALLER="https://tdk-landscape.github.io/install.sh"
17
+
18
+ echo "Using the official TDK installer: ${OFFICIAL_INSTALLER}" >&2
19
+ curl -fsSL "${OFFICIAL_INSTALLER}" | sh