infra-kit 0.13.0 → 0.15.0

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.
Files changed (41) hide show
  1. package/dist/{chunk-FKA65HOC.js → chunk-3UE375II.js} +2 -2
  2. package/dist/{chunk-FKA65HOC.js.map → chunk-3UE375II.js.map} +1 -1
  3. package/dist/chunk-4RZM53X7.js +7 -0
  4. package/dist/{chunk-EU7LD5IV.js.map → chunk-4RZM53X7.js.map} +3 -3
  5. package/dist/{chunk-VDBJ73LS.js → chunk-DVXTZPQ5.js} +1 -1
  6. package/dist/chunk-DVXTZPQ5.js.map +7 -0
  7. package/dist/{chunk-D76UWTR5.js → chunk-EZ4DIT5A.js} +3 -3
  8. package/dist/{chunk-D76UWTR5.js.map → chunk-EZ4DIT5A.js.map} +1 -1
  9. package/dist/chunk-I23MDR4X.js +5 -0
  10. package/dist/chunk-I23MDR4X.js.map +7 -0
  11. package/dist/{chunk-CMF7HEVU.js → chunk-IT6XJWTW.js} +2 -2
  12. package/dist/chunk-IT6XJWTW.js.map +7 -0
  13. package/dist/{chunk-BQPSXIH2.js → chunk-MH37P7W4.js} +2 -2
  14. package/dist/chunk-PP3ZZKB3.js +12 -0
  15. package/dist/chunk-PP3ZZKB3.js.map +7 -0
  16. package/dist/{chunk-Z4ZY2G4O.js → chunk-ZTAUGYJF.js} +2 -2
  17. package/dist/cli.js +117 -109
  18. package/dist/cli.js.map +4 -4
  19. package/dist/dev-server.js +21 -21
  20. package/dist/dev-server.js.map +3 -3
  21. package/dist/{dev-wizard-run-SHX5YW6J.js → dev-wizard-run-6PLC5YEW.js} +2 -2
  22. package/dist/env-load-NURS7WNH.js +2 -0
  23. package/dist/mcp-proxy.js +7 -7
  24. package/dist/mcp-proxy.js.map +3 -3
  25. package/dist/{persistent-ink-dev-ui-P65EJCC6.js → persistent-ink-dev-ui-ZSOS3CF4.js} +2 -2
  26. package/dist/update-check.js +1 -1
  27. package/package.json +3 -3
  28. package/readme.md +5 -2
  29. package/dist/chunk-CMF7HEVU.js.map +0 -7
  30. package/dist/chunk-EU7LD5IV.js +0 -7
  31. package/dist/chunk-LR57E6IP.js +0 -10
  32. package/dist/chunk-LR57E6IP.js.map +0 -7
  33. package/dist/chunk-QSTGO43H.js +0 -4
  34. package/dist/chunk-QSTGO43H.js.map +0 -7
  35. package/dist/chunk-VDBJ73LS.js.map +0 -7
  36. package/dist/env-load-EYVU4TIM.js +0 -2
  37. /package/dist/{chunk-BQPSXIH2.js.map → chunk-MH37P7W4.js.map} +0 -0
  38. /package/dist/{chunk-Z4ZY2G4O.js.map → chunk-ZTAUGYJF.js.map} +0 -0
  39. /package/dist/{dev-wizard-run-SHX5YW6J.js.map → dev-wizard-run-6PLC5YEW.js.map} +0 -0
  40. /package/dist/{env-load-EYVU4TIM.js.map → env-load-NURS7WNH.js.map} +0 -0
  41. /package/dist/{persistent-ink-dev-ui-P65EJCC6.js.map → persistent-ink-dev-ui-ZSOS3CF4.js.map} +0 -0
@@ -1,39 +1,39 @@
1
- import{a as Je,b as N,c as W,d as qe,e as G,g as L,h as Ye,l as Xe,n as Qe,r as Ze,s as et,t as tt,u as U,v as rt}from"./chunk-Z4ZY2G4O.js";import{a as O,b as H,c as _e,d as Fe,e as j,f as Be,g as I,h as Me,i as He,j as je,k as We,l as Ge,m as Ve,n as Ke}from"./chunk-Y3RW74TE.js";import{c as ie,k as se,n as Ce,o as Oe,u as Ie}from"./chunk-CMF7HEVU.js";import"./chunk-AWFGP6GY.js";import{P as T,X as Ue,ca as ae,d as Ne,fa as ze,i as oe,x as Le}from"./chunk-D76UWTR5.js";import"./chunk-MFAFQVTW.js";import"./chunk-FKA65HOC.js";import{c as Te,m as $e}from"./chunk-QSTGO43H.js";import{a as _,b as nt}from"./chunk-VDBJ73LS.js";import{Command as ri}from"commander";import k from"node:process";import{pathToFileURL as ni}from"node:url";import le from"node:process";var ue=n=>{try{le.stderr.write(n)}catch{}},F=(n,e,t=!0)=>{let r=e instanceof Error?`${e.message}
1
+ import{a as qe,b as N,c as j,d as Xe,e as W,g as L,h as Qe,l as Ze,n as et,r as tt,s as rt,t as nt,u as ae,v as it}from"./chunk-ZTAUGYJF.js";import{a as O,b as M,c as Be,d as Me,e as H,f as He,g as I,h as je,i as We,j as Ge,k as Ve,l as Ke,m as Je,n as ze}from"./chunk-Y3RW74TE.js";import{c as ne,k as ie,n as Ie,o as Ne,u as Le}from"./chunk-IT6XJWTW.js";import"./chunk-AWFGP6GY.js";import{P as T,Y as Fe,d as _e,da as oe,ga as Ye,i as se,x as Ue}from"./chunk-EZ4DIT5A.js";import"./chunk-MFAFQVTW.js";import"./chunk-3UE375II.js";import{d as $e,f as Ce,n as Oe}from"./chunk-I23MDR4X.js";import{a as _,b as st}from"./chunk-DVXTZPQ5.js";import{Command as ii}from"commander";import k from"node:process";import{pathToFileURL as si}from"node:url";import le from"node:process";var ue=n=>{try{le.stderr.write(n)}catch{}},U=(n,e,t=!0)=>{let r=e instanceof Error?`${e.message}
2
2
  ${e.stack??"(no stack)"}`:String(e);return`
3
3
  \u26A0\uFE0F ${n}: ${r}
4
4
  ${t?` dev-server kept alive (likely a bug in a handler's async path); restart if it misbehaves.
5
5
  `:` dev-server is shutting down: its stdio is unwritable, so reporting this fault would loop forever.
6
- `}`},hr=(n,e)=>{ue(F(n,e))},gr=(n,e)=>{ue(F(n,e,!1))},fr=n=>{ue(`
6
+ `}`},gr=(n,e)=>{ue(U(n,e))},fr=(n,e)=>{ue(U(n,e,!1))},mr=n=>{ue(`
7
7
  \u2717 dev-server exiting: ${n}
8
- `),N(),le.exit(1)},mr=(n,e)=>{le.on(n,e)},it=({onFault:n=hr,register:e=mr,isTerminalDead:t=()=>!1,fileFault:r=gr,onFatal:i=fr}={})=>{let s=!0,o=a=>l=>{if(!s){r(a,l);return}if(t()){r(a,l),i(`${a} while stdio is unwritable`);return}n(a,l)};return e("uncaughtException",o("uncaughtException")),e("unhandledRejection",o("unhandledRejection")),{disarm:()=>{s=!1}}};import{DEV_CONTEXT_WIRE_VERSION as An,DEV_SERVING_MARKER as qt,loadPackageConfig as Yt,readCloudOrigin as Xt,readLocalContext as Rn,slugifyHostLabel as er}from"@slip-stream-kit/config/internal";import En from"chokidar";import{exec as xn}from"node:child_process";import*as w from"node:fs";import Tn from"node:net";import tr from"node:os";import*as y from"node:path";import v from"node:process";import $n from"node:util";import{z as Se}from"zod";import{loadDev as vr}from"@slip-stream-kit/config/internal";var st=async(n,e,t)=>{let r=e.find(a=>a.name===n),i=t.find(a=>a.name===n);if(!r&&!i)return null;let s={},o=[];if(r&&(s[`${n}/api`]={}),i){let a={};for(let[l,u]of Object.entries((await vr(i.path))?.proxy?.routes??{})){if(!u.from.includes("local"))continue;let d=e.find(h=>h.packageName===u.packageName);if(!d){o.push(`${l} (${u.packageName})`);continue}s[`${d.name}/api`]={},a[l]="local"}s[`${n}/ui`]=Object.keys(a).length>0?{proxy:a}:{}}return{preset:{apps:s},unprovided:o}};import{createHash as yr}from"node:crypto";import*as A from"node:fs";import*as b from"node:path";var wr=n=>[n,b.join(n,"dist")].flatMap(e=>{try{return A.readdirSync(e).filter(t=>t.endsWith(".tsbuildinfo")).map(t=>b.join(e,t))}catch{return[]}}),V=n=>{let e;for(let t of wr(n))try{let{mtimeMs:r}=A.statSync(t);(!e||r>e.mtimeMs)&&(e={file:t,mtimeMs:r})}catch{}if(e)try{let t=JSON.parse(A.readFileSync(e.file,"utf8"));return{dir:b.dirname(e.file),mtimeMs:e.mtimeMs,data:t}}catch{return}},ot=(n,e)=>e.every(t=>{try{return A.statSync(t).mtimeMs<=n.mtimeMs}catch{return!0}}),br=n=>{let e=n.messageText;return typeof e=="string"?e:e?.messageText??""},at=(n,e)=>{let{data:t}=n,r=a=>{let l=t.fileNames?.[a-1];return l===void 0?void 0:b.relative(e,b.resolve(n.dir,l))},i=[],s=[];for(let a of[...t.semanticDiagnosticsPerFile??[],...t.emitDiagnosticsPerFile??[]]){if(typeof a=="number"){s.push({file:r(a),total:1});continue}let[l,u]=a;for(let d of u)i.push({file:r(l),detail:`TS${d.code} ${br(d)}`,total:1})}let o=[...i,...s];return o.length===0?t.errors===!0?{total:1}:void 0:{...o[0],total:o.length}},lt=(n,e)=>{let t=e.total>1?` (+${e.total-1} more)`:"";return e.file===void 0?`${n} has build errors (see the watch log)${t}`:e.detail===void 0?`${n} has errors: ${e.file} was not type-checked (syntax error)${t}`:`${n} has type errors: ${e.file} ${e.detail}${t}`},Sr="\uFEFF",Pr=n=>yr("sha256").update(n).digest("hex"),de=(n,e)=>{let t=n.data.fileNames??[],r=n.data.fileInfos??[],i=[];for(let[s,o]of t.entries()){let a=b.resolve(n.dir,o),l=b.relative(e,a);if(l.startsWith("..")||b.isAbsolute(l)||l.split(b.sep).includes("node_modules"))continue;let u=r[s],d=typeof u=="string"?u:u?.version;if(d===void 0)continue;let h;try{h=A.readFileSync(a,"utf8")}catch{continue}let f=Pr(h.startsWith(Sr)?h.slice(1):h);f!==d&&i.push({file:a,hash:f})}return i},pe=n=>{try{let{name:e}=JSON.parse(A.readFileSync(b.join(n,"package.json"),"utf8"));if(typeof e=="string"&&e!=="")return e}catch{}return b.basename(n)};import{execFile as Dr}from"node:child_process";import*as ut from"node:fs";import*as K from"node:path";import{promisify as kr}from"node:util";var Ar=kr(Dr),Rr=n=>{try{let e=JSON.parse(ut.readFileSync(K.join(n,"package.json"),"utf-8"));return typeof e.name=="string"?e.name:void 0}catch{return}},Er=n=>{let t=(JSON.parse(n).tasks??[]).map(r=>r.package).filter(r=>typeof r=="string");return[...new Set(t)]},xr=n=>async e=>{let{stdout:t}=await Ar("pnpm",["exec","turbo","run","build","--dry=json",`--filter=...${e}`],{cwd:n,maxBuffer:33554432});return Er(t)},Tr=n=>{let e=new Map,t=new Map;for(let r of I(n)){let i=Rr(K.dirname(r));i!==void 0&&(e.set(r,i),t.set(i,r))}return{packageNameByDir:e,dirByName:t}},dt=async(n,e,t=xr(n))=>{let{packageNameByDir:r,dirByName:i}=Tr(n),s=new Map,o=await Promise.all(e.map(async a=>({app:a,closure:await t(a.packageName)})));for(let{app:a,closure:l}of o)for(let u of l){let d=i.get(u);if(d===void 0)continue;let h=s.get(d)??new Set;h.add(a.name),s.set(d,h)}return{dependentsByPackageDir:s,packageNameByDir:r}},pt=(n,e,t)=>{if(e===null||t===void 0)return null;let r=e.dependentsByPackageDir.get(t)??new Set;return n.filter(i=>i.watchDeps&&r.has(i.name))};var $r="this run never launched it",Cr=n=>n.default??n.from[0]??"cloud",ct=(n,e)=>n.from.includes("local")&&e?.has(n.packageName)?"local":Cr(n),ht=n=>n.uis.flatMap(e=>Object.entries(e.routes).flatMap(([t,r])=>{let i=Or(e,t,r,n);return i?[i]:[]})),Or=(n,e,t,{wanted:r,running:i,reasons:s,held:o})=>{let{packageName:a}=t,l=r.has(a)||t.pinnedLocal===!0;if(!t.from.includes("local")||!l||i.has(a))return null;let u=ct(t,o),d=s.get(a),h=u==="cloud"?n.cloudUrl:void 0;return{uiApp:n.app,route:e,packageName:a,fallback:u,apiApp:d?.app,reason:d?.reason??$r,cloudTarget:h}},gt=n=>{let{uis:e,running:t,localOrigin:r,held:i}=n;return e.flatMap(s=>Object.entries(s.routes).sort(([o],[a])=>o.localeCompare(a)).map(([o,a])=>{let l=a.from.includes("local")&&t.has(a.packageName)?"local":ct(a,i),u=l==="local"?r(a.packageName):s.cloudUrl;return{uiApp:s.app,route:o,packageName:a.packageName,source:l,target:u}}))},Ir=n=>{if(n.fallback==="local")return`would proxy ${n.route} at the local alias for "${n.packageName}", which nothing is serving \u2014 every request will fail`;let e=n.cloudTarget??"the cloud backend";return`would proxy ${n.route} to ${e} instead of your local backend`},ft=n=>n.apiApp!=null,Nr=n=>ft(n)?`fix ${n.apiApp}/api and re-run (or drop --no-watch to retry it on the next save)`:`this run never launched "${n.packageName}" \u2014 drop the --app/--self narrowing, add its api to the preset, or set "${n.route}" to "cloud" if you meant to develop against cloud`,mt=(n,e)=>{let t=n.map(r=>{let i=ft(r)?`${r.apiApp}/api`:`"${r.packageName}"`;return` ${r.uiApp}/ui ${r.route} \u2192 ${r.packageName}: ${r.uiApp}/ui ${Ir(r)}.
8
+ `),N(),le.exit(1)},vr=(n,e)=>{le.on(n,e)},ot=({onFault:n=gr,register:e=vr,isTerminalDead:t=()=>!1,fileFault:r=fr,onFatal:i=mr}={})=>{let s=!0,o=a=>l=>{if(!s){r(a,l);return}if(t()){r(a,l),i(`${a} while stdio is unwritable`);return}n(a,l)};return e("uncaughtException",o("uncaughtException")),e("unhandledRejection",o("unhandledRejection")),{disarm:()=>{s=!1}}};import{DEV_CONTEXT_WIRE_VERSION as Rn,DEV_SERVING_MARKER as Xt,loadPackageConfig as Qt,readAppAliasName as Se,readCloudOrigin as Zt,readLocalContext as En}from"@slip-stream-kit/config/internal";import xn from"chokidar";import{exec as Tn}from"node:child_process";import*as w from"node:fs";import $n from"node:net";import rr from"node:os";import*as y from"node:path";import v from"node:process";import Cn from"node:util";import{z as Pe}from"zod";import{loadDev as yr}from"@slip-stream-kit/config/internal";var at=async(n,e,t)=>{let r=e.find(a=>a.name===n),i=t.find(a=>a.name===n);if(!r&&!i)return null;let s={},o=[];if(r&&(s[`${n}/api`]={}),i){let a={};for(let[l,u]of Object.entries((await yr(i.path))?.proxy?.routes??{})){if(!u.from.includes("local"))continue;let d=e.find(h=>h.packageName===u.packageName);if(!d){o.push(`${l} (${u.packageName})`);continue}s[`${d.name}/api`]={},a[l]="local"}s[`${n}/ui`]=Object.keys(a).length>0?{proxy:a}:{}}return{preset:{apps:s},unprovided:o}};import{createHash as wr}from"node:crypto";import*as A from"node:fs";import*as b from"node:path";var br=n=>[n,b.join(n,"dist")].flatMap(e=>{try{return A.readdirSync(e).filter(t=>t.endsWith(".tsbuildinfo")).map(t=>b.join(e,t))}catch{return[]}}),G=n=>{let e;for(let t of br(n))try{let{mtimeMs:r}=A.statSync(t);(!e||r>e.mtimeMs)&&(e={file:t,mtimeMs:r})}catch{}if(e)try{let t=JSON.parse(A.readFileSync(e.file,"utf8"));return{dir:b.dirname(e.file),mtimeMs:e.mtimeMs,data:t}}catch{return}},lt=(n,e)=>e.every(t=>{try{return A.statSync(t).mtimeMs<=n.mtimeMs}catch{return!0}}),Sr=n=>{let e=n.messageText;return typeof e=="string"?e:e?.messageText??""},ut=(n,e)=>{let{data:t}=n,r=a=>{let l=t.fileNames?.[a-1];return l===void 0?void 0:b.relative(e,b.resolve(n.dir,l))},i=[],s=[];for(let a of[...t.semanticDiagnosticsPerFile??[],...t.emitDiagnosticsPerFile??[]]){if(typeof a=="number"){s.push({file:r(a),total:1});continue}let[l,u]=a;for(let d of u)i.push({file:r(l),detail:`TS${d.code} ${Sr(d)}`,total:1})}let o=[...i,...s];return o.length===0?t.errors===!0?{total:1}:void 0:{...o[0],total:o.length}},dt=(n,e)=>{let t=e.total>1?` (+${e.total-1} more)`:"";return e.file===void 0?`${n} has build errors (see the watch log)${t}`:e.detail===void 0?`${n} has errors: ${e.file} was not type-checked (syntax error)${t}`:`${n} has type errors: ${e.file} ${e.detail}${t}`},Pr="\uFEFF",Dr=n=>wr("sha256").update(n).digest("hex"),de=(n,e)=>{let t=n.data.fileNames??[],r=n.data.fileInfos??[],i=[];for(let[s,o]of t.entries()){let a=b.resolve(n.dir,o),l=b.relative(e,a);if(l.startsWith("..")||b.isAbsolute(l)||l.split(b.sep).includes("node_modules"))continue;let u=r[s],d=typeof u=="string"?u:u?.version;if(d===void 0)continue;let h;try{h=A.readFileSync(a,"utf8")}catch{continue}let f=Dr(h.startsWith(Pr)?h.slice(1):h);f!==d&&i.push({file:a,hash:f})}return i},pe=n=>{try{let{name:e}=JSON.parse(A.readFileSync(b.join(n,"package.json"),"utf8"));if(typeof e=="string"&&e!=="")return e}catch{}return b.basename(n)};import{execFile as kr}from"node:child_process";import*as pt from"node:fs";import*as V from"node:path";import{promisify as Ar}from"node:util";var Rr=Ar(kr),Er=n=>{try{let e=JSON.parse(pt.readFileSync(V.join(n,"package.json"),"utf-8"));return typeof e.name=="string"?e.name:void 0}catch{return}},xr=n=>{let t=(JSON.parse(n).tasks??[]).map(r=>r.package).filter(r=>typeof r=="string");return[...new Set(t)]},Tr=n=>async e=>{let{stdout:t}=await Rr("pnpm",["exec","turbo","run","build","--dry=json",`--filter=...${e}`],{cwd:n,maxBuffer:33554432});return xr(t)},$r=n=>{let e=new Map,t=new Map;for(let r of I(n)){let i=Er(V.dirname(r));i!==void 0&&(e.set(r,i),t.set(i,r))}return{packageNameByDir:e,dirByName:t}},ct=async(n,e,t=Tr(n))=>{let{packageNameByDir:r,dirByName:i}=$r(n),s=new Map,o=await Promise.all(e.map(async a=>({app:a,closure:await t(a.packageName)})));for(let{app:a,closure:l}of o)for(let u of l){let d=i.get(u);if(d===void 0)continue;let h=s.get(d)??new Set;h.add(a.name),s.set(d,h)}return{dependentsByPackageDir:s,packageNameByDir:r}},ht=(n,e,t)=>{if(e===null||t===void 0)return null;let r=e.dependentsByPackageDir.get(t)??new Set;return n.filter(i=>i.watchDeps&&r.has(i.name))};var Cr="this run never launched it",Or=n=>n.default??n.from[0]??"cloud",gt=(n,e)=>n.from.includes("local")&&e?.has(n.packageName)?"local":Or(n),ft=n=>n.uis.flatMap(e=>Object.entries(e.routes).flatMap(([t,r])=>{let i=Ir(e,t,r,n);return i?[i]:[]})),Ir=(n,e,t,{wanted:r,running:i,reasons:s,held:o})=>{let{packageName:a}=t,l=r.has(a)||t.pinnedLocal===!0;if(!t.from.includes("local")||!l||i.has(a))return null;let u=gt(t,o),d=s.get(a),h=u==="cloud"?n.cloudUrl:void 0;return{uiApp:n.app,route:e,packageName:a,fallback:u,apiApp:d?.app,reason:d?.reason??Cr,cloudTarget:h}},mt=n=>{let{uis:e,running:t,localOrigin:r,held:i}=n;return e.flatMap(s=>Object.entries(s.routes).sort(([o],[a])=>o.localeCompare(a)).map(([o,a])=>{let l=a.from.includes("local")&&t.has(a.packageName)?"local":gt(a,i),u=l==="local"?r(a.packageName):s.cloudUrl;return{uiApp:s.app,route:o,packageName:a.packageName,source:l,target:u}}))},Nr=n=>{if(n.fallback==="local")return`would proxy ${n.route} at the local alias for "${n.packageName}", which nothing is serving \u2014 every request will fail`;let e=n.cloudTarget??"the cloud backend";return`would proxy ${n.route} to ${e} instead of your local backend`},vt=n=>n.apiApp!=null,Lr=n=>vt(n)?`fix ${n.apiApp}/api and re-run (or drop --no-watch to retry it on the next save)`:`this run never launched "${n.packageName}" \u2014 drop the --app/--self narrowing, add its api to the preset, or set "${n.route}" to "cloud" if you meant to develop against cloud`,yt=(n,e)=>{let t=n.map(r=>{let i=vt(r)?`${r.apiApp}/api`:`"${r.packageName}"`;return` ${r.uiApp}/ui ${r.route} \u2192 ${r.packageName}: ${r.uiApp}/ui ${Nr(r)}.
9
9
  ${i}: ${r.reason}
10
- \u2192 ${Nr(r)}`});return`infra-kit dev: "${e}" is supposed to serve a backend locally, but it is not running \u2014 refusing to bring the frontend up silently pointed somewhere else.
10
+ \u2192 ${Lr(r)}`});return`infra-kit dev: "${e}" is supposed to serve a backend locally, but it is not running \u2014 refusing to bring the frontend up silently pointed somewhere else.
11
11
 
12
12
  ${t.join(`
