@tdk-landscape/tdk-cli-core 1.3.170 → 1.3.172
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/README.md +14 -0
- package/cli/dist/agent-runtimes/custom.js +333 -0
- package/cli/dist/agent-runtimes/registry.js +34 -0
- package/cli/dist/backend-frameworks/registry.js +16 -0
- package/cli/dist/cli.js +4 -0
- package/cli/dist/commands/agent.js +117 -0
- package/cli/dist/commands/completion.js +5 -1
- package/cli/dist/commands/help.js +7 -0
- package/cli/dist/commands/resource.js +54 -14
- package/cli/dist/commands/restart.js +79 -0
- package/cli/dist/mcp/tools.js +68 -13
- package/cli/dist/types/index.js +2 -0
- package/cli/dist/utils/constants.js +4 -0
- package/cli/dist/utils/doctor-report.js +2 -1
- package/cli/dist/utils/doctor-wiring.js +1 -1
- package/cli/dist/utils/json-output.js +2 -1
- package/cli/dist/utils/machine-output.js +2 -1
- package/cli/dist/utils/project-templates.js +4 -0
- package/cli/dist/utils/resource-kind.js +1 -1
- package/cli/dist/utils/service-manifest.js +1 -0
- package/cli/dist/utils/status-ports.js +3 -1
- package/cli/dist-bundle/{chunk-MZBDLTO2.js → chunk-JF2COU6K.js} +69 -69
- package/cli/dist-bundle/cli.js +602 -282
- package/cli/dist-bundle/{cold-preflight-PZKLJJGV.js → cold-preflight-GVGTFUDZ.js} +1 -1
- package/cli/package.json +1 -1
- package/engine/schemas/service-schema.json +26 -1
- package/engine/topologies/platform/docker/compose/compose.star +31 -3
- package/engine/topologies/platform/docker/layers/l4_runtime_layers.star +8 -0
- package/engine/topologies/tilt/manifest/loader.star +9 -0
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
|
|
2
|
-
import{
|
|
2
|
+
import{Qb as a,Rb as b,Sb as c,Tb as d,Ub as e}from"./chunk-JF2COU6K.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
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"type": "string"
|
|
119
119
|
},
|
|
120
120
|
"appType": {
|
|
121
|
-
"description": "Resource type determining build strategy:\n• backend - Hono/Express API server\n• frontend - Vite single-page application (React, Vue, Svelte, Preact, Lit, Solid, Qwik or Vanilla TypeScript, see framework)\n• sdk - Shared library package\n• worker - Background job processor\n• migrator - Database migration runner\n• library - Shared code library\n• mcp - Model Context Protocol server (an HTTP service on Bun, run like a backend)\n• bring-your-own - Wrap an existing service. No app scaffold. Needs Dockerfile or --image.",
|
|
121
|
+
"description": "Resource type determining build strategy:\n• backend - Hono/Express API server\n• frontend - Vite single-page application (React, Vue, Svelte, Preact, Lit, Solid, Qwik or Vanilla TypeScript, see framework)\n• sdk - Shared library package\n• worker - Background job processor\n• migrator - Database migration runner\n• library - Shared code library\n• mcp - Model Context Protocol server (an HTTP service on Bun, run like a backend)\n• agent - Long-running AI agent (a Bun HTTP service with /health and /ready, run like a backend; see agent)\n• bring-your-own - Wrap an existing service. No app scaffold. Needs Dockerfile or --image.",
|
|
122
122
|
"enum": [
|
|
123
123
|
"backend",
|
|
124
124
|
"frontend",
|
|
@@ -127,6 +127,7 @@
|
|
|
127
127
|
"migrator",
|
|
128
128
|
"library",
|
|
129
129
|
"mcp",
|
|
130
|
+
"agent",
|
|
130
131
|
"bring-your-own"
|
|
131
132
|
],
|
|
132
133
|
"type": "string"
|
|
@@ -476,6 +477,7 @@
|
|
|
476
477
|
"migrator",
|
|
477
478
|
"library",
|
|
478
479
|
"mcp",
|
|
480
|
+
"agent",
|
|
479
481
|
"bring-your-own"
|
|
480
482
|
],
|
|
481
483
|
"type": "string"
|
|
@@ -487,6 +489,29 @@
|
|
|
487
489
|
"apiPath": {
|
|
488
490
|
"description": "API path exposed by this resource, when applicable.",
|
|
489
491
|
"type": "string"
|
|
492
|
+
},
|
|
493
|
+
"agent": {
|
|
494
|
+
"description": "Agent settings, used when appType is 'agent'. The agent runtime checkpoints its sessions; TDK provides the volume or database.",
|
|
495
|
+
"type": "object",
|
|
496
|
+
"additionalProperties": false,
|
|
497
|
+
"properties": {
|
|
498
|
+
"runtime": {
|
|
499
|
+
"description": "Agent runtime scaffold. 'custom' is the default and has no vendor dependency.",
|
|
500
|
+
"type": "string",
|
|
501
|
+
"enum": [
|
|
502
|
+
"custom"
|
|
503
|
+
]
|
|
504
|
+
},
|
|
505
|
+
"durability": {
|
|
506
|
+
"description": "files: sessions live in a named volume that tdk down keeps. postgres: sessions live in Postgres via DATABASE_URL.",
|
|
507
|
+
"type": "string",
|
|
508
|
+
"enum": [
|
|
509
|
+
"files",
|
|
510
|
+
"postgres"
|
|
511
|
+
],
|
|
512
|
+
"default": "files"
|
|
513
|
+
}
|
|
514
|
+
}
|
|
490
515
|
}
|
|
491
516
|
},
|
|
492
517
|
"required": [
|
|
@@ -271,6 +271,17 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
|
|
|
271
271
|
no_http_healthcheck_section = NO_HTTP_HEALTHCHECK if (is_worker or health_path == None) else ""
|
|
272
272
|
# Backends with a health path get it in the env, so the shared golden image's HEALTHCHECK can probe it.
|
|
273
273
|
health_env = " - TDK_HEALTH_PATH={}\n".format(health_path) if health_path else ""
|
|
274
|
+
# An agent with files durability keeps its session checkpoints in a named volume. The volume is declared at the top of the
|
|
275
|
+
# generated file (generate_app_compose_from_entries reads the marker line below), so tdk down keeps it.
|
|
276
|
+
agent_env = ""
|
|
277
|
+
agent_volume_section = ""
|
|
278
|
+
if manifest and type(manifest.get('agent')) == 'dict':
|
|
279
|
+
agent_durability = manifest['agent'].get('durability', 'files')
|
|
280
|
+
agent_env = " - AGENT_DURABILITY={}\n".format(agent_durability)
|
|
281
|
+
if agent_durability == 'files':
|
|
282
|
+
agent_volume = res_name + '-agent-state'
|
|
283
|
+
agent_env += " - AGENT_STATE_DIR=/var/lib/tdk-agent\n"
|
|
284
|
+
agent_volume_section = " # tdk-agent-volume: {vol}\n volumes:\n - {vol}:/var/lib/tdk-agent\n".format(vol=agent_volume)
|
|
274
285
|
|
|
275
286
|
if is_worker or is_proxy_disabled_byo:
|
|
276
287
|
traefik_labels = ' - "traefik.enable=false"'
|
|
@@ -311,7 +322,7 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
|
|
|
311
322
|
{infisical_env}
|
|
312
323
|
- RESOURCE_NAME={stack}
|
|
313
324
|
- PORT={port_anchor}
|
|
314
|
-
{health_env} - INSTANCE_ID={instance_label}
|
|
325
|
+
{health_env}{agent_env} - INSTANCE_ID={instance_label}
|
|
315
326
|
- NATS_QUEUE_GROUP={nats_queue}
|
|
316
327
|
- TILT_DATABASE_URL={db_url_for_tilt}
|
|
317
328
|
- TILT_NATS_URL={nats_url}
|
|
@@ -322,7 +333,7 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
|
|
|
322
333
|
# migration/CLI issue) without touching the generator or any service code.
|
|
323
334
|
- AUTO_MIGRATE=${{AUTO_MIGRATE:-true}}
|
|
324
335
|
{auth_env}{secrets_env}
|
|
325
|
-
labels:
|
|
336
|
+
{agent_volume_section} labels:
|
|
326
337
|
{traefik_labels}
|
|
327
338
|
networks:
|
|
328
339
|
- {network_traefik_public}
|
|
@@ -368,6 +379,8 @@ def _generate_single_backend_entry(resource_path, resource_name, res, manifest,
|
|
|
368
379
|
traefik_labels=traefik_labels,
|
|
369
380
|
healthcheck_section=healthcheck_section,
|
|
370
381
|
health_env=health_env,
|
|
382
|
+
agent_env=agent_env,
|
|
383
|
+
agent_volume_section=agent_volume_section,
|
|
371
384
|
infisical_env=infisical_env,
|
|
372
385
|
auth_env=auth_env,
|
|
373
386
|
secrets_env=secrets_env,
|
|
@@ -510,6 +523,20 @@ x-frontend-memory-limit: &frontend-memory-limit
|
|
|
510
523
|
services:
|
|
511
524
|
""".format(port_anchors=port_anchors)
|
|
512
525
|
|
|
526
|
+
# Named volumes used by services (agent session state) must be declared at the top level. Services mark them with a
|
|
527
|
+
# "# tdk-agent-volume: <name>" line, so the declaration follows the services without a separate registry.
|
|
528
|
+
volume_names = []
|
|
529
|
+
for entry in resource_entries:
|
|
530
|
+
for line in entry.split("\n"):
|
|
531
|
+
if line.strip().startswith("# tdk-agent-volume: "):
|
|
532
|
+
name = line.strip()[len("# tdk-agent-volume: "):]
|
|
533
|
+
# Replicas of one agent repeat the marker; Compose rejects a duplicate key under volumes:.
|
|
534
|
+
if name not in volume_names:
|
|
535
|
+
volume_names.append(name)
|
|
536
|
+
volumes_section = ""
|
|
537
|
+
if volume_names:
|
|
538
|
+
volumes_section = "\nvolumes:\n" + "".join([" {}:\n".format(name) for name in volume_names])
|
|
539
|
+
|
|
513
540
|
footer = """
|
|
514
541
|
networks:
|
|
515
542
|
{network_traefik_public}:
|
|
@@ -520,11 +547,12 @@ networks:
|
|
|
520
547
|
external: true
|
|
521
548
|
{network_infisical}:
|
|
522
549
|
external: true
|
|
523
|
-
""".format(
|
|
550
|
+
{volumes_section}""".format(
|
|
524
551
|
network_traefik_public=PlatformDockerConstants.NETWORK_TRAEFIK_PUBLIC,
|
|
525
552
|
network_backend=PlatformDockerConstants.NETWORK_BACKEND,
|
|
526
553
|
network_database=PlatformDockerConstants.NETWORK_DATABASE,
|
|
527
554
|
network_infisical=PlatformDockerConstants.NETWORK_INFISICAL,
|
|
555
|
+
volumes_section=volumes_section,
|
|
528
556
|
)
|
|
529
557
|
|
|
530
558
|
content = header + "\n".join(resource_entries) + footer
|
|
@@ -173,6 +173,14 @@ def L4_generate_backend_runtime(res_path, port = BASE_PORT_BACKEND, cmd = 'bun r
|
|
|
173
173
|
parts.append("RUN apk add --no-cache hugo\n")
|
|
174
174
|
parts.append("USER bun\n")
|
|
175
175
|
|
|
176
|
+
# A files-durability agent keeps its checkpoints in /var/lib/tdk-agent, a named volume. Docker seeds a new volume with the
|
|
177
|
+
# image directory's owner, so create the directory owned by bun, or the agent cannot write its first checkpoint (EACCES).
|
|
178
|
+
agent_cfg = manifest.get('agent') if manifest else None
|
|
179
|
+
if type(agent_cfg) == 'dict' and agent_cfg.get('durability', 'files') == 'files':
|
|
180
|
+
parts.append("USER root\n")
|
|
181
|
+
parts.append("RUN mkdir -p /var/lib/tdk-agent && chown bun:bun /var/lib/tdk-agent\n")
|
|
182
|
+
parts.append("USER bun\n")
|
|
183
|
+
|
|
176
184
|
if has_prisma_config:
|
|
177
185
|
# Prisma v7 migrate deploy reads datasource.url from prisma.config.ts in CWD
|
|
178
186
|
parts.append(prisma_config_copy(res_path))
|
|
@@ -79,6 +79,15 @@ def load_from_file(path):
|
|
|
79
79
|
if type(manifest) == "dict" and manifest.get("appType") == "mcp":
|
|
80
80
|
manifest["appType"] = "backend"
|
|
81
81
|
manifest["mcp"] = True
|
|
82
|
+
|
|
83
|
+
# An `agent` resource is a long-running AI agent: a Bun HTTP service (/health, /ready, SIGTERM drain) that is built, routed
|
|
84
|
+
# and health-checked as a backend, so it reuses the backend code paths and boots health-gated. Its settings are kept under
|
|
85
|
+
# manifest["agent"] for the generators (state volume, AGENT_* environment), with durability defaulting to files.
|
|
86
|
+
if type(manifest) == "dict" and manifest.get("appType") == "agent":
|
|
87
|
+
agent = dict(manifest.get("agent") or {})
|
|
88
|
+
agent["durability"] = agent.get("durability") or "files"
|
|
89
|
+
manifest["appType"] = "backend"
|
|
90
|
+
manifest["agent"] = agent
|
|
82
91
|
|
|
83
92
|
return struct(manifest=manifest, error=None)
|
|
84
93
|
|