@tdk-landscape/tdk-cli-core 1.3.143 → 1.3.144
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/cli/dist/commands/status.js +4 -3
- package/cli/dist/commands/ui.js +3 -2
- package/cli/dist/utils/smoke.js +6 -1
- package/cli/dist/utils/tilt-startup.js +7 -1
- package/cli/dist-bundle/{chunk-FFPLKZUH.js → chunk-2PTDOT3Y.js} +2 -2
- package/cli/dist-bundle/cli.js +251 -251
- package/cli/dist-bundle/{cold-preflight-DUL4575P.js → cold-preflight-CGPSYGDB.js} +1 -1
- package/cli/package.json +1 -1
- package/engine/assets/docker/wake-gateway/Dockerfile +1 -0
- package/engine/assets/docker/wake-gateway/server.ts +3 -0
- package/engine/topologies/tilt/generators/npmrc.star +4 -7
- package/package.json +1 -1
|
@@ -12,6 +12,7 @@ import { findProjectRoot } from "../utils/paths.js";
|
|
|
12
12
|
import { deriveServiceStates } from "../utils/service-runtime-state.js";
|
|
13
13
|
import { buildServicePorts, buildStackPorts } from "../utils/status-ports.js";
|
|
14
14
|
import { getTiltfilePath, isTiltAvailable, runTilt } from "../utils/tilt.js";
|
|
15
|
+
import { getTiltPollingPort } from "../utils/tilt-startup.js";
|
|
15
16
|
import { evaluateTiltReadiness, tiltGetUiResources } from "../utils/up-readiness.js";
|
|
16
17
|
export const statusCommand = new Command("status")
|
|
17
18
|
.description("Show status of resources and stacks")
|
|
@@ -63,9 +64,9 @@ export const statusCommand = new Command("status")
|
|
|
63
64
|
let readiness = null;
|
|
64
65
|
// The same look at Tilt feeds readiness and each service's state, so `tdk status` and `tdk ui` cannot disagree.
|
|
65
66
|
let serviceStates = null;
|
|
67
|
+
const tiltPort = getTiltPollingPort(process.env.TILT_PORT);
|
|
66
68
|
if (tiltAvailable) {
|
|
67
|
-
const
|
|
68
|
-
const text = await tiltGetUiResources(Number.isInteger(port) ? port : 10350);
|
|
69
|
+
const text = await tiltGetUiResources(tiltPort);
|
|
69
70
|
if (text) {
|
|
70
71
|
const deferred = getDeferredResourceNames();
|
|
71
72
|
try {
|
|
@@ -115,7 +116,7 @@ export const statusCommand = new Command("status")
|
|
|
115
116
|
? { blockedBy: serviceStates[resource.name]?.blockedBy }
|
|
116
117
|
: {}),
|
|
117
118
|
})),
|
|
118
|
-
ports: buildStackPorts(portPlan,
|
|
119
|
+
ports: buildStackPorts(portPlan, tiltPort),
|
|
119
120
|
stacks: discovery.stacks.map((stack) => ({
|
|
120
121
|
name: stack.name,
|
|
121
122
|
resourceCount: stack.resourceCount,
|
package/cli/dist/commands/ui.js
CHANGED
|
@@ -16,6 +16,7 @@ import { createStatusMessageController } from "../utils/status-message.js";
|
|
|
16
16
|
import { getListRowFromMouseY, getTerminalRuleWidth } from "../utils/terminal-layout.js";
|
|
17
17
|
import { isTiltAvailable } from "../utils/tilt.js";
|
|
18
18
|
import { loadTiltEvents, stripTerminalControls, TiltEventsLoadError, } from "../utils/tilt-events.js";
|
|
19
|
+
import { getTiltPollingPort } from "../utils/tilt-startup.js";
|
|
19
20
|
import { formatUiKeyHint, formatUiKeyNames, UI_KEYMAP } from "../utils/ui-keymap.js";
|
|
20
21
|
import { applyServiceStates, fetchServiceStates, } from "../utils/ui-service-state.js";
|
|
21
22
|
// biome-ignore lint/correctness/noUnusedFunctionParameters: reserved callback prop kept in the component API
|
|
@@ -116,14 +117,14 @@ export const TUIApp = ({ animated = true }) => {
|
|
|
116
117
|
const [serviceStates, setServiceStates] = useState({});
|
|
117
118
|
useEffect(() => {
|
|
118
119
|
let cancelled = false;
|
|
119
|
-
const tiltPort =
|
|
120
|
+
const tiltPort = getTiltPollingPort(process.env.TILT_PORT);
|
|
120
121
|
// A Tilt call can outlast the 5 s interval; never start a poll while the last one is still running.
|
|
121
122
|
const run = singleFlight((next) => {
|
|
122
123
|
if (cancelled)
|
|
123
124
|
return;
|
|
124
125
|
setServiceStates((previous) => JSON.stringify(previous) === JSON.stringify(next) ? previous : next);
|
|
125
126
|
});
|
|
126
|
-
const poll = () => run(() => fetchServiceStates(services,
|
|
127
|
+
const poll = () => run(() => fetchServiceStates(services, tiltPort));
|
|
127
128
|
void poll();
|
|
128
129
|
const timer = setInterval(() => void poll(), 5000);
|
|
129
130
|
return () => {
|
package/cli/dist/utils/smoke.js
CHANGED
|
@@ -116,7 +116,12 @@ function readPath(value, path) {
|
|
|
116
116
|
return undefined;
|
|
117
117
|
if (!Object.hasOwn(current, part))
|
|
118
118
|
return undefined;
|
|
119
|
-
|
|
119
|
+
// Resolve only own data properties. Besides avoiding inherited properties, this
|
|
120
|
+
// avoids invoking accessors on values supplied by smoke-test responses.
|
|
121
|
+
const descriptor = Object.getOwnPropertyDescriptor(current, part);
|
|
122
|
+
if (!descriptor || !("value" in descriptor))
|
|
123
|
+
return undefined;
|
|
124
|
+
current = descriptor.value;
|
|
120
125
|
}
|
|
121
126
|
return current;
|
|
122
127
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// Copyright (c) 2026 TDK Landscape contributors
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
|
+
import { STANDARD_PORTS } from "./constants.js";
|
|
3
4
|
import { isValidPort } from "./validation.js";
|
|
4
5
|
export function parseTiltPort(value) {
|
|
5
6
|
if (value === undefined || value === "")
|
|
6
7
|
return { ok: true, port: undefined };
|
|
7
8
|
const port = Number(value);
|
|
8
|
-
if (
|
|
9
|
+
if (/[^0-9]/.test(value) || !isValidPort(port)) {
|
|
9
10
|
return {
|
|
10
11
|
ok: false,
|
|
11
12
|
message: `Invalid TILT_PORT "${value}": expected an integer from 1 to 65535.`,
|
|
@@ -13,6 +14,11 @@ export function parseTiltPort(value) {
|
|
|
13
14
|
}
|
|
14
15
|
return { ok: true, port };
|
|
15
16
|
}
|
|
17
|
+
/** Resolve the port for read-only polling, falling back when TILT_PORT is absent or invalid. */
|
|
18
|
+
export function getTiltPollingPort(value) {
|
|
19
|
+
const result = parseTiltPort(value);
|
|
20
|
+
return result.ok ? (result.port ?? STANDARD_PORTS.tiltUi) : STANDARD_PORTS.tiltUi;
|
|
21
|
+
}
|
|
16
22
|
export function secondUpAction(input) {
|
|
17
23
|
if (input.runningPorts.length === 0 || input.force)
|
|
18
24
|
return { action: "start" };
|
|
@@ -9,11 +9,11 @@ To create a stack, use:`},services:{singular:"service",command:"tdk resource <na
|
|
|
9
9
|
To create a service:`},"stack-services":{singular:"service",command:"tdk resource <name> --stack <stack-name>",context:`
|
|
10
10
|
To add services to this stack:`}};function Pu(e,t){let n=uo[e];console.log(t?f.yellow(`No ${n.singular}s found${t}.`):f.yellow(`No ${n.singular}s found.`)),console.log(f.gray(n.context)),console.log(f.gray(` ${n.command}`)),e==="stacks"&&(console.log(f.gray(`
|
|
11
11
|
Or create a new resource with a stack:`)),console.log(f.gray(" tdk resource <name> --stack <stack-name>")))}function vu(e){console.log(f.yellow(e||"Cancelled."))}function wu(e){console.log(f.blue(`TDK ${e}
|
|
12
|
-
`))}function $u(e,t){console.log(f.green(`All ${e} are ${t}!`))}var pt=62;function Ru(e="\u2500",t=pt){return e.repeat(t)}function In(e,t=pt-2){let n=Math.max(0,t-e.length),r=Math.floor(n/2),s=n-r;return" ".repeat(r)+e+" ".repeat(s)}function _u(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e.padEnd(t)}function Ou(e,t){return e.length<=t?e:`${e.slice(0,t-3)}...`}function Au(e){console.log(f.green(`\u2713 ${e}`))}function Du(e){console.log(f.blue(e))}function Cu(e,t=2){console.log(f.gray(`${" ".repeat(t)}${e}`))}function Nu(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function ju(e,t,n=pt){let r=n-2,s="\u2500".repeat(r);console.log(),console.log(f.cyan(`\u256D${s}\u256E`)),console.log(f.cyan("\u2502")+f.bold.white(In(e,r))+f.cyan("\u2502")),t&&(console.log(f.cyan(`\u251C${s}\u2524`)),console.log(f.cyan("\u2502")+f.gray(In(t,r))+f.cyan("\u2502"))),console.log(f.cyan(`\u2570${s}\u256F`))}import{existsSync as po}from"node:fs";import{dirname as fo,join as mo,resolve as Mn}from"node:path";import{cwd as ho}from"node:process";var Fn={name:"tdk-cli-internal",private:!0,version:"1.3.143",description:"TDK CLI \u2014 start services on your machine.",keywords:["tdk","tilt","cli","local-dev","microservices"],homepage:"https://github.com/tdk-landscape/tdk-cli-core#readme",bugs:{url:"https://github.com/tdk-landscape/tdk-cli-core/issues"},repository:{type:"git",url:"git+https://github.com/tdk-landscape/tdk-cli-core.git",directory:"cli"},license:"MIT",author:"TDK Team",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",bin:{tdk:"bin/tdk.js","tdk-cli":"bin/tdk.js"},files:["dist","dist-bundle","bin","templates","README.md","Tiltfile","engine","discovery","specs","ext","!ext/ide-components/code_executor","shared-platform-engineering/docker-templates"],scripts:{build:"tsc && node scripts/bundle.mjs","build:watch":"tsc --watch",lint:"biome check .","lint:fix":"biome check . --write",typecheck:"tsc --project tsconfig.typecheck.json",clean:"rm -rf dist",dev:"bun run build:watch",test:"vitest run","test:watch":"vitest",prepack:"../scripts/stage-npm-engine.sh && npm run build"},dependencies:{commander:"^15.0.0",handlebars:"^4.7.8"},devDependencies:{"@biomejs/biome":"^2.5.13","@types/node":"^22.0.0","@types/react":"^19.3.0",ajv:"^8.17.1",chalk:"^6.0.1",esbuild:"^0.28.2",ink:"^7.1.1",knip:"^6.38.0",react:"^19.3.0","react-devtools-core":"^8.0.0",typescript:"^7.0.2",vite:"^8.3.1",vitest:"^5.0.0"},engines:{node:">=22.12.0"}};function m(e=ho()){let t=Mn(e),n=Mn("/");for(;t!==n;){if(po(mo(t,".tdk",E)))return t;let r=fo(t);if(r===t)break;t=r}return null}var Ce=null;function go(){if(Ce)return Ce;let e=Fn;if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Invalid package.json: expected object");let t=e;return Ce={name:String(t.name??"@tdk-landscape/tdk-cli-core"),version:String(t.version??"0.0.0"),fullPackage:t},Ce}function Ln(){return go().version}import{readFileSync as ko}from"node:fs";import{join as yo}from"node:path";function Ne(){let e=m();if(e)try{let t=ko(yo(e,".tdk",E),"utf-8"),n=JSON.parse(t);if(n?.project?.name)return n.project.name}catch{}return"tdk-project"}function ft(e){let t=Ne(),n=process.env.TDK_SERVICE_BASE_URL??`http://${t}.localhost${e?`:${e}`:""}`;try{let r=new URL(n.includes("://")?n:`http://${n}`),s=r.hostname,o=r.port||(e?String(e):"");if(s==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(s))return{appBase:`${r.protocol}//${s}${o?`:${o}`:""}`,apiBase:`${r.protocol}//${s}${o?`:${o}`:""}`};let i=s.replace(/^(app|api)\./,"");return{appBase:`${r.protocol}//app.${i}${o?`:${o}`:""}`,apiBase:`${r.protocol}//api.${i}${o?`:${o}`:""}`}}catch{return{appBase:`http://app.${t}.localhost`,apiBase:`http://api.${t}.localhost`}}}function So(e){return`${e.replace(/\/+$/,"")}/health`}function mt(e){if(w(e.config?.appType)){let t=e.name.replace(/-api$/,"");return e.config?.apiPath??`/api/${t}`}return e.config?.basePath??`/${e.name}`}function Bn(e,t){let{appBase:n,apiBase:r}=ft(t);return e.filter(s=>s.config?.appType==="frontend"||w(s.config?.appType)).map(s=>{let o=w(s.config.appType)?r:n;return{name:s.name,appType:s.config.appType,url:`${o}${So(mt(s))}`}})}async function bo(e,t){try{let n=await fetch(e.url,{method:"GET",redirect:"manual",signal:AbortSignal.timeout(t)});return{...e,ok:n.ok,status:n.status}}catch(n){let r=n instanceof Error&&n.name==="TimeoutError"?`no response within ${t}ms`:n instanceof Error?n.message:String(n);return{...e,ok:!1,error:r}}}async function Un(e,t){return Promise.all(e.map(n=>bo(n,t)))}import{existsSync as ee,readdirSync as lr,readFileSync as pr,statSync as xt}from"node:fs";import{dirname as oi,join as J}from"node:path";var he=class{data;options;constructor(t){this.data=new Map,this.options=t}has(t){let n=this.data.get(t);return n?Date.now()-n.timestamp>this.options.ttlMs?(this.data.delete(t),!1):!0:!1}get(t){if(this.has(t))return this.data.get(t)?.value}set(t,n){this.data.set(t,{value:n,timestamp:Date.now()})}delete(t){this.data.delete(t)}clear(){this.data.clear()}keys(){let t=[];for(let n of this.data.keys())this.has(n)&&t.push(n);return t}size(){return this.keys().length}};function Hn(e){let t=0;return{isValid(){return Date.now()-t<e},markUpdated(){t=Date.now()},reset(){t=0}}}import{execFileSync as _o,execSync as Oo}from"node:child_process";import{existsSync as vo}from"node:fs";import{delimiter as wo,extname as $o,join as Ro}from"node:path";import{delimiter as Zu,extname as To}from"node:path";function je(){return process.platform==="win32"}function xo(e){return e==="linux"?"linux":e==="darwin"?"darwin":e==="win32"?"windows":null}function Eo(e){return e==="x64"?"amd64":e==="arm64"?"arm64":null}function Po(e,t){let n=xo(e),r=Eo(t);if(!n||!r||n==="windows"&&r!=="amd64")return null;let s=`tdk-${n}-${r}`;return n==="windows"?`${s}.exe`:s}function Qu(){return Po(process.platform,process.arch)}function ed(){return je()?"tdk.exe":"tdk"}function Vn(e,t=je()){return t?To(e)?[e]:[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e]}function $(e){let t=process.env.PATH??process.env.Path??"",n=je(),r=Vn(e,n);if(n&&!$o(e))for(let s of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let o=s.toLowerCase();o&&!r.includes(`${e}${o}`)&&r.push(`${e}${o}`)}for(let s of t.split(wo))if(s)for(let o of r){let i=Ro(s,o);if(vo(i))return i}return null}var Gn=1e4;function Kn(){let e=!1;if(process.platform==="win32")try{return _o($("docker")??"docker",["ps"],{stdio:"ignore",timeout:Gn,windowsHide:!0}),"running"}catch(t){return t.code==="ETIMEDOUT"?"unresponsive":"missing"}for(let t of["docker ps","colima status","podman ps"])try{return Oo(t,{stdio:"ignore",timeout:Gn}),"running"}catch(n){n.code==="ETIMEDOUT"&&(e=!0)}return e?"unresponsive":"missing"}function Ie(e,t){return e[t]??0}function Ao(e,t){let n=Array.from({length:t.length+1},(r,s)=>s);for(let r=1;r<=e.length;r++){let s=[r];for(let o=1;o<=t.length;o++){let i=e[r-1]===t[o-1]?0:1;s[o]=Math.min(Ie(s,o-1)+1,Ie(n,o)+1,Ie(n,o-1)+i)}n=s}return Ie(n,t.length)}function Do(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length-1;n++)if(e[n]!==t[n]&&e[n]===t[n+1]&&e[n+1]===t[n]&&e.slice(0,n)===t.slice(0,n)&&e.slice(n+2)===t.slice(n+2))return!0;return!1}function Wn(e,t){if(e.length<2||t.length===0||t.includes(e))return;let n=e.toLowerCase(),r,s=Number.POSITIVE_INFINITY;for(let o of t){if(o.length===0)continue;let i=o.toLowerCase(),a=Do(n,i)?1:Ao(n,i),c=Math.max(1,Math.min(2,Math.floor(Math.max(n.length,i.length)/3)));a>c||(a<s||a===s&&(r===void 0||o<r))&&(r=o,s=a)}return r}import{spawn as Co}from"node:child_process";import{join as No}from"node:path";function jo(e,t=[],n={}){return new Promise((r,s)=>{let o=[e,...t];n.verbose&&console.log(`Executing: tilt ${o.join(" ")}`);let i=Co($("tilt")??"tilt",o,{stdio:n.inheritStdio?"inherit":"pipe",shell:!1,windowsHide:process.platform==="win32",timeout:n.timeoutMs}),a="",c="";n.inheritStdio||(i.stdout?.on("data",u=>{a+=u.toString()}),i.stderr?.on("data",u=>{c+=u.toString()})),i.on("close",u=>{r({exitCode:u??1,stdout:a,stderr:c})}),i.on("error",u=>{s(new Error(`Failed to spawn tilt: ${u.message}`))})})}async function Jn(){try{return(await jo("version",[],{inheritStdio:!1,timeoutMs:1e4})).exitCode===0}catch{return!1}}function Io(){let e=m();if(!e)throw H.notInProject();return No(e,".tdk",".tdk-out","Tiltfile")}function qn(e){let t=Io();e.push("-f",t)}function hd(e,t={}){let n=[];return qn(n),t.focusTargets&&t.focusTargets.length>0&&n.push("--",`--focus=${t.focusTargets.join(",")}`),n.push(...e),t.verbose&&!t.quiet&&n.push("--verbose"),t.watch&&n.push("--watch"),n}function gd(e={}){let t=[];return qn(t),e.force&&t.push("--force"),e.focusTargets&&e.focusTargets.length>0&&t.push("--",`--focus=${e.focusTargets.join(",")}`),t}function Yn(e){return e instanceof Error?e.message:String(e)}function Pd(e,t){if(process.env.TDK_VERBOSE){let n=t!==void 0?`: ${Yn(t)}`:"";console.warn(f.gray(`${e}${n}`))}}var R=class extends Error{suggestions;exitCode;constructor(t,n=[],r=1){super(t),this.name="TdkError",this.suggestions=n,this.exitCode=r}display(){Lo(this.message,void 0,this.suggestions)}exit(){this.display(),process.exit(this.exitCode)}};function ht(e,t,n=!1){let r=new Set;for(let s of e){let o=Wn(s,t);o&&r.add(n?`Did you mean "${o}" for "${s}"?`:`Did you mean "${o}"?`)}return[...r]}var H={tiltNotInstalled:()=>new R("Tilt CLI is not installed",["Install Tilt: `brew install tilt` (macOS)","Or download from: https://docs.tilt.dev/install.html","Verify with: `tilt version`",`Setup guide: ${ct}`]),dockerNotAvailable:()=>new R("Docker (or a compatible container runtime) is not running",["Start Docker Desktop, then verify with: `docker ps`","Or start Colima: `colima start`","Or start the Docker service on Linux: `sudo systemctl start docker`",`Setup guide: ${ct}`]),dockerNotResponding:()=>new R("Docker is running but not responding (`docker ps` hung for 10s)",["Quit and reopen Docker Desktop, or run `colima restart`","Then verify with: `docker ps`"]),stackNotFound:(e,t=[])=>new R(`Stack "${e}" not found`,[...ht([e],t),"Run `tdk stacks` to see available stacks","Run `tdk stack` to assign resources to a stack"]),resourceNotFound:(e,t=[])=>new R(`Resource "${e}" not found`,[...ht([e],t),"Run `tdk resources` to list all resources","Check the resource name spelling"]),unknownServices:(e,t)=>{let n=ht(e,t,e.length>1);return new R(`Unknown service ${e.join(", ")}. Valid names: ${t.join(", ")}`,n,2)},directoryExists:e=>new R(`Directory already exists: ${e}`,["Use `--path` to specify a different location","Remove the existing directory if no longer needed"]),invalidPath:e=>new R(`Invalid path: ${e}`,["Path must be within the project directory",'Path cannot contain special characters like <>:"|?*']),notInProject:()=>new R("Could not find project root (no .tdk/project.json found)",["Run this from within a TDK project","Run `tdk project --yes` to initialize a new project"])};function vd(){let e=m();return e||H.notInProject().exit()}function Fo(e){e instanceof R&&e.exit(),console.error(f.red(`Error: ${Yn(e)}`)),process.exit(1)}async function Mo(e,t){try{return await e()}catch(n){return t?.verbose&&n instanceof Error&&n.stack&&console.error(f.gray(n.stack)),Fo(n)}}async function wd(e,t){let n=[],r=Kn();return r==="unresponsive"?n.push(H.dockerNotResponding()):r==="missing"&&n.push(H.dockerNotAvailable()),await Jn()||n.push(H.tiltNotInstalled()),n.length>0&&(console.error(f.red(`
|
|
12
|
+
`))}function $u(e,t){console.log(f.green(`All ${e} are ${t}!`))}var pt=62;function Ru(e="\u2500",t=pt){return e.repeat(t)}function In(e,t=pt-2){let n=Math.max(0,t-e.length),r=Math.floor(n/2),s=n-r;return" ".repeat(r)+e+" ".repeat(s)}function _u(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e.padEnd(t)}function Ou(e,t){return e.length<=t?e:`${e.slice(0,t-3)}...`}function Au(e){console.log(f.green(`\u2713 ${e}`))}function Du(e){console.log(f.blue(e))}function Cu(e,t=2){console.log(f.gray(`${" ".repeat(t)}${e}`))}function Nu(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function ju(e,t,n=pt){let r=n-2,s="\u2500".repeat(r);console.log(),console.log(f.cyan(`\u256D${s}\u256E`)),console.log(f.cyan("\u2502")+f.bold.white(In(e,r))+f.cyan("\u2502")),t&&(console.log(f.cyan(`\u251C${s}\u2524`)),console.log(f.cyan("\u2502")+f.gray(In(t,r))+f.cyan("\u2502"))),console.log(f.cyan(`\u2570${s}\u256F`))}import{existsSync as po}from"node:fs";import{dirname as fo,join as mo,resolve as Mn}from"node:path";import{cwd as ho}from"node:process";var Fn={name:"tdk-cli-internal",private:!0,version:"1.3.144",description:"TDK CLI \u2014 start services on your machine.",keywords:["tdk","tilt","cli","local-dev","microservices"],homepage:"https://github.com/tdk-landscape/tdk-cli-core#readme",bugs:{url:"https://github.com/tdk-landscape/tdk-cli-core/issues"},repository:{type:"git",url:"git+https://github.com/tdk-landscape/tdk-cli-core.git",directory:"cli"},license:"MIT",author:"TDK Team",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",bin:{tdk:"bin/tdk.js","tdk-cli":"bin/tdk.js"},files:["dist","dist-bundle","bin","templates","README.md","Tiltfile","engine","discovery","specs","ext","!ext/ide-components/code_executor","shared-platform-engineering/docker-templates"],scripts:{build:"tsc && node scripts/bundle.mjs","build:watch":"tsc --watch",lint:"biome check .","lint:fix":"biome check . --write",typecheck:"tsc --project tsconfig.typecheck.json",clean:"rm -rf dist",dev:"bun run build:watch",test:"vitest run","test:watch":"vitest",prepack:"../scripts/stage-npm-engine.sh && npm run build"},dependencies:{commander:"^15.0.0",handlebars:"^4.7.8"},devDependencies:{"@biomejs/biome":"^2.5.13","@types/node":"^22.0.0","@types/react":"^19.3.0",ajv:"^8.17.1",chalk:"^6.0.1",esbuild:"^0.28.2",ink:"^7.1.1",knip:"^6.38.0",react:"^19.3.0","react-devtools-core":"^8.0.0",typescript:"^7.0.2",vite:"^8.3.1",vitest:"^5.0.0"},engines:{node:">=22.12.0"}};function m(e=ho()){let t=Mn(e),n=Mn("/");for(;t!==n;){if(po(mo(t,".tdk",E)))return t;let r=fo(t);if(r===t)break;t=r}return null}var Ce=null;function go(){if(Ce)return Ce;let e=Fn;if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Invalid package.json: expected object");let t=e;return Ce={name:String(t.name??"@tdk-landscape/tdk-cli-core"),version:String(t.version??"0.0.0"),fullPackage:t},Ce}function Ln(){return go().version}import{readFileSync as ko}from"node:fs";import{join as yo}from"node:path";function Ne(){let e=m();if(e)try{let t=ko(yo(e,".tdk",E),"utf-8"),n=JSON.parse(t);if(n?.project?.name)return n.project.name}catch{}return"tdk-project"}function ft(e){let t=Ne(),n=process.env.TDK_SERVICE_BASE_URL??`http://${t}.localhost${e?`:${e}`:""}`;try{let r=new URL(n.includes("://")?n:`http://${n}`),s=r.hostname,o=r.port||(e?String(e):"");if(s==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(s))return{appBase:`${r.protocol}//${s}${o?`:${o}`:""}`,apiBase:`${r.protocol}//${s}${o?`:${o}`:""}`};let i=s.replace(/^(app|api)\./,"");return{appBase:`${r.protocol}//app.${i}${o?`:${o}`:""}`,apiBase:`${r.protocol}//api.${i}${o?`:${o}`:""}`}}catch{return{appBase:`http://app.${t}.localhost`,apiBase:`http://api.${t}.localhost`}}}function So(e){return`${e.replace(/\/+$/,"")}/health`}function mt(e){if(w(e.config?.appType)){let t=e.name.replace(/-api$/,"");return e.config?.apiPath??`/api/${t}`}return e.config?.basePath??`/${e.name}`}function Bn(e,t){let{appBase:n,apiBase:r}=ft(t);return e.filter(s=>s.config?.appType==="frontend"||w(s.config?.appType)).map(s=>{let o=w(s.config.appType)?r:n;return{name:s.name,appType:s.config.appType,url:`${o}${So(mt(s))}`}})}async function bo(e,t){try{let n=await fetch(e.url,{method:"GET",redirect:"manual",signal:AbortSignal.timeout(t)});return{...e,ok:n.ok,status:n.status}}catch(n){let r=n instanceof Error&&n.name==="TimeoutError"?`no response within ${t}ms`:n instanceof Error?n.message:String(n);return{...e,ok:!1,error:r}}}async function Un(e,t){return Promise.all(e.map(n=>bo(n,t)))}import{existsSync as ee,readdirSync as lr,readFileSync as pr,statSync as xt}from"node:fs";import{dirname as oi,join as J}from"node:path";var he=class{data;options;constructor(t){this.data=new Map,this.options=t}has(t){let n=this.data.get(t);return n?Date.now()-n.timestamp>this.options.ttlMs?(this.data.delete(t),!1):!0:!1}get(t){if(this.has(t))return this.data.get(t)?.value}set(t,n){this.data.set(t,{value:n,timestamp:Date.now()})}delete(t){this.data.delete(t)}clear(){this.data.clear()}keys(){let t=[];for(let n of this.data.keys())this.has(n)&&t.push(n);return t}size(){return this.keys().length}};function Hn(e){let t=0;return{isValid(){return Date.now()-t<e},markUpdated(){t=Date.now()},reset(){t=0}}}import{execFileSync as _o,execSync as Oo}from"node:child_process";import{existsSync as vo}from"node:fs";import{delimiter as wo,extname as $o,join as Ro}from"node:path";import{delimiter as Zu,extname as To}from"node:path";function je(){return process.platform==="win32"}function xo(e){return e==="linux"?"linux":e==="darwin"?"darwin":e==="win32"?"windows":null}function Eo(e){return e==="x64"?"amd64":e==="arm64"?"arm64":null}function Po(e,t){let n=xo(e),r=Eo(t);if(!n||!r||n==="windows"&&r!=="amd64")return null;let s=`tdk-${n}-${r}`;return n==="windows"?`${s}.exe`:s}function Qu(){return Po(process.platform,process.arch)}function ed(){return je()?"tdk.exe":"tdk"}function Vn(e,t=je()){return t?To(e)?[e]:[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e]}function $(e){let t=process.env.PATH??process.env.Path??"",n=je(),r=Vn(e,n);if(n&&!$o(e))for(let s of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let o=s.toLowerCase();o&&!r.includes(`${e}${o}`)&&r.push(`${e}${o}`)}for(let s of t.split(wo))if(s)for(let o of r){let i=Ro(s,o);if(vo(i))return i}return null}var Gn=1e4;function Kn(){let e=!1;if(process.platform==="win32")try{return _o($("docker")??"docker",["ps"],{stdio:"ignore",timeout:Gn,windowsHide:!0}),"running"}catch(t){return t.code==="ETIMEDOUT"?"unresponsive":"missing"}for(let t of["docker ps","colima status","podman ps"])try{return Oo(t,{stdio:"ignore",timeout:Gn}),"running"}catch(n){n.code==="ETIMEDOUT"&&(e=!0)}return e?"unresponsive":"missing"}function Ie(e,t){return e[t]??0}function Ao(e,t){let n=Array.from({length:t.length+1},(r,s)=>s);for(let r=1;r<=e.length;r++){let s=[r];for(let o=1;o<=t.length;o++){let i=e[r-1]===t[o-1]?0:1;s[o]=Math.min(Ie(s,o-1)+1,Ie(n,o)+1,Ie(n,o-1)+i)}n=s}return Ie(n,t.length)}function Do(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length-1;n++)if(e[n]!==t[n]&&e[n]===t[n+1]&&e[n+1]===t[n]&&e.slice(0,n)===t.slice(0,n)&&e.slice(n+2)===t.slice(n+2))return!0;return!1}function Wn(e,t){if(e.length<2||t.length===0||t.includes(e))return;let n=e.toLowerCase(),r,s=Number.POSITIVE_INFINITY;for(let o of t){if(o.length===0)continue;let i=o.toLowerCase(),a=Do(n,i)?1:Ao(n,i),c=Math.max(1,Math.min(2,Math.floor(Math.max(n.length,i.length)/3)));a>c||(a<s||a===s&&(r===void 0||o<r))&&(r=o,s=a)}return r}import{spawn as Co}from"node:child_process";import{join as No}from"node:path";function jo(e,t=[],n={}){return new Promise((r,s)=>{let o=[e,...t];n.verbose&&console.log(`Executing: tilt ${o.join(" ")}`);let i=Co($("tilt")??"tilt",o,{stdio:n.inheritStdio?"inherit":"pipe",shell:!1,windowsHide:process.platform==="win32",timeout:n.timeoutMs}),a="",c="";n.inheritStdio||(i.stdout?.on("data",u=>{a+=u.toString()}),i.stderr?.on("data",u=>{c+=u.toString()})),i.on("close",u=>{r({exitCode:u??1,stdout:a,stderr:c})}),i.on("error",u=>{s(new Error(`Failed to spawn tilt: ${u.message}`))})})}async function Jn(){try{return(await jo("version",[],{inheritStdio:!1,timeoutMs:1e4})).exitCode===0}catch{return!1}}function Io(){let e=m();if(!e)throw H.notInProject();return No(e,".tdk",".tdk-out","Tiltfile")}function qn(e){let t=Io();e.push("-f",t)}function hd(e,t={}){let n=[];return qn(n),t.focusTargets&&t.focusTargets.length>0&&n.push("--",`--focus=${t.focusTargets.join(",")}`),n.push(...e),t.verbose&&!t.quiet&&n.push("--verbose"),t.watch&&n.push("--watch"),n}function gd(e={}){let t=[];return qn(t),e.force&&t.push("--force"),e.focusTargets&&e.focusTargets.length>0&&t.push("--",`--focus=${e.focusTargets.join(",")}`),t}function Yn(e){return e instanceof Error?e.message:String(e)}function Pd(e,t){if(process.env.TDK_VERBOSE){let n=t!==void 0?`: ${Yn(t)}`:"";console.warn(f.gray(`${e}${n}`))}}var R=class extends Error{suggestions;exitCode;constructor(t,n=[],r=1){super(t),this.name="TdkError",this.suggestions=n,this.exitCode=r}display(){Lo(this.message,void 0,this.suggestions)}exit(){this.display(),process.exit(this.exitCode)}};function ht(e,t,n=!1){let r=new Set;for(let s of e){let o=Wn(s,t);o&&r.add(n?`Did you mean "${o}" for "${s}"?`:`Did you mean "${o}"?`)}return[...r]}var H={tiltNotInstalled:()=>new R("Tilt CLI is not installed",["Install Tilt: `brew install tilt` (macOS)","Or download from: https://docs.tilt.dev/install.html","Verify with: `tilt version`",`Setup guide: ${ct}`]),dockerNotAvailable:()=>new R("Docker (or a compatible container runtime) is not running",["Start Docker Desktop, then verify with: `docker ps`","Or start Colima: `colima start`","Or start the Docker service on Linux: `sudo systemctl start docker`",`Setup guide: ${ct}`]),dockerNotResponding:()=>new R("Docker is running but not responding (`docker ps` hung for 10s)",["Quit and reopen Docker Desktop, or run `colima restart`","Then verify with: `docker ps`"]),stackNotFound:(e,t=[])=>new R(`Stack "${e}" not found`,[...ht([e],t),"Run `tdk stacks` to see available stacks","Run `tdk stack` to assign resources to a stack"]),resourceNotFound:(e,t=[])=>new R(`Resource "${e}" not found`,[...ht([e],t),"Run `tdk resources` to list all resources","Check the resource name spelling"]),unknownServices:(e,t)=>{let n=ht(e,t,e.length>1);return new R(`Unknown service ${e.join(", ")}. Valid names: ${t.join(", ")}`,n,2)},directoryExists:e=>new R(`Directory already exists: ${e}`,["Use `--path` to specify a different location","Remove the existing directory if no longer needed"]),invalidPath:e=>new R(`Invalid path: ${e}`,["Path must be within the project directory",'Path cannot contain special characters like <>:"|?*']),notInProject:()=>new R("Could not find project root (no .tdk/project.json found)",["Run this from within a TDK project","Run `tdk project --yes` to initialize a new project"])};function vd(){let e=m();return e||H.notInProject().exit()}function Fo(e){e instanceof R&&e.exit(),console.error(f.red(`Error: ${Yn(e)}`)),process.exit(1)}async function Mo(e,t){try{return await e()}catch(n){return t?.verbose&&n instanceof Error&&n.stack&&console.error(f.gray(n.stack)),Fo(n)}}async function wd(e,t){let n=[],r=Kn();return r==="unresponsive"?n.push(H.dockerNotResponding()):r==="missing"&&n.push(H.dockerNotAvailable()),await Jn()||n.push(H.tiltNotInstalled()),n.length>0&&(console.error(f.red(`
|
|
13
13
|
TDK can't start - missing prerequisites:
|
|
14
14
|
`)),n.forEach((s,o)=>{o>0&&console.error(""),s.display()}),console.error(f.gray("\nRun `tdk doctor` for a full environment check.")),process.exit(1)),Mo(e,t)}function $d(e,t=1){console.error(f.red(`Error: ${e}`)),process.exit(t)}function Lo(e,t,n){if(console.error(f.red(`\u274C ${e}`)),t&&console.error(f.gray(` ${t}`)),n&&n.length>0){console.error(f.yellow(`
|
|
15
15
|
\u{1F4A1} Suggestions:`));for(let r of n)console.error(f.cyan(` \u2192 ${r}`))}}function Rd(e,t){console.error(f.red(`
|
|
16
|
-
tilt ${e} failed with exit code ${t}`)),process.exit(t)}import{existsSync as ir,readFileSync as ar}from"node:fs";import{copyFileSync as zn,mkdirSync as Bo,rmSync as Xn,writeFileSync as Zn}from"node:fs";import{join as Q}from"node:path";var Uo=60,Qn=1e3,er=1e4,tr=200,nr=64*1024,rr=new Set([404,502,503,504]),Ho=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN","EHOSTUNREACH","ENETUNREACH"]),Vo=new Set(["GET","HEAD","OPTIONS"]);function K(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Go(e,t){if(Vo.has(t))return!0;if(!K(e))return!1;let n=K(e.cause)?e.cause:void 0,r=e.code??n?.code;return typeof r=="string"&&Ho.has(r)}function kt(e){if(!K(e))return['smoke: must be an object with "via" and "steps"'];let t=[];return e.via!=="proxy"&&t.push('smoke.via: only "proxy" is supported (the check must go through the public URL)'),e.timeoutSeconds!==void 0&&!(typeof e.timeoutSeconds=="number"&&e.timeoutSeconds>0)&&t.push("smoke.timeoutSeconds: must be a number greater than 0"),!Array.isArray(e.steps)||e.steps.length===0?(t.push("smoke.steps: needs at least one step"),t):(e.steps.forEach((n,r)=>{let s=`smoke.steps[${r}]`;if(!K(n)){t.push(`${s}: must be an object`);return}let o=n.path;(typeof o!="string"||!o.startsWith("/")||o.startsWith("//"))&&t.push(`${s}.path: must start with "/" and is appended to the public URL; a full URL or relative path would skip the proxy`),n.expect!==void 0&&!(typeof n.expect=="number"&&Number.isInteger(n.expect)&&n.expect>=100&&n.expect<=599)&&t.push(`${s}.expect: must be an HTTP status between 100 and 599`),n.bodyContains!==void 0&&typeof n.bodyContains!="string"&&t.push(`${s}.bodyContains: must be a string`),n.save!==void 0&&(K(n.save)&&Object.values(n.save).every(a=>typeof a=="string"&&a.startsWith("$."))||t.push(`${s}.save: must map names to paths such as "$.id"`))}),t)}function jd(e,t){let{appBase:n,apiBase:r}=ft(t),s=[];for(let o of e){let i=o.config;if(!i?.smoke)continue;let a=i.appType,c=w(a)||a===B;if(!c&&a!=="frontend"||i.exposeViaProxy===!1)continue;let u=c?r:n,d=i.healthCheckPath||(c&&a!==B?"/health":void 0);s.push({name:o.name,baseUrl:`${u}${mt(o).replace(/\/+$/,"")}`,...d?.startsWith("/")?{readyPath:d}:{},smoke:i.smoke})}return s}function Ko(e,t){let n=t.replace(/^\$\.?/,"").match(/[^.[\]]+/g)??[],r=e;for(let s of n){if(r==null||s==="__proto__"||s==="constructor"||s==="prototype"||!Object.hasOwn(r,s))return;
|
|
16
|
+
tilt ${e} failed with exit code ${t}`)),process.exit(t)}import{existsSync as ir,readFileSync as ar}from"node:fs";import{copyFileSync as zn,mkdirSync as Bo,rmSync as Xn,writeFileSync as Zn}from"node:fs";import{join as Q}from"node:path";var Uo=60,Qn=1e3,er=1e4,tr=200,nr=64*1024,rr=new Set([404,502,503,504]),Ho=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN","EHOSTUNREACH","ENETUNREACH"]),Vo=new Set(["GET","HEAD","OPTIONS"]);function K(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Go(e,t){if(Vo.has(t))return!0;if(!K(e))return!1;let n=K(e.cause)?e.cause:void 0,r=e.code??n?.code;return typeof r=="string"&&Ho.has(r)}function kt(e){if(!K(e))return['smoke: must be an object with "via" and "steps"'];let t=[];return e.via!=="proxy"&&t.push('smoke.via: only "proxy" is supported (the check must go through the public URL)'),e.timeoutSeconds!==void 0&&!(typeof e.timeoutSeconds=="number"&&e.timeoutSeconds>0)&&t.push("smoke.timeoutSeconds: must be a number greater than 0"),!Array.isArray(e.steps)||e.steps.length===0?(t.push("smoke.steps: needs at least one step"),t):(e.steps.forEach((n,r)=>{let s=`smoke.steps[${r}]`;if(!K(n)){t.push(`${s}: must be an object`);return}let o=n.path;(typeof o!="string"||!o.startsWith("/")||o.startsWith("//"))&&t.push(`${s}.path: must start with "/" and is appended to the public URL; a full URL or relative path would skip the proxy`),n.expect!==void 0&&!(typeof n.expect=="number"&&Number.isInteger(n.expect)&&n.expect>=100&&n.expect<=599)&&t.push(`${s}.expect: must be an HTTP status between 100 and 599`),n.bodyContains!==void 0&&typeof n.bodyContains!="string"&&t.push(`${s}.bodyContains: must be a string`),n.save!==void 0&&(K(n.save)&&Object.values(n.save).every(a=>typeof a=="string"&&a.startsWith("$."))||t.push(`${s}.save: must map names to paths such as "$.id"`))}),t)}function jd(e,t){let{appBase:n,apiBase:r}=ft(t),s=[];for(let o of e){let i=o.config;if(!i?.smoke)continue;let a=i.appType,c=w(a)||a===B;if(!c&&a!=="frontend"||i.exposeViaProxy===!1)continue;let u=c?r:n,d=i.healthCheckPath||(c&&a!==B?"/health":void 0);s.push({name:o.name,baseUrl:`${u}${mt(o).replace(/\/+$/,"")}`,...d?.startsWith("/")?{readyPath:d}:{},smoke:i.smoke})}return s}function Ko(e,t){let n=t.replace(/^\$\.?/,"").match(/[^.[\]]+/g)??[],r=e;for(let s of n){if(r==null||s==="__proto__"||s==="constructor"||s==="prototype"||!Object.hasOwn(r,s))return;let o=Object.getOwnPropertyDescriptor(r,s);if(!o||!("value"in o))return;r=o.value}return r}function sr(e,t){return e.replace(/\{\{(\w+)\}\}/g,(n,r)=>t[r]??n)}function gt(e,t){return typeof e=="string"?sr(e,t):Array.isArray(e)?e.map(n=>gt(n,t)):K(e)?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,gt(r,t)])):e}function Fe(e){let t=e.replace(/\s+/g," ").trim();return t.length>tr?`${t.slice(0,tr)}...`:t}function or(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"step"}function Wo(e,t){let n=or(t),r=(e.get(n)??0)+1;return e.set(n,r),r===1?n:`${n}-${r}`}function Jo(e,t,n,r,s){try{let o=Q(e,or(n.service),t);Bo(o,{recursive:!0});let i=Q(o,"latest.json"),a=Q(o,"body.txt");return r===void 0?Xn(a,{force:!0}):Zn(a,r),Zn(i,`${JSON.stringify({...n,bodyPath:r===void 0?null:"body.txt"},null,2)}
|
|
17
17
|
`),s&&(zn(i,Q(o,"last-success.json")),r===void 0?Xn(Q(o,"last-success-body.txt"),{force:!0}):zn(a,Q(o,"last-success-body.txt"))),i}catch{return}}function qo(e){let t=Buffer.from(e,"utf8");if(t.length<=nr)return{body:e,truncated:!1,bytes:t.length};let n=t.subarray(0,nr).toString("utf8").replace(/\uFFFD$/,"");return{body:n,truncated:!0,bytes:Buffer.byteLength(n,"utf8")}}async function Yo(e,t={}){let n=t.fetch??((d,l)=>fetch(d,l)),r=t.now??Date.now,s=t.sleep??(d=>new Promise(l=>setTimeout(l,d))),o=(e.smoke.timeoutSeconds??Uo)*1e3,i=r()+o,a={},c=kt(e.smoke);if(c.length>0)return{name:e.name,ok:!1,failure:`${e.name}: invalid smoke block: ${c.join("; ")}`};if(e.readyPath){let d=`${e.baseUrl}${e.readyPath}`;for(;;){try{let l=await n(d,{method:"GET",signal:AbortSignal.timeout(er)});if(await l.text(),!rr.has(l.status)&&l.status<500)break}catch{}if(r()>=i)break;await s(Qn)}}i=r()+o;let u=new Map;for(let[d,l]of e.smoke.steps.entries()){let h=l.name??`step ${d+1}`,k=(l.method??"GET").toUpperCase(),g=`${e.baseUrl}${sr(l.path,a)}`,p=l.expect??200,y=l.body!==void 0,v,j="",G,Ze;for(;;){G=void 0,Ze=void 0,v=void 0;let I=!1;try{let _=await n(g,{method:k,headers:y?{"content-type":"application/json"}:void 0,body:y?JSON.stringify(gt(l.body,a)):void 0,signal:AbortSignal.timeout(er)});v=_.status,j=await _.text()}catch(_){I=Go(_,k),G=_ instanceof Error?_.message:String(_);let Y=K(_)?_.code??(K(_.cause)?_.cause.code:void 0):void 0;Ze=typeof Y=="string"?Y:void 0}if(!(G!==void 0&&I||v!==void 0&&v!==p&&rr.has(v))||r()>=i)break;await s(Qn)}let ae=`${e.name}: ${h}: ${k} ${g}`,un;if(t.recordDir){let I=v===void 0?void 0:qo(j),ue=G===void 0&&v===p&&(l.bodyContains===void 0||j.includes(l.bodyContains));un=Jo(t.recordDir,Wo(u,h),{service:e.name,step:h,method:k,url:g,expectedStatus:p,status:v??null,...G===void 0?{}:{error:Ze??G},truncated:I?.truncated??!1,bodyBytes:I?.bytes??0},I?.body,ue)}let ce=I=>({name:e.name,ok:!1,failure:I,recordPath:un});if(G!==void 0)return ce(`${ae} never answered (${G})`);if(v!==p)return ce(`${ae} returned ${v}, expected ${p}${j?`: ${Fe(j)}`:""}`);if(l.bodyContains!==void 0&&!j.includes(l.bodyContains))return ce(`${ae} returned ${v} but the body does not contain "${l.bodyContains}": ${Fe(j)}`);if(l.save){let I;try{I=JSON.parse(j)}catch{return ce(`${ae} returned a body that is not JSON, cannot save: ${Fe(j)}`)}for(let[ue,_]of Object.entries(l.save)){let Y=Ko(I,_);if(Y==null||typeof Y=="object")return ce(`${ae} response has no ${_} to save as {{${ue}}}: ${Fe(j)}`);a[ue]=String(Y)}}}return{name:e.name,ok:!0}}function Id(e){return`Smoke check failed: ${e.failure}${e.recordPath?` (record: ${e.recordPath})`:""}`}async function Fd(e,t={}){return Promise.all(e.map(n=>Yo(n,t)))}var ge=1,Ud="https://tdk-landscape.github.io/schema.service.json",zo={dependencies:"deprecated, use dependsOn (still read for now)",envVars:"deprecated, use params (still read when params is absent)",jwtSecret:"ignored. A secret must not be committed: remove it and set JWT_SECRET in the project .env"},Xo=new Set(["$schema","apiBasePath","apiPath","appName","appType","backendName","basePath","build","buildContext","databaseName","dependencies","dev","dependsOn","dockerfile","enabled","exposeViaProxy","featuresEnabled","framework","healthCheckPath","image","language","name","nats","params","playwright","port","replicas","restart","runtime","sablier","schemaVersion","secrets","smoke","stack","syncs","traefik","type"]),Zo=[{path:["healthCheckPath"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["traefik","host"],pattern:/^[A-Za-z0-9.-]+$/,expected:"a hostname such as shop.backend.myproject.local"},{path:["traefik","pathPrefix"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /api/v1/shop-management"},{path:["traefik","healthCheck"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["nats","queueGroup"],pattern:/^[A-Za-z0-9_.-]+$/,expected:"letters, digits, '_', '.' or '-'"},{path:["databaseName"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["stack"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["image"],pattern:/^[A-Za-z0-9._/:@-]+$/,expected:"an image reference such as ghcr.io/acme/app:1.0"}];function Me(e,t){let n=[],r=new Set;for(let{path:s,pattern:o,expected:i}of Zo){let a=e;for(let u of s)a=a&&typeof a=="object"&&!Array.isArray(a)?a[u]:void 0;if(a==null||a==="")continue;let c=`${t}.${s.join(".")}`;(typeof a!="string"||!o.test(a))&&r.add(c),typeof a!="string"?n.push(`${c}: expected a string`):o.test(a)||n.push(`${c}: must be ${i} (no spaces, line breaks or YAML syntax)`)}for(let[s,o]of Qo(e,t))r.has(s)||n.push(`${s}: ${o}`);return n}function yt(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<32||n===127||n===133||n===8232||n===8233)return!0}return!1}function Qo(e,t){let n=[],r=Object.entries(e).filter(([s])=>s!=="smoke").map(([s,o])=>[o,`${t}.${s}`]);for(let s of Object.keys(e))yt(s)&&n.push([t,"a key contains a line break"]);for(;r.length>0;){let[s,o]=r.pop();if(typeof s=="string")yt(s)&&n.push([o,"must not contain line breaks or control characters"]);else if(Array.isArray(s))for(let[i,a]of s.entries())r.push([a,`${o}[${i}]`]);else if(s&&typeof s=="object")for(let[i,a]of Object.entries(s))yt(i)?n.push([o,"a key contains a line break"]):r.push([a,`${o}.${i}`])}return n.sort(([s],[o])=>s.localeCompare(o))}var ei=["apiPath","basePath"];function St(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let t=e;return ei.filter(n=>n in t&&typeof t[n]!="string")}function bt(e,t){if(!e||typeof e!="object"||Array.isArray(e))return{errors:[`${t}: expected a JSON object`],warnings:[]};let n=e,r=[];for(let a of["appName","appType","stack","schemaVersion"])a in n||r.push(`${t}.${a}: required field is missing`);for(let a of["appName","appType","stack"])a in n&&typeof n[a]!="string"&&r.push(`${t}.${a}: expected a string`);"schemaVersion"in n&&n.schemaVersion!==ge&&r.push(`${t}.schemaVersion: unsupported version ${String(n.schemaVersion)} (supported: ${ge})`);for(let a of St(n))r.push(`${t}.${a}: expected a string`);let s=n.dev,o=s&&typeof s=="object"&&!Array.isArray(s)?s.liveReload:void 0;if(o!==void 0&&typeof o!="boolean"&&r.push(`${t}.dev.liveReload: expected true or false`),r.push(...Me(n,t)),"smoke"in n)for(let a of kt(n.smoke))r.push(`${t}.${a}`);let i=Object.keys(n).flatMap(a=>{let c=zo[a];return c?[`${t}.${a}: ${c}`]:Xo.has(a)?[]:[`${t}.${a}: unknown field is preserved`]});return o===!0&&n.language!=="go"&&i.push(`${t}.dev.liveReload: only applies to Go services (language "go"); it is ignored here`),{errors:r,warnings:i,manifest:n}}function Hd(e,t){if(!ir(e))return[];try{let n=JSON.parse(ar(e,"utf-8"));return!n||typeof n!="object"||Array.isArray(n)?[]:Me(n,t)}catch{return[]}}function Vd(e,t){if(!ir(e))return{errors:[`${t}: file is missing`],warnings:[]};try{let n=JSON.parse(ar(e,"utf-8"));return bt(n,t)}catch(n){let r=n instanceof Error?n.message:String(n);return{errors:[`${t}: invalid JSON (${r})`],warnings:[]}}}function cr(e){if(e.length===0||e.every(n=>n==="unknown"))return"unknown";let t=e.filter(n=>n==="ready").length/e.length;return t>.9?"healthy":t>.5?"degraded":"error"}var ti=/^[a-z0-9-]+$/;function ur(e){return ti.test(e)}var ni="Use lowercase letters, numbers, and hyphens only";function dr(e,t){return`${e} "${t}" is not valid. ${ni}, e.g. "${e==="Resource name"?"my-service":"my-stack"}".`}function ri(e){return e.trim()?ur(e)?{valid:!0}:{valid:!1,error:dr("Resource name",e)}:{valid:!1,error:"Resource name is required"}}function si(e){return e.trim()?ur(e)?{valid:!0}:{valid:!1,error:dr("Stack name",e)}:{valid:!1,error:"Stack name is required"}}function Jd(e){let t=e==="resource"?ri:si;return n=>{let r=t(n);return r.valid?!0:r.error??"Invalid name"}}function qd(e){return Tt(at,e)?{valid:!0}:{valid:!1,error:`Invalid service. Must be one of: ${at.join(", ")}`}}function Yd(e){return Number.isInteger(e)&&e>0&&e<=65535}function zd(e){return!e.includes("\0")&&!/[<>:"|?*]/.test(e)}function Xd(e,t="_"){return e.replace(/[^a-zA-Z0-9-]/g,t).substring(0,100)}function Tt(e,t){return e.includes(t)}var ii=vn;function wt(e,t=5,n=0){let r=[];if(n>t)return r;let s=lr(e,{withFileTypes:!0});for(let o of s){let i=J(e,o.name);if(o.isDirectory()){if(ai(o.name))continue;r.push(...wt(i,t,n+1))}else o.isFile()&&o.name===ii&&r.push(i)}return r}function ul(e){return wt(e)}function ai(e){return Tt($n,e)||e.startsWith(".")}function ci(e){if(!e||typeof e!="object")return!1;let t=e,n=typeof t.runtime=="string"||typeof t.appType=="string"||typeof t.type=="string";return typeof t.appName=="string"&&n}var Le=new Set;var W=class extends Error{reason;constructor(t){super(t),this.reason=t,this.name="InvalidServiceJsonError"}};function Et(e){return e instanceof Error?e.message:String(e)}function ui(e){let t;try{t=pr(e,"utf-8")}catch(c){throw new W(`could not read file: ${Et(c)}`)}let n;try{n=JSON.parse(t)}catch(c){throw new W(`invalid JSON: ${Et(c)}`)}if(!ci(n))throw new W("missing required fields (appName, runtime or appType)");let r=St(n);if(r.length>0)throw new W(r.map(c=>`${c}: expected a string`).join("; "));let s=Me(n,e);if(s.length>0)throw new W(s.join("; "));let o=n;for(let c of bt(n,e).warnings)Le.has(c)||(Le.add(c),console.warn(`\u26A0\uFE0F ${c}`));let i={...o,appType:o.appType||o.type},a=oi(e);return{name:i.appName,path:a,configPath:e,config:i,stack:i.stack,port:i.port,type:i.appType}}function fr(e){let t=wt(e),n=[],r=[];for(let s of t)try{n.push(ui(s))}catch(o){r.push({path:s,reason:o instanceof W?o.reason:Et(o)})}return{resources:n,problems:r}}function di(e){for(let t of e){let n=`skipped ${t.path}: ${t.reason}`;Le.has(n)||(Le.add(n),console.warn(`\u26A0\uFE0F ${n}`))}}function b(e){let{resources:t,problems:n}=fr(e);return di(n),t}function ye(){let e=m();if(!e)throw H.notInProject();return b(e)}function dl(){let e=m();if(!e)throw H.notInProject();let{resources:t,problems:n}=fr(e);if(n.length>0)throw new Error(n.map(r=>`Invalid service.json at ${r.path}: ${r.reason}`).join(`
|
|
18
18
|
`));return t}function ll(e){let t=b(e),n=new Set;for(let r of t)r.stack&&n.add(r.stack);return Array.from(n).sort()}function pl(e){let t=e||ye(),n=new Set;for(let r of t)r.stack&&n.add(r.stack);return Array.from(n).sort()}function fl(e=ye()){let t=new Map;for(let r of e)if(r.stack){let s=t.get(r.stack);s?s.push(r):t.set(r.stack,[r])}let n=[];for(let[r,s]of t)n.push({name:r,description:S(s.length,"resource"),resources:s,resourceCount:s.length});return n.sort((r,s)=>r.name.localeCompare(s.name))}function ml(e,t){return(t??ye()).some(r=>r.stack===e)}var $t=5e3,Pt=new he({ttlMs:$t}),vt=new he({ttlMs:$t}),ke=Hn($t);function hl(){Pt.clear(),vt.clear(),ke.reset()}function li(e,t){if(e==="Dockerfile"||e.startsWith("docker-compose"))return"docker";if(e==="Tiltfile"||e.endsWith(".star"))return"tilt";if(e==="vite.config.ts"||e==="tsconfig.json"||e===D)return"config";if(e==="schema.prisma"||e.includes("migration"))return"prisma";if(t){let n=t.split(`
|
|
19
19
|
`).slice(0,10).join(`
|