13
13
 
14
- `)}`};import{AsyncLocalStorage as Lr}from"node:async_hooks";var ce=new Lr,vt=(n,e)=>ce.run(n,e),yt=n=>{ce.enterWith(n)},J=()=>ce.getStore();import{Buffer as St}from"node:buffer";import D from"node:fs";import $ from"node:path";import x from"node:process";import q from"node:process";var Ur=new Set(["EAGAIN","EINTR"]),z=!1,wt=()=>z,_r=(n,e)=>n===q.stdout?"stdout":n===q.stderr||e===1?"stderr":"stdout",bt=({streams:n=[q.stdout,q.stderr],onDeath:e}={})=>{let t=!1,r=[];for(let[i,s]of n.entries()){let o=_r(s,i),a=l=>{let u=l??new Error("stdio error");u.code!=null&&Ur.has(u.code)||(z=!0,!t&&(t=!0,e?.(o,u)))};s.on("error",a),r.push({stream:s,listener:a})}return{isDead:()=>z,uninstall:()=>{for(let{stream:i,listener:s}of r)i.removeListener("error",s);r.length=0,z=!1,t=!1}}};var Fr=()=>Object.getPrototypeOf(x.stdout).write,he=n=>wt()?!0:Fr().call(x.stdout,n);var kt=()=>new Proxy(x.stdout,{get(n,e,t){if(e==="write")return i=>he(String(i));let r=Reflect.get(n,e,t);return typeof r=="function"?r.bind(n):r}}),Pt=()=>({errors:0,warns:0,lastErrorAt:null}),At=n=>{let e=n.split(/\W+/).filter(t=>t!=="").join("-");return e===""?null:e},Br=()=>{let n=x.env[Te]??"",e=At(n)??"no-session";return $.join($e(),e,"dev",String(x.pid))},Dt=n=>`${At(n)??"unnamed"}.log`,Mr=10080*60*1e3,Hr=n=>{let e=Number(n);if(!Number.isInteger(e)||e<=0)return!1;try{return x.kill(e,0),!0}catch(t){return t.code==="EPERM"}},jr=(n,e)=>{let t;try{t=D.readdirSync(n,{withFileTypes:!0})}catch{return}for(let r of t){if(!r.isDirectory()||Hr(r.name))continue;let i=$.join(n,r.name);try{e-D.statSync(i).mtimeMs>Mr&&D.rmSync(i,{recursive:!0,force:!0})}catch{}}},Wr=256*1024*1024,Gr="INFRA_KIT_DEV_LOG_MAX_BYTES",Vr=()=>{let n=Number(x.env[Gr]);return Number.isInteger(n)&&n>0?n:Wr},Y=class{dir;fds=new Map;counters=new Map;bytes=new Map;capped=new Set;maxBytes;closed=!1;constructor(e=Br(),t=Vr()){this.dir=e,this.maxBytes=t,D.mkdirSync(this.dir,{recursive:!0}),jr($.dirname(this.dir),Date.now()),this.linkLatest()}linkLatest(){let e=$.join($.dirname(this.dir),"latest");try{D.rmSync(e,{force:!0}),D.symlinkSync(this.dir,e,"dir")}catch{}}pathFor(e){return $.join(this.dir,Dt(e))}fdFor(e){let t=this.fds.get(e);if(t!=null)return t;try{let r=D.openSync(this.pathFor(e),"a");this.fds.set(e,r);try{this.bytes.set(e,D.fstatSync(r).size)}catch{this.bytes.set(e,0)}return r}catch{return null}}write(e,t,r={}){if(this.closed)return;let i=this.counters.get(e)??Pt();if(r.level==="error"?(i.errors+=1,i.lastErrorAt=Date.now()):r.level==="warn"&&(i.warns+=1),this.counters.set(e,i),this.capped.has(e))return;let s=this.fdFor(e);if(s==null)return;let o=t.endsWith(`
14
+ `)}`};import{AsyncLocalStorage as _r}from"node:async_hooks";var ce=new _r,wt=(n,e)=>ce.run(n,e),bt=n=>{ce.enterWith(n)},K=()=>ce.getStore();import{Buffer as Dt}from"node:buffer";import D from"node:fs";import $ from"node:path";import x from"node:process";import z from"node:process";var Ur=new Set(["EAGAIN","EINTR"]),J=!1,St=()=>J,Fr=(n,e)=>n===z.stdout?"stdout":n===z.stderr||e===1?"stderr":"stdout",Pt=({streams:n=[z.stdout,z.stderr],onDeath:e}={})=>{let t=!1,r=[];for(let[i,s]of n.entries()){let o=Fr(s,i),a=l=>{let u=l??new Error("stdio error");u.code!=null&&Ur.has(u.code)||(J=!0,!t&&(t=!0,e?.(o,u)))};s.on("error",a),r.push({stream:s,listener:a})}return{isDead:()=>J,uninstall:()=>{for(let{stream:i,listener:s}of r)i.removeListener("error",s);r.length=0,J=!1,t=!1}}};var Br=()=>Object.getPrototypeOf(x.stdout).write,he=n=>St()?!0:Br().call(x.stdout,n);var Rt=()=>new Proxy(x.stdout,{get(n,e,t){if(e==="write")return i=>he(String(i));let r=Reflect.get(n,e,t);return typeof r=="function"?r.bind(n):r}}),kt=()=>({errors:0,warns:0,lastErrorAt:null}),Et=n=>{let e=n.split(/\W+/).filter(t=>t!=="").join("-");return e===""?null:e},Mr=()=>{let n=x.env[$e]??"",e=Et(n)??"no-session";return $.join(Oe(),e,"dev",String(x.pid))},At=n=>`${Et(n)??"unnamed"}.log`,Hr=10080*60*1e3,jr=n=>{let e=Number(n);if(!Number.isInteger(e)||e<=0)return!1;try{return x.kill(e,0),!0}catch(t){return t.code==="EPERM"}},Wr=(n,e)=>{let t;try{t=D.readdirSync(n,{withFileTypes:!0})}catch{return}for(let r of t){if(!r.isDirectory()||jr(r.name))continue;let i=$.join(n,r.name);try{e-D.statSync(i).mtimeMs>Hr&&D.rmSync(i,{recursive:!0,force:!0})}catch{}}},Gr=256*1024*1024,Vr="INFRA_KIT_DEV_LOG_MAX_BYTES",Kr=()=>{let n=Number(x.env[Vr]);return Number.isInteger(n)&&n>0?n:Gr},q=class{dir;fds=new Map;counters=new Map;bytes=new Map;capped=new Set;maxBytes;closed=!1;constructor(e=Mr(),t=Kr()){this.dir=e,this.maxBytes=t,D.mkdirSync(this.dir,{recursive:!0}),Wr($.dirname(this.dir),Date.now()),this.linkLatest()}linkLatest(){let e=$.join($.dirname(this.dir),"latest");try{D.rmSync(e,{force:!0}),D.symlinkSync(this.dir,e,"dir")}catch{}}pathFor(e){return $.join(this.dir,At(e))}fdFor(e){let t=this.fds.get(e);if(t!=null)return t;try{let r=D.openSync(this.pathFor(e),"a");this.fds.set(e,r);try{this.bytes.set(e,D.fstatSync(r).size)}catch{this.bytes.set(e,0)}return r}catch{return null}}write(e,t,r={}){if(this.closed)return;let i=this.counters.get(e)??kt();if(r.level==="error"?(i.errors+=1,i.lastErrorAt=Date.now()):r.level==="warn"&&(i.warns+=1),this.counters.set(e,i),this.capped.has(e))return;let s=this.fdFor(e);if(s==null)return;let o=t.endsWith(`
15
15
  `)?t:`${t}
16
- `,a=St.byteLength(o);if((this.bytes.get(e)??0)+a>this.maxBytes){this.capped.add(e),this.writeRaw(s,e,`[capped] ${Dt(e)} hit ${this.maxBytes} bytes; further lines dropped (likely a logging loop)
17
- `);return}this.writeRaw(s,e,o)}writeRaw(e,t,r){try{D.writeSync(e,r),this.bytes.set(t,(this.bytes.get(t)??0)+St.byteLength(r))}catch{}}statsFor(e){return this.counters.get(e)??Pt()}close(){if(!this.closed){this.closed=!0;for(let e of this.fds.values())try{D.closeSync(e)}catch{}this.fds.clear()}}};import*as Tt from"node:fs";import Kr from"node:module";import*as C from"node:path";import Jr from"node:process";import{fileURLToPath as $t}from"node:url";var zr="ikgen",ge=2e9,Rt=null,Et=!1,xt=new Map,me=n=>{let e=xt.get(n);if(e!==void 0)return e;try{let t=Tt.realpathSync(n);return xt.set(n,t),t}catch{return null}},fe=(n,e)=>n===e||n.startsWith(e+C.sep),qr=(n,e)=>{if(!n.startsWith("file:"))return null;let t;try{t=$t(n)}catch{return null}let r=me(t);if(r===null||!fe(r,e.root)||r.includes(`${C.sep}node_modules${C.sep}`)||fe(r,e.selfDist))return null;e.busted.add(r);let i=new URL(n);return i.searchParams.set(zr,String(e.generation)),i.href},Ct=()=>Kr.registerHooks,Ot=()=>typeof Ct()=="function",ve=n=>{if(n==="0"||n?.toLowerCase()==="off")return{stopEnabled:!1,stopBytes:ge};let e=Number(n);return Number.isInteger(e)&&e>0?{stopEnabled:!0,stopBytes:e}:{stopEnabled:!0,stopBytes:ge}},It=()=>{let n=C.dirname($t(import.meta.url));return me(n)??n},Nt=n=>{let e=Ct();if(typeof e!="function")return null;let t={busted:new Set,generation:0,root:n.root,selfDist:n.selfDist},r=n.stopBytes??ge,i=n.stopEnabled??!0,s=r/2,o=n.warnStrideBytes??r/8,a=n.sampleRss??(()=>Jr.memoryUsage.rss()),l=0,u=0;return Rt=t,Et||(Et=!0,e({resolve:(d,h,f)=>{let p=f(d,h),g=Rt;if(g===null)return p;let m=qr(p.url,g);return m===null?p:{...p,url:m}}})),{bump:()=>(t.generation+=1,t.busted=new Set,t.generation),budgetState:()=>{let d=a();if(i&&d>r){if(l+=1,l>=2)return"stop"}else l=0;return d>=s&&d>=u+o?(u=d,"warn"):"ok"},bustedUnder:d=>{let h=me(d)??d;for(let f of t.busted)if(fe(f,h))return!0;return!1},generation:()=>t.generation}};import ye from"node:process";import Yr from"node:util";var we={log:"info",info:"info",debug:"debug",trace:"debug",warn:"warn",error:"error"},Lt=({sink:n,fallbackService:e,currentService:t})=>{let r=!0,i=()=>t()??e,s=(d,h)=>{n.write(i(),d,{level:h})},o={};for(let d of Object.keys(we))o[d]=console[d],console[d]=(...h)=>{if(!r){o[d](...h);return}s(Yr.format(...h),we[d])};let a=(d,h)=>{let f=d.write.bind(d),p="",g=()=>{p!==""&&(n.write(i(),p,{level:h}),p="")};return d.write=((m,...P)=>{if(!r||typeof m!="string")return f(m,...P);p+=m;let c=p.split(`
18
- `);p=c.pop()??"";for(let E of c)E!==""&&n.write(i(),E,{level:h});p.length>8192&&g();let S=P.find(E=>typeof E=="function");return typeof S=="function"&&ye.nextTick(S),!0}),()=>{g(),Reflect.deleteProperty(d,"write")}},l=a(ye.stdout,"info"),u=a(ye.stderr,"warn");return{uninstall:()=>{if(r){r=!1,l(),u();for(let d of Object.keys(we))console[d]=o[d]}}}};var Xr="/api/v1";function Ut(n){if(n==null||n==="")return;let e=parseInt(n.trim().replace(/^["']|["']$/g,""),10);return Number.isNaN(e)?void 0:e}function _t(n,e,t,r=!0){let s=`${n.replace(/-/g,"_").toUpperCase()}_PORT`,o=Ut(e[s]);if(o!=null)return o;if(r){let a=Ut(e.PORT);if(a!=null)return a}return t[n]?.port??void 0}function Ft(n,e){return e[n]?.prefixUrl??Xr}function Bt(n){let e=n.map(i=>i.port),t=e.filter((i,s)=>e.indexOf(i)!==s),r=n.filter(i=>t.includes(i.port));return{duplicatePorts:t,conflictingApps:r}}import*as X from"node:fs";import*as R from"node:path";import{parse as Qr}from"yaml";var Mt=new Map;var Zr=(n,e)=>{let t=new Set,r;try{r=Qr(X.readFileSync(n,"utf8"))}catch{return t}for(let i of Object.values(r?.functions??{})){let s=i?.handler;if(typeof s!="string")continue;let o=s.split(".")[0]??"";o!==""&&t.add(R.normalize(R.join(e,`${o}.js`)))}return t},en=n=>{let e=R.join(n,"serverless.yml"),t;try{t=X.statSync(e).mtimeMs}catch{return new Set}let r=Mt.get(n);if(r&&r.mtimeMs===t)return r.entries;let i=Zr(e,n);return Mt.set(n,{entries:i,mtimeMs:t}),i},Ht=(n,e)=>en(e).has(R.normalize(n)),tn=2,jt=n=>{let e=n.slice(0,tn).map(r=>R.basename(r)),t=n.length-e.length;return t>0?`${e.join(", ")} (+${t} more)`:e.join(", ")};import{Logger as rn}from"@aws-lambda-powertools/logger";import nn from"fastify";import*as Gt from"node:fs";import*as B from"node:path";import be from"node:process";import{pathToFileURL as sn}from"node:url";import{parse as on}from"yaml";var an=n=>n?.code==="EADDRINUSE",ln=3e4,un=()=>{let n=Number.parseInt(be.env.DEV_SERVER_TIMEOUT_MS??"",10);return Number.isNaN(n)?ln:n},Wt=()=>be.env.DEV_SERVER_REQUEST_LOG==="1",Q=class{constructor(e){this.serverConfig=e;this.importCacheBust=`${Date.now()}`,this.logger=new rn({serviceName:"LocalServer",logLevel:"DEBUG"}),this.serverConfig.prefixUrl=this.serverConfig.prefixUrl??"",this.server=nn({logger:!1}),this.server.addHook("onRequest",async(r,i)=>{let s=this.serverConfig.serviceTag;s!=null&&yt(s),i.header("Access-Control-Allow-Origin","*"),i.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),i.header("Access-Control-Allow-Headers","Content-Type, Authorization, X-Requested-With"),r.method==="OPTIONS"&&i.status(204).send()});let t=this.serverConfig.onRequestLog;(Wt()||t)&&this.server.addHook("onResponse",async(r,i)=>{let s=Math.round(i.elapsedTime),o=r.url.split("?")[0]??r.url;t?.({method:r.method,path:o,status:i.statusCode,ms:s}),Wt()&&be.stdout.write(`${r.method} ${r.url} \u2192 ${i.statusCode} ${s}ms
19
- `)})}serverConfig;importCacheBust;logger;server;controllers={};registeredRouteKeys=new Set;getRegisteredRoutes(){return[...this.registeredRouteKeys].sort()}async start(){this.registerHealthRoute(),await Promise.all(this.loadRoutes());let e=await this.listenWithFallback();return this.serverConfig.port=e,this.logger.info(`Server listening on http://127.0.0.1:${e}`,{address:`http://127.0.0.1:${e}`}),e}async listenWithFallback(){let e=this.serverConfig.port;if(e!=null)try{return await this.server.listen({port:e,host:"127.0.0.1"}),this.readBoundPort()}catch(t){if(!an(t))throw t}return await this.server.listen({port:0,host:"127.0.0.1"}),this.readBoundPort()}readBoundPort(){let e=this.server.server.address();if(e==null||typeof e=="string")throw new Error("Server address unavailable after listen()");return e.port}async close(){let e=this.server.server;typeof e.closeAllConnections=="function"&&e.closeAllConnections(),await this.server.close()}registerHealthRoute(){this.server.route({method:"GET",url:"/__health",handler:(e,t)=>t.code(200).send({status:"ok",app:this.serverConfig.appName??null,port:this.serverConfig.port})})}loadRoutes(){let e=B.join(this.serverConfig.controllersPath,"serverless.yml"),t=Gt.readFileSync(e,"utf8"),r=on(t),i=[];if(!r?.functions)return i;for(let s of Object.values(r.functions))if(s?.events?.length)for(let o of s.events){let a=o?.http;a&&i.push(this.defineRoute(a,s))}return i}async defineRoute(e,t){let r=e.path.toString();r=r.replaceAll("{",":").replaceAll("}","");let i=B.posix.join(this.serverConfig.prefixUrl??"",r);i=i[0]==="/"?i:`/${i}`;let s=["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"],o=String(e.method).toUpperCase();if(!s.includes(o))throw new Error(`Invalid HTTP method: "${e.method}" for URL: ${i}`);let a=`${o} ${i}`;if(this.registeredRouteKeys.has(a))throw new Error(`Duplicate route: ${a}`);this.registeredRouteKeys.add(a);let u=(t.handler??"").split("."),d=u[0]??"",h=u[1]??"",f=B.join(this.serverConfig.controllersPath,`${d}.js`),p=sn(f);p.searchParams.set("v",this.importCacheBust);let g=this.serverConfig.serviceTag,m=async()=>await import(p.href),P=g==null?await m():await vt(g,m);this.controllers[a]={action:P,handler:h};let c=this.logger.createChild({serviceName:"RequestLogger"});this.server.route({method:o,url:i,handler:async(S,E)=>{let M=this.controllers[a];if(!M)throw new Error(`No controller for ${a}`);let xe=M.action[M.handler];if(!xe)throw new Error(`No handler ${M.handler} for ${i}`);let ne=await xe(this.getEventObj(S.body,S.query,S.params,S.headers,o,i),this.getContext(),c),cr=JSON.parse(ne.body);return E.headers(ne.headers??{}),E.code(ne?.statusCode??500).send(cr)}})}getEventObj(e,t,r,i,s="",o=""){let a={body:e?JSON.stringify(e):null,headers:i??{},multiValueHeaders:{},httpMethod:s,isBase64Encoded:!1,path:o,pathParameters:r??null,queryStringParameters:t??null,multiValueQueryStringParameters:null,stageVariables:null,requestContext:{accountId:"",apiId:"",authorizer:void 0,protocol:"",httpMethod:s,identity:{accessKey:null,accountId:null,apiKey:null,apiKeyId:null,caller:null,clientCert:null,cognitoAuthenticationProvider:null,cognitoAuthenticationType:null,cognitoIdentityId:null,cognitoIdentityPoolId:null,principalOrgId:null,sourceIp:"devIp",user:null,userAgent:null,userArn:null},path:o,stage:"",requestId:"",requestTimeEpoch:0,resourceId:"",resourcePath:o},resource:o};return a.source="aws.events",a}getContext(){let e=Date.now(),t=un(),r=new Date().toISOString().split("T")[0]??"";return{callbackWaitsForEmptyEventLoop:!1,functionName:"local-dev",functionVersion:"1.0.0",invokedFunctionArn:"arn:aws:lambda:local:000000000000:function:local-dev",memoryLimitInMB:"1024",awsRequestId:`local-${Date.now()}`,logGroupName:"/aws/lambda/local-dev",logStreamName:`${r}/local`,getRemainingTimeInMillis:()=>Math.max(0,t-(Date.now()-e)),done:(i,s)=>{},fail:i=>{},succeed:i=>{}}}};import{spawn as dn}from"node:child_process";import*as Z from"node:fs";var pn=(n,e)=>[...n.map(t=>`--filter=...${t}`),...e.map(t=>`--filter=${t}^...`)],Vt=({depInclusive:n,depClosure:e,cwd:t,logFile:r,onUnexpectedExit:i,openLog:s})=>{let o=pn(n,e),a=s?s(r):Z.openSync(r,"a"),l=dn("pnpm",["exec","turbo","watch","build",...o,"--continue=dependencies-successful","--env-mode=loose","--log-order=stream"],{cwd:t,detached:!0,stdio:["ignore",a,a]});return Z.closeSync(a),W(l,void 0,i)};import{spawn as cn}from"node:child_process";import hn from"node:process";var gn=[/^error\b/i,/^[✘✖×]/,/^\[vite\][^\n]*\berror\b/i,/^\w*Error: /,/\berror TS\d+\b/,/^Failed to (?:resolve|load url|parse|compile)\b/i,/^(?:ENOENT|EADDRINUSE|ECONNREFUSED)\b/,/pre-transform error/i,/\b(?:build|transform|compilation) failed\b/i],fn=n=>gn.some(e=>e.test(n))?"error":"info",mn=/\u001B\][\s\S]*?(?:\u0007|\u001B\\)/g,vn=/\u001B\[[0-9;?]*[\u0020-\u002F]*[\u0040-\u007E]/g,yn=/[\u0000-\u0008\u000B-\u001F\u007F]/g,Jt=n=>n.replace(mn,"").replace(vn,"").replace(yn,""),wn=/^([^\s:]+):dev:[ \t]?/,bn=/^([^\s#]+)#dev:\s+(?:WARNING|ERROR)\s+command\b/,Sn=n=>bn.exec(Jt(n).trimEnd())?.[1]??null,Pn=n=>/^cache (?:bypass|hit|miss)/.test(n)||n.startsWith("$ "),Dn=n=>{let e=Jt(n).trimEnd(),t=wn.exec(e);if(t==null)return null;let r=e.slice(t[0].length);return r.trim()===""||Pn(r.trim())?null:{pkg:t[1],text:r,level:fn(r)}},kn=64*1024,Kt=(n,e)=>{if(n==null)return;let t="",r=i=>{let s=Sn(i);if(s!=null){e.onTaskFailure?.(s);return}let o=Dn(i);o!=null&&e.onLine?.(o)};n.setEncoding("utf-8"),n.on("data",i=>{e.appendLog?.(i),t+=i;let s=t.split(`
20
- `);t=s.pop()??"";for(let o of s)r(o);t.length>kn&&(r(t),t="")}),n.on("end",()=>{t!==""&&(r(t),t="")}),n.on("error",i=>{e.appendLog?.(`[infra-kit] ui dev stream error: ${i.message}
21
- `)})},zt=({packageNames:n,cwd:e,concurrency:t,env:r,appendLog:i,onLine:s,onTaskFailure:o,onUnexpectedExit:a})=>{let l=n.map(d=>`--filter=${d}`),u=cn("pnpm",["exec","turbo","run","dev",...l,`--concurrency=${t}`,"--env-mode=loose","--only","--continue=dependencies-successful","--output-logs=new-only","--log-order=stream","--no-update-notifier","--ui=stream"],{cwd:e,detached:!0,stdio:["ignore","pipe","pipe"],env:{...hn.env,...r}});return Kt(u.stdout,{appendLog:i,onLine:s,onTaskFailure:o}),Kt(u.stderr,{appendLog:i,onLine:s,onTaskFailure:o}),W(u,void 0,a)};var te="runner",Cn="turbo",On="watch",Pe=n=>`${Math.round(n/1e6)} MB`;function ee(n){let e=tr.homedir();return n===e||n.startsWith(`${e}${y.sep}`)?`~${n.slice(e.length)}`:n}function Qt(n){return n.map(e=>e.packageName).join(", ")}var In=$n.promisify(xn);var Nn=async(n,e)=>{try{let{stderr:t}=await In(n,{maxBuffer:33554432});t&&e&&e(` (build) ${t.trim()}`,"debug"),t&&!e&&console.error("stderr:",t)}catch(t){let r=t;throw e&&(r.stdout||r.stderr)&&(r.stdout&&e(` stdout: ${r.stdout.trim()}`,"error"),r.stderr&&e(` stderr: ${r.stderr.trim()}`,"error")),t}},re=null;function rr(n){re?.write(te,n)}var Ln=()=>new Promise((n,e)=>{let t=Tn.createServer();t.unref(),t.on("error",e),t.listen(0,"127.0.0.1",()=>{let r=t.address(),i=typeof r=="object"&&r!==null?r.port:0;t.close(()=>n(i))})}),Un=[{name:"@slip-stream-kit/vite",floor:"0.1.134"},{name:"@slip-stream-kit/config",floor:"0.1.134"},{name:"infra-kit",floor:"0.1.132"}],_n=(n,e)=>{let t=s=>s.split(".").map(o=>Number.parseInt(o,10)||0),r=t(n),i=t(e);for(let s=0;s<Math.max(r.length,i.length);s+=1){let o=r[s]??0,a=i[s]??0;if(o!==a)return o<a}return!1},Fn=n=>{let e=[n];try{for(let t of w.readdirSync(y.join(n,"apps"),{withFileTypes:!0}))if(t.isDirectory())for(let r of["api","ui"])e.push(y.join(n,"apps",t.name,r))}catch{}return e},Bn=(n,e)=>{try{let t=JSON.parse(w.readFileSync(y.join(n,"package.json"),"utf-8"));return["dependencies","devDependencies"].some(r=>t[r]?.[e]!=null)}catch{return!1}},Mn=(n,e,t)=>{let r=t.split("/"),i=e;for(;;){let s=y.join(i,"node_modules",...r);if(w.existsSync(s))return s;let o=y.dirname(i);if(i===n||o===i)return;i=o}},Hn=(n,e)=>{try{let t=w.realpathSync(e),r=w.realpathSync(n);return t.startsWith(r+y.sep)&&!t.includes(`${y.sep}node_modules${y.sep}`)}catch{return!1}},jn=n=>{try{return w.realpathSync(n)}catch{return n}},Wn=(n,e,t,r)=>{if(Hn(n,r))return;let i;try{let s=JSON.parse(w.readFileSync(y.join(r,"package.json"),"utf-8"));if(typeof s.version!="string")throw new Error("no version field");i=s.version}catch{throw new Error(`infra-kit dev: could not read the version of the pinned \`${e}\` helper (${r}). Refusing to start rather than risk proxying plain HTTP at a TLS listener. Run \`pnpm install\`.`)}if(_n(i,t))throw new Error(`infra-kit dev: this repo pins ${e} ${i}, but dev URLs are now HTTPS and the \`infraKitDev\` helper only understands them from ${t}. An older helper would proxy plain HTTP at a TLS listener \u2014 silently. Bump the dependency:
22
- pnpm add -D ${e}@^${t}`)},Gn=n=>{let e=Fn(n);for(let{name:t,floor:r}of Un){let i=e.filter(o=>Bn(o,t)),s=new Map;for(let o of[...i,n]){let a=Mn(n,o,t);a&&s.set(jn(a),a)}if(s.size===0){if(i.length===0)continue;throw new Error(`infra-kit dev: ${i[0]}/package.json depends on ${t} but it does not resolve from there, so the \`infraKitDev\` helper version cannot be verified. Run \`pnpm install\`.`)}for(let o of s.values())Wn(n,t,r,o)}},Zt=(n,e)=>{let t=er(n);if(t==="")throw new Error(`infra-kit dev: package name "${n}" has no letters or digits to build a hostname from.`);return`${U(e)}.${t}`},Vn=n=>{let t=(n instanceof Error?n.message:String(n)).split(`
23
- `)[0]?.trim()??"";return t===""?"unknown error (see the log)":t},De=class n{monorepoRoot;devContextDir;appServers=[];reqTimes=new Map;lastSummary=null;readyAt=0;watchDebounceTimers=new Map;pendingChanges=new Map;moduleGeneration=null;watcher=null;static WATCH_DEBOUNCE_MS=400;watchedDistDirs=[];nudgedStaleness=new Map;static STALE_BUILD_GRACE_MS=1e3;restartWorkChain=Promise.resolve();static PORT_RELEASE_DELAY_MS=200;livenessTimer=null;reusing=!1;keepAlive=null;servingAnnounced=!1;targetLabel="";health=new Map;firstErrorLogged=new Set;uiTagByPackage=new Map;static LIVENESS_INTERVAL_MS=5e3;static LIVENESS_FAILURE_THRESHOLD=2;static NEVER_UP_DOWN_THRESHOLD=6;options;runBuild;turboWatchFactory;turboWatch=null;uiDevFactory;uiDev=null;sink;intercept;dryRunner;failedApps=[];degradedRoutes=[];heldLocalPkgs=new Set;launchedUis=[];proxyRoutes=[];renderer;healthProbe;proxy;proxyPort=Ue;registeredAliases=new Set;uiPortMap={};shuttingDown=!1;closureMap=null;closureBuild=Promise.resolve();teardown=null;stage="idle";constructor(e={},t=Nn,r=Vt,i=zt,s,o,a=tt,l=Oe(),u){this.options=e,this.runBuild=t,this.turboWatchFactory=r,this.uiDevFactory=i,this.dryRunner=s,this.proxy=l,this.sink=u??new Y,re=this.sink;let d=nr(this.options);this.intercept=d?Lt({sink:this.sink,fallbackService:te,currentService:J}):null,this.renderer=o??new nt({appendLog:rr,verbose:this.options.verbose??!1,isTTY:d}),this.healthProbe=a,this.devContextDir=y.join(v.cwd(),".infra-kit","dev-context"),this.monorepoRoot=O(v.cwd()),(v.env.DOPPLER_PROJECT!=null||v.env.DOPPLER_ENVIRONMENT!=null)&&this.renderer.log("\u{1F510} Doppler env detected (DOPPLER_PROJECT / DOPPLER_ENVIRONMENT)","debug")}discoverApiApps(e){return H(this.monorepoRoot).map(t=>({...t,preferredPort:this.resolvePreferredPort(t.name,e),appScopedPort:this.resolvePreferredPort(t.name,e,!1),prefixUrl:this.resolvePrefixUrl(t.name,e),watchDeps:!0}))}async loadDevConfig(){try{return(await ae()).dev??{}}catch{return{}}}normalizeAppInclude(){return j(this.options.include)}resolvePreferredPort(e,t,r=!0){return _t(e,v.env,t,r)}resolvePrefixUrl(e,t){return Ft(e,t)}async loadDevPresets(){try{return(await ae()).devServersPresets??{}}catch{return{}}}async resolvePresetDef(e,t,r){if(this.options.presetDef!=null)return this.options.presetDef;let i=this.options.preset;if(i==null)return{};let s=e[i];if(s)return s;let o=await st(i,t,r);if(o)return o.unprovided.length>0&&this.renderer.log(`\u26A0\uFE0F No apps/*/api provides these local-capable routes, so they stay on cloud: ${o.unprovided.join(", ")}`,"warn"),o.preset;let[a,...l]=[...new Set([...Object.keys(e),...[...t,...r].map(u=>u.name).toSorted()])];throw a===void 0?new oe(void 0,{operation:`run "${i}"`,remediation:"omit the name to run every app",stderrExcerpt:"no devServersPresets are defined and no apps were discovered"}):new ze({status:"argument_required",argument:"preset",choices:Se.toJSONSchema(Se.object({preset:Se.enum([a,...l])})),agentMode:Ne.source},2,{operation:"pick what infra-kit dev runs",remediation:`pass a preset or an app: ${[a,...l].join(", ")}`,stderrExcerpt:`"${i}" is neither a dev preset nor an app`})}assertPresetKeysValid(e){let t=this.options.preset??"dev",r=We({[t]:e});if(r.length!==0)throw new Error(`infra-kit dev: cannot run this preset \u2014 ${r.map(i=>i.message).join("; ")}`)}async assertPresetProxyLocalityValid(e,t,r,i){let s={[e]:t},{ctx:o,loadErrors:a}=await Je(this.monorepoRoot,s,r,i);if(a.length>0)return;let l=Ke(s,o);if(l.length!==0)throw new Error(`infra-kit dev: cannot run this preset \u2014 ${l.map(u=>u.message).join("; ")}`)}async start(){let e=Date.now(),t=this.normalizeAppInclude(),r=this.options.watch??!1,i=await this.loadDevConfig();v.env.POWERTOOLS_DEV??="true",v.env.LOG_LEVEL??="DEBUG",this.renderer.narrate("\u{1F680} Starting Development Server Runner"),r&&this.renderer.narrate("\u{1F440} Watch mode: will rebuild and restart on file save");let{apps:s,uiApps:o,apiAppsAll:a,uiAppsAll:l,wantedLocalPkgs:u,presetProxy:d}=await this.resolveRunPlan(i,t);if(await this.endsBeforeBoot(s,o))return;this.warnUiMissingVitePlugin(o),r&&this.installModuleGeneration(),await this.bringUpProxy(s),await this.buildAll(s,o,r),s.length>0&&(this.renderer.bootStep("starting servers"),await this.startAllApps(s),this.renderer.narrate(this.failedApps.length===0?"\u{1F389} All servers started!":`\u26A0\uFE0F ${this.appServers.length}/${s.length} servers started \u2014 ${this.failedApps.length} failed`),this.renderer.narrate(`\u{1F4DD} Logs \u2192 ${ee(this.sink.dir)} (one file per service)`),this.assertNoBootFailuresWhenReusing(s.length));let h=Ve({preset:this.options.preset,running:[...s.map(f=>`${f.name}/api`),...o.map(f=>`${f.name}/ui`)],discovered:[...a.map(f=>`${f.name}/api`),...l.map(f=>`${f.name}/ui`)]});if(this.targetLabel=h,r&&this.holdFailedBackendsLocal(),this.degradedRoutes=await this.collectDegradedRoutes(o,u,d),this.degradedRoutes.length>0&&!r)throw new Error(mt(this.degradedRoutes,h));if(await this.printReady(s,o,e,h),this.announceServingOnce(),this.options.routes&&this.printRouteDump(),this.appServers.length===0&&o.length===0&&this.failedApps.length>0)throw new Error(`infra-kit dev: no app started (${this.failedApps.length} of ${s.length} failed). First failure: ${this.failedApps[0]?.reason??"unknown"}`);this.armWatch(s,o,r),o.length>0&&this.startUiDev(o),this.startLivenessMonitor()}async resolveRunPlan(e,t){let r=this.discoverApiApps(e),i=Fe(this.monorepoRoot),s=await this.loadDevPresets(),o=await this.resolvePresetDef(s,r,i);this.assertPresetKeysValid(o);let a={api:r.map(c=>c.name),ui:i.map(c=>c.name)};this.options.presetDef==null&&this.options.preset!=null&&await this.assertPresetProxyLocalityValid(this.options.preset,o,a,r);let l=Ge(o,a);l.unmatched.length>0&&this.renderer.log(`\u26A0\uFE0F Preset targets not found (skipped): ${l.unmatched.join(", ")}`,"warn");let u=new Set(l.targets.filter(c=>c.part==="api").map(c=>c.app)),d=new Set(l.targets.filter(c=>c.part==="ui").map(c=>c.app)),h=c=>!t||t.includes(c),f=new Map(l.targets.filter(c=>c.part==="api").map(c=>[c.app,c.watchDeps])),p=r.filter(c=>u.has(c.name)&&h(c.name)),g=p.map(c=>({...c,watchDeps:f.get(c.name)??c.watchDeps,preferredPort:p.length===1?c.preferredPort:c.appScopedPort})),m=i.filter(c=>d.has(c.name)&&h(c.name)),P=new Set(r.filter(c=>u.has(c.name)).map(c=>c.packageName));return{apps:g,uiApps:m,apiAppsAll:r,uiAppsAll:i,wantedLocalPkgs:P,presetProxy:l.proxy}}async collectDegradedRoutes(e,t,r){if(e.length===0)return[];let i=[];for(let s of e){let o=await Yt(s.path).catch(()=>{}),a=o?.dev;if(!a?.proxy)continue;let l=r[s.name]??{},u=Object.fromEntries(Object.entries(a.proxy.routes).map(([d,h])=>[d,{...h,pinnedLocal:l[d]==="local"}]));i.push({app:s.name,routes:u,cloudUrl:Xt(o?.deployedUrlEnv).url})}return this.launchedUis=i,ht({uis:i,wanted:t,running:new Set(this.appServers.map(({app:s})=>s.packageName)),reasons:new Map(this.failedApps.map(({app:s,reason:o})=>[s.packageName,{app:s.name,reason:o}])),held:this.heldLocalPkgs})}warnUiMissingVitePlugin(e){for(let t of e)!t.managedPort||_e(t.path)||this.renderer.log(`\u26A0\uFE0F ${t.name}/ui is wired with the infra-kit vite helper directly, not the infraKit() plugin \u2014 its proxy is baked at config load and won't react to backend routing changes. Wire the infraKit() vite plugin (from @slip-stream-kit/vite) instead.`,"warn")}proxiesFor(e){let t=this.proxyRoutes.filter(r=>r.uiApp===e).map(r=>({route:r.route,source:r.source,target:r.target}));return t.length>0?t:void 0}async bringUpProxy(e){Gn(O(v.cwd())),await this.ensureProxy(),e.length>0&&this.assertNoPortConflicts(e)}async buildAll(e,t,r){let i=[e.length>0?`building ${Qt(e)}`:"",t.length>0?`warming ${Qt(t)}`:""].filter(Boolean).join(" \xB7 ");this.renderer.bootStep(i),e.length>0&&await this.buildApps(e,r),t.length>0&&await this.buildUiApps(t)}armWatch(e,t,r){r&&(this.appServers.length>0||t.length>0)&&(this.setupWatch(e,t),this.closureBuild=this.buildClosureMapSafe(e).then(i=>{this.closureMap=i}))}async buildUiApps(e){let t=e.map(r=>`--filter=${r.packageName}^...`).join(" ");try{await this.runBuild(`pnpm exec turbo run build ${t} --env-mode=loose --output-logs=errors-only --no-update-notifier`,this.renderer.logFn),this.renderer.narrate("\u2705 UI deps built")}catch(r){this.renderer.log(`\u26A0\uFE0F UI dep build failed (continuing; vite will report unresolved deps): ${String(r)}`,"warn")}}startUiDev(e){let t=e.map(o=>o.name).join(", ");this.renderer.narrate(`\u{1F3A8} Starting ${e.length} UI dev server(s) via \`turbo run dev\`: ${t}`),this.renderer.narrate(" (framework output is routed into the live tail; full detail in the runner log)");let r=Object.keys(this.uiPortMap).length>0?{INFRA_KIT_UI_PORTS:JSON.stringify(this.uiPortMap)}:void 0,i=v.env.NODE_EXTRA_CA_CERTS==null&&w.existsSync(se())?{NODE_EXTRA_CA_CERTS:se()}:void 0,s=new Map(e.map(o=>[o.packageName,`${o.name}/ui`]));this.uiDev=this.uiDevFactory({packageNames:e.map(o=>o.packageName),cwd:v.cwd(),concurrency:Math.max(e.length+4,12),env:r||i?{...r,...i}:void 0,appendLog:o=>{this.sink.write(Cn,o)},onLine:({pkg:o,text:a,level:l})=>{let u=s.get(o)??`${o}/ui`;this.sink.write(u,a,{level:l})},onTaskFailure:o=>{this.markUiTaskFailed(s.get(o)??`${o}/ui`)},onUnexpectedExit:o=>{this.markUiEngineDead(),this.reportEngineDeath("UI dev engine (`turbo run dev`)","frontends stopped reloading",o)}})}formatAppList(e){return e.map(t=>`${t.name}:${t.port}`).join(", ")}assertNoPortConflicts(e){let t=e.filter(s=>s.preferredPort!=null).map(s=>({name:s.name,port:s.preferredPort})),{duplicatePorts:r,conflictingApps:i}=Bt(t);if(r.length!==0)throw this.renderer.log(`\u26A0\uFE0F Port conflict detected! ${r.join(", ")}`,"error"),this.renderer.log(`Conflicting apps: ${this.formatAppList(i)}`,"error"),this.renderer.log("\n\u{1F4A1} Tip: give each app a distinct port via `{APP}_PORT` env (e.g. `CLIENT_PORT=`,","error"),this.renderer.log(" `SEARCH_ENGINE_PORT=`) or `dev.<app>.port` in infra-kit.json; or run a subset with","error"),this.renderer.log(" `--app=<name>,<name>`.\n","error"),new Error(`Port conflict detected: ${r.join(", ")}`)}async buildApps(e,t){let i=`pnpm exec turbo run build ${e.map(s=>`--filter=${s.packageName}`).join(" ")} --env-mode=loose --output-logs=errors-only --no-update-notifier${t?" --force":""}`;try{await this.runBuild(i,this.renderer.logFn),this.renderer.narrate("\u2705 Build complete")}catch(s){this.renderer.log(`\u274C Build failed: ${String(s)}`,"error"),s instanceof Error&&s.message&&this.renderer.log(` ${s.message}`,"error");let o=s;throw o.stdout&&this.renderer.log(` stdout: ${o.stdout.trim()}`,"error"),o.stderr&&this.renderer.log(` stderr: ${o.stderr.trim()}`,"error"),s}}async startAllApps(e){await Promise.all(e.map(async t=>{try{let r=await this.startOneApp(t);r&&this.appServers.push({app:t,...r,startedAt:Date.now(),restarts:0})}catch(r){this.renderer.log(`\u274C Failed to start ${t.name}: ${String(r)}`,"error"),this.failedApps.push({app:t,reason:Vn(r)})}}))}async ensureProxy(){let e=this.proxy.binPath();if(e==null||!await this.proxy.isAvailable())throw new Error("infra-kit dev: portless is not installed, so no dev URL can resolve. It ships as a dependency of infra-kit \u2014 reinstall with `pnpm install`.");let t=Ie(e,this.options.portlessLink??{home:tr.homedir()}),r=await this.proxy.probeProxy(this.proxyPort,!0);if(r!=="serving")throw r==="not-portless"?new Error(`infra-kit dev: something else is already listening on :${this.proxyPort}, and it is not portless (no \`X-Portless\` header on the wire). Find and stop it, e.g. \`sudo lsof -iTCP:${this.proxyPort} -sTCP:LISTEN\`. Installing or trusting portless will not help while another process holds the port.`):this.proxy.isServiceInstalled()==="no"?new Error(`infra-kit dev: no portless daemon is serving HTTPS on :${this.proxyPort}, and its OS service is not installed yet, so no dev URL can resolve. Install it once (this is the only step that needs root):
16
+ `,a=Dt.byteLength(o);if((this.bytes.get(e)??0)+a>this.maxBytes){this.capped.add(e),this.writeRaw(s,e,`[capped] ${At(e)} hit ${this.maxBytes} bytes; further lines dropped (likely a logging loop)
17
+ `);return}this.writeRaw(s,e,o)}writeRaw(e,t,r){try{D.writeSync(e,r),this.bytes.set(t,(this.bytes.get(t)??0)+Dt.byteLength(r))}catch{}}statsFor(e){return this.counters.get(e)??kt()}close(){if(!this.closed){this.closed=!0;for(let e of this.fds.values())try{D.closeSync(e)}catch{}this.fds.clear()}}};import*as Ct from"node:fs";import Jr from"node:module";import*as C from"node:path";import zr from"node:process";import{fileURLToPath as Ot}from"node:url";var qr="ikgen",ge=2e9,xt=null,Tt=!1,$t=new Map,me=n=>{let e=$t.get(n);if(e!==void 0)return e;try{let t=Ct.realpathSync(n);return $t.set(n,t),t}catch{return null}},fe=(n,e)=>n===e||n.startsWith(e+C.sep),Yr=(n,e)=>{if(!n.startsWith("file:"))return null;let t;try{t=Ot(n)}catch{return null}let r=me(t);if(r===null||!fe(r,e.root)||r.includes(`${C.sep}node_modules${C.sep}`)||fe(r,e.selfDist))return null;e.busted.add(r);let i=new URL(n);return i.searchParams.set(qr,String(e.generation)),i.href},It=()=>Jr.registerHooks,Nt=()=>typeof It()=="function",ve=n=>{if(n==="0"||n?.toLowerCase()==="off")return{stopEnabled:!1,stopBytes:ge};let e=Number(n);return Number.isInteger(e)&&e>0?{stopEnabled:!0,stopBytes:e}:{stopEnabled:!0,stopBytes:ge}},Lt=()=>{let n=C.dirname(Ot(import.meta.url));return me(n)??n},_t=n=>{let e=It();if(typeof e!="function")return null;let t={busted:new Set,generation:0,root:n.root,selfDist:n.selfDist},r=n.stopBytes??ge,i=n.stopEnabled??!0,s=r/2,o=n.warnStrideBytes??r/8,a=n.sampleRss??(()=>zr.memoryUsage.rss()),l=0,u=0;return xt=t,Tt||(Tt=!0,e({resolve:(d,h,f)=>{let p=f(d,h),g=xt;if(g===null)return p;let m=Yr(p.url,g);return m===null?p:{...p,url:m}}})),{bump:()=>(t.generation+=1,t.busted=new Set,t.generation),budgetState:()=>{let d=a();if(i&&d>r){if(l+=1,l>=2)return"stop"}else l=0;return d>=s&&d>=u+o?(u=d,"warn"):"ok"},bustedUnder:d=>{let h=me(d)??d;for(let f of t.busted)if(fe(f,h))return!0;return!1},generation:()=>t.generation}};import ye from"node:process";import Xr from"node:util";var we={log:"info",info:"info",debug:"debug",trace:"debug",warn:"warn",error:"error"},Ut=({sink:n,fallbackService:e,currentService:t})=>{let r=!0,i=()=>t()??e,s=(d,h)=>{n.write(i(),d,{level:h})},o={};for(let d of Object.keys(we))o[d]=console[d],console[d]=(...h)=>{if(!r){o[d](...h);return}s(Xr.format(...h),we[d])};let a=(d,h)=>{let f=d.write.bind(d),p="",g=()=>{p!==""&&(n.write(i(),p,{level:h}),p="")};return d.write=((m,...P)=>{if(!r||typeof m!="string")return f(m,...P);p+=m;let c=p.split(`
18
+ `);p=c.pop()??"";for(let E of c)E!==""&&n.write(i(),E,{level:h});p.length>8192&&g();let S=P.find(E=>typeof E=="function");return typeof S=="function"&&ye.nextTick(S),!0}),()=>{g(),Reflect.deleteProperty(d,"write")}},l=a(ye.stdout,"info"),u=a(ye.stderr,"warn");return{uninstall:()=>{if(r){r=!1,l(),u();for(let d of Object.keys(we))console[d]=o[d]}}}};var Qr="/api/v1";function Ft(n){if(n==null||n==="")return;let e=parseInt(n.trim().replace(/^["']|["']$/g,""),10);return Number.isNaN(e)?void 0:e}function Bt(n,e,t,r=!0){let s=`${n.replace(/-/g,"_").toUpperCase()}_PORT`,o=Ft(e[s]);if(o!=null)return o;if(r){let a=Ft(e.PORT);if(a!=null)return a}return t[n]?.port??void 0}function Mt(n,e){return e[n]?.prefixUrl??Qr}function Ht(n){let e=n.map(i=>i.port),t=e.filter((i,s)=>e.indexOf(i)!==s),r=n.filter(i=>t.includes(i.port));return{duplicatePorts:t,conflictingApps:r}}import*as Y from"node:fs";import*as R from"node:path";import{parse as Zr}from"yaml";var jt=new Map;var en=(n,e)=>{let t=new Set,r;try{r=Zr(Y.readFileSync(n,"utf8"))}catch{return t}for(let i of Object.values(r?.functions??{})){let s=i?.handler;if(typeof s!="string")continue;let o=s.split(".")[0]??"";o!==""&&t.add(R.normalize(R.join(e,`${o}.js`)))}return t},tn=n=>{let e=R.join(n,"serverless.yml"),t;try{t=Y.statSync(e).mtimeMs}catch{return new Set}let r=jt.get(n);if(r&&r.mtimeMs===t)return r.entries;let i=en(e,n);return jt.set(n,{entries:i,mtimeMs:t}),i},Wt=(n,e)=>tn(e).has(R.normalize(n)),rn=2,Gt=n=>{let e=n.slice(0,rn).map(r=>R.basename(r)),t=n.length-e.length;return t>0?`${e.join(", ")} (+${t} more)`:e.join(", ")};import{Logger as nn}from"@aws-lambda-powertools/logger";import sn from"fastify";import*as Kt from"node:fs";import*as F from"node:path";import be from"node:process";import{pathToFileURL as on}from"node:url";import{parse as an}from"yaml";var ln=n=>n?.code==="EADDRINUSE",un=3e4,dn=()=>{let n=Number.parseInt(be.env.DEV_SERVER_TIMEOUT_MS??"",10);return Number.isNaN(n)?un:n},Vt=()=>be.env.DEV_SERVER_REQUEST_LOG==="1",X=class{constructor(e){this.serverConfig=e;this.importCacheBust=`${Date.now()}`,this.logger=new nn({serviceName:"LocalServer",logLevel:"DEBUG"}),this.serverConfig.prefixUrl=this.serverConfig.prefixUrl??"",this.server=sn({logger:!1}),this.server.addHook("onRequest",async(r,i)=>{let s=this.serverConfig.serviceTag;s!=null&&bt(s),i.header("Access-Control-Allow-Origin","*"),i.header("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, PATCH, OPTIONS"),i.header("Access-Control-Allow-Headers","Content-Type, Authorization, X-Requested-With"),r.method==="OPTIONS"&&i.status(204).send()});let t=this.serverConfig.onRequestLog;(Vt()||t)&&this.server.addHook("onResponse",async(r,i)=>{let s=Math.round(i.elapsedTime),o=r.url.split("?")[0]??r.url;t?.({method:r.method,path:o,status:i.statusCode,ms:s}),Vt()&&be.stdout.write(`${r.method} ${r.url} \u2192 ${i.statusCode} ${s}ms
19
+ `)})}serverConfig;importCacheBust;logger;server;controllers={};registeredRouteKeys=new Set;getRegisteredRoutes(){return[...this.registeredRouteKeys].sort()}async start(){this.registerHealthRoute(),await Promise.all(this.loadRoutes());let e=await this.listenWithFallback();return this.serverConfig.port=e,this.logger.info(`Server listening on http://127.0.0.1:${e}`,{address:`http://127.0.0.1:${e}`}),e}async listenWithFallback(){let e=this.serverConfig.port;if(e!=null)try{return await this.server.listen({port:e,host:"127.0.0.1"}),this.readBoundPort()}catch(t){if(!ln(t))throw t}return await this.server.listen({port:0,host:"127.0.0.1"}),this.readBoundPort()}readBoundPort(){let e=this.server.server.address();if(e==null||typeof e=="string")throw new Error("Server address unavailable after listen()");return e.port}async close(){let e=this.server.server;typeof e.closeAllConnections=="function"&&e.closeAllConnections(),await this.server.close()}registerHealthRoute(){this.server.route({method:"GET",url:"/__health",handler:(e,t)=>t.code(200).send({status:"ok",app:this.serverConfig.appName??null,port:this.serverConfig.port})})}loadRoutes(){let e=F.join(this.serverConfig.controllersPath,"serverless.yml"),t=Kt.readFileSync(e,"utf8"),r=an(t),i=[];if(!r?.functions)return i;for(let s of Object.values(r.functions))if(s?.events?.length)for(let o of s.events){let a=o?.http;a&&i.push(this.defineRoute(a,s))}return i}async defineRoute(e,t){let r=e.path.toString();r=r.replaceAll("{",":").replaceAll("}","");let i=F.posix.join(this.serverConfig.prefixUrl??"",r);i=i[0]==="/"?i:`/${i}`;let s=["GET","POST","PUT","DELETE","PATCH","HEAD","OPTIONS"],o=String(e.method).toUpperCase();if(!s.includes(o))throw new Error(`Invalid HTTP method: "${e.method}" for URL: ${i}`);let a=`${o} ${i}`;if(this.registeredRouteKeys.has(a))throw new Error(`Duplicate route: ${a}`);this.registeredRouteKeys.add(a);let u=(t.handler??"").split("."),d=u[0]??"",h=u[1]??"",f=F.join(this.serverConfig.controllersPath,`${d}.js`),p=on(f);p.searchParams.set("v",this.importCacheBust);let g=this.serverConfig.serviceTag,m=async()=>await import(p.href),P=g==null?await m():await wt(g,m);this.controllers[a]={action:P,handler:h};let c=this.logger.createChild({serviceName:"RequestLogger"});this.server.route({method:o,url:i,handler:async(S,E)=>{let B=this.controllers[a];if(!B)throw new Error(`No controller for ${a}`);let Te=B.action[B.handler];if(!Te)throw new Error(`No handler ${B.handler} for ${i}`);let re=await Te(this.getEventObj(S.body,S.query,S.params,S.headers,o,i),this.getContext(),c),hr=JSON.parse(re.body);return E.headers(re.headers??{}),E.code(re?.statusCode??500).send(hr)}})}getEventObj(e,t,r,i,s="",o=""){let a={body:e?JSON.stringify(e):null,headers:i??{},multiValueHeaders:{},httpMethod:s,isBase64Encoded:!1,path:o,pathParameters:r??null,queryStringParameters:t??null,multiValueQueryStringParameters:null,stageVariables:null,requestContext:{accountId:"",apiId:"",authorizer:void 0,protocol:"",httpMethod:s,identity:{accessKey:null,accountId:null,apiKey:null,apiKeyId:null,caller:null,clientCert:null,cognitoAuthenticationProvider:null,cognitoAuthenticationType:null,cognitoIdentityId:null,cognitoIdentityPoolId:null,principalOrgId:null,sourceIp:"devIp",user:null,userAgent:null,userArn:null},path:o,stage:"",requestId:"",requestTimeEpoch:0,resourceId:"",resourcePath:o},resource:o};return a.source="aws.events",a}getContext(){let e=Date.now(),t=dn(),r=new Date().toISOString().split("T")[0]??"";return{callbackWaitsForEmptyEventLoop:!1,functionName:"local-dev",functionVersion:"1.0.0",invokedFunctionArn:"arn:aws:lambda:local:000000000000:function:local-dev",memoryLimitInMB:"1024",awsRequestId:`local-${Date.now()}`,logGroupName:"/aws/lambda/local-dev",logStreamName:`${r}/local`,getRemainingTimeInMillis:()=>Math.max(0,t-(Date.now()-e)),done:(i,s)=>{},fail:i=>{},succeed:i=>{}}}};import{spawn as pn}from"node:child_process";import*as Q from"node:fs";var cn=(n,e)=>[...n.map(t=>`--filter=...${t}`),...e.map(t=>`--filter=${t}^...`)],Jt=({depInclusive:n,depClosure:e,cwd:t,logFile:r,onUnexpectedExit:i,openLog:s})=>{let o=cn(n,e),a=s?s(r):Q.openSync(r,"a"),l=pn("pnpm",["exec","turbo","watch","build",...o,"--continue=dependencies-successful","--env-mode=loose","--log-order=stream"],{cwd:t,detached:!0,stdio:["ignore",a,a]});return Q.closeSync(a),j(l,void 0,i)};import{spawn as hn}from"node:child_process";import gn from"node:process";var fn=[/^error\b/i,/^[✘✖×]/,/^\[vite\][^\n]*\berror\b/i,/^\w*Error: /,/\berror TS\d+\b/,/^Failed to (?:resolve|load url|parse|compile)\b/i,/^(?:ENOENT|EADDRINUSE|ECONNREFUSED)\b/,/pre-transform error/i,/\b(?:build|transform|compilation) failed\b/i],mn=n=>fn.some(e=>e.test(n))?"error":"info",vn=/\u001B\][\s\S]*?(?:\u0007|\u001B\\)/g,yn=/\u001B\[[0-9;?]*[\u0020-\u002F]*[\u0040-\u007E]/g,wn=/[\u0000-\u0008\u000B-\u001F\u007F]/g,qt=n=>n.replace(vn,"").replace(yn,"").replace(wn,""),bn=/^([^\s:]+):dev:[ \t]?/,Sn=/^([^\s#]+)#dev:\s+(?:WARNING|ERROR)\s+command\b/,Pn=n=>Sn.exec(qt(n).trimEnd())?.[1]??null,Dn=n=>/^cache (?:bypass|hit|miss)/.test(n)||n.startsWith("$ "),kn=n=>{let e=qt(n).trimEnd(),t=bn.exec(e);if(t==null)return null;let r=e.slice(t[0].length);return r.trim()===""||Dn(r.trim())?null:{pkg:t[1],text:r,level:mn(r)}},An=64*1024,zt=(n,e)=>{if(n==null)return;let t="",r=i=>{let s=Pn(i);if(s!=null){e.onTaskFailure?.(s);return}let o=kn(i);o!=null&&e.onLine?.(o)};n.setEncoding("utf-8"),n.on("data",i=>{e.appendLog?.(i),t+=i;let s=t.split(`
20
+ `);t=s.pop()??"";for(let o of s)r(o);t.length>An&&(r(t),t="")}),n.on("end",()=>{t!==""&&(r(t),t="")}),n.on("error",i=>{e.appendLog?.(`[infra-kit] ui dev stream error: ${i.message}
21
+ `)})},Yt=({packageNames:n,cwd:e,concurrency:t,env:r,appendLog:i,onLine:s,onTaskFailure:o,onUnexpectedExit:a})=>{let l=n.map(d=>`--filter=${d}`),u=hn("pnpm",["exec","turbo","run","dev",...l,`--concurrency=${t}`,"--env-mode=loose","--only","--continue=dependencies-successful","--output-logs=new-only","--log-order=stream","--no-update-notifier","--ui=stream"],{cwd:e,detached:!0,stdio:["ignore","pipe","pipe"],env:{...gn.env,...r}});return zt(u.stdout,{appendLog:i,onLine:s,onTaskFailure:o}),zt(u.stderr,{appendLog:i,onLine:s,onTaskFailure:o}),j(u,void 0,a)};var ee="runner",On="turbo",In="watch",De=n=>`${Math.round(n/1e6)} MB`;function Z(n){let e=rr.homedir();return n===e||n.startsWith(`${e}${y.sep}`)?`~${n.slice(e.length)}`:n}function er(n){return n.map(e=>e.packageName).join(", ")}var Nn=Cn.promisify(Tn);var Ln=async(n,e)=>{try{let{stderr:t}=await Nn(n,{maxBuffer:33554432});t&&e&&e(` (build) ${t.trim()}`,"debug"),t&&!e&&console.error("stderr:",t)}catch(t){let r=t;throw e&&(r.stdout||r.stderr)&&(r.stdout&&e(` stdout: ${r.stdout.trim()}`,"error"),r.stderr&&e(` stderr: ${r.stderr.trim()}`,"error")),t}},te=null;function nr(n){te?.write(ee,n)}var _n=()=>new Promise((n,e)=>{let t=$n.createServer();t.unref(),t.on("error",e),t.listen(0,"127.0.0.1",()=>{let r=t.address(),i=typeof r=="object"&&r!==null?r.port:0;t.close(()=>n(i))})}),tr="dev aliases are now scoped by repo (`<release>.<package>.<repo>.localhost`), and only that helper aims Playwright at them. An older one would test whatever another repo serves on the old repo-less host.",Un="dev URLs are now HTTPS, and only that `infraKitDev` helper understands them. An older one would proxy plain HTTP at a TLS listener, silently.",Fn=[{name:"@slip-stream-kit/vite",floor:"0.15.0",why:tr},{name:"@slip-stream-kit/config",floor:"0.15.0",why:tr},{name:"infra-kit",floor:"0.1.132",why:Un}],Bn=(n,e)=>{let t=s=>s.split(".").map(o=>Number.parseInt(o,10)||0),r=t(n),i=t(e);for(let s=0;s<Math.max(r.length,i.length);s+=1){let o=r[s]??0,a=i[s]??0;if(o!==a)return o<a}return!1},Mn=n=>{let e=[n];try{for(let t of w.readdirSync(y.join(n,"apps"),{withFileTypes:!0}))if(t.isDirectory())for(let r of["api","ui"])e.push(y.join(n,"apps",t.name,r))}catch{}return e},Hn=(n,e)=>{try{let t=JSON.parse(w.readFileSync(y.join(n,"package.json"),"utf-8"));return["dependencies","devDependencies"].some(r=>t[r]?.[e]!=null)}catch{return!1}},jn=(n,e,t)=>{let r=t.split("/"),i=e;for(;;){let s=y.join(i,"node_modules",...r);if(w.existsSync(s))return s;let o=y.dirname(i);if(i===n||o===i)return;i=o}},Wn=(n,e)=>{try{let t=w.realpathSync(e),r=w.realpathSync(n);return t.startsWith(r+y.sep)&&!t.includes(`${y.sep}node_modules${y.sep}`)}catch{return!1}},Gn=n=>{try{return w.realpathSync(n)}catch{return n}},Vn=(n,e,t)=>{let{name:r,floor:i,why:s}=e;if(Wn(n,t))return;let o;try{let a=JSON.parse(w.readFileSync(y.join(t,"package.json"),"utf-8"));if(typeof a.version!="string")throw new Error("no version field");o=a.version}catch{throw new Error(`infra-kit dev: could not read the version of the pinned \`${r}\` helper (${t}). Refusing to start rather than risk proxying plain HTTP at a TLS listener. Run \`pnpm install\`.`)}if(Bn(o,i))throw new Error(`infra-kit dev: this repo pins ${r} ${o}; bump ${r} to >=${i}. From ${i} on, ${s}
22
+ pnpm add -D ${r}@^${i}`)},Kn=n=>{let e=Mn(n);for(let t of Fn){let{name:r}=t,i=e.filter(o=>Hn(o,r)),s=new Map;for(let o of[...i,n]){let a=jn(n,o,r);a&&s.set(Gn(a),a)}if(s.size===0){if(i.length===0)continue;throw new Error(`infra-kit dev: ${i[0]}/package.json depends on ${r} but it does not resolve from there, so the \`infraKitDev\` helper version cannot be verified. Run \`pnpm install\`.`)}for(let o of s.values())Vn(n,t,o)}},Jn=n=>{let t=(n instanceof Error?n.message:String(n)).split(`
23
+ `)[0]?.trim()??"";return t===""?"unknown error (see the log)":t},ke=class n{monorepoRoot;devContextDir;appServers=[];reqTimes=new Map;lastSummary=null;readyAt=0;watchDebounceTimers=new Map;pendingChanges=new Map;moduleGeneration=null;watcher=null;static WATCH_DEBOUNCE_MS=400;watchedDistDirs=[];nudgedStaleness=new Map;static STALE_BUILD_GRACE_MS=1e3;restartWorkChain=Promise.resolve();static PORT_RELEASE_DELAY_MS=200;livenessTimer=null;reusing=!1;keepAlive=null;servingAnnounced=!1;targetLabel="";health=new Map;firstErrorLogged=new Set;uiTagByPackage=new Map;static LIVENESS_INTERVAL_MS=5e3;static LIVENESS_FAILURE_THRESHOLD=2;static NEVER_UP_DOWN_THRESHOLD=6;options;runBuild;turboWatchFactory;turboWatch=null;uiDevFactory;uiDev=null;sink;intercept;dryRunner;failedApps=[];degradedRoutes=[];heldLocalPkgs=new Set;launchedUis=[];proxyRoutes=[];renderer;healthProbe;proxy;proxyPort=Fe;registeredAliases=new Set;uiPortMap={};shuttingDown=!1;closureMap=null;closureBuild=Promise.resolve();teardown=null;stage="idle";constructor(e={},t=Ln,r=Jt,i=Yt,s,o,a=nt,l=Ne(),u){this.options=e,this.runBuild=t,this.turboWatchFactory=r,this.uiDevFactory=i,this.dryRunner=s,this.proxy=l,this.sink=u??new q,te=this.sink;let d=ir(this.options);this.intercept=d?Ut({sink:this.sink,fallbackService:ee,currentService:K}):null,this.renderer=o??new st({appendLog:nr,verbose:this.options.verbose??!1,isTTY:d}),this.healthProbe=a,this.devContextDir=y.join(v.cwd(),".infra-kit","dev-context"),this.monorepoRoot=O(v.cwd()),(v.env.DOPPLER_PROJECT!=null||v.env.DOPPLER_ENVIRONMENT!=null)&&this.renderer.log("\u{1F510} Doppler env detected (DOPPLER_PROJECT / DOPPLER_ENVIRONMENT)","debug")}discoverApiApps(e){return M(this.monorepoRoot).map(t=>({...t,preferredPort:this.resolvePreferredPort(t.name,e),appScopedPort:this.resolvePreferredPort(t.name,e,!1),prefixUrl:this.resolvePrefixUrl(t.name,e),watchDeps:!0}))}async loadDevConfig(){try{return(await oe()).dev??{}}catch{return{}}}normalizeAppInclude(){return H(this.options.include)}resolvePreferredPort(e,t,r=!0){return Bt(e,v.env,t,r)}resolvePrefixUrl(e,t){return Mt(e,t)}async loadDevPresets(){try{return(await oe()).devServersPresets??{}}catch{return{}}}async resolvePresetDef(e,t,r){if(this.options.presetDef!=null)return this.options.presetDef;let i=this.options.preset;if(i==null)return{};let s=e[i];if(s)return s;let o=await at(i,t,r);if(o)return o.unprovided.length>0&&this.renderer.log(`\u26A0\uFE0F No apps/*/api provides these local-capable routes, so they stay on cloud: ${o.unprovided.join(", ")}`,"warn"),o.preset;let[a,...l]=[...new Set([...Object.keys(e),...[...t,...r].map(u=>u.name).toSorted()])];throw a===void 0?new se(void 0,{operation:`run "${i}"`,remediation:"omit the name to run every app",stderrExcerpt:"no devServersPresets are defined and no apps were discovered"}):new Ye({status:"argument_required",argument:"preset",choices:Pe.toJSONSchema(Pe.object({preset:Pe.enum([a,...l])})),agentMode:_e.source},2,{operation:"pick what infra-kit dev runs",remediation:`pass a preset or an app: ${[a,...l].join(", ")}`,stderrExcerpt:`"${i}" is neither a dev preset nor an app`})}assertPresetKeysValid(e){let t=this.options.preset??"dev",r=Ve({[t]:e});if(r.length!==0)throw new Error(`infra-kit dev: cannot run this preset \u2014 ${r.map(i=>i.message).join("; ")}`)}async assertPresetProxyLocalityValid(e,t,r,i){let s={[e]:t},{ctx:o,loadErrors:a}=await qe(this.monorepoRoot,s,r,i);if(a.length>0)return;let l=ze(s,o);if(l.length!==0)throw new Error(`infra-kit dev: cannot run this preset \u2014 ${l.map(u=>u.message).join("; ")}`)}async start(){let e=Date.now(),t=this.normalizeAppInclude(),r=this.options.watch??!1,i=await this.loadDevConfig();v.env.POWERTOOLS_DEV??="true",v.env.LOG_LEVEL??="DEBUG",this.renderer.narrate("\u{1F680} Starting Development Server Runner"),r&&this.renderer.narrate("\u{1F440} Watch mode: will rebuild and restart on file save");let{apps:s,uiApps:o,apiAppsAll:a,uiAppsAll:l,wantedLocalPkgs:u,presetProxy:d}=await this.resolveRunPlan(i,t);if(await this.endsBeforeBoot(s,o))return;this.warnUiMissingVitePlugin(o),r&&this.installModuleGeneration(),await this.bringUpProxy(s),await this.buildAll(s,o,r),s.length>0&&(this.renderer.bootStep("starting servers"),await this.startAllApps(s),this.renderer.narrate(this.failedApps.length===0?"\u{1F389} All servers started!":`\u26A0\uFE0F ${this.appServers.length}/${s.length} servers started \u2014 ${this.failedApps.length} failed`),this.renderer.narrate(`\u{1F4DD} Logs \u2192 ${Z(this.sink.dir)} (one file per service)`),this.assertNoBootFailuresWhenReusing(s.length));let h=Je({preset:this.options.preset,running:[...s.map(f=>`${f.name}/api`),...o.map(f=>`${f.name}/ui`)],discovered:[...a.map(f=>`${f.name}/api`),...l.map(f=>`${f.name}/ui`)]});if(this.targetLabel=h,r&&this.holdFailedBackendsLocal(),this.degradedRoutes=await this.collectDegradedRoutes(o,u,d),this.degradedRoutes.length>0&&!r)throw new Error(yt(this.degradedRoutes,h));if(await this.printReady(s,o,e,h),this.announceServingOnce(),this.options.routes&&this.printRouteDump(),this.appServers.length===0&&o.length===0&&this.failedApps.length>0)throw new Error(`infra-kit dev: no app started (${this.failedApps.length} of ${s.length} failed). First failure: ${this.failedApps[0]?.reason??"unknown"}`);this.armWatch(s,o,r),o.length>0&&this.startUiDev(o),this.startLivenessMonitor()}async resolveRunPlan(e,t){let r=this.discoverApiApps(e),i=Me(this.monorepoRoot),s=await this.loadDevPresets(),o=await this.resolvePresetDef(s,r,i);this.assertPresetKeysValid(o);let a={api:r.map(c=>c.name),ui:i.map(c=>c.name)};this.options.presetDef==null&&this.options.preset!=null&&await this.assertPresetProxyLocalityValid(this.options.preset,o,a,r);let l=Ke(o,a);l.unmatched.length>0&&this.renderer.log(`\u26A0\uFE0F Preset targets not found (skipped): ${l.unmatched.join(", ")}`,"warn");let u=new Set(l.targets.filter(c=>c.part==="api").map(c=>c.app)),d=new Set(l.targets.filter(c=>c.part==="ui").map(c=>c.app)),h=c=>!t||t.includes(c),f=new Map(l.targets.filter(c=>c.part==="api").map(c=>[c.app,c.watchDeps])),p=r.filter(c=>u.has(c.name)&&h(c.name)),g=p.map(c=>({...c,watchDeps:f.get(c.name)??c.watchDeps,preferredPort:p.length===1?c.preferredPort:c.appScopedPort})),m=i.filter(c=>d.has(c.name)&&h(c.name)),P=new Set(r.filter(c=>u.has(c.name)).map(c=>c.packageName));return{apps:g,uiApps:m,apiAppsAll:r,uiAppsAll:i,wantedLocalPkgs:P,presetProxy:l.proxy}}async collectDegradedRoutes(e,t,r){if(e.length===0)return[];let i=[];for(let s of e){let o=await Qt(s.path).catch(()=>{}),a=o?.dev;if(!a?.proxy)continue;let l=r[s.name]??{},u=Object.fromEntries(Object.entries(a.proxy.routes).map(([d,h])=>[d,{...h,pinnedLocal:l[d]==="local"}]));i.push({app:s.name,routes:u,cloudUrl:Zt(o?.deployedUrlEnv).url})}return this.launchedUis=i,ft({uis:i,wanted:t,running:new Set(this.appServers.map(({app:s})=>s.packageName)),reasons:new Map(this.failedApps.map(({app:s,reason:o})=>[s.packageName,{app:s.name,reason:o}])),held:this.heldLocalPkgs})}warnUiMissingVitePlugin(e){for(let t of e)!t.managedPort||Be(t.path)||this.renderer.log(`\u26A0\uFE0F ${t.name}/ui is wired with the infra-kit vite helper directly, not the infraKit() plugin \u2014 its proxy is baked at config load and won't react to backend routing changes. Wire the infraKit() vite plugin (from @slip-stream-kit/vite) instead.`,"warn")}proxiesFor(e){let t=this.proxyRoutes.filter(r=>r.uiApp===e).map(r=>({route:r.route,source:r.source,target:r.target}));return t.length>0?t:void 0}async bringUpProxy(e){Kn(O(v.cwd())),await this.ensureProxy(),e.length>0&&this.assertNoPortConflicts(e)}async buildAll(e,t,r){let i=[e.length>0?`building ${er(e)}`:"",t.length>0?`warming ${er(t)}`:""].filter(Boolean).join(" \xB7 ");this.renderer.bootStep(i),e.length>0&&await this.buildApps(e,r),t.length>0&&await this.buildUiApps(t)}armWatch(e,t,r){r&&(this.appServers.length>0||t.length>0)&&(this.setupWatch(e,t),this.closureBuild=this.buildClosureMapSafe(e).then(i=>{this.closureMap=i}))}async buildUiApps(e){let t=e.map(r=>`--filter=${r.packageName}^...`).join(" ");try{await this.runBuild(`pnpm exec turbo run build ${t} --env-mode=loose --output-logs=errors-only --no-update-notifier`,this.renderer.logFn),this.renderer.narrate("\u2705 UI deps built")}catch(r){this.renderer.log(`\u26A0\uFE0F UI dep build failed (continuing; vite will report unresolved deps): ${String(r)}`,"warn")}}startUiDev(e){let t=e.map(o=>o.name).join(", ");this.renderer.narrate(`\u{1F3A8} Starting ${e.length} UI dev server(s) via \`turbo run dev\`: ${t}`),this.renderer.narrate(" (framework output is routed into the live tail; full detail in the runner log)");let r=Object.keys(this.uiPortMap).length>0?{INFRA_KIT_UI_PORTS:JSON.stringify(this.uiPortMap)}:void 0,i=v.env.NODE_EXTRA_CA_CERTS==null&&w.existsSync(ie())?{NODE_EXTRA_CA_CERTS:ie()}:void 0,s=new Map(e.map(o=>[o.packageName,`${o.name}/ui`]));this.uiDev=this.uiDevFactory({packageNames:e.map(o=>o.packageName),cwd:v.cwd(),concurrency:Math.max(e.length+4,12),env:r||i?{...r,...i}:void 0,appendLog:o=>{this.sink.write(On,o)},onLine:({pkg:o,text:a,level:l})=>{let u=s.get(o)??`${o}/ui`;this.sink.write(u,a,{level:l})},onTaskFailure:o=>{this.markUiTaskFailed(s.get(o)??`${o}/ui`)},onUnexpectedExit:o=>{this.markUiEngineDead(),this.reportEngineDeath("UI dev engine (`turbo run dev`)","frontends stopped reloading",o)}})}formatAppList(e){return e.map(t=>`${t.name}:${t.port}`).join(", ")}assertNoPortConflicts(e){let t=e.filter(s=>s.preferredPort!=null).map(s=>({name:s.name,port:s.preferredPort})),{duplicatePorts:r,conflictingApps:i}=Ht(t);if(r.length!==0)throw this.renderer.log(`\u26A0\uFE0F Port conflict detected! ${r.join(", ")}`,"error"),this.renderer.log(`Conflicting apps: ${this.formatAppList(i)}`,"error"),this.renderer.log("\n\u{1F4A1} Tip: give each app a distinct port via `{APP}_PORT` env (e.g. `CLIENT_PORT=`,","error"),this.renderer.log(" `SEARCH_ENGINE_PORT=`) or `dev.<app>.port` in infra-kit.json; or run a subset with","error"),this.renderer.log(" `--app=<name>,<name>`.\n","error"),new Error(`Port conflict detected: ${r.join(", ")}`)}async buildApps(e,t){let i=`pnpm exec turbo run build ${e.map(s=>`--filter=${s.packageName}`).join(" ")} --env-mode=loose --output-logs=errors-only --no-update-notifier${t?" --force":""}`;try{await this.runBuild(i,this.renderer.logFn),this.renderer.narrate("\u2705 Build complete")}catch(s){this.renderer.log(`\u274C Build failed: ${String(s)}`,"error"),s instanceof Error&&s.message&&this.renderer.log(` ${s.message}`,"error");let o=s;throw o.stdout&&this.renderer.log(` stdout: ${o.stdout.trim()}`,"error"),o.stderr&&this.renderer.log(` stderr: ${o.stderr.trim()}`,"error"),s}}async startAllApps(e){await Promise.all(e.map(async t=>{try{let r=await this.startOneApp(t);r&&this.appServers.push({app:t,...r,startedAt:Date.now(),restarts:0})}catch(r){this.renderer.log(`\u274C Failed to start ${t.name}: ${String(r)}`,"error"),this.failedApps.push({app:t,reason:Jn(r)})}}))}async ensureProxy(){let e=this.proxy.binPath();if(e==null||!await this.proxy.isAvailable())throw new Error("infra-kit dev: portless is not installed, so no dev URL can resolve. It ships as a dependency of infra-kit \u2014 reinstall with `pnpm install`.");let t=Le(e,this.options.portlessLink??{home:rr.homedir()}),r=await this.proxy.probeProxy(this.proxyPort,!0);if(r!=="serving")throw r==="not-portless"?new Error(`infra-kit dev: something else is already listening on :${this.proxyPort}, and it is not portless (no \`X-Portless\` header on the wire). Find and stop it, e.g. \`sudo lsof -iTCP:${this.proxyPort} -sTCP:LISTEN\`. Installing or trusting portless will not help while another process holds the port.`):this.proxy.isServiceInstalled()==="no"?new Error(`infra-kit dev: no portless daemon is serving HTTPS on :${this.proxyPort}, and its OS service is not installed yet, so no dev URL can resolve. Install it once (this is the only step that needs root):
24
24
  ${t}
25
25
  Then trust its local CA (no sudo needed):
26
- ${ie(["trust"],{bin:e})}
26
+ ${ne(["trust"],{bin:e})}
27
27
  \`infra-kit doctor\` checks both.`):new Error(`infra-kit dev: portless's OS service is installed, but no daemon is currently serving HTTPS on :${this.proxyPort} \u2014 it may have crashed or been stopped, so no dev URL can resolve. Check its state:
28
- ${ie(["service","status"],{bin:e})}
28
+ ${ne(["service","status"],{bin:e})}
29
29
  Reinstalling restarts it (still the only step that needs root):
30
30
  ${t}
31
- \`infra-kit doctor\` checks the daemon and CA trust state.`)}async registerAppAlias(e,t,r){let i=Zt(e,t);if(!await this.proxy.registerAlias(i,r))throw new Error(`infra-kit dev: portless refused the alias "${i}" \u2192 127.0.0.1:${r}.`);return this.registeredAliases.add(i),`${i}.localhost`}async startOneApp(e){this.renderer.narrate(`\u{1F504} Starting ${e.name}...`);let t=new Q({controllersPath:e.path,prefixUrl:e.prefixUrl,port:e.preferredPort,appName:e.name,serviceTag:`${e.name}/api`,onRequestLog:({method:s,path:o,status:a,ms:l})=>{if(o==="/__health")return;let u=`${e.name}/api`,d=`${s} ${o} ${a} ${l}ms`;this.sink.write(u,d,{level:a>=500?"error":"info"});let h=this.reqTimes.get(u);h?h.push(Date.now()):this.reqTimes.set(u,[Date.now()])}}),r=await t.start(),i;try{i=await this.registerAppAlias(e.packageName,e.path,r)}catch(s){throw await t.close().catch(()=>{}),s}try{this.writeDevContextFragment(e,r,i)}catch(s){this.renderer.log(`\u26A0\uFE0F Failed to write dev-context fragment for ${e.name}: ${String(s)}`,"warn")}return this.renderer.narrate(`\u2705 ${e.name} started on port ${r}`),{server:t,boundPort:r,alias:i}}holdFailedBackendsLocal(){for(let{app:e}of this.failedApps)try{this.writeDevContextFragment(e,0,`${Zt(e.packageName,e.path)}.localhost`),this.heldLocalPkgs.add(e.packageName)}catch(t){this.renderer.log(`\u26A0\uFE0F Failed to hold ${e.name}'s routes local: ${String(t)}`,"warn")}}writeDevContextFragment(e,t,r){let i={v:An,package:e.packageName,port:t,pid:v.pid,writtenAt:Date.now(),release:U(e.path),alias:r,origin:`https://${r}`},s=y.join(this.devContextDir,`${e.name}.json`),o=y.join(this.devContextDir,`${e.name}.json.${v.pid}.tmp`);w.mkdirSync(this.devContextDir,{recursive:!0}),w.writeFileSync(o,JSON.stringify(i,null,2)),w.renameSync(o,s)}removeDevContextFragment(e){w.rmSync(y.join(this.devContextDir,`${e.name}.json`),{force:!0})}scheduleRestartWork(e){let t=this.restartWorkChain.then(()=>e(),()=>e());return this.restartWorkChain=t.catch(()=>{}),t}async delayPortRelease(){await new Promise(e=>setTimeout(e,n.PORT_RELEASE_DELAY_MS))}restart(e,t=[]){return this.shuttingDown?Promise.resolve():this.scheduleRestartWork(async()=>{this.shuttingDown||(await this.runRestart(e,t),this.recoverLostSaves(this.triggeringBuilds(t)))})}resolveRestartTargets(e){return e.map(t=>({idx:this.appServers.findIndex(r=>r.app.name===t.name),app:t})).filter(t=>t.idx>=0||this.isFailedApp(t.app.name))}isFailedApp(e){return this.failedApps.some(t=>t.app.name===e)}promoteRecoveredApp(e,t){let r={app:e,...t,startedAt:Date.now(),restarts:0},i=`${e.name}/api`;this.healthEntry(i,"api"),this.appServers.push(r);let s=this.failedApps.findIndex(o=>o.app.name===e.name);return s>=0&&this.failedApps.splice(s,1),this.lastSummary&&(this.lastSummary={...this.lastSummary,endpoints:[...this.lastSummary.endpoints,{tag:i,url:_({prefixUrl:e.prefixUrl,alias:t.alias}),health:this.healthOf(i)}],failed:(this.lastSummary.failed??[]).filter(o=>o.tag!==i)}),r}async runRestart(e,t=[]){let r=this.resolveRestartTargets(e);if(r.length===0)return;let i=r.length===1?r[0].app.name:`${r.length} apps`,s=this.moduleGeneration?.budgetState()??"ok";if(s==="stop"){this.reportGenerationBudgetStop(ve(v.env.INFRA_KIT_DEV_STOP_BYTES).stopBytes),this.shutdown().catch(()=>{}).finally(()=>{this.options.onExitRequest?.(1)}).catch(()=>{});return}s==="warn"&&this.reportGenerationBudgetWarn(),this.moduleGeneration?.bump(),this.renderer.log(`\u{1F504} Restarting ${i}...`),await Promise.all(r.map(async({idx:p})=>{if(!(p<0))try{await this.appServers[p].server.close()}catch(g){this.renderer.log(` Close warning: ${String(g)}`,"debug")}})),await this.delayPortRelease();let o=await Promise.all(r.map(async({idx:p,app:g})=>{try{let m=await this.startOneApp(g);if(m){if(p<0){let S=this.promoteRecoveredApp(g,m);return this.renderer.log(`\u2705 ${g.name} recovered \u2014 its routes are served locally again`,"info"),{app:g,entry:S}}let P=this.appServers[p],c={app:g,...m,startedAt:Date.now(),restarts:(P?.restarts??0)+1};return this.appServers[p]=c,{app:g,entry:c}}return{app:g,entry:null}}catch(m){return this.renderer.log(`\u274C Failed to ${p<0?"start":"restart"} ${g.name}: ${String(m)}`,"error"),{app:g,entry:null}}})),a=await Promise.all(o.map(async({app:p,entry:g})=>{let m=`${p.name}/api`;if(g==null)return this.markDown(m,"api"),this.refreshStatus(),{label:`${p.name} \u25CF down`,healthy:!1};let P={tag:m,port:g.boundPort,kind:"api"},c=await this.healthProbe(P);this.recordProbe(P,c),this.refreshStatus();let S=c==="ok";return{label:`${p.name}:${g.boundPort} ${S?"\u25CF up":"\u25CF down"}`,healthy:S}})),l=a.every(p=>p.healthy),u=a.map(p=>p.label).join(", "),h=o.some(p=>p.entry!==null)?this.resolveStaleFiles(t,r):[];if(h.length>0){this.renderer.log(`\u26A0\uFE0F Restarted ${u} \u2014 still serving the OLD ${jt(h)}. Re-run \`infra-kit dev\` to pick this up.`,"warn");return}let f=this.describeBuildErrors(this.triggeringBuilds(t));if(f!==void 0){this.renderer.log(`\u26A0\uFE0F Restarted ${u} \u2014 ${f}`,"warn");return}this.renderer.log(`${l?"\u2705":"\u26A0\uFE0F "} Restarted ${u}`)}triggeringBuilds(e){let t=new Map;for(let r of e){let i=this.watchedDistDirs.find(o=>r===o||r.startsWith(o+y.sep));if(i===void 0)continue;let s=y.dirname(i);t.set(s,[...t.get(s)??[],r])}return[...t].flatMap(([r,i])=>{let s=V(r);return s&&ot(s,i)?[{pkgDir:r,info:s}]:[]})}describeBuildErrors(e){let t=e.flatMap(({pkgDir:r,info:i})=>{let s=at(i,r);return s?[lt(pe(r),s)]:[]});return t.length>0?t.join("; "):void 0}async recoverLostSaves(e){try{for(let{pkgDir:t,info:r}of e)await this.recoverLostSave(t,r)}catch(t){this.renderer.log(` Lost-save check failed: ${String(t)}`,"debug")}}async recoverLostSave(e,t){let r=de(t,e);if(r.length===0){this.nudgedStaleness.delete(e);return}let i=r.map(({file:s,hash:o})=>`${s}:${o}`).join(`
32
- `);this.nudgedStaleness.get(e)!==i&&(await new Promise(s=>{setTimeout(s,n.STALE_BUILD_GRACE_MS)}),!(this.shuttingDown||V(e)?.mtimeMs!==t.mtimeMs)&&(this.nudgedStaleness.set(e,i),await this.forceRebuild(e,r)))}async forceRebuild(e,t){let r=pe(e),i=t.map(({file:a})=>y.relative(e,a)).join(", "),s=new Date;this.renderer.log(`\u{1F440} ${r}: last build missed a save of ${i}; forcing a rebuild`,"debug");for(let{file:a}of t)try{w.utimesSync(a,s,s)}catch{}try{await this.runBuild(`pnpm exec turbo run build --filter=${r} --env-mode=loose --output-logs=errors-only --no-update-notifier --force`,a=>{this.renderer.log(a,"debug")})}catch(a){this.renderer.log(` Forced rebuild of ${r} failed: ${String(a)}`,"debug")}let o=V(e);this.shuttingDown||!o||de(o,e).length===0||this.renderer.log(`\u26A0\uFE0F ${r}: ${i} changed but a forced rebuild still did not compile it \u2014 the server may be serving an older save. Save the file again, or re-run \`infra-kit dev\`.`,"warn")}resolveStaleFiles(e,t){let r=this.moduleGeneration;return r?e.filter(i=>!r.bustedUnder(y.dirname(i))):e.filter(i=>!t.some(s=>Ht(i,s.app.path)))}async buildClosureMapSafe(e){try{return await dt(this.monorepoRoot,e,this.dryRunner)}catch(t){return this.renderer.log(`\u26A0\uFE0F Dependency-closure map unavailable (${String(t)}); package changes restart all apps`,"warn"),null}}reportEngineDeath(e,t,r){this.shuttingDown||this.renderer.log(`\u26A0\uFE0F ${e} ${r} \u2014 ${t}. Restart \`infra-kit dev\`.`,"warn")}markUiEngineDead(){if(!this.shuttingDown){for(let{tag:e,kind:t}of this.uiTargets())this.healthEntry(e,t).dead=!0;this.refreshStatus()}}markUiTaskFailed(e){if(this.shuttingDown)return;if(this.uiHealthEnabled()){if(this.healthOf(e)==="down")return;this.markDown(e,"ui")}let t=this.uiTagByPackage.size>1?"; other frontends are unaffected":"";this.renderer.log(`\u26A0\uFE0F ${e} failed to start \u2014 its \`dev\` task exited${t}`,"error"),this.refreshStatus(),this.options.reuse&&this.shutdown().then(()=>{this.options.onExitRequest?.(1)})}setupWatch(e,t){this.turboWatch=this.turboWatchFactory({depInclusive:e.map(l=>l.packageName),depClosure:t.map(l=>l.packageName),cwd:v.cwd(),logFile:this.sink.pathFor(On),onUnexpectedExit:l=>{this.reportEngineDeath("Watch engine (`turbo watch build`)","file saves no longer rebuild",l)}}),this.renderer.narrate("\u{1F440} Watch mode: started `turbo watch build` engine; watching dist output");let r=Me(e),i=I(this.monorepoRoot),s=[...r,...i];if(this.watchedDistDirs=s,s.length===0){this.renderer.log("\u26A0\uFE0F No app or package dist directories found to watch (were they built?)","warn");return}let o=v.env.DEV_SERVER_CHOKIDAR_POLL==="1",a=En.watch(s,{ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:200,pollInterval:100},ignored:l=>l.endsWith(".tsbuildinfo")||l.endsWith(".map"),...o?{usePolling:!0,interval:400}:{}});this.watcher=a,o&&this.renderer.log("\u{1F440} chokidar: usePolling enabled (DEV_SERVER_CHOKIDAR_POLL=1)","debug");for(let l of["add","change","unlink"])a.on(l,u=>{this.handleDistChange(u,e,r,i)});this.renderer.narrate(`\u{1F440} Watching ${r.length} app dist + ${i.length} package dist dir(s) for changes...`),this.renderer.narrate(this.moduleGeneration?"\u{1F440} Watch reloads the whole local graph in place \u2014 shared packages and services included.":"\u{1F440} Watch reloads serverless handler entry files only; other modules need a re-run of `infra-kit dev`.")}handleDistChange(e,t,r,i){this.renderer.log(`\u{1F440} dist change detected: ${e}`,"debug");let s=He(e,r,i);if(s.kind==="package"){this.handlePackageDistChange(e,t,s.packageDir);return}let o=t.find(a=>y.join(a.path,"dist")===s.app);o&&(this.markChanged(o.name,e),this.scheduleDebounced(o.name,()=>this.restart([o],this.takeChanged(o.name))))}handlePackageDistChange(e,t,r){let i=pt(t,this.closureMap,r);if(i===null){this.markChanged("__packages__",e),this.scheduleDebounced("__packages__",()=>this.restart(t,this.takeChanged("__packages__")));return}for(let s of i)this.markChanged(s.name,e),this.scheduleDebounced(s.name,()=>this.restart([s],this.takeChanged(s.name)))}markChanged(e,t){let r=this.pendingChanges.get(e);r?r.add(t):this.pendingChanges.set(e,new Set([t]))}installModuleGeneration(){if(v.env.INFRA_KIT_DEV_NO_GENERATION==="1"){this.renderer.log("\u{1F440} Module generation disabled (INFRA_KIT_DEV_NO_GENERATION=1)","debug");return}if(!Ot()){this.renderer.log(`\u26A0\uFE0F This Node (${v.version}) has no \`module.registerHooks\`, so only handler entry files reload in place.`,"warn");return}let e=ve(v.env.INFRA_KIT_DEV_STOP_BYTES);this.moduleGeneration=Nt({root:w.realpathSync(this.monorepoRoot),selfDist:It(),stopBytes:e.stopBytes,stopEnabled:e.stopEnabled})}reportGenerationBudgetWarn(){let e=this.moduleGeneration?.generation()??0;this.renderer.log(`\u26A0\uFE0F Reload memory ${Pe(v.memoryUsage.rss())} after ${e} reload(s). Module records cannot be freed in-process, so this only grows \u2014 re-run \`infra-kit dev\` when convenient.`,"warn")}reportGenerationBudgetStop(e){let t=this.moduleGeneration?.generation()??0;this.renderer.log(`\u26D4 Reload memory ${Pe(v.memoryUsage.rss())} exceeds the ${Pe(e)} budget after ${t} reload(s) \u2014 stopping. Module records cannot be freed in-process. Re-run \`infra-kit dev\` to continue, or set INFRA_KIT_DEV_STOP_BYTES to raise the budget (or \`off\` to disable the stop).`,"error")}takeChanged(e){let t=this.pendingChanges.get(e);return this.pendingChanges.delete(e),t?[...t]:[]}scheduleDebounced(e,t){if(this.shuttingDown)return;let r=this.watchDebounceTimers.get(e);r&&clearTimeout(r);let i=setTimeout(()=>{this.watchDebounceTimers.delete(e),!this.shuttingDown&&t().catch(s=>{this.renderer.log(`Restart error (${e}): ${String(s)}`,"error")})},n.WATCH_DEBOUNCE_MS);this.watchDebounceTimers.set(e,i)}uiHealthEnabled(){return(this.options.uiHealth??!0)&&v.env.INFRA_KIT_NO_UI_HEALTH!=="1"}apiTargets(){return this.appServers.map(({app:e,boundPort:t})=>({tag:`${e.name}/api`,port:t,kind:"api"}))}uiTargets(){return this.uiHealthEnabled()?Object.entries(this.uiPortMap).map(([e,{port:t}])=>({tag:this.uiTagByPackage.get(e)??`${e}/ui`,port:t,kind:"ui"})):[]}healthEntry(e,t){let r=this.health.get(e);if(r)return r;let i={kind:t,failures:0,foreignStreak:0,everUp:!1,dead:!1,unverified:!1};return this.health.set(e,i),i}recordProbe(e,t){let r=this.healthEntry(e.tag,e.kind),i=n.LIVENESS_FAILURE_THRESHOLD;if(t==="ok"){let s=r.failures>=i;r.everUp=!0,r.failures=0,r.foreignStreak=0,r.unverified=!1,s&&this.renderer.log(`\u2705 ${e.tag} recovered`);return}if(Ze(t)&&e.kind==="ui"){r.foreignStreak+=1,r.unverified=r.foreignStreak>=i,r.foreignStreak===i&&this.renderer.log(`\u26A0\uFE0F ${e.tag}: ${et(e.port,t)}`,"warn");return}if(r.foreignStreak=0,r.failures+=1,e.kind==="ui"&&r.failures>=i&&(r.unverified=!1),r.failures===i){let s=e.kind==="api"?"/__health not responding":"not answering vite's ping";this.renderer.log(`\u26A0\uFE0F ${e.tag} unhealthy (${s})`,"warn")}}markDown(e,t){let r=this.healthEntry(e,t);r.dead=!0,r.failures=n.LIVENESS_FAILURE_THRESHOLD,r.foreignStreak=0,r.unverified=!1}healthOf(e){let t=this.health.get(e);return t==null?"unknown":t.unverified?"unverified":t.everUp?t.failures>=n.LIVENESS_FAILURE_THRESHOLD?"down":"ok":this.neverUpState(t)}neverUpState(e){return e.kind==="api"||e.dead||e.failures>=n.NEVER_UP_DOWN_THRESHOLD?"down":"starting"}startLivenessMonitor(){this.scheduleLivenessTick()}scheduleLivenessTick(){let e=this.options.livenessIntervalMs??n.LIVENESS_INTERVAL_MS;this.livenessTimer=setTimeout(()=>{this.livenessTick().finally(()=>{this.shuttingDown||this.scheduleLivenessTick()}).catch(()=>{})},e),this.livenessTimer.unref()}refreshStatus(){let e=this.lastSummary;if(e==null)return;let t=Date.now(),r=new Map(this.appServers.map(i=>[`${i.app.name}/api`,i]));this.pruneRequestWindow(t),this.renderer.refresh?.({...e,sessionUptimeMs:t-this.readyAt,degraded:this.degradedRows(),uiRefs:e.uiRefs.map(i=>({...i,errors:this.announceFirstError(i.tag)})),endpoints:e.endpoints.map(i=>{let s=r.get(i.tag);return{...i,health:this.healthOf(i.tag),uptimeMs:s?t-s.startedAt:void 0,restarts:s?.restarts,rpm:(this.reqTimes.get(i.tag)??[]).length,errors:this.announceFirstError(i.tag)}})})}announceFirstError(e){let{errors:t}=this.sink.statsFor(e);return t>0&&!this.firstErrorLogged.has(e)&&(this.firstErrorLogged.add(e),this.renderer.log(`\u26A0\uFE0F ${e} reported its first error \u2192 ${ee(this.sink.pathFor(e))}`,"warn")),t}degradedRows(){if(this.degradedRoutes.length===0)return[];let e=new Set(this.appServers.map(({app:t})=>t.packageName));return this.degradedRoutes.filter(t=>!e.has(t.packageName)).map(t=>({route:t.route,tag:`${t.uiApp}/ui`,fallback:t.fallback,target:t.cloudTarget}))}pruneRequestWindow(e){let t=e-6e4;for(let[r,i]of this.reqTimes)this.reqTimes.set(r,i.filter(s=>s>t))}async livenessTick(){this.shuttingDown||(await Promise.all([...this.apiTargets(),...this.uiTargets()].map(e=>this.probeOne(e))),this.announceServingOnce(),this.refreshStatus())}announceServingOnce(){this.servingAnnounced||this.lastSummary==null||this.failedApps.length>0||!this.lastSummary.endpoints.every(t=>{let r=this.healthOf(t.tag);return r==="ok"||r==="unknown"})||(this.servingAnnounced=!0,this.renderer.log(`${qt} ${this.targetLabel}`))}async findServedApps(e,t){let r=Ce(),i=[...e.map(o=>({tag:`${o.name}/api`,kind:"api",port:Rn(o.path).info.get(o.packageName)?.port??0})),...t.map(o=>{let a=`${U(o.path)}.${er(o.packageName)}`;return{tag:`${o.name}/ui`,kind:"ui",port:r.find(l=>l.name===a||l.name===`${a}.localhost`)?.port??0}})],s=await Promise.all(i.map(async o=>o.port>0&&await this.healthProbe(o)==="ok"));return i.filter((o,a)=>s[a]).map(o=>o.tag)}async endsBeforeBoot(e,t){if(e.length===0&&t.length===0)return this.renderer.log("\u26A0\uFE0F No API or UI apps to run for this preset","warn"),!0;if(!this.options.reuse)return!1;let r=await this.findServedApps(e,t);return r.length>0?(this.idleOverRunningSession(r),!0):(await this.assertCloudRoutesHaveEnv(e,t),!1)}assertNoBootFailuresWhenReusing(e){let[t]=this.failedApps;if(!(!this.options.reuse||!t))throw new Error(`infra-kit dev: ${this.failedApps.length} of ${e} app(s) failed to start. First failure (${t.app.name}): ${t.reason}`)}idleOverRunningSession(e){this.reusing=!0,this.keepAlive=setInterval(()=>{},6e4),this.renderer.log(`\u267B\uFE0F Reusing the dev server this worktree already runs (${e.join(", ")})`),this.servingAnnounced=!0,this.renderer.log(`${qt} ${e.join(", ")}`)}async assertCloudRoutesHaveEnv(e,t){let r=new Set(e.map(s=>s.packageName)),i=[];for(let s of t){let o=await Yt(s.path),a=Object.entries(o?.dev?.proxy?.routes??{}).filter(([,l])=>!l.from.includes("local")||!r.has(l.packageName));if(a.length>0&&!Xt(o?.deployedUrlEnv).url){let l=a.map(([u])=>u);i.push(`${s.name}/ui ${l.join(", ")} (${o?.deployedUrlEnv??"no deployedUrlEnv"})`)}}if(i.length!==0)throw new oe(void 0,{operation:"start the dev servers",remediation:"load an environment first (`infra-kit env-load -c dev`)",stderrExcerpt:`these routes proxy to the deployed app, whose URL is not loaded: ${i.join("; ")}`})}async probeOne(e){let t=await this.healthProbe(e);this.shuttingDown||this.recordProbe(e,t)}async printReady(e,t,r,i){let s=Date.now()-r;await Promise.all(this.apiTargets().map(p=>this.probeOne(p)));let o=this.appServers.map(({app:p,alias:g})=>({tag:`${p.name}/api`,url:_({prefixUrl:p.prefixUrl,alias:g}),health:this.healthOf(`${p.name}/api`)})),a=new Map(this.appServers.map(({app:p,alias:g})=>[p.packageName,_({prefixUrl:p.prefixUrl,alias:g})]));this.proxyRoutes=gt({uis:this.launchedUis,running:new Set(this.appServers.map(({app:p})=>p.packageName)),localOrigin:p=>a.get(p),held:this.heldLocalPkgs}),this.uiPortMap={};let l=[],u=[];for(let p of t){let g=await this.assignUiPort(p),m=`${p.name}/ui`;g!=null?l.push({tag:m,url:_({prefixUrl:"",alias:g.alias}),health:this.seedUiHealth(m),proxies:this.proxiesFor(p.name)}):u.push({tag:m,proxies:this.proxiesFor(p.name)})}let d=this.options.watch??!1,h=e.length+t.length,f=I(this.monorepoRoot).length;this.lastSummary={target:i,watch:d,release:U(v.cwd()),elapsedMs:s,endpoints:[...o,...l],uiRefs:u,failed:this.failedApps.map(({app:p,reason:g})=>({tag:`${p.name}/api`,reason:g})),degraded:this.degradedRows(),watchSummary:`${h} app${h===1?"":"s"} \xB7 ${f} package${f===1?"":"s"}`,logPath:ee(this.sink.dir),logHref:this.sink.dir},this.readyAt=Date.now(),this.renderer.ready(this.lastSummary),this.refreshStatus()}async assignUiPort(e){if(!e.managedPort)return null;let t;try{t=await Ln()}catch{return null}let r=await this.registerAppAlias(e.packageName,e.path,t);return this.uiPortMap[e.packageName]={port:t,alias:r},this.uiTagByPackage.set(e.packageName,`${e.name}/ui`),{port:t,alias:r}}seedUiHealth(e){return this.uiHealthEnabled()?(this.healthEntry(e,"ui"),this.healthOf(e)):"unknown"}printRouteDump(){if(this.appServers.length!==0){this.renderer.log("\u{1F5FA}\uFE0F Registered routes:");for(let{app:e,server:t}of this.appServers){let r=t.getRegisteredRoutes();this.renderer.log(` ${e.name} (${r.length}): ${r.length>0?r.join(", "):"(none)"}`)}}}reportFault(e){this.sink.write(J()??te,e,{level:"error"}),!this.shuttingDown&&this.renderer.log(e,"error",{tee:!1})}fileFault(e){this.sink.write(J()??te,e,{level:"error"})}get shutdownStage(){return this.stage}shutdown(){return this.teardown!=null?this.teardown:(this.teardown=this.doShutdown(),this.teardown.catch(()=>{}),this.teardown)}async doShutdown(){if(this.shuttingDown=!0,this.stage="starting",this.renderer.dispose(),this.intercept?.uninstall(),this.reusing){this.keepAlive&&clearInterval(this.keepAlive),this.keepAlive=null,this.renderer.log("\u267B\uFE0F Left the reused dev server running"),this.stage="done";return}this.renderer.log("\u{1F6D1} Shutting down all servers...");for(let e of this.watchDebounceTimers.values())clearTimeout(e);this.watchDebounceTimers.clear(),this.livenessTimer&&(clearTimeout(this.livenessTimer),this.livenessTimer=null),this.watcher&&(this.stage="watcher.close",await this.watcher.close(),this.watcher=null),this.stage="restartWorkChain",await this.restartWorkChain,this.stage="closureBuild",await this.closureBuild,this.stage="removeAlias",await Promise.all([...this.registeredAliases].map(e=>this.proxy.removeAlias(e))),this.registeredAliases.clear(),this.turboWatch&&(this.stage="turboWatch.kill",await this.turboWatch.kill(),this.turboWatch=null),this.uiDev&&(this.stage="uiDev.kill",await this.uiDev.kill(),this.uiDev=null);for(let{app:e,server:t}of this.appServers){this.stage=`server.close(${e.name})`;try{await t.close()}catch{}this.removeDevContextFragment(e)}for(let{app:e}of this.failedApps)this.heldLocalPkgs.has(e.packageName)&&this.removeDevContextFragment(e);this.intercept?.uninstall(),this.renderer.log(`\u2713 dev stopped \xB7 logs \u2192 ${ee(this.sink.dir)}`),this.sink.close(),re===this.sink&&(re=null),this.stage="done"}},nr=n=>(n.tty??!!v.stdout.isTTY)&&!n.json,Kn=async n=>{if(!nr(n))return;let{PersistentInkDevUi:e}=await import("./persistent-ink-dev-ui-P65EJCC6.js"),{createSafeStream:t}=await import("./safe-stderr-ECYA6DRR.js");return new e({appendLog:rr,verbose:n.verbose??!1,stdout:t(kt())})};async function ir(n={}){let e=await Kn(n),t=new De(n,void 0,void 0,void 0,void 0,e);try{await t.start()}catch(r){throw await t.shutdown().catch(()=>{}),r}return t}import*as Ae from"node:path";import Jn from"node:process";var ke=(n,e,t,r)=>{if(n.length<=1)return;let i=Math.ceil(n.length/2),s=n.slice(0,i),o=n.slice(i);r.push({from:t,direction:e%2===0?"horizontal":"vertical",command:o[0]});let a=r.length;ke(s,e+1,t,r),ke(o,e+1,a,r)},sr=n=>{if(n.length===0)throw new Error("buildOrcaSplitPlan: at least one command is required");let e=[];return ke(n,0,0,e),e};var zn=(n,e)=>n.map(({app:t,targets:r})=>`pnpm exec infra-kit dev ${r&&r.length>0?`--target=${r.join(",")}`:`--app=${t}`}${e?"":" --no-watch"}`),qn=n=>{let e=new Map;for(let t of Object.keys(n?.apps??{})){let r=t.split("/")[0];r===void 0||r==="*"||e.set(r,[...e.get(r)??[],t])}return e},Yn=(n,e)=>{let t=H(n);return e?t.filter(r=>e.includes(r.name)):t},Xn=async(n,e)=>{let t=await Ye();if(t==="absent")return"Orca is not installed";if(t==="unreachable")return"Orca is not running";let r=Ae.basename(n);return(await Xe(n)).registered?await Qe(n,e)?null:`this worktree is hidden in Orca's sidebar \u2014 open Orca \u2192 ${r} \u2192 "hidden worktrees" \u2192 Show`:`${r} is not registered in Orca \u2014 run \`infra-kit worktrees add\` once, it offers to register it`},Qn=async(n,e)=>(await L(["terminal","split","--terminal",n[e.from],"--direction",e.direction,"--command",e.command])).split.handle,or=async n=>{try{await L(["terminal","close","--terminal",n[0],"--tab"]);return}catch(e){T.debug({error:e},"orca: tab close refused, closing panes one by one")}for(let e of n)try{await L(["terminal","close","--terminal",e])}catch(t){T.debug({handle:e,error:t},"orca: pane already gone")}},Zn=async(n,e,t)=>{let i=[(await L(["terminal","create","--worktree",`path:${n}`,"--title",e,"--command",t[0]])).terminal.handle];try{for(let s of sr(t))i.push(await Qn(i,s))}catch(s){throw await or(i),s}return i},ei=(n,e,t)=>{T.info(`\u{1F9E9} Opened Orca tab "${t}" with ${n.length} pane(s):`),n.forEach((r,i)=>{T.info(` \u2022 ${r.name} (${e[i]})`)})},ti=(n,e)=>{G({onSignal:async t=>{T.info(`
33
- Received ${t}, closing Orca tab "${e}"...`),await or(n)}})},ar=async n=>{let e=O(Jn.cwd()),t=Yn(e,j(n.include));if(t.length===0)return{fallback:"no API apps to open a pane for (panes are backend-only)"};let r=await Xn(await Le(e),e);if(r!==null)return{fallback:r};let i=qn(n.presetDef),s=zn(t.map(u=>({app:u.name,targets:i.get(u.name)})),n.watch??!1),o=`${Ae.basename(e)} dev`,a=await Zn(e,o,s);ei(t,s,o),ti(a,o);let l=setInterval(()=>{l.refresh()},2**30);return await new Promise(()=>{}),"ran"};var Re=1,ii=2e4,si=n=>{if(n!=null){for(let e of n)if(je(e)!==null)throw new Error(`infra-kit dev: invalid --target "${e}" (expected "<app>/api" or "<app>/ui").`);return{apps:Object.fromEntries(n.map(e=>[e,{}]))}}},lr=n=>{if(n==null)return null;let e=n.split(",").map(t=>t.trim()).filter(Boolean);return e.length>0?e:null},ur=n=>({watch:n.watch??!0,include:lr(n.app),preset:n.preset,presetDef:si(lr(n.target)),orca:n.orca??!1,self:n.self??!1,verbose:n.verbose??!1,routes:n.routes??!1,uiHealth:n.uiHealth??!0,reuse:n.reuse??!1,...n.reuse?{livenessIntervalMs:1e3}:{}}),oi=n=>!n.self||n.include?n:{...n,include:[Be(k.cwd())]},dr=(n,e)=>{let t=setTimeout(n,e);return t.unref(),()=>{clearTimeout(t)}},ai=(n=dr)=>{let e=!1;return(t,r)=>{if(e)return()=>{};e=!0;let i=n(t,r);return()=>{e=!1,i()}}},pr=(n,e,t)=>{n(),e(t)},li=({getRunner:n,forceReap:e=N,exit:t=s=>{k.exit(s)},setTimer:r=dr,deadlineMs:i=ii})=>{let s=!1;return o=>{if(s)return;s=!0;let a=n();if(a==null){pr(e,t,Re);return}a.fileFault(`
31
+ \`infra-kit doctor\` checks the daemon and CA trust state.`)}async registerAppAlias(e,t,r){let i=Se(e,t);if(!await this.proxy.registerAlias(i,r))throw new Error(`infra-kit dev: portless refused the alias "${i}" \u2192 127.0.0.1:${r}.`);return this.registeredAliases.add(i),`${i}.localhost`}async startOneApp(e){this.renderer.narrate(`\u{1F504} Starting ${e.name}...`);let t=new X({controllersPath:e.path,prefixUrl:e.prefixUrl,port:e.preferredPort,appName:e.name,serviceTag:`${e.name}/api`,onRequestLog:({method:s,path:o,status:a,ms:l})=>{if(o==="/__health")return;let u=`${e.name}/api`,d=`${s} ${o} ${a} ${l}ms`;this.sink.write(u,d,{level:a>=500?"error":"info"});let h=this.reqTimes.get(u);h?h.push(Date.now()):this.reqTimes.set(u,[Date.now()])}}),r=await t.start(),i;try{i=await this.registerAppAlias(e.packageName,e.path,r)}catch(s){throw await t.close().catch(()=>{}),s}try{this.writeDevContextFragment(e,r,i)}catch(s){this.renderer.log(`\u26A0\uFE0F Failed to write dev-context fragment for ${e.name}: ${String(s)}`,"warn")}return this.renderer.narrate(`\u2705 ${e.name} started on port ${r}`),{server:t,boundPort:r,alias:i}}holdFailedBackendsLocal(){for(let{app:e}of this.failedApps)try{this.writeDevContextFragment(e,0,`${Se(e.packageName,e.path)}.localhost`),this.heldLocalPkgs.add(e.packageName)}catch(t){this.renderer.log(`\u26A0\uFE0F Failed to hold ${e.name}'s routes local: ${String(t)}`,"warn")}}writeDevContextFragment(e,t,r){let i={v:Rn,package:e.packageName,port:t,pid:v.pid,writtenAt:Date.now(),release:ae(e.path),alias:r,origin:`https://${r}`,env:v.env[Ce]??""},s=y.join(this.devContextDir,`${e.name}.json`),o=y.join(this.devContextDir,`${e.name}.json.${v.pid}.tmp`);w.mkdirSync(this.devContextDir,{recursive:!0}),w.writeFileSync(o,JSON.stringify(i,null,2)),w.renameSync(o,s)}removeDevContextFragment(e){w.rmSync(y.join(this.devContextDir,`${e.name}.json`),{force:!0})}scheduleRestartWork(e){let t=this.restartWorkChain.then(()=>e(),()=>e());return this.restartWorkChain=t.catch(()=>{}),t}async delayPortRelease(){await new Promise(e=>setTimeout(e,n.PORT_RELEASE_DELAY_MS))}restart(e,t=[]){return this.shuttingDown?Promise.resolve():this.scheduleRestartWork(async()=>{this.shuttingDown||(await this.runRestart(e,t),this.recoverLostSaves(this.triggeringBuilds(t)))})}resolveRestartTargets(e){return e.map(t=>({idx:this.appServers.findIndex(r=>r.app.name===t.name),app:t})).filter(t=>t.idx>=0||this.isFailedApp(t.app.name))}isFailedApp(e){return this.failedApps.some(t=>t.app.name===e)}promoteRecoveredApp(e,t){let r={app:e,...t,startedAt:Date.now(),restarts:0},i=`${e.name}/api`;this.healthEntry(i,"api"),this.appServers.push(r);let s=this.failedApps.findIndex(o=>o.app.name===e.name);return s>=0&&this.failedApps.splice(s,1),this.lastSummary&&(this.lastSummary={...this.lastSummary,endpoints:[...this.lastSummary.endpoints,{tag:i,url:_({prefixUrl:e.prefixUrl,alias:t.alias}),health:this.healthOf(i)}],failed:(this.lastSummary.failed??[]).filter(o=>o.tag!==i)}),r}async runRestart(e,t=[]){let r=this.resolveRestartTargets(e);if(r.length===0)return;let i=r.length===1?r[0].app.name:`${r.length} apps`,s=this.moduleGeneration?.budgetState()??"ok";if(s==="stop"){this.reportGenerationBudgetStop(ve(v.env.INFRA_KIT_DEV_STOP_BYTES).stopBytes),this.shutdown().catch(()=>{}).finally(()=>{this.options.onExitRequest?.(1)}).catch(()=>{});return}s==="warn"&&this.reportGenerationBudgetWarn(),this.moduleGeneration?.bump(),this.renderer.log(`\u{1F504} Restarting ${i}...`),await Promise.all(r.map(async({idx:p})=>{if(!(p<0))try{await this.appServers[p].server.close()}catch(g){this.renderer.log(` Close warning: ${String(g)}`,"debug")}})),await this.delayPortRelease();let o=await Promise.all(r.map(async({idx:p,app:g})=>{try{let m=await this.startOneApp(g);if(m){if(p<0){let S=this.promoteRecoveredApp(g,m);return this.renderer.log(`\u2705 ${g.name} recovered \u2014 its routes are served locally again`,"info"),{app:g,entry:S}}let P=this.appServers[p],c={app:g,...m,startedAt:Date.now(),restarts:(P?.restarts??0)+1};return this.appServers[p]=c,{app:g,entry:c}}return{app:g,entry:null}}catch(m){return this.renderer.log(`\u274C Failed to ${p<0?"start":"restart"} ${g.name}: ${String(m)}`,"error"),{app:g,entry:null}}})),a=await Promise.all(o.map(async({app:p,entry:g})=>{let m=`${p.name}/api`;if(g==null)return this.markDown(m,"api"),this.refreshStatus(),{label:`${p.name} \u25CF down`,healthy:!1};let P={tag:m,port:g.boundPort,kind:"api"},c=await this.healthProbe(P);this.recordProbe(P,c),this.refreshStatus();let S=c==="ok";return{label:`${p.name}:${g.boundPort} ${S?"\u25CF up":"\u25CF down"}`,healthy:S}})),l=a.every(p=>p.healthy),u=a.map(p=>p.label).join(", "),h=o.some(p=>p.entry!==null)?this.resolveStaleFiles(t,r):[];if(h.length>0){this.renderer.log(`\u26A0\uFE0F Restarted ${u} \u2014 still serving the OLD ${Gt(h)}. Re-run \`infra-kit dev\` to pick this up.`,"warn");return}let f=this.describeBuildErrors(this.triggeringBuilds(t));if(f!==void 0){this.renderer.log(`\u26A0\uFE0F Restarted ${u} \u2014 ${f}`,"warn");return}this.renderer.log(`${l?"\u2705":"\u26A0\uFE0F "} Restarted ${u}`)}triggeringBuilds(e){let t=new Map;for(let r of e){let i=this.watchedDistDirs.find(o=>r===o||r.startsWith(o+y.sep));if(i===void 0)continue;let s=y.dirname(i);t.set(s,[...t.get(s)??[],r])}return[...t].flatMap(([r,i])=>{let s=G(r);return s&&lt(s,i)?[{pkgDir:r,info:s}]:[]})}describeBuildErrors(e){let t=e.flatMap(({pkgDir:r,info:i})=>{let s=ut(i,r);return s?[dt(pe(r),s)]:[]});return t.length>0?t.join("; "):void 0}async recoverLostSaves(e){try{for(let{pkgDir:t,info:r}of e)await this.recoverLostSave(t,r)}catch(t){this.renderer.log(` Lost-save check failed: ${String(t)}`,"debug")}}async recoverLostSave(e,t){let r=de(t,e);if(r.length===0){this.nudgedStaleness.delete(e);return}let i=r.map(({file:s,hash:o})=>`${s}:${o}`).join(`
32
+ `);this.nudgedStaleness.get(e)!==i&&(await new Promise(s=>{setTimeout(s,n.STALE_BUILD_GRACE_MS)}),!(this.shuttingDown||G(e)?.mtimeMs!==t.mtimeMs)&&(this.nudgedStaleness.set(e,i),await this.forceRebuild(e,r)))}async forceRebuild(e,t){let r=pe(e),i=t.map(({file:a})=>y.relative(e,a)).join(", "),s=new Date;this.renderer.log(`\u{1F440} ${r}: last build missed a save of ${i}; forcing a rebuild`,"debug");for(let{file:a}of t)try{w.utimesSync(a,s,s)}catch{}try{await this.runBuild(`pnpm exec turbo run build --filter=${r} --env-mode=loose --output-logs=errors-only --no-update-notifier --force`,a=>{this.renderer.log(a,"debug")})}catch(a){this.renderer.log(` Forced rebuild of ${r} failed: ${String(a)}`,"debug")}let o=G(e);this.shuttingDown||!o||de(o,e).length===0||this.renderer.log(`\u26A0\uFE0F ${r}: ${i} changed but a forced rebuild still did not compile it \u2014 the server may be serving an older save. Save the file again, or re-run \`infra-kit dev\`.`,"warn")}resolveStaleFiles(e,t){let r=this.moduleGeneration;return r?e.filter(i=>!r.bustedUnder(y.dirname(i))):e.filter(i=>!t.some(s=>Wt(i,s.app.path)))}async buildClosureMapSafe(e){try{return await ct(this.monorepoRoot,e,this.dryRunner)}catch(t){return this.renderer.log(`\u26A0\uFE0F Dependency-closure map unavailable (${String(t)}); package changes restart all apps`,"warn"),null}}reportEngineDeath(e,t,r){this.shuttingDown||this.renderer.log(`\u26A0\uFE0F ${e} ${r} \u2014 ${t}. Restart \`infra-kit dev\`.`,"warn")}markUiEngineDead(){if(!this.shuttingDown){for(let{tag:e,kind:t}of this.uiTargets())this.healthEntry(e,t).dead=!0;this.refreshStatus()}}markUiTaskFailed(e){if(this.shuttingDown)return;if(this.uiHealthEnabled()){if(this.healthOf(e)==="down")return;this.markDown(e,"ui")}let t=this.uiTagByPackage.size>1?"; other frontends are unaffected":"";this.renderer.log(`\u26A0\uFE0F ${e} failed to start \u2014 its \`dev\` task exited${t}`,"error"),this.refreshStatus(),this.options.reuse&&this.shutdown().then(()=>{this.options.onExitRequest?.(1)})}setupWatch(e,t){this.turboWatch=this.turboWatchFactory({depInclusive:e.map(l=>l.packageName),depClosure:t.map(l=>l.packageName),cwd:v.cwd(),logFile:this.sink.pathFor(In),onUnexpectedExit:l=>{this.reportEngineDeath("Watch engine (`turbo watch build`)","file saves no longer rebuild",l)}}),this.renderer.narrate("\u{1F440} Watch mode: started `turbo watch build` engine; watching dist output");let r=je(e),i=I(this.monorepoRoot),s=[...r,...i];if(this.watchedDistDirs=s,s.length===0){this.renderer.log("\u26A0\uFE0F No app or package dist directories found to watch (were they built?)","warn");return}let o=v.env.DEV_SERVER_CHOKIDAR_POLL==="1",a=xn.watch(s,{ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:200,pollInterval:100},ignored:l=>l.endsWith(".tsbuildinfo")||l.endsWith(".map"),...o?{usePolling:!0,interval:400}:{}});this.watcher=a,o&&this.renderer.log("\u{1F440} chokidar: usePolling enabled (DEV_SERVER_CHOKIDAR_POLL=1)","debug");for(let l of["add","change","unlink"])a.on(l,u=>{this.handleDistChange(u,e,r,i)});this.renderer.narrate(`\u{1F440} Watching ${r.length} app dist + ${i.length} package dist dir(s) for changes...`),this.renderer.narrate(this.moduleGeneration?"\u{1F440} Watch reloads the whole local graph in place \u2014 shared packages and services included.":"\u{1F440} Watch reloads serverless handler entry files only; other modules need a re-run of `infra-kit dev`.")}handleDistChange(e,t,r,i){this.renderer.log(`\u{1F440} dist change detected: ${e}`,"debug");let s=We(e,r,i);if(s.kind==="package"){this.handlePackageDistChange(e,t,s.packageDir);return}let o=t.find(a=>y.join(a.path,"dist")===s.app);o&&(this.markChanged(o.name,e),this.scheduleDebounced(o.name,()=>this.restart([o],this.takeChanged(o.name))))}handlePackageDistChange(e,t,r){let i=ht(t,this.closureMap,r);if(i===null){this.markChanged("__packages__",e),this.scheduleDebounced("__packages__",()=>this.restart(t,this.takeChanged("__packages__")));return}for(let s of i)this.markChanged(s.name,e),this.scheduleDebounced(s.name,()=>this.restart([s],this.takeChanged(s.name)))}markChanged(e,t){let r=this.pendingChanges.get(e);r?r.add(t):this.pendingChanges.set(e,new Set([t]))}installModuleGeneration(){if(v.env.INFRA_KIT_DEV_NO_GENERATION==="1"){this.renderer.log("\u{1F440} Module generation disabled (INFRA_KIT_DEV_NO_GENERATION=1)","debug");return}if(!Nt()){this.renderer.log(`\u26A0\uFE0F This Node (${v.version}) has no \`module.registerHooks\`, so only handler entry files reload in place.`,"warn");return}let e=ve(v.env.INFRA_KIT_DEV_STOP_BYTES);this.moduleGeneration=_t({root:w.realpathSync(this.monorepoRoot),selfDist:Lt(),stopBytes:e.stopBytes,stopEnabled:e.stopEnabled})}reportGenerationBudgetWarn(){let e=this.moduleGeneration?.generation()??0;this.renderer.log(`\u26A0\uFE0F Reload memory ${De(v.memoryUsage.rss())} after ${e} reload(s). Module records cannot be freed in-process, so this only grows \u2014 re-run \`infra-kit dev\` when convenient.`,"warn")}reportGenerationBudgetStop(e){let t=this.moduleGeneration?.generation()??0;this.renderer.log(`\u26D4 Reload memory ${De(v.memoryUsage.rss())} exceeds the ${De(e)} budget after ${t} reload(s) \u2014 stopping. Module records cannot be freed in-process. Re-run \`infra-kit dev\` to continue, or set INFRA_KIT_DEV_STOP_BYTES to raise the budget (or \`off\` to disable the stop).`,"error")}takeChanged(e){let t=this.pendingChanges.get(e);return this.pendingChanges.delete(e),t?[...t]:[]}scheduleDebounced(e,t){if(this.shuttingDown)return;let r=this.watchDebounceTimers.get(e);r&&clearTimeout(r);let i=setTimeout(()=>{this.watchDebounceTimers.delete(e),!this.shuttingDown&&t().catch(s=>{this.renderer.log(`Restart error (${e}): ${String(s)}`,"error")})},n.WATCH_DEBOUNCE_MS);this.watchDebounceTimers.set(e,i)}uiHealthEnabled(){return(this.options.uiHealth??!0)&&v.env.INFRA_KIT_NO_UI_HEALTH!=="1"}apiTargets(){return this.appServers.map(({app:e,boundPort:t})=>({tag:`${e.name}/api`,port:t,kind:"api"}))}uiTargets(){return this.uiHealthEnabled()?Object.entries(this.uiPortMap).map(([e,{port:t}])=>({tag:this.uiTagByPackage.get(e)??`${e}/ui`,port:t,kind:"ui"})):[]}healthEntry(e,t){let r=this.health.get(e);if(r)return r;let i={kind:t,failures:0,foreignStreak:0,everUp:!1,dead:!1,unverified:!1};return this.health.set(e,i),i}recordProbe(e,t){let r=this.healthEntry(e.tag,e.kind),i=n.LIVENESS_FAILURE_THRESHOLD;if(t==="ok"){let s=r.failures>=i;r.everUp=!0,r.failures=0,r.foreignStreak=0,r.unverified=!1,s&&this.renderer.log(`\u2705 ${e.tag} recovered`);return}if(tt(t)&&e.kind==="ui"){r.foreignStreak+=1,r.unverified=r.foreignStreak>=i,r.foreignStreak===i&&this.renderer.log(`\u26A0\uFE0F ${e.tag}: ${rt(e.port,t)}`,"warn");return}if(r.foreignStreak=0,r.failures+=1,e.kind==="ui"&&r.failures>=i&&(r.unverified=!1),r.failures===i){let s=e.kind==="api"?"/__health not responding":"not answering vite's ping";this.renderer.log(`\u26A0\uFE0F ${e.tag} unhealthy (${s})`,"warn")}}markDown(e,t){let r=this.healthEntry(e,t);r.dead=!0,r.failures=n.LIVENESS_FAILURE_THRESHOLD,r.foreignStreak=0,r.unverified=!1}healthOf(e){let t=this.health.get(e);return t==null?"unknown":t.unverified?"unverified":t.everUp?t.failures>=n.LIVENESS_FAILURE_THRESHOLD?"down":"ok":this.neverUpState(t)}neverUpState(e){return e.kind==="api"||e.dead||e.failures>=n.NEVER_UP_DOWN_THRESHOLD?"down":"starting"}startLivenessMonitor(){this.scheduleLivenessTick()}scheduleLivenessTick(){let e=this.options.livenessIntervalMs??n.LIVENESS_INTERVAL_MS;this.livenessTimer=setTimeout(()=>{this.livenessTick().finally(()=>{this.shuttingDown||this.scheduleLivenessTick()}).catch(()=>{})},e),this.livenessTimer.unref()}refreshStatus(){let e=this.lastSummary;if(e==null)return;let t=Date.now(),r=new Map(this.appServers.map(i=>[`${i.app.name}/api`,i]));this.pruneRequestWindow(t),this.renderer.refresh?.({...e,sessionUptimeMs:t-this.readyAt,degraded:this.degradedRows(),uiRefs:e.uiRefs.map(i=>({...i,errors:this.announceFirstError(i.tag)})),endpoints:e.endpoints.map(i=>{let s=r.get(i.tag);return{...i,health:this.healthOf(i.tag),uptimeMs:s?t-s.startedAt:void 0,restarts:s?.restarts,rpm:(this.reqTimes.get(i.tag)??[]).length,errors:this.announceFirstError(i.tag)}})})}announceFirstError(e){let{errors:t}=this.sink.statsFor(e);return t>0&&!this.firstErrorLogged.has(e)&&(this.firstErrorLogged.add(e),this.renderer.log(`\u26A0\uFE0F ${e} reported its first error \u2192 ${Z(this.sink.pathFor(e))}`,"warn")),t}degradedRows(){if(this.degradedRoutes.length===0)return[];let e=new Set(this.appServers.map(({app:t})=>t.packageName));return this.degradedRoutes.filter(t=>!e.has(t.packageName)).map(t=>({route:t.route,tag:`${t.uiApp}/ui`,fallback:t.fallback,target:t.cloudTarget}))}pruneRequestWindow(e){let t=e-6e4;for(let[r,i]of this.reqTimes)this.reqTimes.set(r,i.filter(s=>s>t))}async livenessTick(){this.shuttingDown||(await Promise.all([...this.apiTargets(),...this.uiTargets()].map(e=>this.probeOne(e))),this.announceServingOnce(),this.refreshStatus())}announceServingOnce(){this.servingAnnounced||this.lastSummary==null||this.failedApps.length>0||!this.lastSummary.endpoints.every(t=>{let r=this.healthOf(t.tag);return r==="ok"||r==="unknown"})||(this.servingAnnounced=!0,this.renderer.log(`${Xt} ${this.targetLabel}`))}async findServedApps(e,t){let r=Ie(),i=[...e.map(o=>({tag:`${o.name}/api`,kind:"api",port:En(o.path).info.get(o.packageName)?.port??0})),...t.map(o=>{let a=Se(o.packageName,o.path);return{tag:`${o.name}/ui`,kind:"ui",port:r.find(l=>l.name===a||l.name===`${a}.localhost`)?.port??0}})],s=await Promise.all(i.map(async o=>o.port>0&&await this.healthProbe(o)==="ok"));return i.filter((o,a)=>s[a]).map(o=>o.tag)}async endsBeforeBoot(e,t){if(e.length===0&&t.length===0)return this.renderer.log("\u26A0\uFE0F No API or UI apps to run for this preset","warn"),!0;if(!this.options.reuse)return!1;let r=await this.findServedApps(e,t);return r.length>0?(this.idleOverRunningSession(r),!0):(await this.assertCloudRoutesHaveEnv(e,t),!1)}assertNoBootFailuresWhenReusing(e){let[t]=this.failedApps;if(!(!this.options.reuse||!t))throw new Error(`infra-kit dev: ${this.failedApps.length} of ${e} app(s) failed to start. First failure (${t.app.name}): ${t.reason}`)}idleOverRunningSession(e){this.reusing=!0,this.keepAlive=setInterval(()=>{},6e4),this.renderer.log(`\u267B\uFE0F Reusing the dev server this worktree already runs (${e.join(", ")})`),this.servingAnnounced=!0,this.renderer.log(`${Xt} ${e.join(", ")}`)}async assertCloudRoutesHaveEnv(e,t){let r=new Set(e.map(s=>s.packageName)),i=[];for(let s of t){let o=await Qt(s.path),a=Object.entries(o?.dev?.proxy?.routes??{}).filter(([,l])=>!l.from.includes("local")||!r.has(l.packageName));if(a.length>0&&!Zt(o?.deployedUrlEnv).url){let l=a.map(([u])=>u);i.push(`${s.name}/ui ${l.join(", ")} (${o?.deployedUrlEnv??"no deployedUrlEnv"})`)}}if(i.length!==0)throw new se(void 0,{operation:"start the dev servers",remediation:"load an environment first (`infra-kit env-load -c dev`)",stderrExcerpt:`these routes proxy to the deployed app, whose URL is not loaded: ${i.join("; ")}`})}async probeOne(e){let t=await this.healthProbe(e);this.shuttingDown||this.recordProbe(e,t)}async printReady(e,t,r,i){let s=Date.now()-r;await Promise.all(this.apiTargets().map(p=>this.probeOne(p)));let o=this.appServers.map(({app:p,alias:g})=>({tag:`${p.name}/api`,url:_({prefixUrl:p.prefixUrl,alias:g}),health:this.healthOf(`${p.name}/api`)})),a=new Map(this.appServers.map(({app:p,alias:g})=>[p.packageName,_({prefixUrl:p.prefixUrl,alias:g})]));this.proxyRoutes=mt({uis:this.launchedUis,running:new Set(this.appServers.map(({app:p})=>p.packageName)),localOrigin:p=>a.get(p),held:this.heldLocalPkgs}),this.uiPortMap={};let l=[],u=[];for(let p of t){let g=await this.assignUiPort(p),m=`${p.name}/ui`;g!=null?l.push({tag:m,url:_({prefixUrl:"",alias:g.alias}),health:this.seedUiHealth(m),proxies:this.proxiesFor(p.name)}):u.push({tag:m,proxies:this.proxiesFor(p.name)})}let d=this.options.watch??!1,h=e.length+t.length,f=I(this.monorepoRoot).length;this.lastSummary={target:i,watch:d,release:ae(v.cwd()),elapsedMs:s,endpoints:[...o,...l],uiRefs:u,failed:this.failedApps.map(({app:p,reason:g})=>({tag:`${p.name}/api`,reason:g})),degraded:this.degradedRows(),watchSummary:`${h} app${h===1?"":"s"} \xB7 ${f} package${f===1?"":"s"}`,logPath:Z(this.sink.dir),logHref:this.sink.dir},this.readyAt=Date.now(),this.renderer.ready(this.lastSummary),this.refreshStatus()}async assignUiPort(e){if(!e.managedPort)return null;let t;try{t=await _n()}catch{return null}let r=await this.registerAppAlias(e.packageName,e.path,t);return this.uiPortMap[e.packageName]={port:t,alias:r},this.uiTagByPackage.set(e.packageName,`${e.name}/ui`),{port:t,alias:r}}seedUiHealth(e){return this.uiHealthEnabled()?(this.healthEntry(e,"ui"),this.healthOf(e)):"unknown"}printRouteDump(){if(this.appServers.length!==0){this.renderer.log("\u{1F5FA}\uFE0F Registered routes:");for(let{app:e,server:t}of this.appServers){let r=t.getRegisteredRoutes();this.renderer.log(` ${e.name} (${r.length}): ${r.length>0?r.join(", "):"(none)"}`)}}}reportFault(e){this.sink.write(K()??ee,e,{level:"error"}),!this.shuttingDown&&this.renderer.log(e,"error",{tee:!1})}fileFault(e){this.sink.write(K()??ee,e,{level:"error"})}get shutdownStage(){return this.stage}shutdown(){return this.teardown!=null?this.teardown:(this.teardown=this.doShutdown(),this.teardown.catch(()=>{}),this.teardown)}async doShutdown(){if(this.shuttingDown=!0,this.stage="starting",this.renderer.dispose(),this.intercept?.uninstall(),this.reusing){this.keepAlive&&clearInterval(this.keepAlive),this.keepAlive=null,this.renderer.log("\u267B\uFE0F Left the reused dev server running"),this.stage="done";return}this.renderer.log("\u{1F6D1} Shutting down all servers...");for(let e of this.watchDebounceTimers.values())clearTimeout(e);this.watchDebounceTimers.clear(),this.livenessTimer&&(clearTimeout(this.livenessTimer),this.livenessTimer=null),this.watcher&&(this.stage="watcher.close",await this.watcher.close(),this.watcher=null),this.stage="restartWorkChain",await this.restartWorkChain,this.stage="closureBuild",await this.closureBuild,this.stage="removeAlias",await Promise.all([...this.registeredAliases].map(e=>this.proxy.removeAlias(e))),this.registeredAliases.clear(),this.turboWatch&&(this.stage="turboWatch.kill",await this.turboWatch.kill(),this.turboWatch=null),this.uiDev&&(this.stage="uiDev.kill",await this.uiDev.kill(),this.uiDev=null);for(let{app:e,server:t}of this.appServers){this.stage=`server.close(${e.name})`;try{await t.close()}catch{}this.removeDevContextFragment(e)}for(let{app:e}of this.failedApps)this.heldLocalPkgs.has(e.packageName)&&this.removeDevContextFragment(e);this.intercept?.uninstall(),this.renderer.log(`\u2713 dev stopped \xB7 logs \u2192 ${Z(this.sink.dir)}`),this.sink.close(),te===this.sink&&(te=null),this.stage="done"}},ir=n=>(n.tty??!!v.stdout.isTTY)&&!n.json,zn=async n=>{if(!ir(n))return;let{PersistentInkDevUi:e}=await import("./persistent-ink-dev-ui-ZSOS3CF4.js"),{createSafeStream:t}=await import("./safe-stderr-ECYA6DRR.js");return new e({appendLog:nr,verbose:n.verbose??!1,stdout:t(Rt())})};async function sr(n={}){let e=await zn(n),t=new ke(n,void 0,void 0,void 0,void 0,e);try{await t.start()}catch(r){throw await t.shutdown().catch(()=>{}),r}return t}import*as Re from"node:path";import qn from"node:process";var Ae=(n,e,t,r)=>{if(n.length<=1)return;let i=Math.ceil(n.length/2),s=n.slice(0,i),o=n.slice(i);r.push({from:t,direction:e%2===0?"horizontal":"vertical",command:o[0]});let a=r.length;Ae(s,e+1,t,r),Ae(o,e+1,a,r)},or=n=>{if(n.length===0)throw new Error("buildOrcaSplitPlan: at least one command is required");let e=[];return Ae(n,0,0,e),e};var Yn=(n,e)=>n.map(({app:t,targets:r})=>`pnpm exec infra-kit dev ${r&&r.length>0?`--target=${r.join(",")}`:`--app=${t}`}${e?"":" --no-watch"}`),Xn=n=>{let e=new Map;for(let t of Object.keys(n?.apps??{})){let r=t.split("/")[0];r===void 0||r==="*"||e.set(r,[...e.get(r)??[],t])}return e},Qn=(n,e)=>{let t=M(n);return e?t.filter(r=>e.includes(r.name)):t},Zn=async(n,e)=>{let t=await Qe();if(t==="absent")return"Orca is not installed";if(t==="unreachable")return"Orca is not running";let r=Re.basename(n);return(await Ze(n)).registered?await et(n,e)?null:`this worktree is hidden in Orca's sidebar \u2014 open Orca \u2192 ${r} \u2192 "hidden worktrees" \u2192 Show`:`${r} is not registered in Orca \u2014 run \`infra-kit worktrees add\` once, it offers to register it`},ei=async(n,e)=>(await L(["terminal","split","--terminal",n[e.from],"--direction",e.direction,"--command",e.command])).split.handle,ar=async n=>{try{await L(["terminal","close","--terminal",n[0],"--tab"]);return}catch(e){T.debug({error:e},"orca: tab close refused, closing panes one by one")}for(let e of n)try{await L(["terminal","close","--terminal",e])}catch(t){T.debug({handle:e,error:t},"orca: pane already gone")}},ti=async(n,e,t)=>{let i=[(await L(["terminal","create","--worktree",`path:${n}`,"--title",e,"--command",t[0]])).terminal.handle];try{for(let s of or(t))i.push(await ei(i,s))}catch(s){throw await ar(i),s}return i},ri=(n,e,t)=>{T.info(`\u{1F9E9} Opened Orca tab "${t}" with ${n.length} pane(s):`),n.forEach((r,i)=>{T.info(` \u2022 ${r.name} (${e[i]})`)})},ni=(n,e)=>{W({onSignal:async t=>{T.info(`
33
+ Received ${t}, closing Orca tab "${e}"...`),await ar(n)}})},lr=async n=>{let e=O(qn.cwd()),t=Qn(e,H(n.include));if(t.length===0)return{fallback:"no API apps to open a pane for (panes are backend-only)"};let r=await Zn(await Ue(e),e);if(r!==null)return{fallback:r};let i=Xn(n.presetDef),s=Yn(t.map(u=>({app:u.name,targets:i.get(u.name)})),n.watch??!1),o=`${Re.basename(e)} dev`,a=await ti(e,o,s);ri(t,s,o),ni(a,o);let l=setInterval(()=>{l.refresh()},2**30);return await new Promise(()=>{}),"ran"};var Ee=1,oi=2e4,ai=n=>{if(n!=null){for(let e of n)if(Ge(e)!==null)throw new Error(`infra-kit dev: invalid --target "${e}" (expected "<app>/api" or "<app>/ui").`);return{apps:Object.fromEntries(n.map(e=>[e,{}]))}}},ur=n=>{if(n==null)return null;let e=n.split(",").map(t=>t.trim()).filter(Boolean);return e.length>0?e:null},dr=n=>({watch:n.watch??!0,include:ur(n.app),preset:n.preset,presetDef:ai(ur(n.target)),orca:n.orca??!1,self:n.self??!1,verbose:n.verbose??!1,routes:n.routes??!1,uiHealth:n.uiHealth??!0,reuse:n.reuse??!1,...n.reuse?{livenessIntervalMs:1e3}:{}}),li=n=>!n.self||n.include?n:{...n,include:[He(k.cwd())]},pr=(n,e)=>{let t=setTimeout(n,e);return t.unref(),()=>{clearTimeout(t)}},ui=(n=pr)=>{let e=!1;return(t,r)=>{if(e)return()=>{};e=!0;let i=n(t,r);return()=>{e=!1,i()}}},cr=(n,e,t)=>{n(),e(t)},di=({getRunner:n,forceReap:e=N,exit:t=s=>{k.exit(s)},setTimer:r=pr,deadlineMs:i=oi})=>{let s=!1;return o=>{if(s)return;s=!0;let a=n();if(a==null){cr(e,t,Ee);return}a.fileFault(`
34
34
  \u2717 dev-server exiting: ${o}
35
- `);let l=r(()=>{e(),t(Re)},i);a.shutdown().finally(()=>{l(),t(Re)}).catch(()=>{})}},ui=["SIGINT","SIGTERM"],di=({forceReap:n=N,exit:e=i=>{k.exit(i)},register:t=(i,s)=>{k.on(i,s)},unregister:r=(i,s)=>{k.off(i,s)}}={})=>{let i=new Map;for(let s of ui){let o=()=>{pr(n,e,qe(s))};i.set(s,o),t(s,o)}return{remove:()=>{for(let[s,o]of i)r(s,o)}}},Ee=async n=>{let e=oi(n);if(e.orca){let l=await ar(e);if(l==="ran")return;k.stdout.write(`Orca: ${l.fallback}; falling back to single-terminal dev
36
- `)}let t=null,r=ai(),i=li({getRunner:()=>t,setTimer:r}),s=bt({onDeath:(l,u)=>{i(`stdio unwritable: ${l} ${u.code}`)}}),o=di();try{t=await ir({...e,onExitRequest:l=>{k.exit(l)}})}finally{o.remove()}let a=t;it({onFault:(l,u)=>{a.reportFault(F(l,u))},isTerminalDead:s.isDead,fileFault:(l,u)=>{a.fileFault(F(l,u,!1))},onFatal:i}),G({onSignal:async l=>{he(`
35
+ `);let l=r(()=>{e(),t(Ee)},i);a.shutdown().finally(()=>{l(),t(Ee)}).catch(()=>{})}},pi=["SIGINT","SIGTERM"],ci=({forceReap:n=N,exit:e=i=>{k.exit(i)},register:t=(i,s)=>{k.on(i,s)},unregister:r=(i,s)=>{k.off(i,s)}}={})=>{let i=new Map;for(let s of pi){let o=()=>{cr(n,e,Xe(s))};i.set(s,o),t(s,o)}return{remove:()=>{for(let[s,o]of i)r(s,o)}}},xe=async n=>{let e=li(n);if(e.orca){let l=await lr(e);if(l==="ran")return;k.stdout.write(`Orca: ${l.fallback}; falling back to single-terminal dev
36
+ `)}let t=null,r=ui(),i=di({getRunner:()=>t,setTimer:r}),s=Pt({onDeath:(l,u)=>{i(`stdio unwritable: ${l} ${u.code}`)}}),o=ci();try{t=await sr({...e,onExitRequest:l=>{k.exit(l)}})}finally{o.remove()}let a=t;ot({onFault:(l,u)=>{a.reportFault(U(l,u))},isTerminalDead:s.isDead,fileFault:(l,u)=>{a.fileFault(U(l,u,!1))},onFatal:i}),W({onSignal:async l=>{he(`
37
37
  Received ${l}, shutting down dev-server...
38
- `),await a.shutdown()},describeStall:()=>a.shutdownStage,fileReport:l=>{a.fileFault(l)},setTimer:r})},pi=(n,e,t)=>!n.preset&&!n.app&&!n.self&&!n.orca&&n.watch==null&&!n.verbose&&!n.routes&&!n.reuse&&e&&!t,ci=(n,e)=>({watch:n.watch,orca:n.orca,include:n.include??null,preset:n.preset,presetDef:n.presetDef,self:!1,verbose:!1,routes:!1,uiHealth:e.uiHealth??!0}),uo=async(n,e,t)=>{if(pi(n,e,t)){let{runDevWizard:r}=await import("./dev-wizard-run-SHX5YW6J.js"),i=Promise.all([import("./persistent-ink-dev-ui-P65EJCC6.js"),import("./safe-stderr-ECYA6DRR.js")]).catch(()=>{}),s;try{s=await r()}catch(o){if(rt(o))return;throw o}if(s==null)return;await i,await Ee({...ci(s,n),tty:e,json:t});return}await Ee({...ur(n),tty:e,json:t})},hi=async n=>{let e=new ri;e.name("infra-kit-dev-server").description("Run local dev servers for the apps in a named devServersPresets preset (or all apps)").argument("[preset]","Named preset from devServersPresets (omit to run every app)").option("-w, --watch","Rebuild and restart on file save (the default)").option("--no-watch","Build once and never restart on save").option("--app <names>","Further narrow to these app folder names (comma-separated)").option("--orca","Run each app in its own Orca pane (one tab, N panes; falls back to single terminal when Orca is not running)").option("--self","Run only the app of the current directory (infer from cwd; use inside apps/<app>/\u2026)").option("-V, --verbose","Print full boot narration (default: quiet; full detail always in the session log)").option("--routes","Print each app\u2019s registered METHOD /path routes at startup (default: off)"),e.parse(n),await Ee(ur({...e.opts(),preset:e.args[0]}))};import.meta.url===ni(k.argv[1]??"").href&&hi(k.argv).catch(n=>{console.error(n instanceof Error?n.message:String(n)),k.exit(1)});export{li as createFatalHandler,ai as createSharedDeadlineTimer,di as installBootSignalGuard,Ee as runDevServer,uo as runDevServerCli,pi as shouldRunWizard,ur as toDevServerOptions};
38
+ `),await a.shutdown()},describeStall:()=>a.shutdownStage,fileReport:l=>{a.fileFault(l)},setTimer:r})},hi=(n,e,t)=>!n.preset&&!n.app&&!n.self&&!n.orca&&n.watch==null&&!n.verbose&&!n.routes&&!n.reuse&&e&&!t,gi=(n,e)=>({watch:n.watch,orca:n.orca,include:n.include??null,preset:n.preset,presetDef:n.presetDef,self:!1,verbose:!1,routes:!1,uiHealth:e.uiHealth??!0}),ho=async(n,e,t)=>{if(hi(n,e,t)){let{runDevWizard:r}=await import("./dev-wizard-run-6PLC5YEW.js"),i=Promise.all([import("./persistent-ink-dev-ui-ZSOS3CF4.js"),import("./safe-stderr-ECYA6DRR.js")]).catch(()=>{}),s;try{s=await r()}catch(o){if(it(o))return;throw o}if(s==null)return;await i,await xe({...gi(s,n),tty:e,json:t});return}await xe({...dr(n),tty:e,json:t})},fi=async n=>{let e=new ii;e.name("infra-kit-dev-server").description("Run local dev servers for the apps in a named devServersPresets preset (or all apps)").argument("[preset]","Named preset from devServersPresets (omit to run every app)").option("-w, --watch","Rebuild and restart on file save (the default)").option("--no-watch","Build once and never restart on save").option("--app <names>","Further narrow to these app folder names (comma-separated)").option("--orca","Run each app in its own Orca pane (one tab, N panes; falls back to single terminal when Orca is not running)").option("--self","Run only the app of the current directory (infer from cwd; use inside apps/<app>/\u2026)").option("-V, --verbose","Print full boot narration (default: quiet; full detail always in the session log)").option("--routes","Print each app\u2019s registered METHOD /path routes at startup (default: off)"),e.parse(n),await xe(dr({...e.opts(),preset:e.args[0]}))};import.meta.url===si(k.argv[1]??"").href&&fi(k.argv).catch(n=>{console.error(n instanceof Error?n.message:String(n)),k.exit(1)});export{di as createFatalHandler,ui as createSharedDeadlineTimer,ci as installBootSignalGuard,xe as runDevServer,ho as runDevServerCli,hi as shouldRunWizard,dr as toDevServerOptions};
39
39
  //# sourceMappingURL=dev-server.js.map