@tdk-landscape/tdk-cli-core 1.3.147 → 1.3.149
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/cli/dist/commands/doctor.js +20 -8
- package/cli/dist/commands/import.js +6 -5
- package/cli/dist/commands/status.js +15 -0
- package/cli/dist/components/BaseTooltip.js +2 -2
- package/cli/dist/utils/doctor-runtime.js +2 -2
- package/cli/dist/utils/host-port-config.js +43 -2
- package/cli/dist/utils/shared-infra.js +45 -0
- package/cli/dist-bundle/chunk-PLUWAA7O.js +322 -0
- package/cli/dist-bundle/cli.js +255 -255
- package/cli/dist-bundle/{cold-preflight-D7CAIHND.js → cold-preflight-RABRN55J.js} +1 -1
- package/cli/package.json +1 -1
- package/discovery/AGENTS.md +3 -3
- package/discovery/manifest/loading.star +5 -1
- package/engine/AGENTS.md +15 -15
- package/engine/README.md +1 -1
- package/engine/schemas/service-schema.json +2 -3
- package/engine/topologies/platform/docker/compose/compose.star +3 -0
- package/engine/topologies/platform/docker/networking/traefik.star +16 -7
- package/engine/topologies/tilt/manifest/README.md +1 -1
- package/engine/topologies/tilt/manifest/parser.star +5 -0
- package/engine/topologies/tilt/manifest/tests/test_loader_parser.star +14 -0
- package/package.json +1 -1
- package/cli/dist-bundle/chunk-LNZN426S.js +0 -321
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
|
|
2
|
-
import{
|
|
2
|
+
import{tb as a,ub as b,vb as c,wb as d,xb as e}from"./chunk-PLUWAA7O.js";import"./chunk-42IVF3YT.js";import"./chunk-6EA4DGCY.js";export{e as assertMachineReadyOrExit,d as formatColdPreflight,a as nodeTooOld,b as requireVerifiedDockerVersions,c as runColdPreflight};
|
package/cli/package.json
CHANGED
package/discovery/AGENTS.md
CHANGED
|
@@ -147,8 +147,8 @@ If issues arise with Phase 2:
|
|
|
147
147
|
```bash
|
|
148
148
|
# Restore Phase 1 behavior
|
|
149
149
|
tilt down
|
|
150
|
-
git checkout
|
|
151
|
-
git checkout
|
|
150
|
+
git checkout discovery/constants.star
|
|
151
|
+
git checkout discovery/discovery_orchestrator.star
|
|
152
152
|
tilt up
|
|
153
153
|
```
|
|
154
154
|
|
|
@@ -323,7 +323,7 @@ initialize_discovery(_DISCOVERY_CACHE)
|
|
|
323
323
|
|
|
324
324
|
**Pass 2:** Export to autogenerated Tilt resources
|
|
325
325
|
1. `registry.star` reads from discovery cache
|
|
326
|
-
2. Generates `.
|
|
326
|
+
2. Generates `.tdk/.tdk-out/product_autogenerated_*/` files
|
|
327
327
|
3. Creates Tilt resources from generated files
|
|
328
328
|
|
|
329
329
|
## Important Notes
|
|
@@ -300,12 +300,14 @@ def _apply_manifest_defaults(manifest, resource_path):
|
|
|
300
300
|
root_api_path = result.get('apiPath')
|
|
301
301
|
default_path_prefix = root_api_path if root_api_path else '/api/' + stack
|
|
302
302
|
|
|
303
|
+
# A bring-your-own service without healthCheckPath may not serve HTTP, so it gets no default Traefik health path.
|
|
304
|
+
default_health_path = None if app_type == 'bring-your-own' else HEALTH_CHECK_PATH
|
|
303
305
|
computed_traefik = {
|
|
304
306
|
'host': stack + '.backend.' + PlatformDockerConstants.PROJECT_NAME + '.local',
|
|
305
307
|
'pathPrefix': default_path_prefix,
|
|
306
308
|
# Follows healthCheckPath so a manifest that only sets that keeps one
|
|
307
309
|
# path for both probes; `traefik.healthCheck` overrides just Traefik's.
|
|
308
|
-
'healthCheck': result.get('healthCheckPath') or
|
|
310
|
+
'healthCheck': result.get('healthCheckPath') or default_health_path,
|
|
309
311
|
}
|
|
310
312
|
|
|
311
313
|
# Check for overrides
|
|
@@ -319,6 +321,8 @@ def _apply_manifest_defaults(manifest, resource_path):
|
|
|
319
321
|
'pathPrefix': existing_traefik.get('pathPrefix', computed_traefik['pathPrefix']),
|
|
320
322
|
'healthCheck': existing_traefik.get('healthCheck', computed_traefik['healthCheck']),
|
|
321
323
|
}
|
|
324
|
+
if result['traefik']['healthCheck'] == None:
|
|
325
|
+
result['traefik'].pop('healthCheck')
|
|
322
326
|
|
|
323
327
|
# 🎯 SMART NATS CONFIG
|
|
324
328
|
if result['useNats']:
|
package/engine/AGENTS.md
CHANGED
|
@@ -34,7 +34,7 @@ You don't just manage services; you map, design, and optimize the topology that
|
|
|
34
34
|
|
|
35
35
|
**Topology Architecture:**
|
|
36
36
|
```
|
|
37
|
-
|
|
37
|
+
engine/topologies/
|
|
38
38
|
├── platform/ # Infrastructure topology
|
|
39
39
|
│ ├── docker/ # Dockerfile, compose, golden image
|
|
40
40
|
│ ├── net/ # Proxy, networking
|
|
@@ -105,7 +105,7 @@ You don't just manage services; you map, design, and optimize the topology that
|
|
|
105
105
|
|
|
106
106
|
**The Core Pattern (1 manifest → 1 resource → 10 generators):**
|
|
107
107
|
```starlark
|
|
108
|
-
#
|
|
108
|
+
# engine/topologies/tilt/resources/orchestrator/apply.star
|
|
109
109
|
load("./generators/manifest_resource.star", "ManifestResource")
|
|
110
110
|
|
|
111
111
|
for resource in resource_config.get('resources', []):
|
|
@@ -135,7 +135,7 @@ for resource in resource_config.get('resources', []):
|
|
|
135
135
|
|
|
136
136
|
**Registry Loading:**
|
|
137
137
|
```starlark
|
|
138
|
-
#
|
|
138
|
+
# discovery/registry.star
|
|
139
139
|
load("./discovery.star", "initialize_discovery")
|
|
140
140
|
|
|
141
141
|
_DISCOVERY_CACHE = {
|
|
@@ -159,7 +159,7 @@ def get_resource_by_name(name):
|
|
|
159
159
|
|
|
160
160
|
**Autogenerated Services List:**
|
|
161
161
|
```starlark
|
|
162
|
-
# .
|
|
162
|
+
# .tdk/.tdk-out/product_autogenerated_resource_manifests/services.autogenerated.star
|
|
163
163
|
APP_RESOURCES_AUTOGENERATED = [
|
|
164
164
|
{
|
|
165
165
|
'name': 'order-planner',
|
|
@@ -187,7 +187,7 @@ APP_RESOURCES_AUTOGENERATED = [
|
|
|
187
187
|
|
|
188
188
|
**Vite Config Generator:**
|
|
189
189
|
```starlark
|
|
190
|
-
#
|
|
190
|
+
# engine/topologies/tilt/generators/vite_config.star
|
|
191
191
|
def generate_for_manifest(manifest, backend_manifest, write_fn):
|
|
192
192
|
app_type = manifest.get('appType')
|
|
193
193
|
|
|
@@ -209,7 +209,7 @@ def generate_for_manifest(manifest, backend_manifest, write_fn):
|
|
|
209
209
|
|
|
210
210
|
**TSConfig Generator:**
|
|
211
211
|
```starlark
|
|
212
|
-
#
|
|
212
|
+
# engine/topologies/tilt/generators/tsconfig.star
|
|
213
213
|
def generate_backend(path, prisma_path, write_fn, internal_deps, is_docker):
|
|
214
214
|
config = {
|
|
215
215
|
"compilerOptions": {
|
|
@@ -226,7 +226,7 @@ def generate_backend(path, prisma_path, write_fn, internal_deps, is_docker):
|
|
|
226
226
|
|
|
227
227
|
**Dockerfile Generation:**
|
|
228
228
|
```starlark
|
|
229
|
-
#
|
|
229
|
+
# engine/topologies/platform/docker/dockerfile/dockerfile.star
|
|
230
230
|
def generate_app_dockerfile(path, resource_name, start_command):
|
|
231
231
|
return '''
|
|
232
232
|
# L1: Golden Image Base
|
|
@@ -263,7 +263,7 @@ golden-image-l1 (Base)
|
|
|
263
263
|
|
|
264
264
|
**Golden Image Module:**
|
|
265
265
|
```starlark
|
|
266
|
-
#
|
|
266
|
+
# engine/topologies/platform/docker/build/golden_image.star
|
|
267
267
|
GoldenImage = struct(
|
|
268
268
|
build_l1 = _build_l1_base,
|
|
269
269
|
build_l2 = _build_l2_deps,
|
|
@@ -283,7 +283,7 @@ GoldenImage = struct(
|
|
|
283
283
|
|
|
284
284
|
**Per-Service Database Provisioning:**
|
|
285
285
|
```starlark
|
|
286
|
-
#
|
|
286
|
+
# engine/topologies/platform/state/relational.star
|
|
287
287
|
load("./prisma/db_readiness.star", "wait_for_db")
|
|
288
288
|
load("./prisma/migrate_script.star", "generate_migrate_script")
|
|
289
289
|
|
|
@@ -308,7 +308,7 @@ def get_database_url(resource_name):
|
|
|
308
308
|
|
|
309
309
|
**Database Readiness Checks:**
|
|
310
310
|
```starlark
|
|
311
|
-
#
|
|
311
|
+
# engine/topologies/platform/docker/layers/prisma/db_readiness.star
|
|
312
312
|
def wait_for_db(db_url, timeout=30):
|
|
313
313
|
"""Waits for PostgreSQL to be ready"""
|
|
314
314
|
return '''
|
|
@@ -324,7 +324,7 @@ done
|
|
|
324
324
|
|
|
325
325
|
**Traefik Configuration:**
|
|
326
326
|
```starlark
|
|
327
|
-
#
|
|
327
|
+
# engine/topologies/platform/net/proxy.star
|
|
328
328
|
def generate_traefik_labels(resource_name, port, host, path_prefix):
|
|
329
329
|
return {
|
|
330
330
|
'traefik.enable': 'true',
|
|
@@ -338,7 +338,7 @@ def generate_traefik_labels(resource_name, port, host, path_prefix):
|
|
|
338
338
|
|
|
339
339
|
**Library Discovery & Setup:**
|
|
340
340
|
```starlark
|
|
341
|
-
#
|
|
341
|
+
# engine/topologies/tilt/resources/deps.star
|
|
342
342
|
def discover_resource_libraries(ctx, resource_path):
|
|
343
343
|
"""Discovers @tdk/* dependencies from package.json"""
|
|
344
344
|
package_json = read_json(resource_path + "/package.json")
|
|
@@ -385,7 +385,7 @@ def setup_libraries(ctx, should_enable, DDD_LIBS, PLATFORM_LIBS, PRODUCT_LIBS, g
|
|
|
385
385
|
```
|
|
386
386
|
❌ DON'T MODIFY:
|
|
387
387
|
- **/autogenerated/*.autogenerated.*
|
|
388
|
-
- .
|
|
388
|
+
- .tdk/.tdk-out/product_autogenerated_*/*
|
|
389
389
|
- **/services.autogenerated.star
|
|
390
390
|
- **/domains.autogenerated.star
|
|
391
391
|
```
|
|
@@ -395,7 +395,7 @@ def setup_libraries(ctx, should_enable, DDD_LIBS, PLATFORM_LIBS, PRODUCT_LIBS, g
|
|
|
395
395
|
✅ MODIFY THESE INSTEAD:
|
|
396
396
|
- service.json (or let synthesis auto-configure from directory)
|
|
397
397
|
- package.json (dependencies)
|
|
398
|
-
-
|
|
398
|
+
- discovery/registry.star
|
|
399
399
|
```
|
|
400
400
|
|
|
401
401
|
### Manifest-Driven Rule
|
|
@@ -639,7 +639,7 @@ load('ext://live_update', 'sync', 'run') # Remove this line!
|
|
|
639
639
|
4. Verify in Tilt UI
|
|
640
640
|
|
|
641
641
|
### Adding New Generator
|
|
642
|
-
1. Create generator in
|
|
642
|
+
1. Create generator in `engine/topologies/tilt/generators/`
|
|
643
643
|
2. Export in `index.star`
|
|
644
644
|
3. Call from `manifest_resource.star`
|
|
645
645
|
4. Test with single manifest
|
package/engine/README.md
CHANGED
|
@@ -24,7 +24,7 @@ This directory contains the TDK Landscape Tilt infrastructure framework - the co
|
|
|
24
24
|
|
|
25
25
|
When you see `.tilt-engine/` in paths, know that this is framework code (not generated output).
|
|
26
26
|
|
|
27
|
-
Generated/output files go in `.
|
|
27
|
+
Generated/output files go in `.tdk/.tdk-out/` (which is gitignored).
|
|
28
28
|
|
|
29
29
|
## Learn More
|
|
30
30
|
|
|
@@ -89,8 +89,7 @@
|
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
91
|
"required": [
|
|
92
|
-
"port"
|
|
93
|
-
"healthCheckPath"
|
|
92
|
+
"port"
|
|
94
93
|
]
|
|
95
94
|
}
|
|
96
95
|
}
|
|
@@ -277,7 +276,7 @@
|
|
|
277
276
|
},
|
|
278
277
|
"healthCheckPath": {
|
|
279
278
|
"default": "/health",
|
|
280
|
-
"description": "HTTP endpoint for health checks. Must return 200 OK.",
|
|
279
|
+
"description": "HTTP endpoint for health checks. Must return 200 OK. Optional for bring-your-own: omit it for a service that does not speak HTTP (Postgres, Redis, SMTP, ...), and TDK then skips the HTTP health probes for it.",
|
|
281
280
|
"pattern": "^/[a-z0-9/-]*$",
|
|
282
281
|
"type": "string"
|
|
283
282
|
},
|
|
@@ -180,6 +180,9 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
|
|
|
180
180
|
db_url_with_fallback = PlatformDockerConstants.get_compose_env_database_url(db_name)
|
|
181
181
|
|
|
182
182
|
health_path = manifest.get('healthCheckPath', HEALTH_CHECK_PATH) if manifest else HEALTH_CHECK_PATH
|
|
183
|
+
# A bring-your-own service without healthCheckPath may not serve HTTP. None means no HTTP probe: no Traefik health check labels.
|
|
184
|
+
if manifest and manifest.get('appType') == 'bring-your-own' and not manifest.get('healthCheckPath'):
|
|
185
|
+
health_path = None
|
|
183
186
|
|
|
184
187
|
traefik_cfg = manifest.get('traefik', {}) if manifest else {}
|
|
185
188
|
traefik_host = traefik_cfg.get('host', stack + '.backend.' + _PROJECT_NAME + '.local')
|
|
@@ -164,22 +164,31 @@ def get_backend_traefik_labels(
|
|
|
164
164
|
middleware_config=middleware_config,
|
|
165
165
|
)
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
167
|
+
# No health path (a bring-your-own service that does not speak HTTP): Traefik balances without an active HTTP probe rather than
|
|
168
|
+
# probing a path the service never serves.
|
|
169
|
+
traefik_healthcheck_labels = ""
|
|
170
|
+
if health_path:
|
|
171
|
+
traefik_healthcheck_labels = """ - "traefik.http.services.{traefik_resource_name}.loadbalancer.healthcheck.path={health_path}"
|
|
170
172
|
- "traefik.http.services.{traefik_resource_name}.loadbalancer.healthcheck.interval={health_interval}"
|
|
171
173
|
- "traefik.http.services.{traefik_resource_name}.loadbalancer.healthcheck.timeout={health_timeout}"
|
|
172
174
|
- "traefik.http.services.{traefik_resource_name}.loadbalancer.healthcheck.followredirects=false"
|
|
173
|
-
|
|
175
|
+
""".format(
|
|
176
|
+
traefik_resource_name=traefik_resource_name,
|
|
177
|
+
health_path=health_path,
|
|
178
|
+
health_interval=TRAEFIK_HEALTHCHECK_INTERVAL,
|
|
179
|
+
health_timeout=TRAEFIK_HEALTHCHECK_TIMEOUT,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
labels = """ - "{traefik_enable_label}"
|
|
183
|
+
{backend_router_labels} - "traefik.http.services.{traefik_resource_name}.loadbalancer.server.port={internal_port}"
|
|
184
|
+
{traefik_healthcheck_labels} - "traefik.docker.network={traefik_network}"
|
|
174
185
|
""".format(
|
|
175
186
|
resource_entry_name=resource_entry_name,
|
|
176
187
|
traefik_enable_label=TRAEFIK_ENABLE_LABEL,
|
|
177
188
|
backend_router_labels=backend_router_labels,
|
|
178
189
|
traefik_resource_name=traefik_resource_name,
|
|
179
190
|
internal_port=internal_port,
|
|
180
|
-
|
|
181
|
-
health_interval=TRAEFIK_HEALTHCHECK_INTERVAL,
|
|
182
|
-
health_timeout=TRAEFIK_HEALTHCHECK_TIMEOUT,
|
|
191
|
+
traefik_healthcheck_labels=traefik_healthcheck_labels,
|
|
183
192
|
traefik_network=TRAEFIK_DOCKER_NETWORK,
|
|
184
193
|
)
|
|
185
194
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 📋 Manifest Module
|
|
2
2
|
|
|
3
3
|
**Status:** ✅ All Phases Complete! (Phase 1-5)
|
|
4
|
-
**Location:**
|
|
4
|
+
**Location:** `engine/topologies/tilt/manifest/`
|
|
5
5
|
**Purpose:** Clean, modular manifest parsing, loading, validation, and discovery integration system
|
|
6
6
|
|
|
7
7
|
---
|
|
@@ -185,6 +185,11 @@ def normalize(manifest, resource_path=""):
|
|
|
185
185
|
# Compute appType from path if missing
|
|
186
186
|
if not normalized.get('appType'):
|
|
187
187
|
normalized['appType'] = _determine_app_type(normalized, resource_path)
|
|
188
|
+
|
|
189
|
+
# A bring-your-own service may not speak HTTP (a database, a mail relay). Its health path is optional, so do not invent /health
|
|
190
|
+
# for it. Only an explicit healthCheckPath in service.json gives it one.
|
|
191
|
+
if normalized['appType'] == 'bring-your-own' and 'healthCheckPath' not in manifest:
|
|
192
|
+
normalized.pop('healthCheckPath', None)
|
|
188
193
|
|
|
189
194
|
# Compute stack from path if missing
|
|
190
195
|
if not normalized.get('stack'):
|
|
@@ -419,6 +419,19 @@ def _test_resource_description():
|
|
|
419
419
|
# MAIN
|
|
420
420
|
# =============================================================================
|
|
421
421
|
|
|
422
|
+
def _test_byo_health_path_is_optional():
|
|
423
|
+
"""A bring-your-own service without healthCheckPath gets none; /health is only the default for HTTP types."""
|
|
424
|
+
print("\n🧪 Testing bring-your-own health path is optional...")
|
|
425
|
+
|
|
426
|
+
byo = ManifestParser.normalize({'appType': 'bring-your-own', 'appName': 'postgres', 'stack': 'shop', 'port': 4500}, 'services/shop/postgres')
|
|
427
|
+
assert_true('healthCheckPath' not in byo, "BYO without healthCheckPath gets no default /health")
|
|
428
|
+
|
|
429
|
+
byo_http = ManifestParser.normalize({'appType': 'bring-your-own', 'appName': 'web', 'stack': 'shop', 'port': 4501, 'healthCheckPath': '/status'}, 'services/shop/web')
|
|
430
|
+
assert_equal('/status', byo_http.get('healthCheckPath'), "BYO keeps an explicit healthCheckPath")
|
|
431
|
+
|
|
432
|
+
backend = ManifestParser.normalize({'appType': 'backend', 'appName': 'api', 'stack': 'shop', 'port': 4000}, 'services/shop/api')
|
|
433
|
+
assert_equal('/health', backend.get('healthCheckPath'), "Backends still default to /health")
|
|
434
|
+
|
|
422
435
|
def run_tests():
|
|
423
436
|
"""Run all Phase 2 integration tests."""
|
|
424
437
|
print("\n" + "="*70)
|
|
@@ -436,6 +449,7 @@ def run_tests():
|
|
|
436
449
|
_test_get_normalized()
|
|
437
450
|
_test_resource_description()
|
|
438
451
|
_test_generated_string_fields()
|
|
452
|
+
_test_byo_health_path_is_optional()
|
|
439
453
|
|
|
440
454
|
# Print results
|
|
441
455
|
print("\n" + "="*70)
|