@flisk-sh/flisk 1.4.5 → 1.4.7
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 +37 -14
- package/cli/dist/agent-runtimes/custom.js +94 -13
- package/cli/dist/commands/agent.js +144 -123
- package/cli/dist/commands/doctor.js +62 -12
- package/cli/dist/commands/down.js +33 -1
- package/cli/dist/commands/logs.js +107 -3
- package/cli/dist/commands/project.js +27 -0
- package/cli/dist/commands/resource.js +3 -1
- package/cli/dist/commands/status.js +82 -34
- package/cli/dist/commands/ui.js +41 -2
- package/cli/dist/commands/up.js +173 -12
- package/cli/dist/commands/upgrade.js +2 -2
- package/cli/dist/components/DetailPanel.js +23 -3
- package/cli/dist/mcp/tools.js +9 -6
- package/cli/dist/types/index.js +0 -2
- package/cli/dist/utils/agent-format.js +18 -0
- package/cli/dist/utils/agent-sessions.js +122 -0
- package/cli/dist/utils/agent-skills.js +64 -0
- package/cli/dist/utils/bun-requirement.js +7 -4
- package/cli/dist/utils/cold-preflight.js +55 -32
- package/cli/dist/utils/doctor-fix-first.js +93 -0
- package/cli/dist/utils/doctor-native.js +96 -0
- package/cli/dist/utils/doctor-report.js +3 -0
- package/cli/dist/utils/native-project.js +41 -0
- package/cli/dist/utils/native-runtime.js +516 -0
- package/cli/dist/utils/native-service.js +95 -0
- package/cli/dist/utils/native-up.js +156 -0
- package/cli/dist/utils/platform.js +1 -1
- package/cli/dist/utils/project-templates.js +1 -1
- package/cli/dist/utils/service-manifest.js +10 -1
- package/cli/dist/utils/services.js +11 -1
- package/cli/dist/utils/startup-report.js +45 -3
- package/cli/dist/utils/status-groups.js +23 -0
- package/cli/dist/utils/tilt-logs.js +8 -0
- package/cli/dist/utils/up-hints.js +42 -0
- package/cli/dist/utils/up-progress.js +117 -0
- package/cli/dist/utils/up-readiness.js +5 -0
- package/cli/dist-bundle/{chunk-Z5QEE4SW.js → chunk-6OW2GVQV.js} +1 -1
- package/cli/dist-bundle/chunk-B2JOM3HN.js +35 -0
- package/cli/dist-bundle/{chunk-VMVTECCK.js → chunk-F2DLIM75.js} +1 -1
- package/cli/dist-bundle/chunk-L6O7TT3K.js +18 -0
- package/cli/dist-bundle/chunk-MFY7RZ76.js +130 -0
- package/cli/dist-bundle/{chunk-SFOFTVYM.js → chunk-MYAYJF4Q.js} +1 -1
- package/cli/dist-bundle/{chunk-LUUJ4JB7.js → chunk-P7GZ6NGM.js} +1 -1
- package/cli/dist-bundle/{chunk-BP2M4OJ4.js → chunk-QEBN6ZVQ.js} +1 -1
- package/cli/dist-bundle/{chunk-4J2FLFUA.js → chunk-T44DEEL6.js} +1 -1
- package/cli/dist-bundle/{chunk-U42XZWXB.js → chunk-TIPSERWO.js} +1 -1
- package/cli/dist-bundle/{chunk-V36PT2HF.js → chunk-VYPB7MY5.js} +1 -1
- package/cli/dist-bundle/{chunk-TIYTGN5R.js → chunk-XHENT4KO.js} +1 -1
- package/cli/dist-bundle/{chunk-CGTWXWBU.js → chunk-YTBTCAWY.js} +1 -1
- package/cli/dist-bundle/cli.js +486 -396
- package/cli/dist-bundle/cold-preflight-DQVJUGBB.js +2 -0
- package/cli/dist-bundle/{demo-stage-G4W23BXW.js → demo-stage-F4YA7UL2.js} +1 -1
- package/cli/dist-bundle/{open-HQFT6WDC.js → open-ZUSSVPD3.js} +1 -1
- package/cli/dist-bundle/project-JFCTPRP5.js +2 -0
- package/cli/dist-bundle/{project-templates-IMJ3OX5I.js → project-templates-2VQPUBSQ.js} +1 -1
- package/cli/dist-bundle/{services-GLFKZBBZ.js → services-DOHDHOCT.js} +1 -1
- package/cli/dist-bundle/{tilt-port-owner-PJN4MPYE.js → tilt-port-owner-XODQHXHX.js} +1 -1
- package/cli/package.json +1 -1
- package/cli/templates/agent-skills/flisk-agent-ops/SKILL.md +39 -0
- package/cli/templates/agent-skills/flisk-build/SKILL.md +85 -0
- package/cli/templates/agent-skills/flisk-doctor/SKILL.md +28 -0
- package/cli/templates/agent-skills/flisk-recipe-ai-agent/SKILL.md +45 -0
- package/cli/templates/agent-skills/flisk-recipe-blog/SKILL.md +36 -0
- package/cli/templates/agent-skills/flisk-recipe-saas/SKILL.md +39 -0
- package/cli/templates/agent-skills/flisk-recipe-shop/SKILL.md +41 -0
- package/cli/templates/agent-skills/flisk-recipe-starters/SKILL.md +46 -0
- package/cli/templates/agent-skills/flisk-resource/SKILL.md +27 -0
- package/cli/templates/agent-skills/flisk-status/SKILL.md +25 -0
- package/cli/templates/agent-skills/flisk-troubleshoot/SKILL.md +227 -0
- package/cli/templates/agent-skills/flisk-up/SKILL.md +37 -0
- package/examples/{tdk-example → flisk-example}/README.md +2 -2
- package/package.json +2 -2
- package/runtime/discovery/AGENTS.md +1 -1
- package/runtime/discovery/TILT_DISCOVERY.star +1 -1
- package/runtime/discovery/deterministic.star +1 -1
- package/runtime/engine/AGENTS.md +3 -3
- package/runtime/engine/README.md +1 -1
- package/runtime/engine/REFACTORING_MANIFEST_SYSTEM.md +1 -1
- package/runtime/engine/assets/docker/wake-gateway/decide.ts +1 -1
- package/runtime/engine/assets/docker/wake-gateway/server.ts +2 -2
- package/runtime/engine/assets/scripts/mac-m1-resource-monitor.sh +6 -6
- package/runtime/engine/schemas/service-schema.json +87 -21
- package/runtime/engine/scripts/debug-container.sh +1 -1
- package/runtime/engine/scripts/generate-manifest.sh +2 -2
- package/runtime/engine/topologies/platform/docker/compose/traefik_standalone.star +19 -4
- package/runtime/engine/topologies/platform/docker/constants.star +2 -2
- package/runtime/engine/topologies/platform/docker/networking/traefik_static_routes.star +2 -2
- package/runtime/engine/topologies/tilt/manifest/mapper.star +1 -1
- package/runtime/engine/topologies/tilt/resources/orchestrator/apply_compose_resource_registration.star +8 -2
- package/runtime/ext/ide-components/README.md +1 -1
- package/runtime/ext/ui-enhancements/extension.yaml +2 -2
- package/runtime/specs/specs/TILT_SERVICE_DEFAULTS.star +1 -1
- package/runtime/specs/specs/TILT_TECH_STACK.star +1 -1
- package/cli/dist-bundle/chunk-BMHPPX2Q.js +0 -35
- package/cli/dist-bundle/chunk-PEZQEZVV.js +0 -17
- package/cli/dist-bundle/chunk-ULMQVD7J.js +0 -122
- package/cli/dist-bundle/cold-preflight-3BNDOLGS.js +0 -2
- package/cli/dist-bundle/project-JZO2CPZZ.js +0 -2
- /package/examples/{tdk-example → flisk-example}/LICENSE +0 -0
- /package/examples/{tdk-example → flisk-example}/TILT_SERVICE_DEFAULTS.star +0 -0
- /package/examples/{tdk-example → flisk-example}/TILT_TECH_STACK.star +0 -0
- /package/examples/{tdk-example → flisk-example}/Tiltfile +0 -0
- /package/examples/{tdk-example → flisk-example}/services/platform/messaging/docker-compose.yml +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-api/package.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-api/service.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-api/src/index.ts +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/index.html +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/package.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/public/.gitkeep +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/service.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/src/main.tsx +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/src/orders.tsx +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-app/src/style.css +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-worker/package.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-worker/service.json +0 -0
- /package/examples/{tdk-example → flisk-example}/services/shop/orders-worker/src/index.ts +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
+
import{N as Z,b as p,e as H,h as ke,i as be,m as we,n as Ae,r as J,u as Te,v as Re,x as R}from"./chunk-TIPSERWO.js";import ct,{existsSync as C,readdirSync as cn,readFileSync as un,statSync as pe}from"node:fs";import{dirname as fn,join as b}from"node:path";var P=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 _e(e){let t=0;return{isValid(){return Date.now()-t<e},markUpdated(){t=Date.now()},reset(){t=0}}}function pt(e,t,n){return e===1?t:n||`${t}s`}function Ce(e,t,n){return`${e} ${pt(e,t,n)}`}var dt={month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"};function vn(e){return new Date(e).toLocaleString("en-US",dt)}function kn(e){return new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var Y={success:{color:"green",icon:"\u2713",chalkFn:p.green},error:{color:"red",icon:"\u2717",chalkFn:p.red},warning:{color:"yellow",icon:"\u25CB",chalkFn:p.yellow},unknown:{color:"gray",icon:"?",chalkFn:p.gray}};function Q(e){if(!e)return"unknown";let t=e.toLowerCase();return t==="ready"||t==="healthy"||t==="active"||t==="running"?"success":t==="error"||t==="failed"||t==="critical"||t==="stopped"?"error":t==="pending"||t==="starting"||t==="building"||t==="degraded"?"warning":"unknown"}function bn(e){return Y[Q(e)].color}function wn(e){return Y[Q(e)].icon}function An(e,t){return Y[Q(t)].chalkFn(e)}var lt={resources:{singular:"resource",command:"flisk resource <name>",context:`
|
|
3
|
+
To create a resource:`},stacks:{singular:"stack",command:"flisk stack <stack-name>",context:`
|
|
4
|
+
To create a stack, use:`},services:{singular:"service",command:"flisk resource <name>",context:`
|
|
5
|
+
To create a service:`},"stack-services":{singular:"service",command:"flisk resource <name> --stack <stack-name>",context:`
|
|
6
|
+
To add services to this stack:`}};function Tn(e,t){let n=lt[e];console.log(t?p.yellow(`No ${n.singular}s found${t}.`):p.yellow(`No ${n.singular}s found.`)),console.log(p.gray(n.context)),console.log(p.gray(` ${n.command}`)),e==="stacks"&&(console.log(p.gray(`
|
|
7
|
+
Or create a new resource with a stack:`)),console.log(p.gray(" flisk resource <name> --stack <stack-name>")))}function Rn(e){console.log(p.yellow(e||"Cancelled."))}function _n(e){console.log(p.blue(`Flisk ${e}
|
|
8
|
+
`))}function On(e,t){console.log(p.green(`All ${e} are ${t}!`))}var X=62;function Cn(e="\u2500",t=X){return e.repeat(t)}function Oe(e,t=X-2){let n=Math.max(0,t-e.length),r=Math.floor(n/2),o=n-r;return" ".repeat(r)+e+" ".repeat(o)}function Dn(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e.padEnd(t)}function Fn(e,t){return e.length<=t?e:`${e.slice(0,t-3)}...`}function Nn(e){console.log(p.green(`\u2713 ${e}`))}function jn(e){console.log(p.blue(e))}function Pn(e,t=2){console.log(p.gray(`${" ".repeat(t)}${e}`))}function In(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function Mn(e,t,n=X){let r=n-2,o="\u2500".repeat(r);console.log(),console.log(p.cyan(`\u256D${o}\u256E`)),console.log(p.cyan("\u2502")+p.bold.white(Oe(e,r))+p.cyan("\u2502")),t&&(console.log(p.cyan(`\u251C${o}\u2524`)),console.log(p.cyan("\u2502")+p.gray(Oe(t,r))+p.cyan("\u2502"))),console.log(p.cyan(`\u2570${o}\u256F`))}var mt=["image","dockerfile"];function v(e){return typeof e?.command=="string"&&e.command.trim()!==""}function ee(e){return v(e.config)}function B(e){let t=ht(e),n=[];if("command"in e&&!v(e)&&n.push(`service ${t}: command must be a non-empty string`),!v(e))return n;let r=mt.filter(s=>e[s]!==void 0&&e[s]!=="");r.length>0&&n.push(`service ${t}: declares both command and ${r.join(" and ")}; a service has exactly one runtime source (remove ${r.length===1?"it":"them"} to run the command locally, or remove command to run in Docker)`);let o=e.env;if(o!==void 0){let s=o!==null&&typeof o=="object"&&!Array.isArray(o),i=s?Object.entries(o).filter(([a,c])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)||typeof c!="string").map(([a])=>a):[];s?i.length>0&&n.push(`service ${t}: env ${i.join(", ")}: names must be letters, digits or _ (not starting with a digit) and values must be strings`):n.push(`service ${t}: env must be an object of string values`)}return n}function ht(e){let t=e.appName;return typeof t=="string"&&t?`"${t}"`:"(unnamed)"}function Un(e,t=e){let n=t.filter(ee).map(r=>r.name);return e.length>0&&e.every(ee)?{mode:"native",mixed:[]}:{mode:"container",mixed:n}}function Ln(e,t){return[`This run mixes services that run as local processes (${e.join(", ")}) with services that run in Docker (${t.join(", ")}).`,"Flisk cannot start both kinds in one project yet.","Give every service a `command` to run without Docker, or remove `command` from these services to run them in Docker."].join(`
|
|
9
|
+
`)}function Vn(e){return e.length>0&&e.every(ee)}function Wn(e){let t=e.trim().split(/\s+/);for(let n of t)if(!/^[A-Za-z_][A-Za-z0-9_]*=/.test(n)&&!(n==="exec"||n==="env"))return/^[A-Za-z0-9_./@+-]+$/.test(n)?n:null;return null}import{existsSync as rt,readFileSync as ot}from"node:fs";import{copyFileSync as Ge,mkdirSync as Vt,rmSync as qe,writeFileSync as Ke}from"node:fs";import{join as O}from"node:path";function A(e){return e==="backend"||e==="mcp"||e==="agent"}import{existsSync as Dt,readFileSync as Ft}from"node:fs";import{join as Nt}from"node:path";import{randomBytes as Fe}from"node:crypto";import{existsSync as ne,readFileSync as Ne,writeFileSync as je}from"node:fs";import{join as re}from"node:path";import{randomBytes as gt}from"node:crypto";import{closeSync as yt,fchmodSync as St,fsyncSync as $t,openSync as xt,renameSync as Et,rmSync as vt,statSync as kt,writeFileSync as bt}from"node:fs";import{basename as wt,dirname as At,join as Tt}from"node:path";function De(e,t){let n=Tt(At(e),`.${wt(e)}.${process.pid}.${gt(4).toString("hex")}.tmp`),r;try{r=kt(e).mode&511}catch{r=void 0}try{let o=xt(n,"wx");try{r!==void 0&&St(o,r),bt(o,t,"utf-8"),$t(o)}finally{yt(o)}Et(n,e)}catch(o){throw vt(n,{force:!0}),o}}var T=[{name:"VERDACCIO_URL_DOCKER",description:"Docker-internal URL of the private npm registry (Verdaccio, a paid feature)",required:!1,default:"http://verdaccio:4873",example:"http://verdaccio:4873"},{name:"VERDACCIO_URL",description:"Local URL of the private npm registry (Verdaccio, a paid feature)",required:!1,default:"http://localhost:4873"},{name:"TILT_ENV",description:"Tilt environment name",required:!0,default:"dev",example:"dev",complete:!0},{name:"DATABASE_URL",description:"PostgreSQL connection string (uses the generated DB_PASSWORD below)",required:!1},{name:"DB_PASSWORD",description:"PostgreSQL superuser password (docker-compose POSTGRES_PASSWORD)",required:!0,example:"postgres",complete:!0},{name:"JWT_SECRET",description:"Secret that signs local-jwt tokens (generated once per project; never shared between projects)",required:!1,complete:!0}],Pe=()=>Fe(16).toString("hex"),Rt=()=>Fe(32).toString("hex"),er=T.filter(e=>e.complete).map(e=>e.name);function te(e,t){return e==="DB_PASSWORD"?t:e==="JWT_SECRET"?Rt():e==="DATABASE_URL"?`postgresql://postgres:${t}@postgres:5432/app_dev`:T.find(n=>n.name===e)?.default??""}function _t(e){let t=e.trim(),n=t[0];if(n==='"'||n==="'"){let o=!1;for(let s=1;s<t.length;s+=1){let i=t[s];if(o){o=!1;continue}if(i==="\\"){o=!0;continue}if(i===n){let a=t.slice(1,s);if(n==='"'){let c={n:`
|
|
10
|
+
`,r:"\r",t:" ",'"':'"',"\\":"\\",$:"$"};return a.replace(/\\([nrt"\\$])/g,(f,d)=>c[d]??d)}return a.replace(/\\'/g,"'")}}return t}let r=e.search(/\s#/);return(r===-1?e:e.slice(0,r)).trim()}function _(e){let t=new Map,n=e.startsWith("\uFEFF")?e.slice(1):e;for(let r of n.split(/\r?\n/)){let o=r.trim();if(!o||o.startsWith("#"))continue;let s=o.startsWith("export ")?o.slice(7).trim():o,i=s.indexOf("=");if(i<=0)continue;let a=s.slice(0,i).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&t.set(a,_t(s.slice(i+1)))}return t}function Ie(e){let t=[`# ${e.description}`];return e.required&&t.push("# Required (the value below is a working default)"),e.example&&t.push(`# Example: ${e.example}`),t}function Me(){let e=Pe(),t=["# \u{1F527} Flisk Environment Configuration","# Generated by `flisk project`. The defaults work as-is; edit only to change them.","# Keep this file out of git: it holds a generated database password and JWT secret.","#","# After editing, run: flisk config regenerate && flisk up",""];for(let n of T)t.push(...Ie(n)),t.push(`${n.name}=${te(n.name,e)}`),t.push("");return t.join(`
|
|
11
|
+
`)}function Ot(e){let t=e.match(/^[a-z][a-z0-9+.-]*:\/\/[^:/@\s]+:([^@\s]*)@/i);if(!(!t||t[1].includes("$")))return t[1]}function tr(e){let t=re(e,".env"),n={missing:[],invalid:[],warnings:[]};if(!ne(t))return{missing:T.filter(i=>i.required).map(i=>i.name),invalid:[],warnings:[".env file not found - will be auto-generated"]};let r=_(Ne(t,"utf-8"));for(let i of T)i.required&&!r.has(i.name)&&n.missing.push(i.name),r.has(i.name)&&!(r.get(i.name)??"").trim()&&n.invalid.push(`${i.name} is set but empty`);let o=r.get("DATABASE_URL"),s=r.get("DB_PASSWORD");if(o&&s){let i=Ot(o);i!==void 0&&i!==s&&n.warnings.push("DATABASE_URL carries a different password than DB_PASSWORD; the database container uses DB_PASSWORD")}return n}function Ct(e,t,n){if(!_(e).has(t))return e;let o=e.indexOf("=");if(o<0)return e;let s=e.slice(o+1),i=s.search(/\s#/),a=i<0?"":s.slice(i);return e.slice(0,o+1)+n+a}function nr(e){let t=re(e,".env");if(!ne(t))return je(t,Me(),{mode:384}),T.map(u=>u.name);let n=Ne(t,"utf-8"),r=_(n),o=T.filter(u=>u.complete?r.has(u.name)?!(r.get(u.name)??"").trim():!0:!1);if(o.length===0)return[];let s=o.filter(u=>!r.has(u.name)),i=o.filter(u=>r.has(u.name)),a=r.get("DB_PASSWORD"),c=a?.trim()?a:Pe(),f=n.split(/(\r\n|\n|\r)/);for(let u of i){let h=-1;for(let l=0;l<f.length;l+=2)_(f[l]).has(u.name)&&(h=l);if(h<0)throw new Error(`Could not locate empty .env assignment for ${u.name}`);f[h]=Ct(f[h],u.name,te(u.name,c))}let d=f.join("");if(s.length>0){let u=["","# Added by Flisk: keys this version expects. Existing values above were not changed.",""];for(let l of s)u.push(...Ie(l)),u.push(`${l.name}=${te(l.name,c)}`),u.push("");let h=d.endsWith(`
|
|
12
|
+
`)||d.endsWith("\r")?"":`
|
|
13
|
+
`;d+=h+u.join(`
|
|
14
|
+
`)}return De(t,d),o.map(u=>u.name)}function rr(e){let t=re(e,".env");return ne(t)?!1:(je(t,Me(),{mode:384}),!0)}var jt="[REDACTED]",oe=class extends Error{path;constructor(t,n){super(`Could not read ${t}: ${n}`),this.path=t,this.name="EnvUnreadableError"}},Pt=8;function It(e,t=[]){let n=[...Be(Nt(e,".env")),...t.flatMap(r=>Be(r))];return[...new Set(n)].sort((r,o)=>o.length-r.length)}function Be(e){if(!Dt(e))return[];let t;try{t=Ft(e,"utf-8")}catch(n){throw new oe(e,n instanceof Error?n.message:String(n))}return[..._(t).values()].filter(n=>n.length>=Pt)}function Le(e,t){let n=e;for(let r of t)n=n.split(r).join(jt);return n}function Ue(e,t){return t.length===0?e:typeof e=="string"?Le(e,t):Array.isArray(e)?e.map(n=>Ue(n,t)):e!==null&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,Ue(r,t)])):e}function Ve(e,t=[]){let n;try{n=It(e,t)}catch(r){return()=>{throw r}}return r=>Le(r,n)}import{readFileSync as Mt}from"node:fs";import{join as Bt}from"node:path";function mr(){return We(R())}function We(e){if(e)try{let t=Mt(Bt(e,".flisk",we),"utf-8"),n=JSON.parse(t);if(n?.project?.name)return n.project.name}catch{}return"flisk-project"}function U(e,t){let n=We(t??R()),r=process.env.FLISK_SERVICE_BASE_URL??`http://${n}.localhost${e?`:${e}`:""}`;try{let o=new URL(r.includes("://")?r:`http://${r}`),s=o.hostname,i=o.protocol==="https:"?"443":"80",a=o.port||(e?String(e):""),c=a===i?"":a;if(s==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(s))return{appBase:`${o.protocol}//${s}${c?`:${c}`:""}`,apiBase:`${o.protocol}//${s}${c?`:${c}`:""}`};let f=s.replace(/^(app|api)\./,"");return{appBase:`${o.protocol}//app.${f}${c?`:${c}`:""}`,apiBase:`${o.protocol}//api.${f}${c?`:${c}`:""}`}}catch{return{appBase:`http://app.${n}.localhost`,apiBase:`http://api.${n}.localhost`}}}function Ut(e){return`${e.replace(/\/+$/,"")}/health`}function L(e){if(A(e.config?.appType)){let t=e.name.replace(/-api$/,"");return e.config?.apiPath??`/api/${t}`}return e.config?.basePath??`/${e.name}`}function hr(e,t){let n=e.config?.appType;if(n!=="frontend"&&!A(n))return;let{appBase:r,apiBase:o}=U(t);return`${n==="frontend"?r:o}${L(e)}`}function gr(e,t){return ze(e,t,n=>Ut(n))}function yr(e,t){return ze(e,t,n=>n)}function ze(e,t,n){let{appBase:r,apiBase:o}=U(t);return e.filter(s=>s.config?.appType==="frontend"||A(s.config?.appType)).map(s=>{let i=A(s.config.appType)?o:r;return{name:s.name,appType:s.config.appType,url:`${i}${n(L(s))}`}})}async function Lt(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 Sr(e,t){return Promise.all(e.map(n=>Lt(n,t)))}var Xe=60,He=1e3,Je=1e4,Ze=200,Ye=64*1024,Qe=new Set([404,502,503,504]),Wt=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN","EHOSTUNREACH","ENETUNREACH"]),zt=new Set(["GET","HEAD","OPTIONS"]);function k(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function Gt(e,t){if(zt.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"&&Wt.has(r)}function ie(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 o=`smoke.steps[${r}]`;if(!k(n)){t.push(`${o}: must be an object`);return}let s=n.path;(typeof s!="string"||!s.startsWith("/")||s.startsWith("//"))&&t.push(`${o}.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(`${o}.expect: must be an HTTP status between 100 and 599`),n.bodyContains!==void 0&&typeof n.bodyContains!="string"&&t.push(`${o}.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(`${o}.save: must map names to paths such as "$.id"`))}),t)}function Ar(e,t){let{appBase:n,apiBase:r}=U(t),o=[];for(let s of e){let i=s.config;if(!i?.smoke)continue;let a=i.appType,c=A(a)||a===H;if(!c&&a!=="frontend"||i.exposeViaProxy===!1)continue;let f=c?r:n,d=i.healthCheckPath||(c&&a!==H?"/health":void 0);o.push({name:s.name,baseUrl:`${f}${L(s).replace(/\/+$/,"")}`,...d?.startsWith("/")?{readyPath:d}:{},smoke:i.smoke})}return o}var qt=10;function Tr(e,t={}){let n=t.timeoutSeconds??qt;return e.flatMap(r=>{let o=r.smoke.steps.filter(i=>(i.method??"GET").toUpperCase()==="GET"&&i.body===void 0&&!i.path.includes("{{")).map(i=>({...i,bodyContains:void 0}));if(o.length===0)return[];let s=Math.min(r.smoke.timeoutSeconds??Xe,n);return[{name:r.name,baseUrl:r.baseUrl,smoke:{via:r.smoke.via,timeoutSeconds:s,steps:o}}]})}function Kt(e,t){let n=t.replace(/^\$\.?/,"").match(/[^.[\]]+/g)??[],r=e;for(let o of n){if(r==null||o==="__proto__"||o==="constructor"||o==="prototype"||!Object.hasOwn(r,o))return;let s=Object.getOwnPropertyDescriptor(r,o);if(!s||!("value"in s))return;r=s.value}return r}function et(e,t){return e.replace(/\{\{(\w+)\}\}/g,(n,r)=>t[r]??n)}function se(e,t){return typeof e=="string"?et(e,t):Array.isArray(e)?e.map(n=>se(n,t)):k(e)?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,se(r,t)])):e}function V(e){let t=e.replace(/\s+/g," ").trim();return t.length>Ze?`${t.slice(0,Ze)}...`:t}function tt(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"step"}function Ht(e,t){let n=tt(t),r=(e.get(n)??0)+1;return e.set(n,r),r===1?n:`${n}-${r}`}function Jt(e,t,n,r,o){try{let s=O(e,tt(n.service),t);Vt(s,{recursive:!0});let i=O(s,"latest.json"),a=O(s,"body.txt");return r===void 0?qe(a,{force:!0}):Ke(a,r),Ke(i,`${JSON.stringify({...n,bodyPath:r===void 0?null:"body.txt"},null,2)}
|
|
15
|
+
`),o&&(Ge(i,O(s,"last-success.json")),r===void 0?qe(O(s,"last-success-body.txt"),{force:!0}):Ge(a,O(s,"last-success-body.txt"))),i}catch{return}}function Zt(e){let t=Buffer.from(e,"utf8");if(t.length<=Ye)return{body:e,truncated:!1,bytes:t.length};let n=t.subarray(0,Ye).toString("utf8").replace(/\uFFFD$/,"");return{body:n,truncated:!0,bytes:Buffer.byteLength(n,"utf8")}}async function Yt(e,t={}){let n=t.fetch??((d,u)=>fetch(d,u)),r=t.now??Date.now,o=t.sleep??(d=>new Promise(u=>setTimeout(u,d))),s=(e.smoke.timeoutSeconds??Xe)*1e3,i=r()+s,a={},c=ie(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 u=await n(d,{method:"GET",signal:AbortSignal.timeout(Je)});if(await u.text(),!Qe.has(u.status)&&u.status<500)break}catch{}if(r()>=i)break;await o(He)}}i=r()+s;let f=new Map;for(let[d,u]of e.smoke.steps.entries()){let h=u.name??`step ${d+1}`,l=(u.method??"GET").toUpperCase(),ye=`${e.baseUrl}${et(u.path,a)}`,D=u.expect??200,Se=u.body!==void 0,y,F="",E,G;for(;;){E=void 0,G=void 0,y=void 0;let g=!1;try{let m=await n(ye,{method:l,headers:Se?{"content-type":"application/json"}:void 0,body:Se?JSON.stringify(se(u.body,a)):void 0,signal:AbortSignal.timeout(Je)});y=m.status,F=await m.text()}catch(m){g=Gt(m,l),E=m instanceof Error?m.message:String(m);let w=k(m)?m.code??(k(m.cause)?m.cause.code:void 0):void 0;G=typeof w=="string"?w:void 0}if(!(E!==void 0&&g||y!==void 0&&y!==D&&Qe.has(y))||r()>=i)break;await o(He)}let $e=!1,q=g=>{if(!$e){if(!t.redact)return g;try{return t.redact(g)}catch($){$e=!0;let m=$ instanceof Error?$.message:String($);t.warn?.(`${e.name}: ${h}: the response text was neither shown nor stored: ${m}`);return}}},K=q(ye),S=y===void 0?void 0:q(F),xe=E===void 0?void 0:q(E),Ee=E===void 0?void 0:G??xe,N=`${e.name}: ${h}: ${l} ${K??"(url withheld)"}`,ve;if(t.recordDir){let g=S===void 0?void 0:Zt(S),$=E===void 0&&y===D&&(u.bodyContains===void 0||F.includes(u.bodyContains));ve=Jt(t.recordDir,Ht(f,h),{service:e.name,step:h,method:l,...K===void 0?{}:{url:K},expectedStatus:D,status:y??null,...Ee===void 0?{}:{error:Ee},truncated:g?.truncated??!1,bodyBytes:g?.bytes??0},g?.body,$)}let j=g=>({name:e.name,ok:!1,failure:g,recordPath:ve});if(E!==void 0)return j(`${N} never answered (${xe??"the error was withheld"})`);if(y!==D)return j(`${N} returned ${y}, expected ${D}${S?`: ${V(S)}`:""}`);if(u.bodyContains!==void 0&&!F.includes(u.bodyContains))return j(`${N} returned ${y} but the body does not contain "${u.bodyContains}"${S?`: ${V(S)}`:""}`);if(u.save){let g;try{g=JSON.parse(F)}catch{return j(`${N} returned a body that is not JSON, cannot save${S?`: ${V(S)}`:""}`)}for(let[$,m]of Object.entries(u.save)){let w=Kt(g,m);if(w==null||typeof w=="object")return j(`${N} response has no ${m} to save as {{${$}}}${S?`: ${V(S)}`:""}`);a[$]=String(w)}}}return{name:e.name,ok:!0}}function Rr(e){return`Smoke check failed: ${e.failure}${e.recordPath?` (record: ${e.recordPath})`:""}`}function _r(e,t,n={}){return{redact:Ve(e,n.envFiles??[]),...t?{warn:t}:{}}}async function Or(e,t={}){return Promise.all(e.map(n=>Yt(n,t)))}var nt=1,jr="https://flisk.sh/schema.service.json",Qt={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"},Xt=new Set(["$schema","agent","apiBasePath","apiPath","appName","appType","backendName","basePath","build","buildContext","command","databaseName","dependencies","dev","dependsOn","dockerfile","enabled","env","exposeViaProxy","featuresEnabled","framework","healthCheckPath","image","language","name","nats","params","playwright","port","replicas","restart","runtime","sablier","schemaVersion","secrets","smoke","stack","syncs","traefik","type"]),en=[{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"},{path:["basePath"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /storefront"}];function W(e,t){let n=[],r=new Set;for(let{path:o,pattern:s,expected:i}of en){let a=e;for(let f of o)a=a&&typeof a=="object"&&!Array.isArray(a)?a[f]:void 0;if(a==null||a==="")continue;let c=`${t}.${o.join(".")}`;(typeof a!="string"||!s.test(a))&&r.add(c),typeof a!="string"?n.push(`${c}: expected a string`):s.test(a)||n.push(`${c}: must be ${i} (no spaces, line breaks or YAML syntax)`)}for(let[o,s]of tn(e,t))r.has(o)||n.push(`${o}: ${s}`);return n}function ae(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 tn(e,t){let n=[],r=Object.entries(e).filter(([o])=>o!=="smoke").map(([o,s])=>[s,`${t}.${o}`]);for(let o of Object.keys(e))ae(o)&&n.push([t,"a key contains a line break"]);for(;r.length>0;){let[o,s]=r.pop();if(typeof o=="string")ae(o)&&n.push([s,"must not contain line breaks or control characters"]);else if(Array.isArray(o))for(let[i,a]of o.entries())r.push([a,`${s}[${i}]`]);else if(o&&typeof o=="object")for(let[i,a]of Object.entries(o))ae(i)?n.push([s,"a key contains a line break"]):r.push([a,`${s}.${i}`])}return n.sort(([o],[s])=>o.localeCompare(s))}var nn=["apiPath","basePath"];function ce(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let t=e;return nn.filter(n=>n in t&&typeof t[n]!="string")}function ue(e,t){if(!e||typeof e!="object"||Array.isArray(e))return{errors:[`${t}: expected a JSON object`],warnings:[]};let n=e,r=[],o=v(n)?["appName","appType","schemaVersion"]:["appName","appType","stack","schemaVersion"];for(let c of o)c in n||r.push(`${t}.${c}: required field is missing`);for(let c of["appName","appType","stack"])c in n&&typeof n[c]!="string"&&r.push(`${t}.${c}: expected a string`);"schemaVersion"in n&&n.schemaVersion!==nt&&r.push(`${t}.schemaVersion: unsupported version ${String(n.schemaVersion)} (supported: ${nt})`);for(let c of ce(n))r.push(`${t}.${c}: expected a string`);let s=n.dev,i=s&&typeof s=="object"&&!Array.isArray(s)?s.liveReload:void 0;if(i!==void 0&&typeof i!="boolean"&&r.push(`${t}.dev.liveReload: expected true or false`),r.push(...W(n,t)),r.push(...B(n).map(c=>`${t}: ${c}`)),"smoke"in n)for(let c of ie(n.smoke))r.push(`${t}.${c}`);let a=Object.keys(n).flatMap(c=>{let f=Qt[c];return f?[`${t}.${c}: ${f}`]:Xt.has(c)?[]:[`${t}.${c}: unknown field is preserved`]});return i===!0&&n.language!=="go"&&a.push(`${t}.dev.liveReload: only applies to Go services (language "go"); it is ignored here`),{errors:r,warnings:a,manifest:n}}function Pr(e,t){if(!rt(e))return[];try{let n=JSON.parse(ot(e,"utf-8"));return!n||typeof n!="object"||Array.isArray(n)?[]:W(n,t)}catch{return[]}}function Ir(e,t){if(!rt(e))return{errors:[`${t}: file is missing`],warnings:[]};try{let n=JSON.parse(ot(e,"utf-8"));return ue(n,t)}catch(n){let r=n instanceof Error?n.message:String(n);return{errors:[`${t}: invalid JSON (${r})`],warnings:[]}}}function st(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 rn=/^[a-z0-9-]+$/;function it(e){return rn.test(e)}var on="Use lowercase letters, numbers, and hyphens only";function at(e,t){return`${e} "${t}" is not valid. ${on}, e.g. "${e==="Resource name"?"my-service":"my-stack"}".`}function sn(e){return e.trim()?it(e)?{valid:!0}:{valid:!1,error:at("Resource name",e)}:{valid:!1,error:"Resource name is required"}}function an(e){return e.trim()?it(e)?{valid:!0}:{valid:!1,error:at("Stack name",e)}:{valid:!1,error:"Stack name is required"}}function Lr(e){let t=e==="resource"?sn:an;return n=>{let r=t(n);return r.valid?!0:r.error??"Invalid name"}}function Vr(e){return fe(J,e)?{valid:!0}:{valid:!1,error:`Invalid service. Must be one of: ${J.join(", ")}`}}function Wr(e){return Number.isInteger(e)&&e>0&&e<=65535}function zr(e){return!e.includes("\0")&&!/[<>:"|?*]/.test(e)}function Gr(e,t="_"){return e.replace(/[^a-zA-Z0-9-]/g,t).substring(0,100)}function fe(e,t){return e.includes(t)}var pn=ke;function he(e,t=5,n=0){let r=[];if(n>t)return r;let o=ct.readdirSync(e,{withFileTypes:!0});for(let s of o){let i=b(e,s.name);if(s.isDirectory()){if(dn(s.name))continue;r.push(...he(i,t,n+1))}else s.isFile()&&s.name===pn&&r.push(i)}return r}function oo(e){return he(e)}function dn(e){return fe(Te,e)||e.startsWith(".")}function ln(e){if(!e||typeof e!="object")return!1;let t=e;if(v(t))return typeof t.appName=="string"&&typeof t.appType=="string";let n=typeof t.runtime=="string"||typeof t.appType=="string"||typeof t.type=="string";return typeof t.appName=="string"&&n}var I=new Set;function so(){I.clear()}var x=class extends Error{reason;constructor(t){super(t),this.reason=t,this.name="InvalidServiceJsonError"}};function de(e){return e instanceof Error?e.message:String(e)}function mn(e){let t;try{t=ct.readFileSync(e,"utf-8")}catch(f){throw new x(`could not read file: ${de(f)}`)}let n;try{n=JSON.parse(t)}catch(f){throw new x(`invalid JSON: ${de(f)}`)}if(!ln(n))throw new x(v(n)?"missing required fields (appName and appType)":"missing required fields (appName, runtime or appType)");let r=B(n);if(r.length>0)throw new x(r.join("; "));let o=ce(n);if(o.length>0)throw new x(o.map(f=>`${f}: expected a string`).join("; "));let s=W(n,e);if(s.length>0)throw new x(s.join("; "));let i=n;for(let f of ue(n,e).warnings)I.has(f)||(I.add(f),console.warn(`\u26A0\uFE0F ${f}`));let a={...i,appType:i.appType||i.type},c=fn(e);return{name:a.appName,path:c,configPath:e,config:a,stack:a.stack,port:a.port,type:a.appType}}function ut(e){let t=he(e),n=[],r=[];for(let o of t)try{n.push(mn(o))}catch(s){r.push({path:o,reason:s instanceof x?s.reason:de(s)})}return{resources:n,problems:r}}function hn(e){for(let t of e){let n=`skipped ${t.path}: ${t.reason}`;I.has(n)||(I.add(n),console.warn(`\u26A0\uFE0F ${n}`))}}function ft(e){let{resources:t,problems:n}=ut(e);return hn(n),t}function z(){let e=R();if(!e)throw Z.notInProject();return ft(e)}function io(e){let t=e;if(!t){let n=R();if(!n)throw Z.notInProject();t=ut(n)}if(t.problems.length>0)throw new Error(t.problems.map(n=>`Invalid service.json at ${n.path}: ${n.reason}`).join(`
|
|
16
|
+
`));return t.resources}function ao(e,t){let n=t??ft(e);return gn(n)}function gn(e){let t=e||z(),n=new Set;for(let r of t)r.stack&&n.add(r.stack);return Array.from(n).sort()}function co(e=z()){let t=new Map;for(let r of e)if(r.stack){let o=t.get(r.stack);o?o.push(r):t.set(r.stack,[r])}let n=[];for(let[r,o]of t)n.push({name:r,description:Ce(o.length,"resource"),resources:o,resourceCount:o.length});return n.sort((r,o)=>r.name.localeCompare(o.name))}function uo(e,t){return(t??z()).filter(r=>r.stack===e)}function fo(e,t){return(t??z()).some(r=>r.stack===e)}var ge=5e3,le=new P({ttlMs:ge}),me=new P({ttlMs:ge}),M=_e(ge);function po(){le.clear(),me.clear(),M.reset()}function yn(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===Ae)return"config";if(e==="schema.prisma"||e.includes("migration"))return"prisma";if(t){let n=t.split(`
|
|
17
|
+
`).slice(0,10).join(`
|
|
18
|
+
`);if(n.includes("GENERATED BY Flisk")||n.includes("AUTOGENERATED"))return"generated"}return"unknown"}function Sn(e){let t=e.configPath;if(M.isValid()){let l=le.get(t);if(l)return l}let n=e.path,r=pe(e.configPath),o=r.mtime.toISOString(),s=r.mtime.toISOString(),i=$n(n),a=C(b(n,"Dockerfile")),c=C(b(n,"Tiltfile")),f=C(b(n,be))||C(b(n,"docker-compose.yaml")),d=e.config?.appType,u=d||"backend";d||(e.name.includes("frontend")?u="frontend":(e.name.includes("sdk")||e.name.includes("lib")||e.name.includes("infra"))&&(u="library"));let h={name:e.name,stack:e.stack,type:u,port:e.config?.port,createdAt:o,lastModified:s,dependencies:e.config?.dependsOn??[],hasDockerfile:a,hasTiltfile:c,hasDockerCompose:f,autogeneratedFiles:i,status:"unknown"};return le.set(t,h),M.markUpdated(),h}function $n(e){let t=[];for(let r of Re){let o=b(e,r);if(C(o)){let s=pe(o),i=un(o,"utf-8");t.push({name:r,path:o,type:yn(r,i),size:s.size,lastModified:s.mtime.toISOString()})}}let n=b(e,"prisma");if(C(n)){let r=cn(n);for(let o of r)if(o==="schema.prisma"||o.includes("migration")){let s=b(n,o),i=pe(s);t.push({name:`prisma/${o}`,path:s,type:"prisma",size:i.size,lastModified:i.mtime.toISOString()})}}return t.sort((r,o)=>r.name.localeCompare(o.name))}function lo(e){let t=e.name;if(M.isValid()){let c=me.get(t);if(c)return c}let n=e.resources.map(c=>Sn(c)),r=n.map(c=>new Date(c.createdAt).getTime()),o=Math.min(...r),s=Math.max(...r),i=st(n.map(c=>c.status)),a={name:e.name,resourceCount:n.length,createdAt:new Date(o).toISOString(),lastModified:new Date(s).toISOString(),resources:n,overallStatus:i};return me.set(t,a),M.markUpdated(),a}export{Ce as a,vn as b,kn as c,bn as d,wn as e,An as f,Tn as g,Rn as h,_n as i,On as j,X as k,Cn as l,Dn as m,Fn as n,Nn as o,jn as p,Pn as q,In as r,Mn as s,ee as t,Un as u,Ln as v,Vn as w,Wn as x,A as y,De as z,er as A,_ as B,tr as C,nr as D,rr as E,oe as F,It as G,Le as H,Ue as I,mr as J,U as K,Ut as L,L as M,hr as N,gr as O,yr as P,Sr as Q,Ar as R,Tr as S,Rr as T,_r as U,Or as V,nt as W,jr as X,ue as Y,Pr as Z,Ir as _,st as $,sn as aa,an as ba,Lr as ca,Vr as da,Wr as ea,zr as fa,Gr as ga,fe as ha,oo as ia,so as ja,ut as ka,hn as la,ft as ma,z as na,io as oa,ao as pa,gn as qa,co as ra,uo as sa,fo as ta,po as ua,Sn as va,lo as wa};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
+
import{p as It,w as Lt}from"./chunk-MYAYJF4Q.js";import{f as A,g as Mt,h as Ht,i as Wt,j as Y,k as Le,l as Vt,m as Ut,n as Bt,o as Gt,p as le,q as Kt,s as qt,t as Jt}from"./chunk-T44DEEL6.js";import{c as Ft}from"./chunk-GPUJ55MI.js";import{b as B,c as zt,d as Q}from"./chunk-3J6XI3NX.js";import{a as At,f as jt,g as ce,j as Xt,k as Yt,l as Qt,m as Zt,o as es,p as Me,q as He,r as ts,s as We,t as Ve,u as ss,v as Ue,w as ns}from"./chunk-VYPB7MY5.js";import{C as Dt,F as $t,G as je,H as oe,I as Ct,J as ie,O as Fe,P as Nt,Q as ae,R as Tt,S as Et,U as Rt,V as Ot,W as Ie,a as D,ka as _t,ma as v,t as X,w as re,x as Pt,y as bt}from"./chunk-L6O7TT3K.js";import{C as w,D as vt,L as xt,b as f,d as b,h as yt,j as F,m as U,n as z,o as _e,q as Ae,x as h,y as wt}from"./chunk-TIPSERWO.js";import{execFileSync as Cn}from"node:child_process";import{readFileSync as ti}from"node:fs";import{join as si}from"node:path";import{execFileSync as uo,execSync as cn}from"node:child_process";import{existsSync as C,readdirSync as hn,readFileSync as K}from"node:fs";import{join as x,normalize as $e,relative as Ce}from"node:path";import{Command as po}from"commander";import{existsSync as _n}from"node:fs";var ue="docs/agent-hosts.md",Be=`WebContainers cannot run Flisk: there is no Docker daemon or Tilt. Run \`flisk up\` on a machine with Docker. See ${ue}.`,rs=`Docker is not reachable from this Dev Container. Mount the host Docker socket (-v /var/run/docker.sock:/var/run/docker.sock) or add the docker-outside-of-docker feature to devcontainer.json, then retry. Docker-in-docker is not supported. See ${ue}.`;function An(){return{env:process.env,versions:process.versions,platform:process.platform,fileExists:_n}}function os(e=An()){let{env:t,versions:s,platform:n,fileExists:r}=e;return s.webcontainer?{kind:"webcontainer",canUp:!1}:t.CODESPACES==="true"?{kind:"codespaces",canUp:!0}:t.REMOTE_CONTAINERS||r("/.dockerenv")&&t.DEVCONTAINER?{kind:"devcontainer",canUp:!0}:n==="win32"?{kind:"native-windows",canUp:t.FLISK_ALLOW_NATIVE_WINDOWS==="1"}:n==="linux"&&t.WSL_DISTRO_NAME?{kind:"wsl2",canUp:!0}:{kind:"local",canUp:!0}}function is(e){return e==="devcontainer"||e==="codespaces"}function de(e){return e.some(t=>!X(t)&&(bt(t.config?.appType)||t.config?.appType==="frontend"||t.config?.appType==="worker"))}import{existsSync as jn,readFileSync as Fn}from"node:fs";import{join as In,relative as as,resolve as cs,sep as Ln}from"node:path";var Mn=2,pe=["services/*/*"];function ls(e){return e.split(Ln).filter(Boolean)}function Hn(e,t){let s=0,n=0,r=-1,o=0;for(;n<t.length;)if(s<e.length&&e[s]!=="*"&&(e[s]==="?"||e[s]===t[n]))s++,n++;else if(s<e.length&&e[s]==="*")r=s++,o=n;else if(r!==-1)s=r+1,n=++o;else return!1;for(;s<e.length&&e[s]==="*";)s++;return s===e.length}function Wn(e,t){return e.length===t.length&&e.every((s,n)=>Hn(s,t[n]))}function Ge(e){let t=In(e,".flisk",U);if(!jn(t))return pe;let s="discovery.paths must be an array of strings";try{let n=JSON.parse(Fn(t,"utf-8"))?.discovery?.paths;if(n===void 0)return pe;if(Array.isArray(n)&&n.every(r=>typeof r=="string"))return n}catch(n){s=String(n)}return console.warn(`Ignoring discovery configuration in ${t}: ${s}; using default paths: ${pe.join(", ")}`),pe}function fe(e,t,s){let n=ls(as(e,cs(e,t)));return s.some(r=>{let o=ls(as(e,cs(e,r)));for(let i=0;i<=Mn;i++){let a=n.length-i;if(a>0&&Wn(o,n.slice(0,a)))return!0}return!1})}function vi(e,t,s,n){let r=Ge(e);if(fe(e,t,r))return{path:t};let o=`services/${s}/${n}`;return fe(e,o,r)?{path:o,adjustedFrom:t}:{path:t}}import{execFile as Vn}from"node:child_process";import{promisify as Un}from"node:util";var Bn=Un(Vn),Gn=1e4,Kn=5,us=10*6e4,qn=3,Jn=200,zn=async e=>{let{stdout:t,stderr:s}=await Bn("docker",e,{encoding:"utf-8",timeout:Gn,windowsHide:!0});return`${t}${s}`};function Xn(e,t){let s=Xt(t).toLowerCase(),n=e.replace(/-/g,"_").toLowerCase();return n===s||n.startsWith(`${s}_`)}function Yn(e,t=Date.now()){if(e.status==="restarting")return!0;if(e.restartCount<Kn)return!1;if(e.status==="running"){let n=Date.parse(e.startedAt);return Number.isNaN(n)||t-n<us}let s=Date.parse(e.finishedAt??"");return e.exitCode!==0&&!Number.isNaN(s)&&t-s<us}function Qn(e,t){let s=/database "([^"]+)" does not exist/i.exec(e);return s?`database "${s[1]}" does not exist: re-run the project's database provisioning (flisk up) or create it`:/Cannot find module|MODULE_NOT_FOUND|module not found/i.test(e)?"a module is missing from the image: rebuild it (flisk up --force) after checking the resource's dependencies":/EADDRINUSE|address already in use/i.test(e)?"the port inside the container is already in use: check for two processes started by the same command":/ECONNREFUSED|connection refused|could not connect/i.test(e)?"a dependency is not reachable: check that the service it connects to is running and healthy":/\b(?:environment variable|env var)\b.*\b(?:missing|not set|required|undefined)\b/i.test(e)||/\b[A-Z][A-Z0-9_]{2,}\b (?:is )?(?:not set|required|missing)\b/.test(e)?"a required environment variable is missing: check the project's .env":t.exitCode===137?"killed (exit 137), usually out of memory: raise the container's memory limit":null}function Zn(e){let t=[];for(let s of e.split(/\r?\n/)){let[n,r,o,i,a,c]=s.split(" ");!n||r===void 0||t.push({name:n.replace(/^\//,""),restartCount:Number(r)||0,status:o??"",startedAt:i??"",exitCode:Number(a)||0,finishedAt:c??""})}return t}async function ds(e,t=[],s=zn,n=Date.now()){let r="Crash-looping containers",o;try{o=(await s(["ps","-a","--format",'{{.ID}} {{.Label "com.docker.compose.project"}}'])).split(/\r?\n/).map(m=>m.split(" ")).filter(([m,d])=>m&&d&&Xn(d,e)).map(([m])=>m)}catch{return{name:r,didPass:!0,isSkipped:!0,message:"Docker not available - skipped crash-loop check"}}if(o.length===0)return{name:r,didPass:!0,isSkipped:!0,message:"No project containers to check"};let i;try{i=Zn(await s(["inspect","--format","{{.Name}} {{.RestartCount}} {{.State.Status}} {{.State.StartedAt}} {{.State.ExitCode}} {{.State.FinishedAt}}",...o]))}catch{return{name:r,didPass:!0,isSkipped:!0,message:"Containers changed while checking - skipped crash-loop check"}}let a=i.filter(u=>Yn(u,n));if(a.length===0)return{name:r,didPass:!0,message:"No project container is crash-looping"};let c=[],l=new Set;for(let u of a){let m="";try{m=await s(["logs","--tail",String(qn),u.name])}catch{}let d=oe(m,t).split(/\r?\n/).map(k=>k.trim().slice(0,Jn)).filter(Boolean),g=Qn(m,u);g&&l.add(g),c.push([`${u.name}: ${u.status}, restarted ${u.restartCount} times`,...d.map(k=>` | ${k}`)].join(`
|
|
3
|
+
`))}return{name:r,didPass:!1,message:`${a.length} container${a.length===1?" is":"s are"} crash-looping:
|
|
4
|
+
${c.join(`
|
|
5
|
+
`)}`,fix:[...l,"Read the full log: docker logs <container>"].join("; ")}}import{execFile as dr,execFileSync as pr}from"node:child_process";import{existsSync as fr,realpathSync as Ss,statfsSync as mr}from"node:fs";import{homedir as hr}from"node:os";import{join as gr}from"node:path";import{promisify as kr}from"node:util";import{statfsSync as er}from"node:fs";import{homedir as tr}from"node:os";var G="Disk Space",sr=1024**3,nr=2,Ke=10,ps=["Free disk space, then retry: flisk doctor"," docker system prune -af # unused images and build cache (needs Docker running)"," npm cache clean --force"," bun pm cache rm"," brew cleanup -s"].join(`
|
|
6
|
+
`);function fs(e=er,t=tr()){let s;try{let r=e(t);s=Number(r.bavail)*Number(r.bsize)/sr}catch{return{name:G,didPass:!0,isSkipped:!0,message:"Could not read free disk space"}}let n=`${s.toFixed(1)} GB free`;return s<nr?{name:G,didPass:!1,message:`${n}: Docker cannot build or start containers`,fix:ps}:s<Ke?{name:G,didPass:!1,isWarning:!0,message:`${n}: image builds may fail`,fix:ps}:{name:G,didPass:!0,message:n}}var rr="Quit Docker Desktop completely (whale icon > Quit Docker Desktop), reopen it, and wait until it shows Running. If it keeps getting stuck, check free disk space. Then retry: flisk doctor";function ms(e,t=process.platform){return t!=="darwin"||!e?null:{name:"Container Runtime",didPass:!1,message:"Docker Desktop is open, but its engine is not responding",fix:rr}}import{execFileSync as or}from"node:child_process";var qe=(e,t)=>or(e,t,{encoding:"utf-8",stdio:"pipe",windowsHide:!0}),hs=["traefik-public","traefik-private","backend","database","infisical-network","verdaccio-network","proxy"];function Je(e){let t=e.replace(/-/g,"_");return hs.map(s=>`${t}_${s}`)}function gs(e){let t=new Set;for(let s of e)for(let n of["traefik-public","traefik-private"])s.endsWith(`_${n}`)&&t.add(s.slice(0,-(n.length+1)));return t}function ze(e,t){for(let s of hs)if(e.endsWith(`_${s}`)){let n=e.slice(0,-(s.length+1));if(t.has(n))return n}return null}function Oi(e,t=qe){let s=new Set(t("docker",["network","ls","--format","{{.Name}}"]).split(/\r?\n/).map(r=>r.trim()).filter(Boolean)),n={removed:[],kept:[]};for(let r of Je(e))if(s.has(r))try{t("docker",["network","rm",r]),n.removed.push(r)}catch(o){let i=String(o.stderr??o).trim();n.kept.push({name:r,reason:i.split(/\r?\n/)[0]??""})}return n}function me(e,t=process.platform,s=qe){if(t==="win32")return[];let n;try{n=s("ps",["-axo","pid=,command="])}catch{return[]}let r=[];for(let o of n.split(/\r?\n/)){let i=/^\s*(\d+)\s+(.*)$/.exec(o);if(!i)continue;let a=i[2]??"",c=(a.split(/\s+/)[0]??"").split("/").at(-1),l=` -f ${e}`,u=a.indexOf(l),m=a[u+l.length];c==="tilt"&&/^\S+\s+up\s/.test(a)&&u>0&&(m===void 0||m===" ")&&r.push(Number(i[1]))}return r}function _i(e,t=process.platform,s=qe){let n=me(e,t,s);for(let r of n)try{s("kill",["-TERM",String(r)])}catch{}return n}async function Ai(e,t=8e3,s=me){let n=Date.now()+t;for(;s(e).length>0;){if(Date.now()>=n)return!1;await new Promise(r=>setTimeout(r,250))}return!0}import{execFile as ks}from"node:child_process";function Xe(e){return new Promise(t=>{ks(w("tilt")??"tilt",["get","uiresources","-o","json","--port",String(e)],{timeout:15e3,maxBuffer:16*1024*1024},(s,n)=>t(s?null:n))})}function Mi(e,t){return new Promise(s=>{ks(w("tilt")??"tilt",["logs",t,"--port",String(e)],{timeout:15e3,maxBuffer:16*1024*1024},(n,r)=>s(n?null:r))})}function ir(e){let s=(JSON.parse(e).items??[]).filter(n=>n.status?.disableStatus?.state!=="Disabled").map(n=>n.status?.updateStatus==="not_applicable"?{...n,status:{...n.status,updateStatus:"ok"}}:n);return JSON.stringify({items:s})}function ar(e){return(JSON.parse(e).items??[]).filter(t=>t.status?.disableStatus?.state!=="Disabled").flatMap(t=>t.metadata?.name?[t.metadata.name]:[])}function cr(e,t){let s=JSON.parse(e).items??[],n=new Map(s.map(r=>[r.metadata?.name,r]));return{missing:t.filter(r=>!n.has(r)),disabled:t.filter(r=>n.get(r)?.status?.disableStatus?.state==="Disabled")}}function lr(e){return e.endsWith("-typecheck")}function ur(e,t,s){let n=Zt(ir(e),t),r=n.failures.filter(i=>!lr(i.name)),o={ready:r.length===0&&n.pendingCount===0&&n.okCount>0,failures:r.map(i=>({name:i.name,message:i.error||`${i.updateStatus}/${i.runtimeStatus}`})),pending:n.pendingCount,timedOut:!1,enabled:ar(e)};if(s&&s.length>0){let{missing:i,disabled:a}=cr(e,s);if(i.length>0&&(o={...o,ready:!1,pending:o.pending+i.length}),a.length>0)return{settled:!0,result:{...o,ready:!1,failures:[...o.failures,...a.map(c=>({name:c,message:"disabled in Tilt"}))]}}}return{result:o,settled:o.ready||o.failures.length>0&&o.pending===0}}async function Hi(e,t={}){let s=t.timeoutMs??Number(process.env.FLISK_UP_READY_TIMEOUT_MS??9e5),n=t.intervalMs??2e3,r=t.fetchJson??Xe,o=t.deferred??Qt(),i=Date.now()+s,a={ready:!1,failures:[],pending:0,timedOut:!1,enabled:[]};for(;;){let c=await r(e);if(c)try{let l=ur(c,o,t.expected);if(a=l.result,l.settled||a.failures.length>0&&t.isStalled?.(c))return a}catch{}if(Date.now()>=i)return{...a,ready:!1,timedOut:!0};await new Promise(l=>setTimeout(l,n))}}var M=kr(dr),Sr=15e3,yr=/^flisk_doctor_probe_(\d+)$/,wr=async e=>{let{stdout:t}=await M("docker",e,{encoding:"utf-8",timeout:Sr,windowsHide:!0});return t};function vr(){try{return pr("docker",["info","--format","{{.ServerVersion}}"],{encoding:"utf-8",timeout:15e3,stdio:["ignore","pipe","ignore"]}),!0}catch{return!1}}function he(e){return String(e.stderr??e).trim().split(/\r?\n/)[0]??""}var xr=120;function Pr(e){let t=/^\s*(?:(?:(\d+)-)?(\d+):)?(\d+):(\d+)\s*$/.exec(e);if(!t)return null;let[,s="0",n="0",r="0",o="0"]=t;return((Number(s)*24+Number(n))*60+Number(r))*60+Number(o)}async function br(e,t=Xe,s=2,n=r=>new Promise(o=>setTimeout(o,r))){for(let r=0;r<s;r++){r>0&&await n(1e3);for(let o of e)if(await t(o)!==null)return!0}return!1}async function Dr(e){if(process.platform==="win32")return"unknown";try{let{stdout:t}=await M("ps",["-p",String(e),"-o","etime="],{encoding:"utf-8",timeout:5e3}),s=Pr(t);if(s===null||s<xr)return"unknown";let{stdout:n}=await M("lsof",["-nP","-a","-p",String(e),"-iTCP","-sTCP:LISTEN","-Fn"],{encoding:"utf-8",timeout:5e3}),r=[...n.matchAll(/^n.*:(\d+)$/gm)].map(o=>Number(o[1]));return await br(r)?"healthy":"stale"}catch{return"unknown"}}function $r(e=wr){return{colima:Cr,colimaStatus:()=>B(),dockerAnswers:vr,async listNetworks(){let t=(await e(["network","ls","--format","{{.Name}}"])).split(/\r?\n/).map(n=>n.trim()).filter(Boolean);return(await Promise.all(t.map(async n=>{try{let r=await e(["network","inspect","--format","{{len .Containers}}",n]);return{name:n,containers:Number(r.trim())||0}}catch(r){if(/no such network|not found/i.test(String(r)))return null;throw r}}))).filter(n=>n!==null)},async removeNetwork(t){try{await e(["network","rm",t])}catch(s){throw new Error(he(s))}},freeDiskGib(){try{let t=mr(hr());return Number(t.bavail)*Number(t.bsize)/1024**3}catch{return null}},async reclaimable(){let t=null;try{let n=await e(["system","df","--format","{{.Type}} {{.Reclaimable}}"]);for(let r of n.split(/\r?\n/)){let[o,i]=r.split(" ");o==="Build Cache"&&i&&(t=i.replace(/\s*\(.*\)/,"").trim())}}catch{}let s=0;try{s=(await e(["images","-q","-f","dangling=true"])).split(/\r?\n/).filter(Boolean).length}catch{}return{buildCache:t,danglingImages:s}},async prune(t){try{await e(t==="builder"?["builder","prune","-f"]:["image","prune","-f"])}catch(s){throw new Error(he(s))}},async tiltStatus(t){return Dr(t)},stopProcess(t){process.kill(t,"SIGTERM")},isProcessAlive(t){try{return process.kill(t,0),!0}catch(s){return s.code==="EPERM"}}}}var ys=$r();async function Cr(e){if(e==="native-lima"){let n=Q();if(!n){let o=fr("/opt/homebrew/bin/brew")?"/opt/homebrew/bin/brew":"brew";if(await M(o,["reinstall","lima"],{encoding:"utf-8",timeout:3e5}),n=Q(),!n)throw new Error("brew reinstall lima did not provide a native limactl")}let r=n?{...process.env,PATH:`${n}:${process.env.PATH??""}`}:process.env;await M("colima",["start"],{encoding:"utf-8",timeout:3e5,env:r});return}let t=Q(),s=t?{...process.env,PATH:`${t}:${process.env.PATH??""}`}:process.env;await M("colima",[e],{encoding:"utf-8",timeout:3e5,env:s})}async function ws(e,t=ys,s={}){let n=[],r=[];for(let d of s.tiltPids??[])await t.tiltStatus(d)==="stale"?n.push({id:`stop-tilt:${d}`,check:"Tilt processes",scope:"project",command:`kill -TERM ${d}`,status:"planned",reason:"this project's Tilt is running but its UI does not answer"}):r.push(d);let o=r.length>0?`Tilt is running for this project (pid ${r.join(", ")}); run flisk down first`:void 0,i=t.colimaStatus(),a=zt(i,t.dockerAnswers());if(a==="start")n.push({id:"colima:start",check:"Colima",scope:"host",command:"colima start",status:"planned",reason:i.problem??"the Colima VM is not running"});else if(a==="restart")n.push({id:"colima:restart",check:"Colima",scope:"host",command:"colima restart",status:"planned",reason:"the Colima VM is running but its Docker daemon does not answer"});else if(a==="native-lima"){let d=Q();n.push({id:"colima:native-lima",check:"Colima",scope:"host",command:d?`PATH="${d}:$PATH" colima start`:"brew reinstall lima",status:"planned",reason:d?`the colima CLI on this PATH cannot see the VM; a native limactl is installed in ${d}`:"the colima CLI on this PATH cannot see the VM; lima is installed as an x86_64 build (brew reinstall lima)"})}let c=await t.listNetworks(),l=t.freeDiskGib();if(l!==null&&l<Ke){let{buildCache:d,danglingImages:g}=await t.reclaimable(),k=`${l.toFixed(1)} GB free`;d&&!/^0(\.0+)?\s*B$/i.test(d)&&n.push({id:"prune:builder",check:"Disk Space",scope:"host",command:"docker builder prune -f",status:"planned",reason:`${k}; ${d} of build cache reclaimable`}),g>0&&n.push({id:"prune:images",check:"Disk Space",scope:"host",command:"docker image prune -f",status:"planned",reason:`${k}; ${g} untagged image${g===1?"":"s"}`})}let u=new Set(e?Je(e):[]),m=gs(c.map(d=>d.name));for(let d of c){let g=yr.exec(d.name),k,y,$="unused network";if(g)k="probe",y="Orphaned probe networks";else if(u.has(d.name))k="project",y="Docker networks";else if(s.machine&&ze(d.name,m))k="machine",y="Docker networks",$=`unused network of project "${ze(d.name,m)}"`;else continue;let N={id:`remove-network:${d.name}`,check:y,scope:k,command:`docker network rm ${d.name}`,status:"planned",reason:$};d.containers>0?(N.status="skipped",N.reason=`${d.containers} container(s) still attached`):k==="project"&&o?(N.status="skipped",N.reason=o):g&&t.isProcessAlive(Number(g[1]))&&(N.status="skipped",N.reason=`probe of a running process (pid ${g[1]})`),n.push(N)}return n}async function vs(e,t,s=ys){let n=[];for(let r of e){if(r.status!=="planned"||t.dryRun){n.push(r);continue}if(!t.confirm){n.push({...r,status:"skipped",reason:"confirmation required; run in a terminal or pass --yes"});continue}let o=!1;try{o=await t.confirm(r)}catch{}if(!o){n.push({...r,status:"skipped",reason:"not confirmed"});continue}try{if(r.id.startsWith("prune:")){await s.prune(r.id==="prune:builder"?"builder":"images"),n.push({...r,status:"applied",reason:"pruned"});continue}if(r.id.startsWith("colima:")){let i=r.id.slice(7);if(i==="start"||i==="restart"){await s.colima(i),n.push({...r,status:"applied",reason:`colima ${i} ran`});continue}try{await s.colima("native-lima"),n.push({...r,status:"applied",reason:"native lima repaired and colima started"})}catch(a){n.push({...r,status:"failed",reason:he(a)})}continue}if(r.id.startsWith("stop-tilt:")){s.stopProcess(Number(r.id.slice(10))),n.push({...r,status:"applied",reason:"stopped"});continue}await s.removeNetwork(r.id.slice(15)),n.push({...r,status:"applied",reason:"removed"})}catch(i){n.push({...r,status:"failed",reason:he(i)})}}return n}function xs(e){return e.some(t=>t.status==="failed")}async function Nr(e){try{let{stdout:t}=await M(e,["--version"],{encoding:"utf-8",timeout:5e3,windowsHide:!0});return t.trim().split(/\r?\n/)[0]||null}catch{return null}}async function Tr(e=vt("flisk"),t=Nr){let s=new Set,n=[];for(let r of e){let o=r;try{o=Ss(r)}catch{}s.has(o)||(s.add(o),n.push({path:r,version:await t(r)}))}return n}async function Ye(e){let t=e??await Tr();if(t.length<=1)return{name:"Flisk installs",didPass:!0,message:"One flisk install on PATH"};let s=t.map(r=>`${r.path} (${r.version??"version unknown"})`).join(", "),n=new Set(t.map(r=>r.version));return{name:"Flisk installs",didPass:!1,isWarning:!0,message:`${t.length} flisk installs on PATH${n.size>1?" with different versions":""}: ${s}`,fix:"Keep one: remove the others, or run flisk upgrade. The first on PATH is the one your shell runs; tools that launch /usr/local/bin/flisk directly may use another"}}function Ps(e,t=me){let s=new Set([e]);try{s.add(Ss(e))}catch{}let n=new Set;for(let r of s)for(let o of t(gr(r,".flisk",".flisk-out","Tiltfile")))n.add(o);return[...n]}var Qe=e=>e==="darwin"||e==="linux";function bs(e){let t=/^\s*(\d{2,5}) \(/m.exec(e.message);return t?Number(t[1]):null}function Er(e,t){return t===null?null:e==="darwin"?`lsof -nP -iTCP:${t} -sTCP:LISTEN`:e==="linux"?`ss -ltnp 'sport = :${t}'`:null}var Rr={[b]:{tier:0,command:e=>e==="darwin"?"open -a Docker":e==="linux"&&!process.env.WSL_DISTRO_NAME?"sudo systemctl start docker":null},Colima:{tier:1,command:e=>Qe(e)?"colima start":null},"Host Ports":{tier:2,command:(e,t)=>Er(e,bs(t))},"Ingress Ports":{tier:2,command:()=>null},"Tilt CLI":{tier:3,command:e=>Qe(e)?"curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash":null},Bun:{tier:3,command:e=>Qe(e)?"curl -fsSL https://bun.sh/install | bash":null},"Docker Network Pool":{tier:4,command:()=>"flisk down --prune-networks"},"Docker networks":{tier:4,command:()=>"flisk down --prune-networks"},[G]:{tier:5,command:()=>"docker system prune -af"},"Flisk installs":{tier:6,command:()=>"flisk upgrade"},"Flisk version":{tier:6,command:()=>"flisk upgrade"},"Master Configs":{tier:7,command:()=>"flisk project"},"Generated Runtime Assets":{tier:7,command:()=>"flisk config regenerate"},"Starlark Load Exports":{tier:7,command:()=>"flisk config regenerate"}},Or=99;function _r(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function ge(e,t=process.platform){let s=e.filter(r=>!r.didPass&&!r.isSkipped).map((r,o)=>{let i=Rr[r.name];return{result:r,index:o,tier:i?.tier??Or,command:i?.command(t,r)??null}}).filter(r=>r.command!==null),n=r=>(r.result.isWarning?1e3:0)+r.tier*10+(r.result.name==="Host Ports"&&bs(r.result)===5432?0:1);return s.sort((r,o)=>n(r)-n(o)||r.index-o.index),s.map((r,o)=>({rank:o+1,checkId:_r(r.result.name),check:r.result.name,command:r.command}))}function Ds(e){return e.length===0?[]:e.flatMap(t=>[` ${t.rank}. ${t.check}`,` ${t.command}`])}import{spawn as Ar}from"node:child_process";import{appendFileSync as jr,existsSync as Os,mkdirSync as Fr,readFileSync as _s,rmSync as As,writeFileSync as $s}from"node:fs";import{connect as Ir}from"node:net";import{join as H}from"node:path";var tt=H(".flisk","native"),Lr="run.json",js=6e4,Mr=1e3,Fs=5e3,Cs=5,Hr=1e4;function ke(e,t=""){return`http://localhost:${e}${t}`}function Wr(e,t,s=()=>{}){return e.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-([^}]*))?\}/g,(n,r,o)=>{let i=t[r];return i!==void 0&&i!==""?i:o!==void 0?o:(s(r),"")})}function Ze(e){let t=new Set(e.map(o=>o.name)),s=new Map(e.map(o=>[o.name,o.dependsOn.filter(i=>t.has(i))])),n=new Set,r=[];for(;s.size>0;){let o=[...s.entries()].filter(([,i])=>i.every(a=>n.has(a))).map(([i])=>i).sort();if(o.length===0)throw new Error(`circular dependsOn between ${[...s.keys()].sort().join(", ")}`);for(let i of o)s.delete(i),n.add(i);r.push(o)}return r}function st(e,t=process.env){let s=[],n=[],r=new Set(e.map(a=>a.name)),o=new Map,i=e.map(a=>{let c=a.config??{},l=Array.isArray(c.dependsOn)?c.dependsOn:[];for(let g of l)r.has(g)||s.push(`service "${a.name}" dependsOn "${g}", which is not a service with a command in this project. Shared infrastructure such as a database or the gateway still needs Docker: add a "${g}" service with a command, or remove it from dependsOn.`);let u=typeof c.port=="number"?c.port:void 0;if(u!==void 0){let g=o.get(u);g?s.push(`services "${g}" and "${a.name}" both use port ${u}`):o.set(u,a.name)}let m={};for(let[g,k]of Object.entries(c.env??{}))m[g]=Wr(String(k),{...t,...m},y=>n.push(`${a.name}: ${y}`));u!==void 0&&(m.PORT=String(u));let d=typeof c.healthCheckPath=="string"?c.healthCheckPath:"";return{name:a.name,command:String(c.command),cwd:a.path,port:u,env:m,dependsOn:l.filter(g=>r.has(g)),healthUrl:u!==void 0&&d?ke(u,d):void 0,url:u!==void 0?ke(u):void 0,restart:c.restart!=="no"}});try{Ze(i)}catch(a){s.push(a instanceof Error?a.message:String(a))}return{services:i,errors:s,missingVars:n}}function Is(e,t=w,s=Os){let n=[];for(let r of e){let o=Pt(r.command);if(!o||["cd",".","source","true",":"].includes(o))continue;(o.includes("/")?s(H(r.cwd,o)):t(o))||n.push({name:r.name,program:o})}return n}function nt(e,t=1e3){return new Promise(s=>{let n=Ir({host:"localhost",port:e}),r=o=>{n.destroy(),s(o)};n.setTimeout(t,()=>r(!1)),n.once("connect",()=>r(!0)),n.once("error",()=>r(!1))})}async function Vr(e){try{let t=await fetch(e,{signal:AbortSignal.timeout(2e3),redirect:"manual"});return await t.body?.cancel(),t.status<400}catch{return!1}}async function Ns(e,t){let s=Date.now()+(t.timeoutMs??js),n=t.intervalMs??250;if(!e.healthUrl&&e.port===void 0)return await et(Mr),t.isAlive();for(;Date.now()<s;){if(!t.isAlive())return!1;if(e.healthUrl?await Vr(e.healthUrl):await nt(e.port))return!0;await et(n)}return!1}function et(e){return new Promise(t=>setTimeout(t,e))}function Se(e){return H(e,tt,Lr)}function Ls(e,t){return H(e,tt,"logs",`${t}.log`)}function ye(e){try{let t=JSON.parse(_s(Se(e),"utf-8"));return t&&typeof t.pid=="number"&&t.services?t:null}catch{return null}}function Ur(e,t){let s=H(e,tt);Fr(H(s,"logs"),{recursive:!0});let n=H(s,".gitignore");Os(n)||$s(n,`*
|
|
7
|
+
`),$s(Se(e),`${JSON.stringify(t,null,2)}
|
|
8
|
+
`)}function I(e){try{return process.kill(e,0),!0}catch(t){return t.code==="EPERM"}}function Ts(e,t){try{process.kill(-e,t)}catch{try{process.kill(e,t)}catch{}}}async function Ms(e,t){let s=Date.now()+t;for(;Date.now()<s;){if(!I(e))return!0;await et(100)}return!I(e)}async function Hs(e,t=Fs){Ts(e,"SIGTERM"),await Ms(e,t)||Ts(e,"SIGKILL")}async function la(e,t={}){let s=ye(e);if(!s)return{wasRunning:!1,services:[]};let n=t.timeoutMs??Fs*2;if(s.pid!==process.pid&&I(s.pid)){try{process.kill(s.pid,"SIGTERM")}catch{}await Ms(s.pid,n)}for(let r of Object.values(s.services))r.pid&&I(r.pid)&&await Hs(r.pid);return As(Se(e),{force:!0}),{wasRunning:!0,services:Object.keys(s.services),supervisorPid:s.pid}}function ua(e,t){let s=ye(e),n=s!==null&&I(s.pid);return Object.fromEntries(t.map(r=>{let o=s?.services[r];return!n||!o?[r,{status:"unknown",reason:"not running"}]:!o.pid||!I(o.pid)?[r,{status:"pending",reason:"restarting"}]:o.ready?[r,{status:"ready"}]:[r,{status:"pending",reason:"starting"}]}))}function da(e,t,s){let n=s.sinceMs===void 0?null:(s.now??Date.now())-s.sinceMs,r=[];for(let o of t){let i;try{i=_s(Ls(e,o),"utf-8")}catch{continue}for(let a of i.split(`
|
|
9
|
+
`)){if(!a)continue;let c=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z) (.*)$/.exec(a),l=c?.[1]??null;n!==null&&(!l||Date.parse(l)<n)||r.push({time:l,resource:o,level:null,source:null,text:c?.[2]??a})}}return r.sort((o,i)=>(o.time??"").localeCompare(i.time??"")),r.slice(-s.tail)}var Es=[f.cyan,f.magenta,f.green,f.yellow,f.blue,f.red],Rs=class{projectRoot;events;options;services=new Map;startedAt=new Date().toISOString();stopping=!1;constructor(t,s,n={},r={}){this.projectRoot=t,this.events=n,this.options=r;for(let o of s)this.services.set(o.name,{plan:o,startedAt:0,quickCrashes:0,gaveUp:!1,isReady:!1})}get prefixWidth(){return Math.max(...[...this.services.keys()].map(t=>t.length))}async start(){this.saveState();let t=[...this.services.values()].map(r=>r.plan),s=new Map,n=[];for(let r of Ze(t).flat()){let o=this.services.get(r);s.set(r,(async()=>{let i=await Promise.all(o.plan.dependsOn.map(c=>s.get(c)));if(!i.every(Boolean)){let c=o.plan.dependsOn.filter((l,u)=>!i[u]);return n.push({name:r,reason:`not started: ${c.join(", ")} did not start`}),!1}if(this.stopping)return!1;this.spawn(o);let a=await Ns(o.plan,{isAlive:()=>!this.stopping&&!o.gaveUp,timeoutMs:this.options.readyTimeoutMs});return a?(o.isReady=!0,this.saveState(),this.events.onNote?.(r,"ready")):this.stopping||n.push({name:r,reason:o.gaveUp?"kept exiting; see its output above":`not ready after ${Math.round((this.options.readyTimeoutMs??js)/1e3)}s (${o.plan.healthUrl?`no answer from ${o.plan.healthUrl}`:`nothing listening on port ${o.plan.port}`})`}),a})())}return await Promise.all(s.values()),n}async stop(){if(this.stopping)return;this.stopping=!0;let t=Ze([...this.services.values()].map(s=>s.plan)).flat().reverse();for(let s of t){let n=this.services.get(s);n.restartTimer&&clearTimeout(n.restartTimer);let r=n.child?.pid;r&&n.child?.exitCode===null&&n.child.signalCode===null&&await Hs(r)}As(Se(this.projectRoot),{force:!0})}pidOf(t){return this.services.get(t)?.child?.pid}spawn(t){let{plan:s}=t;t.startedAt=Date.now();let n=Ar(s.command,{cwd:s.cwd,env:{...this.options.baseEnv??process.env,...s.env},shell:!0,detached:!0,stdio:["ignore","pipe","pipe"]});t.child=n,this.events.onNote?.(s.name,`started: ${s.command}${n.pid?` (pid ${n.pid})`:""}`),this.pipeLines(s.name,n.stdout,"stdout"),this.pipeLines(s.name,n.stderr,"stderr"),n.once("error",r=>{this.events.onNote?.(s.name,`could not start: ${r.message}`)}),n.once("exit",(r,o)=>this.onExit(t,n,r,o)),this.saveState()}onExit(t,s,n,r){if(this.stopping||t.child!==s)return;t.isReady=!1,this.saveState();let o=r?`was stopped by ${r}`:`exited with code ${n}`;if(!t.plan.restart){t.gaveUp=!0,this.events.onNote?.(t.plan.name,`${o}; not restarting ("restart": "no")`);return}let i=Date.now()-t.startedAt;if(t.quickCrashes=i<Hr?t.quickCrashes+1:1,t.quickCrashes>=Cs){t.gaveUp=!0,this.events.onNote?.(t.plan.name,`${o}; it exited ${Cs} times in a row, so it is not restarted. Fix it, then run flisk up again.`);return}let a=(this.options.restartDelayMs??1e3)*2**(t.quickCrashes-1);this.events.onNote?.(t.plan.name,`${o}; restarting in ${a/1e3}s`),t.restartTimer=setTimeout(()=>{this.stopping||(this.spawn(t),Ns(t.plan,{isAlive:()=>!this.stopping&&t.child?.exitCode===null,timeoutMs:this.options.readyTimeoutMs}).then(c=>{!c||this.stopping||(t.isReady=!0,this.saveState(),this.events.onNote?.(t.plan.name,"ready again"))}))},a)}pipeLines(t,s,n){if(!s)return;let r=Ls(this.projectRoot,t),o="",i=a=>{try{jr(r,`${new Date().toISOString()} ${a}
|
|
10
|
+
`)}catch{}this.events.onLine?.(t,a,n)};s.setEncoding?.("utf-8"),s.on("data",a=>{let c=(o+a).split(/\r?\n/);o=c.pop()??"";for(let l of c)i(l)}),s.on("end",()=>{o&&i(o),o=""})}saveState(){let t={};for(let[s,n]of this.services)t[s]={pid:n.child?.pid,port:n.plan.port,url:n.plan.url,ready:n.isReady};Ur(this.projectRoot,{pid:process.pid,startedAt:this.startedAt,services:t})}};function pa(e,t,s){return(Es[t%Es.length]??f.cyan)(`${e.padEnd(s)} | `)}function Ws(e){return{name:"Runtime",didPass:!0,message:`Local processes: ${D(e.length,"service")} declare a command, so Docker, Compose and Tilt are not needed`}}function Vs(e,t=w){let s=Is(st(e.filter(X)).services,t);return s.length===0?{name:"Service commands",didPass:!0,message:"Every service command starts a program that is installed"}:{name:"Service commands",didPass:!1,message:`${D(s.length,"service")} run a program that is not on PATH:
|
|
11
|
+
${s.map(({name:n,program:r})=>`${n}: ${r}`).join(`
|
|
12
|
+
`)}`,fix:'Install the program, or change "command" in the service.json'}}function Us(e){let t=new Set(e.map(n=>n.name)),s=e.flatMap(n=>{let r=n.config?.dependsOn;return(Array.isArray(r)?r:[]).filter(o=>!t.has(o)).map(o=>`${n.name} dependsOn "${o}", which is not a service of this project`)});return s.length===0?{name:"Service dependencies",didPass:!0,message:"Every dependsOn names a service of this project"}:{name:"Service dependencies",didPass:!1,message:s.join(`
|
|
13
|
+
`),fix:"Add the missing service with a command, or remove it from dependsOn. A database or the gateway still needs the Docker path."}}async function Bs(e,t,s){let n=ye(e);if(!n||!I(n.pid))return{name:"Service Health",didPass:!0,isSkipped:!0,message:"Not running - start it with flisk up"};let r=[];for(let o of st(t.filter(X)).services){if(o.port===void 0)continue;(o.healthUrl?await fetch(o.healthUrl,{signal:AbortSignal.timeout(s)}).then(a=>a.status<400).catch(()=>!1):await nt(o.port,s))||r.push(`${o.name}: no answer from ${o.healthUrl??ke(o.port)}`)}return r.length===0?{name:"Service Health",didPass:!0,message:"Every running service answers"}:{name:"Service Health",didPass:!1,message:r.join(`
|
|
14
|
+
`),fix:"Read the service output in .flisk/native/logs/<service>.log, or the flisk up terminal"}}var rt=1;function Br(e,t=[]){return{schemaVersion:rt,data:e,errors:t}}function Gr(e){return e instanceof xt?{error:{code:"COMMAND_FAILED",message:e.message,...e.suggestions.length>0?{suggestions:e.suggestions}:{}},exitCode:e.exitCode}:{error:{code:"INTERNAL",message:e instanceof Error?e.message:String(e)},exitCode:2}}function wa(e){let t=Gr(e);console.log(JSON.stringify(Br(null,[t.error]))),console.error(t.error.message),process.exit(t.exitCode)}async function Ks(e,t){let s=[],n=[],r=o=>{o.status==="fulfilled"?s.push(o.value):n.push({code:"INTERNAL",message:o.reason instanceof Error?o.reason.message:String(o.reason)})};for(let o of await Promise.allSettled(e.map(i=>Promise.resolve().then(i))))r(o);for(let o of t)for(let i of await Promise.allSettled([Promise.resolve().then(o)]))r(i);return{checks:s,errors:n}}function Gs(e){let t=e.find(s=>s.name===b);return t?t.didPass:null}function L(e,t,s=[],n,r){let o=ge(e);return{schemaVersion:rt,data:{ready:s.length===0&&e.every(i=>i.didPass||i.isSkipped||i.isWarning),inProject:t,checks:e,...o.length>0?{fixFirst:o}:{},...r?{host:{...r,containerRuntimeReachable:Gs(e),canUp:r.canUp&&Gs(e)!==!1}}:{},...n!==void 0?{ports:{http:{requested:n?.requested.ingressHttp??80,chosen:n?.ingressHttp??null,explicit:n?.explicit.ingressHttp??!!process.env.FLISK_HTTP_PORT,reason:n?.reason.ingressHttp??"port planning failed"},https:{requested:n?.requested.ingressHttps??443,chosen:n?.ingressHttps??null,explicit:n?.explicit.ingressHttps??!!process.env.FLISK_HTTPS_PORT,reason:n?.reason.ingressHttps??"port planning failed"},postgres:{requested:n?.requested.postgres??5432,chosen:n?.postgres??null,explicit:n?.explicit.postgres??!!process.env.FLISK_POSTGRES_PORT,reason:n?.reason.postgres??"port planning failed"}}}:{}},errors:s}}function qs(e){return e.errors.length>0?2:e.data.ready?0:1}import{existsSync as it,readFileSync as Js}from"node:fs";import{dirname as Kr,join as ot,normalize as qr}from"node:path";function Jr(e){let t=new Set,s=/^load\s*\(([\s\S]*?)\)/gm;for(let n of e.matchAll(s)){let r=n[1]??"",o=/["']([^"']+)["']/g,i=Array.from(r.matchAll(o),a=>a[1]);for(let a of i.slice(1))a.startsWith("_")&&t.add(a)}return Array.from(t).sort()}function zs(e,t,s){return t==="ext://flisk-cli"?ot(s,".flisk",".flisk-out","flisk-cli-ext","Tiltfile"):t.startsWith(".")||!t.includes("://")&&!t.startsWith("@")?qr(ot(Kr(e),t)):null}function zr(e,t,s){let n=[],r=/^load\s*\(([\s\S]*?)\)/gm;for(let o of t.matchAll(r)){let c=(o[1]??"").match(/["']([^"']+)["']/)?.[1];if(!c)continue;let l=zs(e,c,s);l&&(it(l)||n.push(`${e}: ${c} -> ${l}`))}return n}function Xr(e,t,s){let n=[],r=/^load\s*\(([\s\S]*?)\)/gm;for(let o of t.matchAll(r)){let c=(o[1]??"").match(/["']([^"']+)["']/)?.[1];if(c){let l=zs(e,c,s);l&&n.push(l)}}return n}function Yr(e,t){let s=new Set,n=[e];for(;n.length>0;){let r=n.pop();if(!r||s.has(r)||!it(r))continue;s.add(r);let o=Js(r,"utf-8");for(let i of Xr(r,o,t))s.has(i)||n.push(i)}return Array.from(s).sort()}function Xs(){let e=h()??process.cwd(),t=ot(e,".flisk",".flisk-out","Tiltfile");if(!it(t))return{name:"Starlark Load Exports",didPass:!0,isSkipped:!0,message:"No generated Tiltfile to check"};let s=[],n=[],r=Yr(t,e);for(let i of r){let a=Js(i,"utf-8"),c=Jr(a);c.length>0&&s.push(`${i}: ${c.join(", ")}`);for(let l of zr(i,a,e))n.push(l)}if(s.length===0&&n.length===0)return{name:"Starlark Load Exports",didPass:!0,message:`${D(r.length,"reachable Starlark file")} ${r.length===1?"has":"have"} valid load exports and paths`};let o=[];return s.length>0&&o.push(`Private exported symbols:
|
|
15
|
+
${s.join(`
|
|
16
|
+
`)}`),n.length>0&&o.push(`Missing relative load targets:
|
|
17
|
+
${n.join(`
|
|
18
|
+
`)}`),{name:"Starlark Load Exports",didPass:!1,message:`Starlark load() issues will stop Tilt before services start:
|
|
19
|
+
${o.join(`
|
|
20
|
+
|
|
21
|
+
`)}`,fix:"Regenerate with a current Flisk (`flisk config regenerate`). If the issue remains, rename loaded symbols without leading underscores and update stale load paths."}}import{readFileSync as Qr}from"node:fs";import{join as Zr}from"node:path";function Ys(e){let t=e.trim().match(/(\d+)\.(\d+)(?:\.(\d+))?/);return t?[Number(t[1]),Number(t[2]),Number(t[3]??0)]:null}function eo(e){try{return JSON.parse(Qr(Zr(e,".flisk",U),"utf-8"))?.minFliskVersion}catch{return}}function Qs(e,t){let s=eo(e);if(s===void 0)return{status:"none"};let n=typeof s=="string"?Ys(s):null;if(!n||!/^\d+\.\d+\.\d+$/.test(String(s).trim()))return{status:"malformed",message:`.flisk/project.json minFliskVersion ${JSON.stringify(s)} is not a version like "1.3.80"`,fix:'Set minFliskVersion to a MAJOR.MINOR.PATCH string, for example "1.3.80".'};let r=Ys(t),o=r!==null&&(()=>{for(let[a,c]of n.entries()){let l=r[a]??0;if(l!==c)return l>c}return!0})(),i=n.join(".");return o?{status:"ok",required:i}:{status:"too-old",required:i,message:`flisk ${t} is older than the ${i} this project requires (minFliskVersion)`,fix:"Run: flisk upgrade"}}import{existsSync as to,readdirSync as so}from"node:fs";import{join as Zs}from"node:path";function en(e,t=0){if(to(Zs(e,yt)))return!0;if(t>=2)return!1;try{return so(e,{withFileTypes:!0}).some(s=>s.isDirectory()&&!s.name.startsWith(".")&&s.name!=="node_modules"&&en(Zs(e,s.name),t+1))}catch{return!1}}function tn(e=process.cwd()){let t=h(e)??(en(e)?e:null);if(!t)return null;try{let{resources:s}=_t(t);return re(s)?{projectRoot:t,resources:s}:null}catch{return null}}import{relative as no}from"node:path";function we(e,t){return no(e,t.configPath)||t.configPath}function sn(e){let t=e.config?.dependsOn;return t===void 0?[]:Array.isArray(t)&&t.every(s=>typeof s=="string")?t:null}function ro(e){let t=new Set(e.map(a=>a.name)),s=new Map(e.map(a=>[a.name,(sn(a)??[]).filter(c=>t.has(c))])),n=new Map,r=new Map,o=[],i=a=>{r.set(a,"visiting"),o.push(a);for(let c of s.get(a)??[])if(r.get(c)==="visiting"){let l=o.slice(o.indexOf(c)),u=l.indexOf([...l].sort()[0]??c),m=[...l.slice(u),...l.slice(0,u)];n.set(m.join(">"),[...m,m[0]??c])}else r.has(c)||i(c);o.pop(),r.set(a,"done")};for(let a of[...s.keys()].sort())r.has(a)||i(a);return[...n.values()]}function ve(e=h()??process.cwd(),t=v(e)){let s=t.flatMap(n=>sn(n)===null?[`${we(e,n)} dependsOn ${JSON.stringify(n.config?.dependsOn)}: expected an array of service names`]:[]);return s.length===0?{name:"dependsOn",didPass:!0,message:"Every dependsOn is a list of service names"}:{name:"dependsOn",didPass:!1,message:`${D(s.length,"invalid dependsOn","invalid dependsOn")}:
|
|
22
|
+
${s.join(`
|
|
23
|
+
`)}`,fix:'Write "dependsOn" as an array of service names, for example ["postgres", "api"]'}}function xe(e=h()??process.cwd(),t=v(e)){let s=new Map(t.map(o=>[o.name,o])),n=ro(t);if(n.length===0)return{name:"Circular dependencies",didPass:!0,message:"No service depends on itself through dependsOn"};let r=n.map(o=>{let i=s.get(o[0]??""),a=o[1]??"";return`${i?we(e,i):o[0]} dependsOn "${a}": circular dependency ${o.join(" -> ")}`});return{name:"Circular dependencies",didPass:!1,message:`${n.length} ${n.length===1?"circular dependency":"circular dependencies"}:
|
|
24
|
+
${r.join(`
|
|
25
|
+
`)}`,fix:'Remove one "dependsOn" entry in each cycle so the services no longer wait on each other, or move what they share into a third service'}}function Pe(e=h()??process.cwd(),t=v(e)){let s=t.flatMap(n=>{let r=n.config?.port;return r===void 0?[]:typeof r=="number"&&Number.isInteger(r)&&r>=1&&r<=65535?[]:[`${we(e,n)} port ${JSON.stringify(r)}: not an integer from 1 to 65535`]});return s.length===0?{name:"Service ports",didPass:!0,message:"Every declared port is valid"}:{name:"Service ports",didPass:!1,message:`${D(s.length,"invalid port")}:
|
|
26
|
+
${s.join(`
|
|
27
|
+
`)}`,fix:'Set "port" to the port the service listens on, an integer from 1 to 65535'}}function be(e=h()??process.cwd(),t=!1,s=v(e)){let n=[],r=[];for(let i of s){let a=i.config?.schemaVersion;if(a===Ie)continue;let c=we(e,i);a===void 0?n.push(`${c} schemaVersion: missing`):r.push(`${c} schemaVersion ${JSON.stringify(a)}: this flisk supports ${Ie}`)}if(n.length===0&&r.length===0)return{name:"schemaVersion",didPass:!0,message:"Every service.json has a supported schemaVersion"};let o=[...n.length>0?["Run `flisk config migrate` to add the missing schemaVersion"]:[],...r.length>0?["A version this flisk does not support cannot be migrated: upgrade flisk"]:[]];return{name:"schemaVersion",didPass:!1,isWarning:!t,message:`${D(n.length+r.length,"service.json file")} without a supported schemaVersion:
|
|
28
|
+
${[...n,...r].join(`
|
|
29
|
+
`)}`,fix:o.join(". ")}}function za(e,t){let s=be(e,!1,t);s.didPass||(console.warn(f.yellow(`\u26A0 ${s.message}`)),s.fix&&console.warn(f.gray(` ${s.fix}`)))}function Xa(e,t={},s=process.exit){let n=t.resources??v(e),r=[Y(e,n),ve(e,n),xe(e,n),Pe(e,n)].filter(i=>!i.didPass);if(r.length===0)return;let o=r.map(i=>`${i.message}${i.fix?`
|
|
30
|
+
Fix: ${i.fix}`:""}`).join(`
|
|
31
|
+
`);t.onInvalid?.(o);for(let i of r)console.error(f.red(`\u2717 ${i.message}`)),i.fix&&console.error(f.gray(` Fix: ${i.fix}`));s(1)}import{execFileSync as Z}from"node:child_process";import{lookup as oo}from"node:dns/promises";var nn="Windows did not resolve *.flisk.localhost to 127.0.0.1. Browser URLs with hostnames will fail until you fix hosts or use the 127.0.0.1 URLs printed by flisk networks.";function io(e){return e.length>0&&e.every(t=>t==="127.0.0.1"||t==="::1")}function ao(e){return e.split(/\r?\n/).flatMap(t=>{let s=t.match(/^\s*(\d+)\s+(\d+)(?:\s|$)/);return s?[[Number(s[1]),Number(s[2])]]:[]})}function co(e,t,s){let n=s.replace(/-/g,"_").toLowerCase();return e.filter(r=>{let o=t.find(a=>a.publishedPorts.includes(r));if(!o||!n)return!0;let i=o.name.toLowerCase();return!i.startsWith(`${n}_`)&&!i.startsWith(`${n}-`)})}function lo(){return w("docker")}function rn(){let e=lo();if(!e)return{name:"Windows Runtime Tools",didPass:!1,message:"Docker is not running or not installed.",fix:`1. Install Docker Desktop: https://www.docker.com/products/docker-desktop/
|
|
32
|
+
2. Start Docker Desktop and wait for "Running" status
|
|
33
|
+
3. Enable WSL2 backend in Settings \u2192 General
|
|
34
|
+
4. Enable WSL Integration for Ubuntu in Settings \u2192 Resources \u2192 WSL Integration
|
|
35
|
+
5. Verify: docker version && docker compose version
|
|
36
|
+
Docs: https://docs.docker.com/desktop/wsl/`};if(!w("tilt"))return{name:"Windows Runtime Tools",didPass:!1,message:"tilt.exe not found on PATH.",fix:`Install Tilt:
|
|
37
|
+
curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
|
|
38
|
+
Or download from: https://docs.tilt.dev/install.html
|
|
39
|
+
Verify: tilt version`};let t=w("bun");return((process.argv[1]??"").toLowerCase().includes("node_modules")?w("node"):!0)?{name:"Windows Runtime Tools",didPass:!0,message:t?`Docker (${e}), Tilt, and Bun found on PATH`:`Docker (${e}) and Tilt found on PATH; \u26A0\uFE0F Bun was not found (generated services need Bun)
|
|
40
|
+
Fix: curl -fsSL https://bun.sh/install | bash
|
|
41
|
+
Verify: bun --version`}:{name:"Windows Runtime Tools",didPass:!1,message:"node.exe not found on PATH for this npm installation.",fix:`Install Node.js 22.12+: https://nodejs.org/
|
|
42
|
+
Or use Bun (includes Node.js): https://bun.sh/install`}}function on(){try{return Z(w("docker")??"docker",["info","--format","{{.OSType}}"],{encoding:"utf-8",timeout:1e4,windowsHide:!0}).trim().toLowerCase()==="windows"?{name:"Docker container mode",didPass:!1,message:"Docker Desktop is using Windows containers. Flisk requires Linux containers.",fix:`1. Open Docker Desktop \u2192 Settings \u2192 General
|
|
43
|
+
2. Ensure "Use WSL 2 instead of Hyper-V" is checked
|
|
44
|
+
3. Click "Apply & Restart"
|
|
45
|
+
4. Verify: docker info --format '{{.OSType}}' (should print "linux")
|
|
46
|
+
Docs: https://docs.docker.com/desktop/wsl/`}:{name:"Docker container mode",didPass:!0,message:"Docker Desktop is using Linux containers"}}catch{return{name:"Docker container mode",didPass:!1,message:"Docker daemon is not responding.",fix:`1. Start Docker Desktop and wait for "Running" status
|
|
47
|
+
2. Verify: docker version
|
|
48
|
+
3. If stuck: restart Docker Desktop or run \`systemctl restart docker\` in WSL2
|
|
49
|
+
Docs: https://docs.docker.com/desktop/troubleshoot/`}}}async function an(){let e=[],t=[];try{let l=Z("netsh",["interface","ipv4","show","excludedportrange","protocol=tcp"],{encoding:"utf-8",timeout:1e4,windowsHide:!0});t=ao(l)}catch{e.push(`Could not inspect Windows Hyper-V excluded TCP port ranges.
|
|
50
|
+
Fix: run as Administrator: netsh interface ipv4 show excludedportrange protocol=tcp
|
|
51
|
+
If netsh fails, this check is skipped.`)}let s=[80,443,5432],n=s.filter(l=>t.some(([u,m])=>l>=u&&l<=m));n.length>0&&e.push(`\u26A0\uFE0F Windows reserved port${n.length>1?"s":""} ${n.join(", ")} for Hyper-V/WSL.
|
|
52
|
+
Fix 1 (reset reserved ranges): run as Administrator: net stop winnat && net start winnat
|
|
53
|
+
Fix 2 (change Flisk ports): set FLISK_HTTP_PORT, FLISK_HTTPS_PORT, FLISK_POSTGRES_PORT in project config
|
|
54
|
+
Verify: flisk doctor
|
|
55
|
+
Docs: https://github.com/flisk-sh/flisk/blob/main/docs/wsl2.md#troubleshooting`);let r=[];for(let l of s)await ts(l)==="in-use"&&r.push(l);let o=[];try{let l=Z(w("docker")??"docker",["ps","--format","{{.Names}}\\t{{.Ports}}"],{encoding:"utf-8",timeout:1e4,windowsHide:!0});o=Yt(l,s)}catch{}let i=h()?ie():"",a=co(r,o,i);if(a.length>0)try{let l=Z("powershell.exe",["-NoProfile","-Command",`$ports = '${a.join(",")}'.Split(','); foreach ($port in $ports) { Get-NetTCPConnection -LocalPort ([int]$port) -State Listen -ErrorAction SilentlyContinue | ForEach-Object { $connection = $_; $service = Get-CimInstance Win32_Service | Where-Object { $_.ProcessId -eq $connection.OwningProcess } | Select-Object -First 1; if ([int]$port -eq 80 -and ($service.Name -eq 'W3SVC' -or $connection.OwningProcess -eq 4)) { '80: IIS / World Wide Web Publishing (HTTP.sys)' } elseif ($service) { '{0}: {1}' -f $port, $service.DisplayName } else { '{0}: PID {1}' -f $port, $connection.OwningProcess } } }`],{encoding:"utf-8",timeout:1e4,windowsHide:!0}).trim();e.push(`\u26A0\uFE0F Ports ${a.join(", ")} are already listening${l?`:
|
|
56
|
+
${l}`:"."}
|
|
57
|
+
Fix: stop the conflicting service or change Flisk ports (FLISK_HTTP_PORT, etc.)
|
|
58
|
+
Verify: flisk doctor
|
|
59
|
+
Docs: https://github.com/flisk-sh/flisk/blob/main/docs/wsl2.md#troubleshooting`)}catch{e.push(`\u26A0\uFE0F Ports ${a.join(", ")} are already in use.
|
|
60
|
+
Fix: netstat -ano | findstr :${a.join(" :")}
|
|
61
|
+
Verify: flisk doctor`)}let c=!0;for(let l of["flisk.localhost","example.flisk.localhost"])try{let u=await oo(l,{all:!0,verbatim:!0});io(u.map(m=>m.address))||(c=!1)}catch{c=!1}c||e.push(`${nn}
|
|
62
|
+
Fix: add these lines to C:\\Windows\\System32\\drivers\\etc\\hosts (run Notepad as Administrator):
|
|
63
|
+
127.0.0.1 flisk.localhost
|
|
64
|
+
127.0.0.1 example.flisk.localhost
|
|
65
|
+
Verify: ping flisk.localhost (should resolve to 127.0.0.1)
|
|
66
|
+
Docs: https://github.com/flisk-sh/flisk/blob/main/docs/wsl2.md#troubleshooting`);try{Z("git",["config","core.autocrlf"],{encoding:"utf-8",timeout:5e3,windowsHide:!0}).trim().toLowerCase()==="true"&&e.push(`git core.autocrlf is true; generated files may get CRLF while Docker Linux containers expect LF.
|
|
67
|
+
Fix: git config core.autocrlf input (run in Flisk repo root)
|
|
68
|
+
Verify: git config core.autocrlf (should show "input")`)}catch{}return e.push(`Docker Desktop Settings \u2192 Resources \u2192 File sharing must include this project directory.
|
|
69
|
+
Fix: Docker Desktop \u2192 Settings \u2192 Resources \u2192 File sharing \u2192 add project path
|
|
70
|
+
Verify: flisk doctor`),{name:"Windows ports and DNS",didPass:c&&a.length===0,message:e.length>0?e.join(`
|
|
71
|
+
|
|
72
|
+
`):"Required ports are available and Flisk localhost DNS resolves to loopback",...c?{}:{fix:nn}}}var O=1e4,ft={dockerMissing:"See https://docs.docker.com/get-docker/",dockerDaemonDown:"Start Docker Desktop, OrbStack, or Colima, then retry: flisk doctor",tiltMissing:"curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash",bunMissing:"curl -fsSL https://bun.sh/install | bash",port80:"Stop the process bound to port 80, or stop local nginx/caddy. Then: flisk doctor",port5432:"Stop local Postgres or change the host port. Then: flisk doctor",notProject:"flisk project --yes"},ln="WSL2 detected. Use Docker Desktop WSL integration. Guide: docs/wsl2.md",un="Native Windows landscape boot is unsupported. Use WSL2 Ubuntu with Docker Desktop integration. Guide: docs/wsl2.md",at=[0,25,0],W=[1,2,0];function Ne(e,t){let s=ut(e);return s?dt(s,t):!1}function dn(e,t,s=process.platform==="linux"&&!!process.env.WSL_DISTRO_NAME){if(!s)return{name:"WSL project location",didPass:!0,isSkipped:!0,message:"Not running in WSL2 - skipped project filesystem check"};let n=e.replace(/\\/g,"/").replace(/\/+$/,"").toLowerCase();if(n!=="/mnt/c"&&!n.startsWith("/mnt/c/"))return{name:"WSL project location",didPass:!0,message:`${ln} Project is on the WSL filesystem.`};let r=`${ln} Project is under /mnt/c (${e}); hot reload may be broken. Move it into the WSL filesystem, such as ~/projects.`;return{name:"WSL project location",didPass:!t,isWarning:!t,message:r,fix:"Move the repository under your WSL home directory (for example, ~/projects) and retry flisk doctor."}}function fo(e){let t=e.replace(/^\[(.*)\]$/,"$1");return t==="0.0.0.0"||/^[0:]*:0\.0\.0\.0$/.test(t)?!0:t.includes(":")&&/^[0:]+$/.test(t)}function mo(e=process.env,t=!1){let s=(e.FLISK_BIND_ADDRESS??"").trim();return fo(s)?{name:"Dev Port Bind Address",didPass:!t,isWarning:!t,message:`FLISK_BIND_ADDRESS is ${s}: Traefik and Postgres are reachable from other machines on the network.`,fix:"Unset FLISK_BIND_ADDRESS to keep dev ports on 127.0.0.1. Keep it only when you test from another device on purpose."}:{name:"Dev Port Bind Address",didPass:!0,message:s?`Dev ports bind to ${s}`:"Dev ports bind to 127.0.0.1 (this machine only)"}}function gn(e){let t=e.filter(n=>!n.didPass&&!n.isSkipped&&!n.isWarning),s=e.filter(n=>n.didPass||n.isSkipped||n.isWarning);return t.sort((n,r)=>{let o=i=>i.name==="Host Ports"&&/\b5432\b/.test(i.message)?0:i.name==="Host Ports"?1:i.name==="Ingress Ports"?2:3;return o(n)-o(r)}),[...t,...s]}function ho(e,t){return t?e?"Doctor passed. Next: flisk up":"Doctor passed. Next: flisk project example":"Doctor failed. Fix the items above, then run: flisk doctor"}var lt={checkDockerOperatingSystem:"Docker OS",checkDockerCompose:"Docker Compose",checkDockerVersions:"Docker Versions",checkDockerNetworkCapacity:"Docker Network Pool",checkContainerResourceHealth:"Container Resource Health",checkCrashLoopingContainers:"Crash-looping containers",checkTiltResourceHealth:"Tilt Resources",checkServiceHealth:"Service Health",checkServiceSmoke:"Service Smoke",checkAdvertisedEndpoints:"Advertised Endpoints"},pn=new Set(["Docker OS","Docker Compose","Docker Versions","Docker Network Pool","Container Resource Health","Crash-looping containers","Tilt Resources","Service Health","Service Smoke","Advertised Endpoints",...Object.keys(lt)]);function go(e){return!!(e.requiresContainerRuntime||e.checkName&&pn.has(e.checkName)||e.name&&pn.has(e.name))}function R(e,t){let s=()=>t();return s.requiresContainerRuntime=!0,s.checkName=e,s}async function ko(e,t={}){let s=[],n=!!t.containerRuntimeFailed;for(let r of e){if(n&&go(r)){let i=r.checkName??(r.name&<[r.name]?lt[r.name]:r.name&&r.name!=="check"&&r.name!=="fn"?r.name:"Container check");s.push({name:i,didPass:!0,isSkipped:!0,message:`Docker not running - skipped ${i} check`});continue}let o=await r();if(s.push(o),o.name===b&&!o.didPass&&(n=!0),!t.all&&!o.didPass&&!o.isSkipped&&!o.isWarning)break}return s}function So(e){let t=0,s=0,n=0,r=0;for(let o of e)o.isSkipped?n++:o.isWarning?r++:o.didPass?t++:s++;return r>0?`${t} passed, ${r} warned, ${s} failed, ${n} skipped`:`${t} passed, ${s} failed, ${n} skipped`}function mt(e){return Mt(e)}function yo(e,t,s,n,r){return async(o=A)=>{try{return await o(t,O),{name:e,didPass:!0,message:s}}catch(i){return mt(i)?{name:e,didPass:!1,message:`${e} did not respond within ${O/1e3}s`,fix:r}:{name:e,didPass:!1,message:n,fix:r}}}}async function ct(e){try{return await A(e,O),!0}catch{return!1}}async function wo(){let e=B();return e.isColima?e.running&&!e.problem?{name:"Colima",didPass:!0,message:`Colima VM is running${e.arch?` (${e.arch})`:""}`}:{name:"Colima",didPass:!1,message:e.problem??"The Colima VM is not running",fix:e.fix??`Start Colima: colima start
|
|
73
|
+
Verify: colima status
|
|
74
|
+
Docs: https://github.com/abiosoft/colima`}:{name:"Colima",didPass:!0,message:"Docker does not run on Colima"}}async function ht(){if(process.platform==="win32")try{return await A("docker ps",O),{name:b,didPass:!0,message:"Docker Desktop Linux container engine is running"}}catch{return{name:b,didPass:!1,message:"Docker is not running",fix:`Start Docker Desktop, enable WSL2 integration, then retry: flisk doctor
|
|
75
|
+
Verify: docker ps
|
|
76
|
+
Docs: https://docs.docker.com/desktop/wsl/`}}let e=!!w("docker");try{return await A("docker ps",O),{name:b,didPass:!0,message:"Docker daemon is running"}}catch(s){if(mt(s))return{name:b,didPass:!1,message:"Docker daemon is not responding (timeout)",fix:`Restart Docker daemon: systemctl restart docker (Linux) or restart Docker Desktop/Colima
|
|
77
|
+
Verify: docker ps
|
|
78
|
+
Docs: https://docs.docker.com/config/daemon/`}}let t=ms(await ct("pgrep -f com.docker.backend"));return t||(await ct("colima status")?{name:b,didPass:!0,message:"Colima (Docker runtime) is running"}:w("colima")?{name:b,didPass:!1,message:"Colima is installed but not running",fix:`Start Colima: colima start
|
|
79
|
+
Verify: colima status
|
|
80
|
+
Docs: https://github.com/abiosoft/colima`}:await ct("podman ps")?{name:b,didPass:!0,message:"Podman is running"}:e?{name:b,didPass:!1,message:"Docker daemon is not running",fix:`Start Docker daemon: systemctl start docker (Linux) or start Docker Desktop
|
|
81
|
+
Verify: docker ps
|
|
82
|
+
Docs: https://docs.docker.com/engine/daemon/`}:{name:b,didPass:!1,message:"Docker is not installed",fix:`Install Docker: https://docs.docker.com/get-docker/
|
|
83
|
+
Verify: docker --version
|
|
84
|
+
After install, start Docker and retry: flisk doctor`})}var ee=yo("Docker Compose","docker compose version","Docker Compose plugin available","Docker Compose plugin not found","Install Docker Compose: https://docs.docker.com/compose/install/");ee.requiresContainerRuntime=!0;ee.checkName="Docker Compose";var vo=[25,0,0],xo=[2,20,2];function ut(e){let t=e.trim().match(/(\d+)\.(\d+)(?:\.(\d+))?/);return t?[Number(t[1]),Number(t[2]),Number(t[3]??0)]:null}function dt(e,t){for(let[s,n]of t.entries()){let r=e[s]??0;if(r!==n)return r>n}return!0}async function te(e=A){let t=async a=>String(await e(a,O)).trim(),s,n;try{[s,n]=await Promise.all([t("docker version --format '{{.Server.Version}}'"),t("docker compose version --short")])}catch{return{name:"Docker Versions",didPass:!0,isSkipped:!0,message:"Could not read Docker Engine/Compose versions - skipped version check"}}let r=ut(s),o=ut(n);if(!r||!o)return{name:"Docker Versions",didPass:!0,isSkipped:!0,message:`Unrecognized Docker version output (engine "${s}", compose "${n}") - skipped version check`};let i=[];return dt(r,vo)||i.push(`Docker Engine ${s} (need 25.0+)`),dt(o,xo)||i.push(`Docker Compose ${n} (need 2.20.2+)`),i.length===0?{name:"Docker Versions",didPass:!0,message:`Docker Engine ${s} and Compose ${n} support generated healthchecks`}:{name:"Docker Versions",didPass:!1,message:`Docker is too old for generated healthchecks (they use start_interval):
|
|
85
|
+
${i.join(`
|
|
86
|
+
`)}`,fix:`Update Docker: Docker Desktop (auto-updates), or Linux: apt/yum/dnf update docker-ce docker-compose-plugin
|
|
87
|
+
Verify: docker version --format '{{.Server.Version}}' && docker compose version --short
|
|
88
|
+
Docs: https://docs.docker.com/engine/install/`}}te.requiresContainerRuntime=!0;te.checkName="Docker Versions";async function gt(e=A){let t;try{t=String(await e("tilt version",O)).trim()}catch{return{name:"Tilt CLI",didPass:!1,message:"Tilt CLI not found",fix:`Install Tilt: curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash
|
|
89
|
+
Verify: tilt version
|
|
90
|
+
Docs: https://docs.tilt.dev/install.html`}}return Ne(t,at)?{name:"Tilt CLI",didPass:!0,message:`Tilt ${t} is available`}:{name:"Tilt CLI",didPass:!1,message:`Tilt ${t||"version unknown"} is below the required v${at.join(".")} floor`,fix:`Upgrade Tilt to v${at.join(".")} or newer: https://docs.tilt.dev/install.html
|
|
91
|
+
Verify: tilt version
|
|
92
|
+
If using Homebrew: brew upgrade tilt`}}async function kt(e=A){let t;try{t=String(await e("docker info --format '{{.OSType}}'",O)).trim().toLowerCase()}catch{return{name:"Docker OS",didPass:!0,isSkipped:!0,message:"Docker OS unavailable - daemon failure reported separately"}}return t!=="linux"?{name:"Docker OS",didPass:!1,message:`Docker is using the ${t||"unknown"} engine; Flisk requires Linux containers`,fix:`Switch Docker Desktop to Linux containers: Settings > General > Use the WSL 2 based engine
|
|
93
|
+
Or on Windows: docker context use default (if using WSL2 backend)
|
|
94
|
+
Verify: docker info --format '{{.OSType}}'
|
|
95
|
+
Docs: https://docs.docker.com/desktop/wsl/`}:{name:"Docker OS",didPass:!0,message:"Docker is using Linux containers"}}kt.requiresContainerRuntime=!0;kt.checkName="Docker OS";async function Po(e=A){let t=h();if(!t)return{name:"Bun",didPass:!0,isSkipped:!0,message:"Not in a project - skipping Bun check"};if(!de(v(t)))return{name:"Bun",didPass:!0,isSkipped:!0,message:"No generated JS services - skipping Bun check"};try{let s=String(await e("bun --version",O)).trim();return Ne(s,W)?{name:"Bun",didPass:!0,message:`Bun ${s} is available`}:{name:"Bun",didPass:!1,message:`Bun ${s||"version unknown"} is below the required ${W.join(".")} floor`,fix:`Upgrade Bun to ${W.join(".")} or newer: https://bun.sh/install
|
|
96
|
+
Verify: bun --version
|
|
97
|
+
If using npm: npm install -g bun@latest`}}catch{return{name:"Bun",didPass:!1,message:"Bun is not installed",fix:`Install Bun: curl -fsSL https://bun.sh/install | bash
|
|
98
|
+
Verify: bun --version
|
|
99
|
+
Docs: https://bun.sh/docs/installation`}}}function bo(){let e=h()??process.cwd(),t=Dt(e);if(t.missing.length>0)return{name:"Environment Variables",didPass:!1,message:`Missing required env variables: ${t.missing.join(", ")}`,fix:C(x(e,".env"))?`Edit .env and set these values:
|
|
100
|
+
${t.missing.map(n=>`${n}=<value>`).join(`
|
|
101
|
+
`)}`:"No .env file yet. Run `flisk project` to create one with working defaults."};if(t.invalid.length>0)return{name:"Environment Variables",didPass:!1,message:`Invalid env variables: ${t.invalid.join(", ")}`,fix:"Edit .env and provide values for empty variables"};let s=t.warnings.filter(n=>!n.startsWith(".env file not found"));return{name:"Environment Variables",didPass:!0,message:s.length>0?`All required environment variables are set (warning: ${s.join("; ")})`:"All required environment variables are set"}}function Do(){let e=h()??process.cwd(),t=x(e,".flisk",".flisk-out"),s=_e.filter(n=>!C(x(t,n)));return s.length===0?{name:"Master Configs",didPass:!0,message:`${_e.join(", ")} found`}:{name:"Master Configs",didPass:!1,message:`Master configs missing: ${s.join(", ")}`,fix:"Run: flisk project"}}function fn(e=wt()){let t=h();if(!t)return{name:"Flisk version",didPass:!0,isSkipped:!0,message:"Not in a project - skipping Flisk version check"};let s=Qs(t,e);return s.status==="none"?{name:"Flisk version",didPass:!0,isSkipped:!0,message:`flisk ${e} (no minFliskVersion in .flisk/project.json)`}:s.status==="malformed"||s.status==="too-old"?{name:"Flisk version",didPass:!1,message:s.message,fix:s.fix}:{name:"Flisk version",didPass:!0,message:`flisk ${e} meets minFliskVersion ${s.required}`}}function $o(){let e=h()??process.cwd(),t=Ge(e),s=v(e).filter(r=>!fe(e,r.path,t));if(s.length===0)return{name:"Resource Discovery",didPass:!0,message:`All resources are covered by discovery.paths ${JSON.stringify(t)}`};let n=s.map(r=>$e(Ce(e,r.path))).join(", ");return{name:"Resource Discovery",didPass:!1,message:`${D(s.length,"resource")} outside discovery.paths ${JSON.stringify(t)}: ${n}. \`flisk up\` will not start them`,fix:"Move each under services/<stack>/<name>, or add a matching pattern to discovery.paths in .flisk/project.json and run: flisk config regenerate"}}function Co(e){let t=[],s=(n,r)=>{for(let o of hn(n,{withFileTypes:!0})){if(r===""&&o.name===".flisk-contract")continue;let i=r===""?o.name:`${r}/${o.name}`;o.isDirectory()?s(x(n,o.name),i):o.isFile()&&t.push(i)}};return s(e,""),t.sort()}function No(e=!1){let t=h()??process.cwd(),s=v(t).filter(o=>(o.config?.appType??o.type)!=="library");if(s.length===0)return{name:"Generated Files",didPass:!0,isSkipped:!0,message:"No resources to check"};let n=[],r=[];for(let o of s){let i=$e(Ce(t,o.path)),a=x(o.path,F),c=C(a)?Co(a):[];c.length===0?(r.push(i),n.push(`${i}: no ${F}/ files`)):n.push(`${i}: ${c.join(", ")}`)}return r.length===0?{name:"Generated Files",didPass:!0,message:`${D(s.length,"resource")} with generated files:
|
|
102
|
+
${n.join(`
|
|
103
|
+
`)}`}:{name:"Generated Files",didPass:!1,isWarning:!e,message:`${r.length} of ${D(s.length,"resource")} not generated yet:
|
|
104
|
+
${n.join(`
|
|
105
|
+
`)}`,fix:"Run `flisk up` to generate them (it needs Docker, Compose and Tilt). `flisk config verify` checks the project-level files only."}}var To=["install-deps.sh","bun-hoisted-symlink-fix.sh","prisma-bun-client-link-fix.sh","prisma-normalize-client.sh","infisical-entrypoint.sh"],Eo=/shared-platform-engineering\/docker-templates\/([\w.-]+)/g;function Ro(e){let t=new Set;for(let s of v(e)){let n=x(s.path,F);if(C(n)){for(let r of hn(n))if(!(!r.startsWith("Dockerfile")||r.endsWith(".dockerignore")))for(let o of K(x(n,r),"utf-8").matchAll(Eo))t.add(o[1])}}return[...t]}function Oo(){let e=h()??process.cwd(),t=[];C(x(e,z))||t.push(`${z} (workspace root manifest)`);let s=x(e,"shared-platform-engineering","docker-templates"),n=[];try{n=Ro(e)}catch{}for(let r of new Set([...To,...n]))C(x(s,r))||t.push(`shared-platform-engineering/docker-templates/${r}`);return t.length===0?{name:"Generated Runtime Assets",didPass:!0,message:"Generated Docker runtime assets are present"}:{name:"Generated Runtime Assets",didPass:!1,message:`Generated Dockerfiles reference missing project runtime assets:
|
|
106
|
+
${t.join(`
|
|
107
|
+
`)}`,fix:"Run `flisk project --yes` (or `flisk config regenerate`) with an updated Flisk. `flisk up` also refreshes these assets before starting Tilt."}}function _o(){let e=h()??process.cwd(),t=v(e),s=[];for(let n of t){let r=x(n.path,z);if(!C(r))continue;let o=n.config?.appType??"backend",i=Ae[o]??Ae.backend,a;try{a=JSON.parse(K(r,"utf-8")).scripts??{}}catch{s.push(`${n.name} (package.json is invalid JSON)`);continue}let c=i.filter(l=>!a[l]);c.length>0&&s.push(`${n.name}: missing "${c.join('", "')}"`)}return s.length===0?{name:"Startup Scripts",didPass:!0,message:"All services have required package.json scripts"}:{name:"Startup Scripts",didPass:!1,message:`Services missing required package.json scripts:
|
|
108
|
+
${s.join(`
|
|
109
|
+
`)}`,fix:`Add the missing scripts to each service's package.json, e.g.:
|
|
110
|
+
"dev": "bun run src/index.ts",
|
|
111
|
+
"build": "tsc",
|
|
112
|
+
"start": "bun run dist/index.js"`}}function kn(e){if(e.startsWith("@"))return[e.split("/").slice(0,2).join("/")];let t=e.split("/")[0]??e;return[`@types/${t}`,t]}function Sn(e,t,s=0){let n=e[t];if(typeof n!="string"||s>3)return!1;if(/(^|[\s;&|(])tsc(\s|$)/.test(n))return!0;for(let r of n.matchAll(/\b(?:bun|npm|pnpm|yarn)\s+run\s+([\w:.-]+)/g))if(Sn(e,r[1],s+1))return!0;return!1}function mn(e){let t=kn(e);return e.includes("/")||e.startsWith("@")?t[t.length-1]:t[0]}var Ao={"@types/bun":"^1.4.2","@types/node":"^20.0.0"};function jo(e,t){return(t.includes("bun")||e.has("@types/bun"))&&!e.has("@types/node")}function Fo(){let e=h()??process.cwd(),t=v(e),s=[],n=new Set;for(let o of t){let i=x(o.path,z),a=x(o.path,F,"tsconfig.docker.autogenerated.json");if(!C(i)||!C(a))continue;let u=pt(a)?.compilerOptions?.types;if(!Array.isArray(u))continue;let m=pt(i),d=m?.scripts??{};if(!Sn(d,"build"))continue;let g=new Set([...Object.keys(m?.devDependencies??{}),...Object.keys(m?.dependencies??{})]),k=u.filter(y=>typeof y=="string").filter(y=>!kn(y).some($=>g.has($)));for(let y of k)n.add(mn(y));if(k.length>0){let y=k.map($=>`"${$}" (needs ${mn($)})`).join(", ");s.push(`${o.name}: "types" lists ${y}`)}jo(g,u)&&(n.add("@types/node"),s.push(`${o.name}: uses @types/bun, which references node types internally, but @types/node is not a direct dependency`))}if(s.length===0)return{name:"TypeScript Type Dependencies",didPass:!0,message:`Every service's Docker tsconfig "types" entry has its @types package installed`};let r=[...n].map(o=>{let i=Ao[o];return i?`"${o}": "${i}"`:`${o} (bun add -d ${o})`});return{name:"TypeScript Type Dependencies",didPass:!1,message:`\`bun run build\` will fail with TS2688 (Cannot find type definition file) because a @types package it needs is not a direct dependency:
|
|
113
|
+
${s.join(`
|
|
114
|
+
`)}`,fix:`Add to each service's package.json devDependencies: ${r.join(", ")}`}}function pt(e){try{return JSON.parse(K(e,"utf-8"))}catch{return null}}function Io(e){let s=pt(e)?.compilerOptions;return s?.allowSyntheticDefaultImports===!0||s?.esModuleInterop===!0}function Lo(){let e=h()??process.cwd(),t=v(e).filter(n=>n.config?.appType==="frontend");if(t.length===0)return{name:"Frontend Docker Preflight",didPass:!0,isSkipped:!0,message:"No frontend services to check"};let s=[];for(let n of t){C(x(n.path,"public"))||s.push(`${n.name}: no public/ folder, but the Docker build copies it. Create it: mkdir -p ${$e(Ce(e,x(n.path,"public")))} && touch ${$e(Ce(e,x(n.path,"public",".gitkeep")))}`);let r=x(n.path,F,"Dockerfile.app.autogenerated"),o=x(n.path,F,"tsconfig.docker.autogenerated.json");if(C(r)){let i=K(r,"utf-8"),a=/\bEXPOSE\s+80\b/.test(i),c=n.config?.stack,l=c?x(e,"services",c,F,"docker-compose.app.autogenerated.yml"):"";if(a&&l&&C(l)){let u=K(l,"utf-8"),m=n.name.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),d=new RegExp(`traefik\\.http\\.services\\.${m}\\.loadbalancer\\.server\\.port=(\\d+)`),k=u.match(d)?.[1];k&&k!=="80"&&s.push(`${n.name}: nginx runtime exposes 80, but generated Traefik routes to ${k}`)}}if(C(o)&&!Io(o)){let i=x(n.path,"src","main.tsx");if(C(i)){let a=K(i,"utf-8"),c=[/import\s+\w+\s+from\s+["']react["']/,/import\s+\w+\s+from\s+["']react-dom\/client["']/].filter(l=>l.test(a)).map(l=>l.source.includes("react-dom")?"react-dom/client":"react");c.length>0&&s.push(`${n.name}: Docker tsconfig does not allow synthetic default imports, but src/main.tsx default-imports ${c.join(" and ")}`)}}}return s.length===0?{name:"Frontend Docker Preflight",didPass:!0,message:`${D(t.length,"frontend")} ${t.length===1?"has":"have"} compatible Docker build/routing metadata`}:{name:"Frontend Docker Preflight",didPass:!1,message:`Frontend Docker metadata has issues that will make \`flisk up\` fail or route 404:
|
|
115
|
+
${s.join(`
|
|
116
|
+
`)}`,fix:'Regenerate with a current Flisk (`flisk config regenerate`) and ensure frontend nginx runtimes route to port 80. For React entrypoints, prefer named imports: `import { StrictMode } from "react"` and `import { createRoot } from "react-dom/client"`.'}}var Mo=90,Ho=80;function Wo(e){return e.split(`
|
|
117
|
+
`).map(t=>t.trim()).filter(Boolean).map(t=>{let[s,n,r]=t.split(",");return{name:s??"unknown",memPct:Number.parseFloat((n??"").replace(/%/g,"")),cpuPct:Number.parseFloat((r??"").replace(/%/g,""))}}).filter(t=>Number.isFinite(t.memPct)&&Number.isFinite(t.cpuPct))}var Vo=Object.assign(function(){let t;try{t=uo(w("docker")??"docker",["stats","--no-stream","--format","{{.Name}},{{.MemPerc}},{{.CPUPerc}}"],{stdio:"pipe",encoding:"utf-8",timeout:O,windowsHide:process.platform==="win32"})}catch(o){return{name:"Container Resource Health",didPass:!0,isSkipped:!0,message:mt(o)?"Docker not responding - skipped container resource check":"Docker not running - skipped container resource check"}}let s=Wo(t);if(s.length===0)return{name:"Container Resource Health",didPass:!0,isSkipped:!0,message:"No running containers to check"};let n=s.filter(o=>o.memPct>=Mo&&o.cpuPct>=Ho);if(n.length===0)return{name:"Container Resource Health",didPass:!0,message:`${D(s.length,"container")} within normal resource usage`};let r=n.map(o=>`${o.name} (mem ${o.memPct.toFixed(0)}%, cpu ${o.cpuPct.toFixed(0)}%)`).join(`
|
|
118
|
+
`);return{name:"Container Resource Health",didPass:!1,message:`${D(n.length,"container")} pinned near its memory limit while burning CPU -- likely stuck in a boot-time retry/fetch loop, not a normal crash:
|
|
119
|
+
${r}`,fix:"Check the container's boot logs for a network fetch loop (e.g. `bunx <pkg>` re-downloading a CLI on every start instead of using one already installed): docker logs <container>. If a Prisma auto-migration is the cause, set AUTO_MIGRATE=false in the project's .env as a temporary unblock."}},{requiresContainerRuntime:!0,checkName:"Container Resource Health"}),Uo=5e3;async function Bo(e,t){let s=h()??process.cwd(),n=Fe(v(s),t);return n.length===0?{name:"Service Health",didPass:!0,isSkipped:!0,message:"No routable services to ping"}:We(await ae(n,e))}async function Go(e,t){let s=h()??process.cwd(),n=v(s),r=Et(Tt(n,t),{timeoutSeconds:Math.ceil(e/1e3)});return r.length===0?Ve([]):(await ae(Fe(n,t),e)).some(i=>i.status!==void 0)?Ve(await Ot(r,Rt(s))):{name:"Service Smoke",didPass:!0,isSkipped:!0,message:"No services responded - skipped smoke checks"}}async function Ko(e,t){let s=h()??process.cwd(),n=v(s),r=Nt(n,t);return r.length===0?{name:"Advertised Endpoints",didPass:!0,isSkipped:!0,message:"No routable services to check"}:ss(await ae(r,e))}function qo(e,t){if(e.length===0){console.log(`${f.green("\u2713")} Nothing to repair
|
|
120
|
+
`);return}for(let s of e){let n=s.status==="planned"?`${f.cyan("would run")}`:s.status==="applied"?f.green("ran"):s.status==="failed"?f.red("failed"):f.gray("skipped"),r=s.status==="planned"?"":` (${s.reason})`;console.log(`${n}: ${s.command}${r}`)}t&&console.log(f.gray(`
|
|
121
|
+
Dry run: nothing was changed.`)),console.log("")}function De(e){for(let t of gn(e))!t.didPass&&!t.isSkipped&&!t.isWarning?(console.log(`${f.red("\u2717")} ${t.message}`),t.fix&&console.log(`${f.blue("\u2139")} Fix: ${t.fix}`)):t.isWarning?(console.log(`${f.yellow("\u26A0")} ${f.yellow(t.message)}`),t.fix&&console.log(`${f.blue("\u2139")} Fix: ${t.fix}`)):t.isSkipped?(console.log(`${f.gray("\u25CB")} ${f.gray(t.message)}`),t.fix&&console.log(`${f.blue("\u2139")} ${t.fix}`)):console.log(`${f.green("\u2713")} ${t.message}`)}function Jo(e,t,s,n={},r){let o=r??[...e,...t],i=()=>{let a=Ds(ge(o));if(a.length!==0){console.log(f.bold("Fix first"));for(let c of a)console.log(c);console.log("")}};n.all?(console.log(f.bold("Machine")),De(e),console.log(`
|
|
122
|
+
${f.bold("Project")}`),s?t.length>0&&De(t):console.log(`${f.gray("\u25CB")} ${f.gray("Not in a Flisk project, so project checks were skipped")}`),console.log(""),console.log(So(o)),i()):(De(o),console.log(""),i(),o.every(c=>c.didPass||c.isSkipped||c.isWarning)&&!s&&(console.log(`${f.gray("\u25CB")} ${f.gray("Not in a Flisk project, so project checks were skipped")}`),console.log("")))}var zo=new po("doctor").description("Check environment readiness for Flisk").option("--all","Run every check and show Machine and Project sections with a summary",!1).option("--json","Output a versioned JSON readiness report",!1).exitOverride(e=>{e.exitCode===0&&process.exit(0),zo.opts().json&&console.log(JSON.stringify(L([],!1,[{code:"USAGE",message:e.message}]))),process.exit(2)}).option("--no-ping","Skip pinging running services' /health endpoints").option("--strict","Fail warnings such as a WSL project under /mnt/c").option("--fix","Repair this project's unused Docker networks and leftover doctor probes",!1).option("--dry-run","With --fix: list the repairs without changing anything",!1).option("--scope <scope>","With --fix: project (default) or machine, which also removes unused networks of other Flisk projects","project").option("-y, --yes","With --fix: apply every repair without asking",!1).option("--ping-timeout <ms>","Per-service ping timeout in milliseconds",String(Uo)).action(async e=>{let t=Number(e.pingTimeout);if(!/^\d+$/.test(e.pingTimeout)||!Number.isSafeInteger(t)||t<=0){let p="--ping-timeout must be a positive integer number of milliseconds";e.json&&console.log(JSON.stringify(L([],!1,[{code:"USAGE",message:p}]))),console.error(p),process.exit(2);return}let s=!["project","machine"].includes(e.scope),n=e.scope!=="project"&&!e.fix;if(s||n||(e.dryRun||e.yes)&&!e.fix){let p=s?`--scope must be project or machine, got "${e.scope}"`:n?"--scope only applies with --fix":`${e.dryRun?"--dry-run":"--yes"} only applies with --fix`;e.json&&console.log(JSON.stringify(L([],!1,[{code:"USAGE",message:p}]))),console.error(p),process.exit(2);return}let r=tn(),o=r?.resources??null;e.json||console.log(o?"Flisk doctor checks what this project's local processes need; its services declare commands, so Docker and Tilt are not checked.":"Flisk doctor checks your local Docker + Tilt development environment; it does not check cluster deployments.");let i=os();if(process.platform==="win32"){let P=[{name:"Native Windows support",didPass:!1,message:un,fix:"Use WSL2 Ubuntu with Docker Desktop integration. Guide: docs/wsl2.md"},rn(),on(),await an()],V=null;try{V=await At()}catch{}e.json?console.log(JSON.stringify(L(P,!!h(),[],V,{...i,canUp:!1}))):(De(P),console.log("")),console.error(un),process.exit(1);return}if(i.kind==="webcontainer"){let p=L([{name:"Host",didPass:!1,message:Be,fix:`Use a machine with Docker. Guide: ${ue}`}],!!h(),[],void 0,i);e.json&&console.log(JSON.stringify(p)),console.error(Be),process.exit(1);return}e.json||(console.log(`
|
|
123
|
+
${f.bold("\u{1F50D} Flisk Doctor")}
|
|
124
|
+
`),console.log(`Checking environment...
|
|
125
|
+
`));let a=h()??r?.projectRoot??null,c;if(e.fix&&o)c=[];else if(e.fix){try{let p;if(a)try{p=It(a).project.name}catch{}let P=a?Ps(a):[],V=await ws(p,void 0,{tiltPids:P,machine:e.scope==="machine"});c=await vs(V,{dryRun:e.dryRun,confirm:e.yes||!e.json&&process.stdin.isTTY?async E=>e.yes||await Lt({message:`Run \`${E.command}\` (${E.check}, ${E.reason})?`}):void 0})}catch(p){c=[{id:"plan-fixes",check:"Docker networks",scope:"project",command:"docker network ls",status:"failed",reason:`could not list Docker networks: ${(p instanceof Error?p.message:String(p)).split(/\r?\n/)[0]}`}]}e.json||qo(c,e.dryRun)}let l,u;if(!o)try{l=await ce(a??process.cwd())}catch(p){l=null,u=p instanceof Error?p.message:String(p)}let m=[()=>l?{name:"Host Ports",didPass:!0,message:`HTTP ${l.ingressHttp}, HTTPS ${l.ingressHttps}, Postgres ${l.postgres}`}:{name:"Host Ports",didPass:!1,message:u??"Could not select host ports",fix:"Set FLISK_HTTP_PORT, FLISK_HTTPS_PORT, or FLISK_POSTGRES_PORT to available host ports."},()=>l?He(cn,void 0,[l.ingressHttp,l.ingressHttps]):{name:"Ingress Ports",didPass:!1,message:"Ingress port plan is unavailable"},wo,ht,()=>fs(),R("Docker OS",kt),gt,R("Docker Compose",ee),R("Docker Versions",te),Po,()=>dn(h()??process.cwd(),e.strict),()=>mo(process.env,e.strict),R("Docker Network Pool",()=>Jt()),()=>Ye()],d=[()=>fn(),Do,Oo,()=>No(e.strict),Xs,_o,()=>ns(),Fo,Lo,$o,()=>Wt(),()=>Y(),()=>ve(),()=>xe(),()=>Pe(),()=>be(void 0,e.strict),()=>Le(),()=>Vt(),()=>Bt(),()=>Ut(),()=>le(),()=>Ht(),()=>Kt(),()=>Gt(),()=>qt(),bo,async()=>{let p=h()??process.cwd(),P=es(p)?await Ft(p):!0;return Me(cn,p,void 0,P)},R("Container Resource Health",Vo),R("Crash-looping containers",()=>{let p=h()??process.cwd(),P=[];try{P=je(p)}catch{return{name:"Crash-looping containers",didPass:!0,isSkipped:!0,message:"Could not read .env - skipped crash-loop check"}}return ds(ie(),P)}),R("Tilt Resources",Ue)],g=o?[()=>Ws(o),()=>Vs(o),()=>dn(h()??process.cwd(),e.strict),()=>Ye()]:m,k=o?[()=>fn(),()=>Y(),()=>ve(),()=>Us(o),()=>xe(),()=>Pe(),()=>be(void 0,e.strict),()=>Le()]:d;if(e.ping&&o&&a&&k.push(()=>Bs(a,o,t)),e.ping&&!o){let p=a?jt(a,l?.ingressHttp):l?.ingressHttp;k.push(R("Service Health",()=>Bo(t,p))),k.push(R("Service Smoke",()=>Go(t,p))),k.push(R("Advertised Endpoints",()=>Ko(t,p)))}let y=!!a,$=[],N=[],S,T=[];if(e.json||!e.all){let p=await Ks(g,y?k:[]);S=p.checks,T=p.errors}else{let p=async(E,Rn=!1)=>{let On=E.map(ne=>{let Re=async()=>{try{return await ne()}catch(Oe){return T.push({code:"INTERNAL",message:Oe instanceof Error?Oe.message:String(Oe)}),{name:ne.checkName??"Doctor check",didPass:!1,isSkipped:!1,message:"Check failed with an internal error"}}};return Re.requiresContainerRuntime=ne.requiresContainerRuntime,Re.checkName=ne.checkName,Re});return ko(On,{all:!!e.all,containerRuntimeFailed:Rn})};$=await p(g);let P=$.some(E=>!E.didPass&&!E.isSkipped&&!E.isWarning),V=$.some(E=>E.name===b&&!E.didPass);y&&(e.all||!P)&&(N=await p(k,V)),S=[...$,...N]}if(is(i.kind))for(let p of S)p.name===b&&!p.didPass&&(p.fix=rs);let _=L(gn(S),y,T,l,i);c&&(_.data.actions=c),c&&xs(c)&&(_.data.ready=!1);let J=qs(_),St=_.data.ready;if(e.json){let p;try{p=je(h()??process.cwd())}catch(P){if(!(P instanceof $t))throw P;console.log(JSON.stringify(L([],y,[...T,{code:"ENV_UNREADABLE",message:P.message}]))),console.error(P.message),process.exit(1)}console.log(JSON.stringify(Ct(_,p)));for(let P of T)console.error(oe(P.message,p));J!==0&&process.exit(J);return}for(let p of T)console.error(`${f.red("\u2717")} Doctor check failed: ${p.message}`);Jo($,N,y,e,S);let En=ho(y,St);console.log(`${St?f.green(f.bold("\u2713")):f.red(f.bold("\u2717"))} ${En}`),J!==0&&process.exit(J)});function yn(e){return Ne(e,W)}var se=`${W[0]}.${W[1]}+`;import{execFileSync as wn}from"node:child_process";import{accessSync as vn,constants as xn,readdirSync as Xo}from"node:fs";import{delimiter as Yo,join as q}from"node:path";var j="flisk",Pn="@flisk-sh/flisk",Qo="https://github.com/flisk-sh/flisk",bn="@tdk-landscape/tdk-cli-core";function Dn(e=j,t=process.env){let s=t.PATH??t.Path??"";for(let n of s.split(Yo)){if(!n)continue;let r=[q(n,e),q(n,`${e}.cmd`),q(n,`${e}.exe`)];for(let o of r)try{return vn(o,xn.X_OK),!0}catch{}}return!1}function Zo(e=process.env){let t=e.HOME??e.USERPROFILE??"";if(!t)return"flisk-workspace";let s=q(t,"Documents");try{return vn(s,xn.F_OK),q(s,"flisk")}catch{return q(t,"flisk")}}function ei(e){try{return Xo(e).every(t=>t.startsWith("."))}catch{return!0}}function $n(e=process.env,t=process.cwd()){if(!Dn(j,e))return`The \`${j}\` command is not on PATH (this run is not a global install). Install it with \`npm install -g ${Pn}\`, then run \`${j} project --yes\`. If npm reports EEXIST for \`flisk\`, the old package still owns that command: run \`npm uninstall -g ${bn}\` first. The current release is published from ${Qo}.`;if(ei(t))return`Next: ${j} project --yes`;let s=Zo(e);return`Next: mkdir -p ${s} && cd ${s} && ${j} project --yes
|
|
126
|
+
(${j} project writes .flisk/ and the master configs into the current folder, so it starts clean in a folder of its own. Or clone a starter: ${j} project example)`}function Xc(e=process.env){if(Dn(j,e))return"present";let t=e.npm_execpath?.includes("bun")?"bun":"npm",s=t==="bun"?"bun remove -g":"npm uninstall -g";try{wn(s,[bn],{stdio:"ignore",timeout:12e4})}catch{}try{return wn(t,["install","-g",Pn],{stdio:"ignore",timeout:3e5}),"installed"}catch{return"failed"}}var ni=["node","bun"];function Tn(e){return e==="scaffold"?oi:e==="native"?ni:ii}var ri=["docker","compose","tilt"],oi=["node","bun","ports"],ii=["node",...ri,"bun","ports"];function ai(e,t){return{id:e,ok:t.didPass||!!t.isSkipped,message:t.message,fix:t.fix}}function Nn(e){let[t=0,s=0]=String(e).split(".").map(n=>Number.parseInt(n,10));return!Number.isFinite(t)||!Number.isFinite(s)||t<22||t===22&&s<12}async function Te(e,t,s){try{return ai(e,await t())}catch{return{id:e,ok:!1,message:s}}}function ci(e){return e.isSkipped?{...e,didPass:!1,isSkipped:!1,message:`Could not verify Docker Engine/Compose minimum versions: ${e.message}`,fix:e.fix??"Start Docker and ensure Docker Engine 25+ and Compose 2.20.2+ are installed."}:e}function li(e){try{return v(e).some(t=>t.config?.featuresEnabled?.includes("prisma")??!1)}catch{return!1}}async function ui(e,t){try{let s=await ce(e,t==="scaffold"?{inspectDocker:!1}:{});return{id:"ports",ok:!0,message:`HTTP ${s.ingressHttp}, HTTPS ${s.ingressHttps}, Postgres ${s.postgres}`}}catch(s){return{id:"ports",ok:!1,message:s instanceof Error?s.message:String(s),fix:"Set FLISK_HTTP_PORT, FLISK_HTTPS_PORT, or FLISK_POSTGRES_PORT to available host ports."}}}async function di(e={}){let t=e.cwd??process.cwd(),s=h(t),n=!!s,r=s?v(s):[],i=re(r)?"native":e.scope??"runtime",a=[],c=process.versions.node;if(a.push({id:"node",ok:!Nn(c),message:c,fix:Nn(c)?`Install Node.js 22.12+ (current: ${c}). https://nodejs.org`:void 0}),i==="runtime"){let S=B();S.isColima&&a.push({id:"colima",ok:S.running,message:S.running?`Colima VM is running${S.arch?` (${S.arch})`:""}`:S.problem??"The Colima VM is not running",fix:S.running?void 0:S.fix}),a.push(await Te("docker",ht,"Docker daemon is not running")),a.push(await Te("compose",async()=>{let[T,_]=await Promise.all([ee(),te()]);return T.didPass?ci(_):T},"Docker Engine or Compose version check failed")),a.push(await Te("tilt",gt,"Tilt CLI not found"))}let l=s?de(r):!0,u=!1,m=l?w("bun"):void 0;if(m)try{let S=Cn(m,["--version"],{encoding:"utf-8",timeout:1e4}).trim();u=yn(S)}catch{}if(a.push(l?{id:"bun",ok:u,message:u?`Bun ${se} is available on PATH`:`Bun ${se} not found on PATH`,fix:u?void 0:"curl -fsSL https://bun.sh/install | bash"}:{id:"bun",ok:!0,message:"Bun not needed: no generated JS services"}),i!=="native"&&a.push(await ui(s??t,i)),s&&i==="runtime"){let S=await Te("nats",()=>le(s),"NATS broker check failed");if(S.ok||a.push(S),li(s)){let T=!1;try{let _=JSON.parse(ti(si(s,".flisk",U),"utf-8")),Ee=String(_?.project?.name??"").replace(/-/g,"_");Ee&&(T=Cn(w("docker")??"docker",["ps","--filter",`label=com.docker.compose.project=${Ee}`,"--filter","label=com.docker.compose.service=postgres","--filter","health=healthy","--format","{{.Names}}"],{encoding:"utf-8",timeout:3e3}).trim().length>0)}catch{}T||a.push({id:"prisma",ok:!1,message:"A Prisma resource is configured, but the project Postgres service is not healthy",fix:"Run `flisk up` to start the bundled Postgres, then check `flisk doctor`."})}}let d=a.filter(S=>!S.ok).slice(0,8),g=Tn(i),k=d.some(S=>g.includes(S.id)),y=d.some(S=>S.id==="bun"),$=d.length?k?i==="native"?"Cannot start the local processes. Fix the machine checks below.":i==="scaffold"?y?`Project setup blocked. Bun ${se} must be installed on PATH.
|
|
127
|
+
Fix the machine checks below.`:"Project setup blocked. Fix the machine checks below.":y?`Cold start blocked. Bun ${se} must be installed on PATH.
|
|
128
|
+
Prisma/NATS configuration is project-specific and generated after \`flisk project\`. Fix the machine checks below.`:"Cold start blocked. Bun/Prisma/NATS are not the first failure.\nThey are generated after `flisk project`. Fix the machine checks below.":"Machine is ready. Project wiring is not.":"",N=d.length?"":n?"Environment ready for Flisk":`This machine is ready for Flisk.
|
|
129
|
+
${$n()}`;return{ok:d.length===0,inProject:n,scope:i,items:d,header:$,footer:N}}function pi(e,t={}){let s=[e.header];for(let n of e.items)s.push(`FAIL ${n.id.padEnd(7)} ${n.message}`),n.fix&&s.push(` ${n.fix}`);return e.footer&&(t.includeSuccessFooter??!0)&&s.push(e.footer),s.filter(Boolean).join(`
|
|
130
|
+
`)}async function fl(e={}){let t=await di({scope:e.scope}),s=Tn(t.scope);if(t.items.some(r=>s.includes(r.id))){console.error(pi(t));for(let r of e.hints??[])console.error(`\u2192 ${r}`);process.exit(1)}}function ml(e=w){return{hasDockerCli:!!e("docker"),hasTiltCli:!!e("tilt")}}function hl(e){let t=[];return e.hasDockerCli||t.push(`Docker is not installed. ${ft.dockerMissing}`),e.hasTiltCli||t.push(`Tilt is not installed. ${ft.tiltMissing}`),t.push("Docker and Tilt are only needed to start the stack: start them, then run `flisk doctor` (readiness) and `flisk up`."),t}export{Br as a,Gr as b,wa as c,Be as d,rs as e,os as f,is as g,Ge as h,fe as i,vi as j,Oi as k,_i as l,Ai as m,Xe as n,Mi as o,ir as p,lr as q,ur as r,Hi as s,tt as t,Ze as u,st as v,Is as w,nt as x,Se as y,ye as z,I as A,la as B,ua as C,da as D,Rs as E,pa as F,Qs as G,en as H,za as I,Xa as J,zo as K,bn as L,Xc as M,ni as N,ri as O,oi as P,ii as Q,Nn as R,ci as S,li as T,di as U,pi as V,fl as W,ml as X,hl as Y};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{c as se,e as ie}from"./chunk-GPUJ55MI.js";import{a as oe}from"./chunk-
|
|
2
|
+
import{c as se,e as ie}from"./chunk-GPUJ55MI.js";import{a as oe}from"./chunk-YTBTCAWY.js";import{Z as te,_ as ne,ia as K,ma as re,z as G}from"./chunk-L6O7TT3K.js";import{b as Q,f as w,g as k,i as Z,j as I,k as C,l as U,m as ee,n as F,s as u,t as M}from"./chunk-TIPSERWO.js";import{a as O}from"./chunk-KJZUBHLO.js";import{appendFileSync as Te,existsSync as H,mkdirSync as _e,readFileSync as be,writeFileSync as ae}from"node:fs";import{dirname as ve,resolve as x}from"node:path";function _t(t,e,n){for(let[r,s]of e.entries())console.log(Q.blue(`${s.emoji} ${s.description}...`)),s.type==="json"?xe(t,s.filename,s.content):Ie(t,s.filename,String(s.content)),n&&n(s,r,e.length)}function we(t,e,n=2){let r=`${JSON.stringify(e,null,n)}
|
|
3
3
|
`;ae(t,r,"utf-8")}function xe(t,e,n,r=2){let s=x(t,e);we(s,n,r)}function q(t,e){ae(t,e,"utf-8")}function Ie(t,e,n){let r=x(t,e);q(r,n)}function bt(t){H(t)||_e(t,{recursive:!0})}var Fe=[".env",".flisk/.flisk-out/",".flisk/.project-id",".flisk/smoke/","node_modules/"];function $e(t){let e=x(t,".gitignore"),n=H(e)?be(e,"utf-8"):"",r=new Set(n.split(`
|
|
4
4
|
`).map(d=>d.trim().replace(/\/$/,""))),s=Fe.filter(d=>!r.has(d.replace(/\/$/,"")));if(s.length===0)return[];let l=n&&!n.endsWith(`
|
|
5
5
|
`)?`
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{E as C,t as $}from"./chunk-
|
|
2
|
+
import{E as C,t as $}from"./chunk-TIPSERWO.js";var g=class extends Error{kind;constructor(i,a){super(i),this.kind=a,this.name="TiltEventsLoadError"}};function m(n){return typeof n=="object"&&n!==null&&!Array.isArray(n)?n:null}var w="\x1B",k="\x07",I=new RegExp(`${w}(?:\\[[0-?]*[ -/]*[@-~]|\\][^${k}${w}]*(?:${k}|${w}\\\\)?|[@-Z\\\\-_])`,"g"),O=new RegExp("[\\u0000-\\u0008\\u000b-\\u001f\\u007f-\\u009f]","g");function U(n){return n.replace(I,"").replace(O,"")}function r(n){return typeof n!="string"?void 0:U(n).trim()||void 0}function _(n){return Array.isArray(n)?n.flatMap(i=>{let a=r(i);return a?[a]:[]}):[]}function L(n){let i=m(n);if(!i||!Array.isArray(i.items))throw new Error("Tilt returned an invalid UIResource list");let a=[],e=[];for(let s of i.items){let u=m(s),N=m(u?.metadata),t=r(N?.name);if(!u||!t)continue;let c=m(u.status);a.push({name:t,runtimeStatus:r(c?.runtimeStatus),updateStatus:r(c?.updateStatus),hasPendingChanges:typeof c?.hasPendingChanges=="boolean"?c.hasPendingChanges:void 0});let x=Array.isArray(c?.buildHistory)?c.buildHistory:[];for(let[d,A]of x.entries()){let o=m(A);if(!o)continue;let f=r(o.error),l=_(o.warnings),p=[f,...l].filter(S=>!!S),h=r(o.spanID);e.push({id:`${t}:build:${h??String(d)}`,resourceName:t,kind:f?"failed":l.length?"warning":"success",title:f?"Build failed":l.length?"Build completed with warnings":"Build completed",occurredAt:r(o.finishTime)??r(o.startTime),details:p.length?p.join("; "):void 0})}let T=m(c?.currentBuild);T&&e.push({id:`${t}:current-build`,resourceName:t,kind:"running",title:"Build in progress",occurredAt:r(T.startTime)});let b=r(c?.pendingBuildSince);!T&&(c?.queued===!0||b)&&e.push({id:`${t}:queued`,resourceName:t,kind:"warning",title:"Update queued",occurredAt:b});let y=r(c?.lastDeployTime),E=y?Date.parse(y):Number.NaN,R=e.some(d=>d.resourceName===t&&d.kind==="success"&&d.occurredAt!==void 0&&Date.parse(d.occurredAt)===E);y&&!R&&e.push({id:`${t}:last-deploy`,resourceName:t,kind:"success",title:"Last deployed",occurredAt:y});let B=Array.isArray(c?.conditions)?c.conditions:[];for(let[d,A]of B.entries()){let o=m(A);if(!o)continue;let f=r(o.type),l=r(o.status),p=r(o.reason),h=r(o.message);if(!f&&!p&&!h||l==="True"&&!p&&!h)continue;let S=[p,h].filter(D=>!!D).join(": ");e.push({id:`${t}:condition:${d}:${f??"status"}`,resourceName:t,kind:l==="False"?"warning":"status",title:`Condition ${f??"status"}${l?`: ${l}`:""}`,occurredAt:r(o.lastTransitionTime),details:S||void 0})}}return e.sort((s,u)=>{if(s.kind==="running"&&u.kind!=="running")return-1;if(u.kind==="running"&&s.kind!=="running")return 1;let N=s.occurredAt?Date.parse(s.occurredAt):Number.NaN,t=u.occurredAt?Date.parse(u.occurredAt):Number.NaN;return Number.isNaN(N)?Number.isNaN(t)?s.resourceName.localeCompare(u.resourceName):1:Number.isNaN(t)?-1:t-N}),{resources:a,events:e}}async function q(){let n=process.env.TILT_PORT??String($.tiltUi),i;try{i=await C("get",["uiresources","-o","json","--port",n],{inheritStdio:!1,timeoutMs:1e4})}catch(e){let s=e instanceof Error?e.message:String(e),u=/ENOENT|not found|no such file|connection refused|failed to connect|could not connect|unable to connect|Tilt is not running/i.test(s)?"unavailable":"error";throw new g(s,u)}if(i.exitCode!==0){let e=i.stderr.trim()||`tilt get exited with code ${i.exitCode}`,s=/connection refused|failed to connect|could not connect|unable to connect|Tilt is not running|no running Tilt/i.test(e)?"unavailable":"error";throw new g(e,s)}let a;try{a=JSON.parse(i.stdout)}catch{throw new g("Tilt returned invalid UIResource JSON","error")}try{return L(a)}catch(e){throw new g(e instanceof Error?e.message:"Tilt returned an invalid UIResource list","error")}}export{g as a,U as b,q as c};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
var s={demo:{repo:"https://github.com/flisk-sh/flisk-restaurant-example.git",description:"The demo stack: restaurant ops with reservations, kitchen and floor control",fixedDir:"flisk-demo"},restaurant:{repo:"https://github.com/flisk-sh/flisk-restaurant-example.git",description:"Restaurant ops: reservations, kitchen, floor control (Hono + Vite + Bun)"},saas:{repo:"https://github.com/flisk-sh/flisk-saas-starter.git",description:"SaaS starter: account dashboard and a working checkout button (Hono + Vite + Bun)"},erp:{repo:"https://github.com/flisk-sh/flisk-erp-system.git",description:"Enterprise ERP: 100 microservices across 7 business domains"},"user-management":{repo:"https://github.com/flisk-sh/flisk-user-management.git",description:"User/auth management services"},ecommerce:{repo:"https://github.com/flisk-sh/flisk-ecommerce-example.git",description:"Vue 3 storefront and Hono catalog API (needs Flisk 1.3.75+ for --framework vue)"},example:{repo:"https://github.com/flisk-sh/flisk-example.git",bundledPath:"examples/
|
|
2
|
+
var s={demo:{repo:"https://github.com/flisk-sh/flisk-restaurant-example.git",description:"The demo stack: restaurant ops with reservations, kitchen and floor control",fixedDir:"flisk-demo"},restaurant:{repo:"https://github.com/flisk-sh/flisk-restaurant-example.git",description:"Restaurant ops: reservations, kitchen, floor control (Hono + Vite + Bun)"},saas:{repo:"https://github.com/flisk-sh/flisk-saas-starter.git",description:"SaaS starter: account dashboard and a working checkout button (Hono + Vite + Bun)"},erp:{repo:"https://github.com/flisk-sh/flisk-erp-system.git",description:"Enterprise ERP: 100 microservices across 7 business domains"},"user-management":{repo:"https://github.com/flisk-sh/flisk-user-management.git",description:"User/auth management services"},ecommerce:{repo:"https://github.com/flisk-sh/flisk-ecommerce-example.git",description:"Vue 3 storefront and Hono catalog API (needs Flisk 1.3.75+ for --framework vue)"},example:{repo:"https://github.com/flisk-sh/flisk-example.git",bundledPath:"examples/flisk-example",description:"Hono + Postgres + NATS worker + Vite example with a routed write path"},"agent-stack":{repo:"https://github.com/flisk-sh/flisk-agent-stack.git",description:"AI agent stack: Bun agent + MCP tool server + Postgres + NATS"}};function i(t){let e=t[2];if(!(!e||e.startsWith("-")))return e in s?e:void 0}export{s as a,i as b};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import{createRequire as __fliskRequire}from'node:module';const require=__fliskRequire(import.meta.url);
|
|
2
|
-
import{b as N}from"./chunk-
|
|
2
|
+
import{b as N}from"./chunk-XHENT4KO.js";import{a as m,ma as f,y as T}from"./chunk-L6O7TT3K.js";import{C as I,L as O,e as $,f as C,i as F,j as E,m as U,n as P,x as u}from"./chunk-TIPSERWO.js";import{execFileSync as de,execSync as le}from"node:child_process";import{existsSync as A,readdirSync as V,readFileSync as y}from"node:fs";import{basename as ue,dirname as me,join as l,relative as k}from"node:path";function Oe(t){return M(t,!1)}function Ne(t){return M(t,!0)}function M(t,e){return`import { Hono } from 'hono';
|
|
3
3
|
import { cors } from 'hono/cors';
|
|
4
4
|
${e?`import { sql } from 'drizzle-orm';
|
|
5
5
|
import { db } from './db.js';
|
|
@@ -3,7 +3,7 @@ function G(e,t,r){let o=e.indexOf(t);if(o===-1)return e;let n=t.length,s=0,i="";
|
|
|
3
3
|
`:`
|
|
4
4
|
`)+r,n=o+1,o=e.indexOf(`
|
|
5
5
|
`,n)}while(o!==-1);return s+=e.slice(n),s}var Y=(e=0)=>t=>`\x1B[${t+e}m`,S=(e=0)=>t=>`\x1B[${38+e};5;${t}m`,I=(e=0)=>(t,r,o)=>`\x1B[${38+e};2;${t};${r};${o}m`,he=e=>`\x1B[58;5;${e<90?e-30:e-90+8}m`,l={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],underlineDouble:["4:2",24],underlineCurly:["4:3",24],underlineDotted:["4:4",24],underlineDashed:["4:5",24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]},underlineColor:{underlineBlack:["58;5;0",59],underlineRed:["58;5;1",59],underlineGreen:["58;5;2",59],underlineYellow:["58;5;3",59],underlineBlue:["58;5;4",59],underlineMagenta:["58;5;5",59],underlineCyan:["58;5;6",59],underlineWhite:["58;5;7",59],underlineBlackBright:["58;5;8",59],underlineGray:["58;5;8",59],underlineGrey:["58;5;8",59],underlineRedBright:["58;5;9",59],underlineGreenBright:["58;5;10",59],underlineYellowBright:["58;5;11",59],underlineBlueBright:["58;5;12",59],underlineMagentaBright:["58;5;13",59],underlineCyanBright:["58;5;14",59],underlineWhiteBright:["58;5;15",59]}},K=Object.keys(l.modifier),_=Object.keys(l.color),N=Object.keys(l.bgColor),ge=Object.keys(l.underlineColor),H=[..._,...N];function be(){let e=new Map;for(let[t,r]of Object.entries(l)){for(let[o,n]of Object.entries(r))l[o]={open:`\x1B[${n[0]}m`,close:`\x1B[${n[1]}m`},r[o]=l[o],e.set(Number.parseInt(n[0],10),n[1]);Object.defineProperty(l,t,{value:r,enumerable:!1})}return Object.defineProperty(l,"codes",{value:e,enumerable:!1}),l.color.close="\x1B[39m",l.bgColor.close="\x1B[49m",l.underlineColor.close="\x1B[59m",l.color.ansi=Y(),l.color.ansi256=S(),l.color.ansi16m=I(),l.bgColor.ansi=Y(10),l.bgColor.ansi256=S(10),l.bgColor.ansi16m=I(10),l.underlineColor.ansi=he,l.underlineColor.ansi256=S(20),l.underlineColor.ansi16m=I(20),Object.defineProperties(l,{rgbToAnsi256:{value(t,r,o){return t===r&&r===o?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(r/255*5)+Math.round(o/255*5)},enumerable:!1},hexToRgb:{value(t){let r=/[\da-f]{6}|[\da-f]{3}/i.exec(t.toString(16));if(!r)return[0,0,0];let[o]=r;o.length===3&&(o=[...o].map(s=>s+s).join(""));let n=Number.parseInt(o,16);return[n>>16&255,n>>8&255,n&255]},enumerable:!1},hexToAnsi256:{value:t=>l.rgbToAnsi256(...l.hexToRgb(t)),enumerable:!1},ansi256ToAnsi:{value(t){if(t<8)return 30+t;if(t<16)return 90+(t-8);let r,o,n;if(t>=232)r=((t-232)*10+8)/255,o=r,n=r;else{t-=16;let a=t%36;r=Math.floor(t/36)/5,o=Math.floor(a/6)/5,n=a%6/5}let s=Math.max(r,o,n)*2;if(s===0)return 30;let i=30+(Math.round(n)<<2|Math.round(o)<<1|Math.round(r));return s===2&&(i+=60),i},enumerable:!1},rgbToAnsi:{value:(t,r,o)=>l.ansi256ToAnsi(l.rgbToAnsi256(t,r,o)),enumerable:!1},hexToAnsi:{value:t=>l.ansi256ToAnsi(l.hexToAnsi256(t)),enumerable:!1}}),l}var xe=be(),m=xe;import j from"node:process";import Ee from"node:os";import W from"node:tty";function d(e,t=globalThis.Deno?globalThis.Deno.args:j.argv){let r=e.startsWith("-")?"":e.length===1?"-":"--",o=t.indexOf(r+e),n=t.indexOf("--");return o!==-1&&(n===-1||o<n)}var{env:c}=j,R;d("no-color")||d("no-colors")||d("color=false")||d("color=never")?R=0:(d("color")||d("colors")||d("color=true")||d("color=always"))&&(R=1);function z(){return/^\d+$/.test(c.FORCE_COLOR)}function Te(){if("FORCE_COLOR"in c){if(c.FORCE_COLOR==="false")return 0;if(c.FORCE_COLOR==="true"||c.FORCE_COLOR.length===0)return 1;if(z())return Math.min(Number.parseInt(c.FORCE_COLOR,10),3)}}function Ce(e){return e===0?!1:{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function Re(e,{streamIsTTY:t,sniffFlags:r=!0}={}){let o=Te();o!==void 0&&(R=o);let n=r?R:o;if(n===0)return 0;if(r){if(d("color=16m")||d("color=full")||d("color=truecolor"))return 3;if(d("color=256"))return 2}if(n!==void 0&&z())return n;if("TF_BUILD"in c&&"AGENT_NAME"in c)return 1;if(e&&!t&&n===void 0)return 0;let s=n||0;if(c.TERM==="dumb")return s;if(j.platform==="win32"){let i=Ee.release().split(".");return Number(i[0])>=10&&Number(i[2])>=10586?Number(i[2])>=14931?3:2:1}if("CI"in c)return["GITHUB_ACTIONS","GITEA_ACTIONS","CIRCLECI"].some(i=>i in c)?3:["TRAVIS","APPVEYOR","GITLAB_CI","BUILDKITE","DRONE"].some(i=>i in c)||c.CI_NAME==="codeship"?1:s;if("TEAMCITY_VERSION"in c)return/^(?:9\.0*[1-9]\d*\.|\d{2,}\.)/.test(c.TEAMCITY_VERSION)?1:0;if(c.COLORTERM==="truecolor"||c.TERM==="xterm-kitty"||c.TERM==="xterm-ghostty"||c.TERM==="wezterm")return 3;if("TERM_PROGRAM"in c){let i=Number.parseInt((c.TERM_PROGRAM_VERSION||"").split(".",1)[0],10);switch(c.TERM_PROGRAM){case"iTerm.app":return i>=3?3:2;case"Apple_Terminal":return 2}}return/-256(?:color)?$/i.test(c.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(c.TERM)||"COLORTERM"in c?1:s}function J(e,t={}){let r=Re(e,{streamIsTTY:e&&e.isTTY,...t});return Ce(r)}var ke={stdout:J({isTTY:W.isatty(1)}),stderr:J({isTTY:W.isatty(2)})},X=ke;var{stdout:q,stderr:Q}=X,b=Symbol("GENERATOR"),x=Symbol("STYLER"),y=Symbol("IS_EMPTY"),k=Symbol("LEVEL"),E=Object.create(null),Z=e=>{if(!Number.isSafeInteger(e)||e<0||e>3)throw new Error("The `level` should be an integer from 0 to 3")},ye={enumerable:!0,get(){return this[k]},set(e){Z(e),this[k]=e}},Oe=(e,t={})=>{t.level!==void 0&&Z(t.level);let r=q?q.level:0;e[k]=t.level===void 0?r:t.level};var ve=e=>{let t=(...r)=>r.join(" ");return Oe(t,e),Object.setPrototypeOf(t,T.prototype),t};function T(e){return ve(e)}Object.setPrototypeOf(T.prototype,Function.prototype);for(let[e,t]of Object.entries(m))E[e]={get(){let r=M(this,ee(t.open,t.close,this[x]),this[y]);return Object.defineProperty(this,e,{value:r}),r}};E.visible={get(){let e=M(this,this[x],!0);return Object.defineProperty(this,"visible",{value:e}),e}};var Ae=(e,t)=>{let r=m[t];if(e==="rgb"){let n=(i,a,u)=>r.ansi(m.rgbToAnsi(i,a,u));return[n,n,(i,a,u)=>r.ansi256(m.rgbToAnsi256(i,a,u)),r.ansi16m]}if(e==="hex"){let n=i=>r.ansi(m.hexToAnsi(i));return[n,n,i=>r.ansi256(m.hexToAnsi256(i)),i=>r.ansi16m(...m.hexToRgb(i))]}let o=n=>r.ansi(m.ansi256ToAnsi(n));return[o,o,r.ansi256,r.ansi256]},we=["rgb","hex","ansi256"];for(let e of we){let t=e[0].toUpperCase()+e.slice(1);for(let[r,o]of[[e,"color"],["bg"+t,"bgColor"],["underline"+t,"underlineColor"]]){let{close:n}=m[o],s=Ae(e,o);E[r]={get(){let i=function(a,u,f){let me=s[this.level](a,u,f);return M(this,ee(me,n,this[x]),this[y])};return Object.defineProperty(this,r,{value:i}),i}}}}var Se=Object.defineProperties(()=>{},{...E,level:{enumerable:!0,get(){return this[b].level},set(e){this[b].level=e}}}),ee=(e,t,r)=>{let o,n;return r===void 0?(o=e,n=t):(o=r.openAll+e,n=t+r.closeAll),{open:e,close:t,openAll:o,closeAll:n,parent:r}},M=(e,t,r)=>{let o=(...n)=>n.length===1?F(o,""+n[0]):n.length===2?F(o,`${n[0]??""} ${n[1]??""}`):F(o,n.join(" "));return Object.setPrototypeOf(o,Se),o[b]=e[b]??e,o[x]=t,o[y]=r,o},F=(e,t)=>{if(e[b][k]<=0||!t)return e[y]?"":t;let r=e[x];if(r===void 0)return t;let{openAll:o,closeAll:n}=r;if(t.includes("\x1B"))for(;r!==void 0;)t=G(t,r.close,r.open),r=r.parent;let s=t.indexOf(`
|
|
6
|
-
`);return s!==-1&&(t=V(t,n,o,s)),o+t+n};Object.defineProperties(T.prototype,{...E,level:ye});var Ie=T(),ut=T({level:Q?Q.level:0});var h=Ie;var te={name:"flisk-cli-internal",private:!0,version:"1.4.5",description:"Flisk CLI \u2014 start services on your machine.",keywords:["flisk","tilt","cli","local-dev","microservices"],homepage:"https://github.com/flisk-sh/flisk#readme",bugs:{url:"https://github.com/flisk-sh/flisk/issues"},repository:{type:"git",url:"git+https://github.com/flisk-sh/flisk.git",directory:"cli"},license:"MIT",author:"Flisk Team",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",bin:{flisk:"bin/flisk.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","check:dist":"npm run build && ../scripts/check-cli-dist.sh",lint:"biome check . ../tests/generated ../tests/runtime-layout","lint:fix":"biome check . ../tests/generated ../tests/runtime-layout --write",typecheck:"tsc --project tsconfig.typecheck.json",clean:"rm -rf dist",dev:"bun run build:watch",test:"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage --coverage.reportOnFailure --coverage.reporter=text --coverage.reporter=html --coverage.reporter=json-summary --coverage.reporter=json --coverage.reportsDirectory=coverage --reporter=default --reporter=json --outputFile.json=test-results/vitest.json",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":"^26.6.5","@types/react":"^19.3.0","@vitest/coverage-v8":"5.0.5",ajv:"^8.17.1",chalk:"^6.0.1",esbuild:"^0.28.2",ink:"^8.0.0",knip:"^6.38.0",react:"^19.3.0","react-devtools-core":"^8.0.0",typescript:"^7.0.2",vite:"^8.3.3",vitest:"5.0.5"},engines:{node:">=22.12.0"}};var mt="Container Runtime",P="bring-your-own";var ht="database-management",gt=".tiltignore",bt="service.json",Ne="docker-compose.yml",xt=".autogenerated",je="TILT_TECH_STACK.star",Fe="TILT_RESOURCE_DEFAULTS.star",re="project.json",Et="package.json",Tt=[je,Fe,"spec.master"],Ct=["backend","frontend","library","sdk","worker","migrator","mcp","agent",P],Rt={backend:["dev","build","start"],worker:["dev","build","start"],migrator:["dev","build","start"],mcp:["dev","build","start"],agent:["dev","build","start"],frontend:["dev","build"],library:["dev","build"],sdk:["dev","build"],[P]:[]};var kt=["monitoring","elk","debezium","golden_image","verdaccio"],yt={frontend:{base:3e3,min:3e3,max:3999,range:"3000-3999"},backend:{base:4e3,min:4e3,max:4999,range:"4000-4999"},mcp:{base:4e3,min:4e3,max:5999,range:"4000-5999"},agent:{base:4e3,min:4e3,max:5999,range:"4000-5999"},[P]:{base:4e3,min:4e3,max:5999,range:"4000-5999"},worker:{base:6e3,min:6e3,max:6999,range:"6000-6999"},health:{base:5e3,min:5e3,max:5999,range:"5000-5999"},migrator:{base:7e3,min:7e3,max:7999,range:"7000-7999"}},Ot={tiltUi:10350,traefik:8080},B="https://flisk.sh/docs/quickstart/";var vt=["node_modules",".git",".tilt",".tilt-engine","dist","build",".prisma",".turbo","coverage","tmp","temp","__tests__","test","tests",".github",".vscode","docs"],At=["Dockerfile",Ne,"docker-compose.yaml","Tiltfile","vite.config.ts","tsconfig.json","tsconfig.build.json"],Me={infra:"\u{1F3D7}\uFE0F",core:"\u{1F527}",api:"\u26A1",app:"\u{1F3A8}",orchestrator:"\u2699\uFE0F"};function wt(e){let t=e.toLowerCase();for(let[r,o]of Object.entries(Me))if(t.includes(r))return o;return"\u{1F4E6}"}import{existsSync as Pe}from"node:fs";import{dirname as Be,join as De,resolve as oe}from"node:path";import{cwd as Le}from"node:process";function v(e=Le()){let t=oe(e),r=oe("/");for(;t!==r;){if(Pe(De(t,".flisk",re)))return t;let o=Be(t);if(o===t)break;t=o}return null}var O=null;function $e(){if(O)return O;let e=te;if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Invalid package.json: expected object");let t=e;return O={name:String(t.name??"@flisk-sh/flisk"),version:String(t.version??"0.0.0"),fullPackage:t},O}function Mt(){return $e().version}import{existsSync as ne}from"node:fs";import{delimiter as se,extname as ie,join as le}from"node:path";import{delimiter as Dt,extname as Ue}from"node:path";function C(){return process.platform==="win32"}function Ge(e){return e==="linux"?"linux":e==="darwin"?"darwin":e==="win32"?"windows":null}function Ve(e){return e==="x64"?"amd64":e==="arm64"?"arm64":null}function Ye(e,t){let r=Ge(e),o=Ve(t);if(!r||!o||r==="windows"&&o!=="amd64")return null;let n=`tdk-${r}-${o}`;return r==="windows"?`${n}.exe`:n}function Lt(){return Ye(process.platform,process.arch)}function $t(){return C()?"flisk.exe":"flisk"}function D(e,t=C()){return t?Ue(e)?[e]:[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e]}function A(e){let t=process.env.PATH??process.env.Path??"",r=C(),o=D(e,r);if(r&&!ie(e))for(let n of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let s=n.toLowerCase();s&&!o.includes(`${e}${s}`)&&o.push(`${e}${s}`)}for(let n of t.split(se))if(n)for(let s of o){let i=le(n,s);if(ne(i))return i}return null}function Kt(e){let t=process.env.PATH??process.env.Path??"",r=C(),o=D(e,r);if(r&&!ie(e))for(let i of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let a=i.toLowerCase();a&&!o.includes(`${e}${a}`)&&o.push(`${e}${a}`)}let n=[],s=new Set;for(let i of t.split(se))if(i)for(let a of o){let u=le(i,a);if(!ne(u))continue;let f=r?u.toLowerCase():u;s.has(f)||(s.add(f),n.push(u))}return n}import{execFileSync as Ke,execSync as He}from"node:child_process";var ce=1e4;function ae(){let e=!1;if(process.platform==="win32")try{return Ke(A("docker")??"docker",["ps"],{stdio:"ignore",timeout:ce,windowsHide:!0}),"running"}catch(t){return t.code==="ETIMEDOUT"?"unresponsive":"missing"}for(let t of["docker ps","colima status","podman ps"])try{return He(t,{stdio:"ignore",timeout:ce}),"running"}catch(r){r.code==="ETIMEDOUT"&&(e=!0)}return e?"unresponsive":"missing"}function w(e,t){return e[t]??0}function We(e,t){let r=Array.from({length:t.length+1},(o,n)=>n);for(let o=1;o<=e.length;o++){let n=[o];for(let s=1;s<=t.length;s++){let i=e[o-1]===t[s-1]?0:1;n[s]=Math.min(w(n,s-1)+1,w(r,s)+1,w(r,s-1)+i)}r=n}return w(r,t.length)}function Je(e,t){if(e.length!==t.length)return!1;for(let r=0;r<e.length-1;r++)if(e[r]!==t[r]&&e[r]===t[r+1]&&e[r+1]===t[r]&&e.slice(0,r)===t.slice(0,r)&&e.slice(r+2)===t.slice(r+2))return!0;return!1}function ue(e,t){if(e.length<2||t.length===0||t.includes(e))return;let r=e.toLowerCase(),o,n=Number.POSITIVE_INFINITY;for(let s of t){if(s.length===0)continue;let i=s.toLowerCase(),a=Je(r,i)?1:We(r,i),u=Math.max(1,Math.min(2,Math.floor(Math.max(r.length,i.length)/3)));a>u||(a<n||a===n&&(o===void 0||s<o))&&(o=s,n=a)}return o}import{spawn as ze}from"node:child_process";import{join as Xe}from"node:path";function qe(e,t=[],r={}){return new Promise((o,n)=>{let s=[e,...t];r.verbose&&console.log(`Executing: tilt ${s.join(" ")}`);let i=ze(A("tilt")??"tilt",s,{stdio:r.inheritStdio?"inherit":"pipe",shell:!1,windowsHide:process.platform==="win32",timeout:r.timeoutMs}),a="",u="";r.inheritStdio||(i.stdout?.on("data",f=>{a+=f.toString()}),i.stderr?.on("data",f=>{u+=f.toString()})),i.on("close",f=>{o({exitCode:f??1,stdout:a,stderr:u})}),i.on("error",f=>{n(new Error(`Failed to spawn tilt: ${f.message}`))})})}async function fe(){try{return(await qe("version",[],{inheritStdio:!1,timeoutMs:1e4})).exitCode===0}catch{return!1}}function Qe(){let e=v();if(!e)throw g.notInProject();return Xe(e,".flisk",".flisk-out","Tiltfile")}function de(e){let t=Qe();e.push("-f",t)}function rr(e,t={}){let r=[];return de(r),t.focusTargets&&t.focusTargets.length>0&&r.push("--",`--focus=${t.focusTargets.join(",")}`),r.push(...e),t.verbose&&!t.quiet&&r.push("--verbose"),t.watch&&r.push("--watch"),r}function or(e={}){let t=[];return de(t),e.focusTargets&&e.focusTargets.length>0&&t.push("--",`--focus=${e.focusTargets.join(",")}`),t}function pe(e){return e instanceof Error?e.message:String(e)}function fr(e,t){if(process.env.FLISK_VERBOSE){let r=t!==void 0?`: ${pe(t)}`:"";console.warn(h.gray(`${e}${r}`))}}var p=class extends Error{suggestions;exitCode;constructor(t,r=[],o=1){super(t),this.name="FliskError",this.suggestions=r,this.exitCode=o}display(){U(this.message,void 0,this.suggestions)}exit(){this.display(),process.exit(this.exitCode)}},$=class extends Error{code;constructor(t=1){super(`process.exit(${t})`),this.name="ProcessExitError",this.code=t}};function L(e,t,r=!1){let o=new Set;for(let n of e){let s=ue(n,t);s&&o.add(r?`Did you mean "${s}" for "${n}"?`:`Did you mean "${s}"?`)}return[...o]}var g={tiltNotInstalled:()=>new p("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: ${B}`]),dockerNotAvailable:()=>new p("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: ${B}`]),dockerNotResponding:()=>new p("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 p(`Stack "${e}" not found`,[...L([e],t),"Run `flisk stacks` to see available stacks","Run `flisk stack` to assign resources to a stack"]),resourceNotFound:(e,t=[])=>new p(`Resource "${e}" not found`,[...L([e],t),"Run `flisk resources` to list all resources","Check the resource name spelling"]),unknownServices:(e,t)=>{let r=L(e,t,e.length>1);return new p(`Unknown service ${e.join(", ")}. Valid names: ${t.join(", ")}`,r,2)},directoryExists:e=>new p(`Directory already exists: ${e}`,["Use `--path` to specify a different location","Remove the existing directory if no longer needed"]),invalidPath:e=>new p(`Invalid path: ${e}`,["Path must be within the project directory",'Path cannot contain special characters like <>:"|?*']),notInProject:()=>new p("Could not find project root (no .flisk/project.json found)",["Run this from within a Flisk project","Run `flisk project --yes` to initialize a new project"])};function dr(){let e=v();return e||g.notInProject().exit()}function Ze(e){e instanceof p&&e.exit(),U(pe(e)),process.exit(1)}async function et(e,t){try{return await e()}catch(r){if(r instanceof $)throw r;return t?.verbose&&r instanceof Error&&r.stack&&console.error(h.gray(r.stack)),Ze(r)}}async function pr(e,t){let r=[],o=ae();return o==="unresponsive"?r.push(g.dockerNotResponding()):o==="missing"&&r.push(g.dockerNotAvailable()),await fe()||r.push(g.tiltNotInstalled()),r.length>0&&(console.error(h.red(`
|
|
6
|
+
`);return s!==-1&&(t=V(t,n,o,s)),o+t+n};Object.defineProperties(T.prototype,{...E,level:ye});var Ie=T(),ut=T({level:Q?Q.level:0});var h=Ie;var te={name:"flisk-cli-internal",private:!0,version:"1.4.7",description:"Flisk CLI \u2014 start services on your machine.",keywords:["flisk","tilt","cli","local-dev","microservices"],homepage:"https://github.com/flisk-sh/flisk#readme",bugs:{url:"https://github.com/flisk-sh/flisk/issues"},repository:{type:"git",url:"git+https://github.com/flisk-sh/flisk.git",directory:"cli"},license:"MIT",author:"Flisk Team",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",bin:{flisk:"bin/flisk.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","check:dist":"npm run build && ../scripts/check-cli-dist.sh",lint:"biome check . ../tests/generated ../tests/runtime-layout","lint:fix":"biome check . ../tests/generated ../tests/runtime-layout --write",typecheck:"tsc --project tsconfig.typecheck.json",clean:"rm -rf dist",dev:"bun run build:watch",test:"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage --coverage.reportOnFailure --coverage.reporter=text --coverage.reporter=html --coverage.reporter=json-summary --coverage.reporter=json --coverage.reportsDirectory=coverage --reporter=default --reporter=json --outputFile.json=test-results/vitest.json",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":"^26.6.5","@types/react":"^19.3.0","@vitest/coverage-v8":"5.0.5",ajv:"^8.17.1",chalk:"^6.0.1",esbuild:"^0.28.2",ink:"^8.0.0",knip:"^6.38.0",react:"^19.3.0","react-devtools-core":"^8.0.0",typescript:"^7.0.2",vite:"^8.3.3",vitest:"5.0.5"},engines:{node:">=22.12.0"}};var mt="Container Runtime",P="bring-your-own";var ht="database-management",gt=".tiltignore",bt="service.json",Ne="docker-compose.yml",xt=".autogenerated",je="TILT_TECH_STACK.star",Fe="TILT_RESOURCE_DEFAULTS.star",re="project.json",Et="package.json",Tt=[je,Fe,"spec.master"],Ct=["backend","frontend","library","sdk","worker","migrator","mcp","agent",P],Rt={backend:["dev","build","start"],worker:["dev","build","start"],migrator:["dev","build","start"],mcp:["dev","build","start"],agent:["dev","build","start"],frontend:["dev","build"],library:["dev","build"],sdk:["dev","build"],[P]:[]};var kt=["monitoring","elk","debezium","golden_image","verdaccio"],yt={frontend:{base:3e3,min:3e3,max:3999,range:"3000-3999"},backend:{base:4e3,min:4e3,max:4999,range:"4000-4999"},mcp:{base:4e3,min:4e3,max:5999,range:"4000-5999"},agent:{base:4e3,min:4e3,max:5999,range:"4000-5999"},[P]:{base:4e3,min:4e3,max:5999,range:"4000-5999"},worker:{base:6e3,min:6e3,max:6999,range:"6000-6999"},health:{base:5e3,min:5e3,max:5999,range:"5000-5999"},migrator:{base:7e3,min:7e3,max:7999,range:"7000-7999"}},Ot={tiltUi:10350,traefik:8080},B="https://flisk.sh/docs/quickstart/";var vt=["node_modules",".git",".tilt",".tilt-engine","dist","build",".prisma",".turbo","coverage","tmp","temp","__tests__","test","tests",".github",".vscode","docs"],At=["Dockerfile",Ne,"docker-compose.yaml","Tiltfile","vite.config.ts","tsconfig.json","tsconfig.build.json"],Me={infra:"\u{1F3D7}\uFE0F",core:"\u{1F527}",api:"\u26A1",app:"\u{1F3A8}",orchestrator:"\u2699\uFE0F"};function wt(e){let t=e.toLowerCase();for(let[r,o]of Object.entries(Me))if(t.includes(r))return o;return"\u{1F4E6}"}import{existsSync as Pe}from"node:fs";import{dirname as Be,join as De,resolve as oe}from"node:path";import{cwd as Le}from"node:process";function v(e=Le()){let t=oe(e),r=oe("/");for(;t!==r;){if(Pe(De(t,".flisk",re)))return t;let o=Be(t);if(o===t)break;t=o}return null}var O=null;function $e(){if(O)return O;let e=te;if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Invalid package.json: expected object");let t=e;return O={name:String(t.name??"@flisk-sh/flisk"),version:String(t.version??"0.0.0"),fullPackage:t},O}function Mt(){return $e().version}import{existsSync as ne}from"node:fs";import{delimiter as se,extname as ie,join as le}from"node:path";import{delimiter as Dt,extname as Ue}from"node:path";function C(){return process.platform==="win32"}function Ge(e){return e==="linux"?"linux":e==="darwin"?"darwin":e==="win32"?"windows":null}function Ve(e){return e==="x64"?"amd64":e==="arm64"?"arm64":null}function Ye(e,t){let r=Ge(e),o=Ve(t);if(!r||!o||r==="windows"&&o!=="amd64")return null;let n=`flisk-${r}-${o}`;return r==="windows"?`${n}.exe`:n}function Lt(){return Ye(process.platform,process.arch)}function $t(){return C()?"flisk.exe":"flisk"}function D(e,t=C()){return t?Ue(e)?[e]:[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e]}function A(e){let t=process.env.PATH??process.env.Path??"",r=C(),o=D(e,r);if(r&&!ie(e))for(let n of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let s=n.toLowerCase();s&&!o.includes(`${e}${s}`)&&o.push(`${e}${s}`)}for(let n of t.split(se))if(n)for(let s of o){let i=le(n,s);if(ne(i))return i}return null}function Kt(e){let t=process.env.PATH??process.env.Path??"",r=C(),o=D(e,r);if(r&&!ie(e))for(let i of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let a=i.toLowerCase();a&&!o.includes(`${e}${a}`)&&o.push(`${e}${a}`)}let n=[],s=new Set;for(let i of t.split(se))if(i)for(let a of o){let u=le(i,a);if(!ne(u))continue;let f=r?u.toLowerCase():u;s.has(f)||(s.add(f),n.push(u))}return n}import{execFileSync as Ke,execSync as He}from"node:child_process";var ce=1e4;function ae(){let e=!1;if(process.platform==="win32")try{return Ke(A("docker")??"docker",["ps"],{stdio:"ignore",timeout:ce,windowsHide:!0}),"running"}catch(t){return t.code==="ETIMEDOUT"?"unresponsive":"missing"}for(let t of["docker ps","colima status","podman ps"])try{return He(t,{stdio:"ignore",timeout:ce}),"running"}catch(r){r.code==="ETIMEDOUT"&&(e=!0)}return e?"unresponsive":"missing"}function w(e,t){return e[t]??0}function We(e,t){let r=Array.from({length:t.length+1},(o,n)=>n);for(let o=1;o<=e.length;o++){let n=[o];for(let s=1;s<=t.length;s++){let i=e[o-1]===t[s-1]?0:1;n[s]=Math.min(w(n,s-1)+1,w(r,s)+1,w(r,s-1)+i)}r=n}return w(r,t.length)}function Je(e,t){if(e.length!==t.length)return!1;for(let r=0;r<e.length-1;r++)if(e[r]!==t[r]&&e[r]===t[r+1]&&e[r+1]===t[r]&&e.slice(0,r)===t.slice(0,r)&&e.slice(r+2)===t.slice(r+2))return!0;return!1}function ue(e,t){if(e.length<2||t.length===0||t.includes(e))return;let r=e.toLowerCase(),o,n=Number.POSITIVE_INFINITY;for(let s of t){if(s.length===0)continue;let i=s.toLowerCase(),a=Je(r,i)?1:We(r,i),u=Math.max(1,Math.min(2,Math.floor(Math.max(r.length,i.length)/3)));a>u||(a<n||a===n&&(o===void 0||s<o))&&(o=s,n=a)}return o}import{spawn as ze}from"node:child_process";import{join as Xe}from"node:path";function qe(e,t=[],r={}){return new Promise((o,n)=>{let s=[e,...t];r.verbose&&console.log(`Executing: tilt ${s.join(" ")}`);let i=ze(A("tilt")??"tilt",s,{stdio:r.inheritStdio?"inherit":"pipe",shell:!1,windowsHide:process.platform==="win32",timeout:r.timeoutMs}),a="",u="";r.inheritStdio||(i.stdout?.on("data",f=>{a+=f.toString()}),i.stderr?.on("data",f=>{u+=f.toString()})),i.on("close",f=>{o({exitCode:f??1,stdout:a,stderr:u})}),i.on("error",f=>{n(new Error(`Failed to spawn tilt: ${f.message}`))})})}async function fe(){try{return(await qe("version",[],{inheritStdio:!1,timeoutMs:1e4})).exitCode===0}catch{return!1}}function Qe(){let e=v();if(!e)throw g.notInProject();return Xe(e,".flisk",".flisk-out","Tiltfile")}function de(e){let t=Qe();e.push("-f",t)}function rr(e,t={}){let r=[];return de(r),t.focusTargets&&t.focusTargets.length>0&&r.push("--",`--focus=${t.focusTargets.join(",")}`),r.push(...e),t.verbose&&!t.quiet&&r.push("--verbose"),t.watch&&r.push("--watch"),r}function or(e={}){let t=[];return de(t),e.focusTargets&&e.focusTargets.length>0&&t.push("--",`--focus=${e.focusTargets.join(",")}`),t}function pe(e){return e instanceof Error?e.message:String(e)}function fr(e,t){if(process.env.FLISK_VERBOSE){let r=t!==void 0?`: ${pe(t)}`:"";console.warn(h.gray(`${e}${r}`))}}var p=class extends Error{suggestions;exitCode;constructor(t,r=[],o=1){super(t),this.name="FliskError",this.suggestions=r,this.exitCode=o}display(){U(this.message,void 0,this.suggestions)}exit(){this.display(),process.exit(this.exitCode)}},$=class extends Error{code;constructor(t=1){super(`process.exit(${t})`),this.name="ProcessExitError",this.code=t}};function L(e,t,r=!1){let o=new Set;for(let n of e){let s=ue(n,t);s&&o.add(r?`Did you mean "${s}" for "${n}"?`:`Did you mean "${s}"?`)}return[...o]}var g={tiltNotInstalled:()=>new p("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: ${B}`]),dockerNotAvailable:()=>new p("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: ${B}`]),dockerNotResponding:()=>new p("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 p(`Stack "${e}" not found`,[...L([e],t),"Run `flisk stacks` to see available stacks","Run `flisk stack` to assign resources to a stack"]),resourceNotFound:(e,t=[])=>new p(`Resource "${e}" not found`,[...L([e],t),"Run `flisk resources` to list all resources","Check the resource name spelling"]),unknownServices:(e,t)=>{let r=L(e,t,e.length>1);return new p(`Unknown service ${e.join(", ")}. Valid names: ${t.join(", ")}`,r,2)},directoryExists:e=>new p(`Directory already exists: ${e}`,["Use `--path` to specify a different location","Remove the existing directory if no longer needed"]),invalidPath:e=>new p(`Invalid path: ${e}`,["Path must be within the project directory",'Path cannot contain special characters like <>:"|?*']),notInProject:()=>new p("Could not find project root (no .flisk/project.json found)",["Run this from within a Flisk project","Run `flisk project --yes` to initialize a new project"])};function dr(){let e=v();return e||g.notInProject().exit()}function Ze(e){e instanceof p&&e.exit(),U(pe(e)),process.exit(1)}async function et(e,t){try{return await e()}catch(r){if(r instanceof $)throw r;return t?.verbose&&r instanceof Error&&r.stack&&console.error(h.gray(r.stack)),Ze(r)}}async function pr(e,t){let r=[],o=ae();return o==="unresponsive"?r.push(g.dockerNotResponding()):o==="missing"&&r.push(g.dockerNotAvailable()),await fe()||r.push(g.tiltNotInstalled()),r.length>0&&(console.error(h.red(`
|
|
7
7
|
Flisk can't start - missing prerequisites:
|
|
8
8
|
`)),r.forEach((n,s)=>{s>0&&console.error(""),n.display()}),console.error(h.gray("\nRun `flisk doctor` for a full environment check.")),process.exit(1)),et(e,t)}function mr(e,t=1,r){U(e,void 0,r),process.exit(t)}function U(e,t,r){if(console.error(h.red(`\u274C ${e}`)),t&&console.error(h.gray(` ${t}`)),r&&r.length>0){console.error(h.yellow(`
|
|
9
9
|
\u{1F4A1} Suggestions:`));for(let o of r)console.error(h.cyan(` \u2192 ${o}`))}}function hr(e,t){console.error(h.red(`
|