@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.
- package/.github/workflows/ci.yml +13 -0
- package/.github/workflows/release-binaries.yml +76 -1
- package/CHANGELOG.md +50 -0
- package/README.md +54 -17
- package/cli/README.md +16 -43
- package/cli/biome.json +0 -4
- package/cli/dist/commands/help.d.ts.map +1 -1
- package/cli/dist/commands/help.js +22 -39
- package/cli/dist/commands/help.js.map +1 -1
- package/cli/dist/commands/project.d.ts +6 -0
- package/cli/dist/commands/project.d.ts.map +1 -1
- package/cli/dist/commands/project.js +16 -0
- package/cli/dist/commands/project.js.map +1 -1
- package/cli/dist/commands/up.d.ts.map +1 -1
- package/cli/dist/commands/up.js +5 -0
- package/cli/dist/commands/up.js.map +1 -1
- package/cli/dist/commands/upgrade.d.ts +3 -0
- package/cli/dist/commands/upgrade.d.ts.map +1 -1
- package/cli/dist/commands/upgrade.js +43 -1
- package/cli/dist/commands/upgrade.js.map +1 -1
- package/cli/dist/utils/constants.d.ts +1 -1
- package/cli/dist/utils/constants.d.ts.map +1 -1
- package/cli/dist/utils/constants.js +1 -1
- package/cli/dist/utils/constants.js.map +1 -1
- package/cli/dist/utils/doctor-runtime.js +5 -5
- package/cli/dist/utils/doctor-runtime.js.map +1 -1
- package/cli/dist/utils/prompt.d.ts.map +1 -1
- package/cli/dist/utils/prompt.js +6 -1
- package/cli/dist/utils/prompt.js.map +1 -1
- package/cli/dist/utils/service-urls.js +1 -1
- package/cli/dist/utils/service-urls.js.map +1 -1
- package/cli/package.json +2 -1
- package/cli/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
- package/cli/src/commands/__tests__/doctor.test.ts +8 -8
- package/cli/src/commands/__tests__/upgrade.test.ts +90 -3
- package/cli/src/commands/help.ts +22 -39
- package/cli/src/commands/project.ts +20 -0
- package/cli/src/commands/up.ts +10 -0
- package/cli/src/commands/upgrade.ts +52 -1
- package/cli/src/utils/constants.ts +1 -1
- package/cli/src/utils/doctor-runtime.ts +5 -5
- package/cli/src/utils/prompt.ts +8 -1
- package/cli/src/utils/service-urls.ts +1 -1
- package/discovery/identity-management-backend/service.yaml +2 -2
- package/discovery/identity-management-frontend/service.yaml +1 -1
- package/discovery/registry.star +3 -1
- package/discovery/services/platform/orchestrator/orchestrator-glue-backend/service.yaml +2 -2
- package/docs/demo.svg +217 -0
- package/engine/assets/docker/golden-layers.Dockerfile +18 -18
- package/engine/assets/docker/wake-gateway/Dockerfile +4 -3
- package/engine/assets/docker/wake-gateway/decide.test.ts +72 -1
- package/engine/assets/docker/wake-gateway/decide.ts +51 -2
- package/engine/assets/docker/wake-gateway/server.ts +165 -28
- package/engine/assets/scripts/mac-m1-resource-monitor.sh +1 -1
- package/engine/scripts/debug-container.sh +8 -3
- package/engine/spec.master +2 -2
- package/engine/topologies/platform/docker/compose/traefik_standalone.star +23 -1
- package/engine/topologies/platform/docker/layers/prisma/prisma_build.star +1 -1
- package/engine/topologies/platform/docker/networking/traefik_static_routes.star +62 -8
- package/engine/topologies/tilt/common/utils.star +1 -1
- package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +89 -12
- package/engine/topologies/tilt/resources/orchestrator/builders/typescript.star +20 -0
- package/install.sh +19 -242
- package/openspec/changes/prioritized-cold-start/design.md +27 -3
- package/openspec/changes/prioritized-cold-start/proposal.md +1 -0
- package/openspec/changes/prioritized-cold-start/specs/on-demand-resource-startup/spec.md +9 -3
- package/openspec/changes/prioritized-cold-start/tasks.md +24 -1
- package/package.json +1 -1
- package/platform/services/platform/proxy/service.yaml +1 -1
- package/scripts/record-demo.sh +43 -0
- package/scripts/release-binaries.sh +8 -5
- package/shared-platform-engineering/docker-templates/infisical-entrypoint.sh +2 -2
- package/tests/tilt-engine/test_sablier_defer_start.py +41 -0
- package/tests/tilt-engine/test_standalone_traefik.py +14 -0
- package/tests/tilt-engine/test_traefik_static_wake_route.py +68 -0
- package/openspec/changes/archive/2026-04-29-scan-repo-gaps-fix/codebase-audit-report.md +0 -62
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/.openspec.yaml +0 -5
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/design.md +0 -94
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/proposal.md +0 -46
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CLEANUP_REPORT_8.md +0 -174
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/ai-slop-cleanup/CRITICAL_ASSESSMENT_8.md +0 -160
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/circular-deps/CRITICAL_ASSESSMENT_4.md +0 -381
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/dead-code/CRITICAL_ASSESSMENT_3.md +0 -316
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/CRITICAL_ASSESSMENT_1.md +0 -290
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/deduplication/IMPLEMENTATION_SUMMARY_1.md +0 -233
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/defensive-cleanup/CRITICAL_ASSESSMENT_6.md +0 -835
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/CRITICAL_ASSESSMENT_7.md +0 -254
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/legacy-cleanup/IMPLEMENTATION_SUMMARY_7.md +0 -187
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/strong-typing/CRITICAL_ASSESSMENT_5.md +0 -269
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/CRITICAL_ASSESSMENT_2.md +0 -312
- package/openspec/changes/archive/2026-05-04-comprehensive-cleanup-final/specs/type-consolidation/IMPLEMENTATION_SUMMARY.md +0 -170
- 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
|
|
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
|
|
17
|
-
#
|
|
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
|
-
|
|
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
|
-
- {
|
|
125
|
+
- {strip_middleware_name}
|
|
126
|
+
- {headers_middleware_name}
|
|
80
127
|
priority: {priority}
|
|
81
128
|
middlewares:
|
|
82
|
-
{
|
|
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
|
-
|
|
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.,
|
|
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",
|
package/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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.
|
|
293
|
-
#
|
|
294
|
-
|
|
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
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|