infra-kit 0.3.15 → 0.4.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 (52) hide show
  1. package/dist/boot-AJLBGRED.js +2 -0
  2. package/dist/boot-AJLBGRED.js.map +7 -0
  3. package/dist/{chunk-LKKKDB6V.js → chunk-7POMR4QK.js} +1 -1
  4. package/dist/chunk-7POMR4QK.js.map +7 -0
  5. package/dist/{chunk-OKO3DKIM.js → chunk-D7QNBU5A.js} +2 -2
  6. package/dist/chunk-D7QNBU5A.js.map +7 -0
  7. package/dist/{chunk-YDW6324A.js → chunk-NKXTDKWV.js} +2 -2
  8. package/dist/chunk-NKXTDKWV.js.map +7 -0
  9. package/dist/chunk-NS5KIBXS.js +2 -0
  10. package/dist/chunk-NS5KIBXS.js.map +7 -0
  11. package/dist/{chunk-MKMT6KQT.js → chunk-PVMF4FH7.js} +2 -2
  12. package/dist/chunk-PVMF4FH7.js.map +7 -0
  13. package/dist/chunk-QRY6BS6K.js +249 -0
  14. package/dist/chunk-QRY6BS6K.js.map +7 -0
  15. package/dist/{chunk-X46DP23W.js → chunk-QWVLAZ6N.js} +1 -1
  16. package/dist/chunk-QWVLAZ6N.js.map +7 -0
  17. package/dist/chunk-TVG47UHG.js +2 -0
  18. package/dist/chunk-TVG47UHG.js.map +7 -0
  19. package/dist/{chunk-TPVXMJ7N.js → chunk-WIZJQ57Q.js} +1 -1
  20. package/dist/chunk-WIZJQ57Q.js.map +7 -0
  21. package/dist/{chunk-XR6HR4LL.js → chunk-Z2SKAHP4.js} +1 -1
  22. package/dist/chunk-Z2SKAHP4.js.map +7 -0
  23. package/dist/cli.js +12 -11
  24. package/dist/cli.js.map +4 -4
  25. package/dist/dev-server.js +3 -3
  26. package/dist/dev-server.js.map +2 -2
  27. package/dist/{dev-wizard-run-AU7SZJV7.js → dev-wizard-run-YMH3L7GE.js} +2 -2
  28. package/dist/{dev-wizard-run-AU7SZJV7.js.map → dev-wizard-run-YMH3L7GE.js.map} +2 -2
  29. package/dist/mcp.js +1 -1
  30. package/dist/mcp.js.map +4 -4
  31. package/dist/{persistent-ink-dev-ui-QNFTO2B2.js → persistent-ink-dev-ui-P65EJCC6.js} +2 -2
  32. package/dist/persistent-ink-dev-ui-P65EJCC6.js.map +7 -0
  33. package/dist/safe-stderr-ECYA6DRR.js +2 -0
  34. package/dist/update-check.js +1 -1
  35. package/package.json +16 -15
  36. package/readme.md +14 -6
  37. package/dist/boot-OA6HGGO6.js +0 -2
  38. package/dist/boot-OA6HGGO6.js.map +0 -7
  39. package/dist/chunk-KATIE633.js +0 -247
  40. package/dist/chunk-KATIE633.js.map +0 -7
  41. package/dist/chunk-LKKKDB6V.js.map +0 -7
  42. package/dist/chunk-MKMT6KQT.js.map +0 -7
  43. package/dist/chunk-OKO3DKIM.js.map +0 -7
  44. package/dist/chunk-TPVXMJ7N.js.map +0 -7
  45. package/dist/chunk-VFU2USJG.js +0 -2
  46. package/dist/chunk-VFU2USJG.js.map +0 -7
  47. package/dist/chunk-X46DP23W.js.map +0 -7
  48. package/dist/chunk-XR6HR4LL.js.map +0 -7
  49. package/dist/chunk-YDW6324A.js.map +0 -7
  50. package/dist/persistent-ink-dev-ui-QNFTO2B2.js.map +0 -7
  51. package/dist/safe-stderr-HXDR2DNJ.js +0 -2
  52. /package/dist/{safe-stderr-HXDR2DNJ.js.map → safe-stderr-ECYA6DRR.js.map} +0 -0
@@ -1,4 +1,4 @@
1
- import{a as Le,c as L,f as re,j as Oe,k as N,l as H,m as Ue,n as B,t as Fe,u as Me,v as He,y as Be}from"./chunk-MKMT6KQT.js";import"./chunk-LKKKDB6V.js";import{a as O,b as je}from"./chunk-VDBJ73LS.js";import{J as T,K as C,L as F,M as Pe,N as De,O as M,P as ke,Q as $,R as xe,S as Ae,T as Re,U as Ee,V as Te,W as Ce,X as $e,Z as Ne,da as te}from"./chunk-XR6HR4LL.js";import{d as Ie,e as ne,m as _e}from"./chunk-CHETBZ6M.js";import{Command as Un}from"commander";import P from"node:process";import{pathToFileURL as Fn}from"node:url";import*as Ge from"node:path";import Kt from"node:process";var Vt=r=>({pane:{surfaces:[{type:"terminal",command:r}]}}),ie=(r,e)=>{if(r.length===1)return Vt(r[0]);let t=Math.ceil(r.length/2),n=r.slice(0,t),i=r.slice(t);return{direction:e%2===0?"horizontal":"vertical",split:Math.round(t/r.length*100)/100,children:[ie(n,e+1),ie(i,e+1)]}},We=r=>{if(r.length===0)throw new Error("buildCmuxLayout: at least one command is required");return ie(r,0)};var Jt=(r,e)=>r.map(({app:t,targets:n})=>`pnpm exec infra-kit dev ${n&&n.length>0?`--target=${n.join(",")}`:`--app=${t}`}${e?" --watch":""}`),qt=r=>{let e=new Map;for(let t of Object.keys(r?.apps??{})){let n=t.split("/")[0];n===void 0||n==="*"||e.set(n,[...e.get(n)??[],t])}return e},zt=(r,e)=>{let t=F(r);return e?t.filter(n=>e.includes(n.name)):t},Yt=(r,e)=>{T.info(`\u{1F9E9} Opened cmux dev workspace ${e} with ${r.length} pane(s):`);for(let t of r)T.info(` \u2022 ${t.name} (infra-kit dev --app=${t.name})`)},Xt=r=>{B({onSignal:async e=>{T.info(`
1
+ import{a as Le,c as L,f as re,j as Oe,k as N,l as H,m as Ue,n as B,t as Fe,u as Me,v as He,y as Be}from"./chunk-PVMF4FH7.js";import"./chunk-7POMR4QK.js";import{a as O,b as je}from"./chunk-VDBJ73LS.js";import{J as T,K as C,L as F,M as Pe,N as De,O as M,P as ke,Q as $,R as xe,S as Ae,T as Re,U as Ee,V as Te,W as Ce,X as $e,Z as Ne,da as te}from"./chunk-Z2SKAHP4.js";import{d as Ie,e as ne,m as _e}from"./chunk-CHETBZ6M.js";import{Command as Un}from"commander";import P from"node:process";import{pathToFileURL as Fn}from"node:url";import*as Ge from"node:path";import Kt from"node:process";var Vt=r=>({pane:{surfaces:[{type:"terminal",command:r}]}}),ie=(r,e)=>{if(r.length===1)return Vt(r[0]);let t=Math.ceil(r.length/2),n=r.slice(0,t),i=r.slice(t);return{direction:e%2===0?"horizontal":"vertical",split:Math.round(t/r.length*100)/100,children:[ie(n,e+1),ie(i,e+1)]}},We=r=>{if(r.length===0)throw new Error("buildCmuxLayout: at least one command is required");return ie(r,0)};var Jt=(r,e)=>r.map(({app:t,targets:n})=>`pnpm exec infra-kit dev ${n&&n.length>0?`--target=${n.join(",")}`:`--app=${t}`}${e?" --watch":""}`),qt=r=>{let e=new Map;for(let t of Object.keys(r?.apps??{})){let n=t.split("/")[0];n===void 0||n==="*"||e.set(n,[...e.get(n)??[],t])}return e},zt=(r,e)=>{let t=F(r);return e?t.filter(n=>e.includes(n.name)):t},Yt=(r,e)=>{T.info(`\u{1F9E9} Opened cmux dev workspace ${e} with ${r.length} pane(s):`);for(let t of r)T.info(` \u2022 ${t.name} (infra-kit dev --app=${t.name})`)},Xt=r=>{B({onSignal:async e=>{T.info(`
2
2
  Received ${e}, closing cmux dev workspace ${r}...`),await He(r)}})},Ve=async r=>{let e=C(Kt.cwd()),t=zt(e,M(r.include));if(t.length===0){T.warn("No API apps found to run");return}let n=qt(r.presetDef),i=Jt(t.map(u=>({app:u.name,targets:n.get(u.name)})),r.watch??!1),s=We(i),o=`${Ge.basename(e)} dev`,a=await Me({cwd:e,title:o,layout:s});Yt(t,a),Xt(a);let l=setInterval(()=>{l.refresh()},2**30);await new Promise(()=>{})};import se from"node:process";var oe=r=>{try{se.stderr.write(r)}catch{}},I=(r,e,t=!0)=>{let n=e instanceof Error?`${e.message}
3
3
  ${e.stack??"(no stack)"}`:String(e);return`
4
4
  \u26A0\uFE0F ${r}: ${n}
@@ -29,10 +29,10 @@ Then trust its local CA (no sudo needed):
29
29
  ${L(["service","status"],{bin:e})}
30
30
  Reinstalling restarts it (still the only step that needs root):
31
31
  ${L(["service","install"],{sudo:!0,bin:e})}
32
- \`infra-kit doctor\` checks the daemon and CA trust state.`)}async registerAppAlias(e,t,n){let i=ve(t),s=sn(e);if(s==="")throw new Error(`infra-kit dev: package name "${e}" has no letters or digits to build a hostname from.`);let o=`${i}.${s}`;if(!await this.proxy.registerAlias(o,n))throw new Error(`infra-kit dev: portless refused the alias "${o}" \u2192 127.0.0.1:${n}.`);return this.registeredAliases.add(o),`${o}.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()])}}),n=await t.start(),i;try{i=await this.registerAppAlias(e.packageName,e.path,n)}catch(s){throw await t.close().catch(()=>{}),s}try{this.writeDevContextFragment(e,n,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 ${n}`),{server:t,boundPort:n,alias:i}}writeDevContextFragment(e,t,n){let i={v:rn,package:e.packageName,port:t,pid:m.pid,writtenAt:Date.now(),release:ve(e.path),alias:n,origin:`https://${n}`},s=w.join(this.devContextDir,`${e.name}.json`),o=w.join(this.devContextDir,`${e.name}.json.${m.pid}.tmp`);v.mkdirSync(this.devContextDir,{recursive:!0}),v.writeFileSync(o,JSON.stringify(i,null,2)),v.renameSync(o,s)}removeDevContextFragment(e){v.rmSync(w.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,r.PORT_RELEASE_DELAY_MS))}restart(e,t=[]){return this.shuttingDown?Promise.resolve():this.scheduleRestartWork(()=>this.shuttingDown?Promise.resolve():this.runRestart(e,t))}resolveRestartTargets(e){return e.map(t=>({idx:this.appServers.findIndex(n=>n.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 n={app:e,...t,startedAt:Date.now(),restarts:0},i=`${e.name}/api`;this.healthEntry(i,"api"),this.appServers.push(n);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:O({prefixUrl:e.prefixUrl,alias:t.alias}),health:this.healthOf(i)}],failed:(this.lastSummary.failed??[]).filter(o=>o.tag!==i)}),n}async runRestart(e,t=[]){let n=this.resolveRestartTargets(e);if(n.length===0)return;let i=n.length===1?n[0].app.name:`${n.length} apps`,s=this.moduleGeneration?.budgetState()??"ok";if(s==="stop"){this.reportGenerationBudgetStop(ce(m.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(n.map(async({idx:g})=>{if(!(g<0))try{await this.appServers[g].server.close()}catch(p){this.renderer.log(` Close warning: ${String(p)}`,"debug")}})),await this.delayPortRelease();let o=await Promise.all(n.map(async({idx:g,app:p})=>{try{let f=await this.startOneApp(p);if(f){if(g<0){let c=this.promoteRecoveredApp(p,f);return this.renderer.log(`\u2705 ${p.name} recovered \u2014 its routes are served locally again`,"info"),{app:p,entry:c}}let y=this.appServers[g],b={app:p,...f,startedAt:Date.now(),restarts:(y?.restarts??0)+1};return this.appServers[g]=b,{app:p,entry:b}}return{app:p,entry:null}}catch(f){return this.renderer.log(`\u274C Failed to ${g<0?"start":"restart"} ${p.name}: ${String(f)}`,"error"),{app:p,entry:null}}})),a=await Promise.all(o.map(async({app:g,entry:p})=>{let f=`${g.name}/api`;if(p==null)return this.markDown(f,"api"),this.refreshStatus(),{label:`${g.name} \u25CF down`,healthy:!1};let y={tag:f,port:p.boundPort,kind:"api"},b=await this.healthProbe(y);this.recordProbe(y,b),this.refreshStatus();let c=b==="ok";return{label:`${g.name}:${p.boundPort} ${c?"\u25CF up":"\u25CF down"}`,healthy:c}})),l=a.every(g=>g.healthy),u=a.map(g=>g.label).join(", "),h=o.some(g=>g.entry!==null)?this.resolveStaleFiles(t,n):[];if(h.length>0){this.renderer.log(`\u26A0\uFE0F Restarted ${u} \u2014 still serving the OLD ${Rt(h)}. Re-run \`infra-kit dev\` to pick this up.`,"warn");return}this.renderer.log(`${l?"\u2705":"\u26A0\uFE0F "} Restarted ${u}`)}resolveStaleFiles(e,t){let n=this.moduleGeneration;return n?e.filter(i=>!n.bustedUnder(w.dirname(i))):e.filter(i=>!t.some(s=>At(i,s.app.path)))}async buildClosureMapSafe(e){try{return await qe(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,n){this.shuttingDown||this.renderer.log(`\u26A0\uFE0F ${e} ${n} \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()}setupWatch(e,t){this.turboWatch=this.turboWatchFactory({depInclusive:e.map(l=>l.packageName),depClosure:t.map(l=>l.packageName),cwd:m.cwd(),logFile:this.sink.pathFor(hn),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 n=xe(e),i=$(this.monorepoRoot),s=[...n,...i];if(s.length===0){this.renderer.log("\u26A0\uFE0F No app or package dist directories found to watch (were they built?)","warn");return}let o=m.env.DEV_SERVER_CHOKIDAR_POLL==="1",a=an.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,n,i)});this.renderer.narrate(`\u{1F440} Watching ${n.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,n,i){this.renderer.log(`\u{1F440} dist change detected: ${e}`,"debug");let s=Ae(e,n,i);if(s.kind==="package"){this.handlePackageDistChange(e,t,s.packageDir);return}let o=t.find(a=>w.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,n){let i=ze(t,this.closureMap,n);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 n=this.pendingChanges.get(e);n?n.add(t):this.pendingChanges.set(e,new Set([t]))}installModuleGeneration(){if(m.env.INFRA_KIT_DEV_NO_GENERATION==="1"){this.renderer.log("\u{1F440} Module generation disabled (INFRA_KIT_DEV_NO_GENERATION=1)","debug");return}if(!vt()){this.renderer.log(`\u26A0\uFE0F This Node (${m.version}) has no \`module.registerHooks\`, so only handler entry files reload in place.`,"warn");return}let e=ce(m.env.INFRA_KIT_DEV_STOP_BYTES);this.moduleGeneration=wt({root:v.realpathSync(this.monorepoRoot),selfDist:yt(),stopBytes:e.stopBytes,stopEnabled:e.stopEnabled})}reportGenerationBudgetWarn(){let e=this.moduleGeneration?.generation()??0;this.renderer.log(`\u26A0\uFE0F Reload memory ${me(m.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 ${me(m.memoryUsage.rss())} exceeds the ${me(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 n=this.watchDebounceTimers.get(e);n&&clearTimeout(n);let i=setTimeout(()=>{this.watchDebounceTimers.delete(e),!this.shuttingDown&&t().catch(s=>{this.renderer.log(`Restart error (${e}): ${String(s)}`,"error")})},r.WATCH_DEBOUNCE_MS);this.watchDebounceTimers.set(e,i)}uiHealthEnabled(){return(this.options.uiHealth??!0)&&m.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 n=this.health.get(e);if(n)return n;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 n=this.healthEntry(e.tag,e.kind),i=r.LIVENESS_FAILURE_THRESHOLD;if(t==="ok"){let s=n.failures>=i;n.everUp=!0,n.failures=0,n.foreignStreak=0,n.unverified=!1,s&&this.renderer.log(`\u2705 ${e.tag} recovered`);return}if(yn(t)&&e.kind==="ui"){n.foreignStreak+=1,n.unverified=n.foreignStreak>=i,n.foreignStreak===i&&this.renderer.log(`\u26A0\uFE0F ${e.tag}: ${wn(e.port,t)}`,"warn");return}if(n.foreignStreak=0,n.failures+=1,e.kind==="ui"&&n.failures>=i&&(n.unverified=!1),n.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 n=this.healthEntry(e,t);n.dead=!0,n.failures=r.LIVENESS_FAILURE_THRESHOLD,n.foreignStreak=0,n.unverified=!1}healthOf(e){let t=this.health.get(e);return t==null?"unknown":t.unverified?"unverified":t.everUp?t.failures>=r.LIVENESS_FAILURE_THRESHOLD?"down":"ok":this.neverUpState(t)}neverUpState(e){return e.kind==="api"||e.dead||e.failures>=r.NEVER_UP_DOWN_THRESHOLD?"down":"starting"}startLivenessMonitor(){this.scheduleLivenessTick()}scheduleLivenessTick(){let e=this.options.livenessIntervalMs??r.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(),n=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=n.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 ${Y(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[n,i]of this.reqTimes)this.reqTimes.set(n,i.filter(s=>s>t))}async livenessTick(){this.shuttingDown||(await Promise.all([...this.apiTargets(),...this.uiTargets()].map(e=>this.probeOne(e))),this.refreshStatus())}async probeOne(e){let t=await this.healthProbe(e);this.shuttingDown||this.recordProbe(e,t)}async printReady(e,t,n,i){let s=Date.now()-n;await Promise.all(this.apiTargets().map(p=>this.probeOne(p)));let o=this.appServers.map(({app:p,alias:f})=>({tag:`${p.name}/api`,url:O({prefixUrl:p.prefixUrl,alias:f}),health:this.healthOf(`${p.name}/api`)})),a=new Map(this.appServers.map(({app:p,alias:f})=>[p.packageName,O({prefixUrl:p.prefixUrl,alias:f})]));this.proxyRoutes=Ze({uis:this.launchedUis,running:new Set(this.appServers.map(({app:p})=>p.packageName)),localOrigin:p=>a.get(p),env:m.env[ne]}),this.uiPortMap={};let l=[],u=[];for(let p of t){let f=await this.assignUiPort(p),y=`${p.name}/ui`;f!=null?l.push({tag:y,url:O({prefixUrl:"",alias:f.alias}),health:this.seedUiHealth(y),proxies:this.proxiesFor(p.name)}):u.push({tag:y,proxies:this.proxiesFor(p.name)})}let d=this.options.watch??!1,h=e.length+t.length,g=$(this.monorepoRoot).length;this.lastSummary={target:i,watch:d,release:ve(m.cwd()),elapsedMs:s,endpoints:[...o,...l],uiRefs:u,failed:this.failedApps.map(({app:p,reason:f})=>({tag:`${p.name}/api`,reason:f})),degraded:this.degradedRows(),watchSummary:`${h} app${h===1?"":"s"} \xB7 ${g} package${g===1?"":"s"}`,logPath:Y(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 vn()}catch{return null}let n=await this.registerAppAlias(e.packageName,e.path,t);return this.uiPortMap[e.packageName]={port:t,alias:n},this.uiTagByPackage.set(e.packageName,`${e.name}/ui`),{port:t,alias:n}}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 n=t.getRegisteredRoutes();this.renderer.log(` ${e.name} (${n.length}): ${n.length>0?n.join(", "):"(none)"}`)}}}reportFault(e){this.sink.write(W()??X,e,{level:"error"}),!this.shuttingDown&&this.renderer.log(e,"error",{tee:!1})}fileFault(e){this.sink.write(W()??X,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(){this.shuttingDown=!0,this.stage="starting",this.renderer.dispose(),this.intercept?.uninstall(),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)}this.intercept?.uninstall(),this.renderer.log(`\u2713 dev stopped \xB7 logs \u2192 ${Y(this.sink.dir)}`),this.sink.close(),Q===this.sink&&(Q=null),this.stage="done"}},Ft=r=>(r.tty??!!m.stdout.isTTY)&&!r.json,_n=async r=>{if(!Ft(r))return;let{PersistentInkDevUi:e}=await import("./persistent-ink-dev-ui-QNFTO2B2.js"),{createSafeStream:t}=await import("./safe-stderr-HXDR2DNJ.js");return new e({appendLog:Ut,verbose:r.verbose??!1,stdout:t(ut())})};async function Mt(r={}){let e=await _n(r),t=new ye(r,void 0,void 0,void 0,void 0,e);try{await t.start()}catch(n){throw await t.shutdown().catch(()=>{}),n}return t}var we=1,Mn=2e4,Hn=r=>{if(r!=null){for(let e of r)if(Re(e)!==null)throw new Error(`infra-kit dev: invalid --target "${e}" (expected "<app>/api" or "<app>/ui").`);return{apps:Object.fromEntries(r.map(e=>[e,{}]))}}},Ht=r=>{if(r==null)return null;let e=r.split(",").map(t=>t.trim()).filter(Boolean);return e.length>0?e:null},Bt=r=>({watch:r.watch??!1,include:Ht(r.app),preset:r.preset,presetDef:Hn(Ht(r.target)),cmux:r.cmux??!1,self:r.self??!1,verbose:r.verbose??!1,routes:r.routes??!1,uiHealth:r.uiHealth??!0}),Bn=r=>!r.self||r.include?r:{...r,include:[ke(P.cwd())]},jt=(r,e)=>{let t=setTimeout(r,e);return t.unref(),()=>{clearTimeout(t)}},jn=(r=jt)=>{let e=!1;return(t,n)=>{if(e)return()=>{};e=!0;let i=r(t,n);return()=>{e=!1,i()}}},Wt=(r,e,t)=>{r(),e(t)},Wn=({getRunner:r,forceReap:e=N,exit:t=s=>{P.exit(s)},setTimer:n=jt,deadlineMs:i=Mn})=>{let s=!1;return o=>{if(s)return;s=!0;let a=r();if(a==null){Wt(e,t,we);return}a.fileFault(`
32
+ \`infra-kit doctor\` checks the daemon and CA trust state.`)}async registerAppAlias(e,t,n){let i=ve(t),s=sn(e);if(s==="")throw new Error(`infra-kit dev: package name "${e}" has no letters or digits to build a hostname from.`);let o=`${i}.${s}`;if(!await this.proxy.registerAlias(o,n))throw new Error(`infra-kit dev: portless refused the alias "${o}" \u2192 127.0.0.1:${n}.`);return this.registeredAliases.add(o),`${o}.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()])}}),n=await t.start(),i;try{i=await this.registerAppAlias(e.packageName,e.path,n)}catch(s){throw await t.close().catch(()=>{}),s}try{this.writeDevContextFragment(e,n,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 ${n}`),{server:t,boundPort:n,alias:i}}writeDevContextFragment(e,t,n){let i={v:rn,package:e.packageName,port:t,pid:m.pid,writtenAt:Date.now(),release:ve(e.path),alias:n,origin:`https://${n}`},s=w.join(this.devContextDir,`${e.name}.json`),o=w.join(this.devContextDir,`${e.name}.json.${m.pid}.tmp`);v.mkdirSync(this.devContextDir,{recursive:!0}),v.writeFileSync(o,JSON.stringify(i,null,2)),v.renameSync(o,s)}removeDevContextFragment(e){v.rmSync(w.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,r.PORT_RELEASE_DELAY_MS))}restart(e,t=[]){return this.shuttingDown?Promise.resolve():this.scheduleRestartWork(()=>this.shuttingDown?Promise.resolve():this.runRestart(e,t))}resolveRestartTargets(e){return e.map(t=>({idx:this.appServers.findIndex(n=>n.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 n={app:e,...t,startedAt:Date.now(),restarts:0},i=`${e.name}/api`;this.healthEntry(i,"api"),this.appServers.push(n);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:O({prefixUrl:e.prefixUrl,alias:t.alias}),health:this.healthOf(i)}],failed:(this.lastSummary.failed??[]).filter(o=>o.tag!==i)}),n}async runRestart(e,t=[]){let n=this.resolveRestartTargets(e);if(n.length===0)return;let i=n.length===1?n[0].app.name:`${n.length} apps`,s=this.moduleGeneration?.budgetState()??"ok";if(s==="stop"){this.reportGenerationBudgetStop(ce(m.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(n.map(async({idx:g})=>{if(!(g<0))try{await this.appServers[g].server.close()}catch(p){this.renderer.log(` Close warning: ${String(p)}`,"debug")}})),await this.delayPortRelease();let o=await Promise.all(n.map(async({idx:g,app:p})=>{try{let f=await this.startOneApp(p);if(f){if(g<0){let c=this.promoteRecoveredApp(p,f);return this.renderer.log(`\u2705 ${p.name} recovered \u2014 its routes are served locally again`,"info"),{app:p,entry:c}}let y=this.appServers[g],b={app:p,...f,startedAt:Date.now(),restarts:(y?.restarts??0)+1};return this.appServers[g]=b,{app:p,entry:b}}return{app:p,entry:null}}catch(f){return this.renderer.log(`\u274C Failed to ${g<0?"start":"restart"} ${p.name}: ${String(f)}`,"error"),{app:p,entry:null}}})),a=await Promise.all(o.map(async({app:g,entry:p})=>{let f=`${g.name}/api`;if(p==null)return this.markDown(f,"api"),this.refreshStatus(),{label:`${g.name} \u25CF down`,healthy:!1};let y={tag:f,port:p.boundPort,kind:"api"},b=await this.healthProbe(y);this.recordProbe(y,b),this.refreshStatus();let c=b==="ok";return{label:`${g.name}:${p.boundPort} ${c?"\u25CF up":"\u25CF down"}`,healthy:c}})),l=a.every(g=>g.healthy),u=a.map(g=>g.label).join(", "),h=o.some(g=>g.entry!==null)?this.resolveStaleFiles(t,n):[];if(h.length>0){this.renderer.log(`\u26A0\uFE0F Restarted ${u} \u2014 still serving the OLD ${Rt(h)}. Re-run \`infra-kit dev\` to pick this up.`,"warn");return}this.renderer.log(`${l?"\u2705":"\u26A0\uFE0F "} Restarted ${u}`)}resolveStaleFiles(e,t){let n=this.moduleGeneration;return n?e.filter(i=>!n.bustedUnder(w.dirname(i))):e.filter(i=>!t.some(s=>At(i,s.app.path)))}async buildClosureMapSafe(e){try{return await qe(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,n){this.shuttingDown||this.renderer.log(`\u26A0\uFE0F ${e} ${n} \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()}setupWatch(e,t){this.turboWatch=this.turboWatchFactory({depInclusive:e.map(l=>l.packageName),depClosure:t.map(l=>l.packageName),cwd:m.cwd(),logFile:this.sink.pathFor(hn),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 n=xe(e),i=$(this.monorepoRoot),s=[...n,...i];if(s.length===0){this.renderer.log("\u26A0\uFE0F No app or package dist directories found to watch (were they built?)","warn");return}let o=m.env.DEV_SERVER_CHOKIDAR_POLL==="1",a=an.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,n,i)});this.renderer.narrate(`\u{1F440} Watching ${n.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,n,i){this.renderer.log(`\u{1F440} dist change detected: ${e}`,"debug");let s=Ae(e,n,i);if(s.kind==="package"){this.handlePackageDistChange(e,t,s.packageDir);return}let o=t.find(a=>w.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,n){let i=ze(t,this.closureMap,n);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 n=this.pendingChanges.get(e);n?n.add(t):this.pendingChanges.set(e,new Set([t]))}installModuleGeneration(){if(m.env.INFRA_KIT_DEV_NO_GENERATION==="1"){this.renderer.log("\u{1F440} Module generation disabled (INFRA_KIT_DEV_NO_GENERATION=1)","debug");return}if(!vt()){this.renderer.log(`\u26A0\uFE0F This Node (${m.version}) has no \`module.registerHooks\`, so only handler entry files reload in place.`,"warn");return}let e=ce(m.env.INFRA_KIT_DEV_STOP_BYTES);this.moduleGeneration=wt({root:v.realpathSync(this.monorepoRoot),selfDist:yt(),stopBytes:e.stopBytes,stopEnabled:e.stopEnabled})}reportGenerationBudgetWarn(){let e=this.moduleGeneration?.generation()??0;this.renderer.log(`\u26A0\uFE0F Reload memory ${me(m.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 ${me(m.memoryUsage.rss())} exceeds the ${me(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 n=this.watchDebounceTimers.get(e);n&&clearTimeout(n);let i=setTimeout(()=>{this.watchDebounceTimers.delete(e),!this.shuttingDown&&t().catch(s=>{this.renderer.log(`Restart error (${e}): ${String(s)}`,"error")})},r.WATCH_DEBOUNCE_MS);this.watchDebounceTimers.set(e,i)}uiHealthEnabled(){return(this.options.uiHealth??!0)&&m.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 n=this.health.get(e);if(n)return n;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 n=this.healthEntry(e.tag,e.kind),i=r.LIVENESS_FAILURE_THRESHOLD;if(t==="ok"){let s=n.failures>=i;n.everUp=!0,n.failures=0,n.foreignStreak=0,n.unverified=!1,s&&this.renderer.log(`\u2705 ${e.tag} recovered`);return}if(yn(t)&&e.kind==="ui"){n.foreignStreak+=1,n.unverified=n.foreignStreak>=i,n.foreignStreak===i&&this.renderer.log(`\u26A0\uFE0F ${e.tag}: ${wn(e.port,t)}`,"warn");return}if(n.foreignStreak=0,n.failures+=1,e.kind==="ui"&&n.failures>=i&&(n.unverified=!1),n.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 n=this.healthEntry(e,t);n.dead=!0,n.failures=r.LIVENESS_FAILURE_THRESHOLD,n.foreignStreak=0,n.unverified=!1}healthOf(e){let t=this.health.get(e);return t==null?"unknown":t.unverified?"unverified":t.everUp?t.failures>=r.LIVENESS_FAILURE_THRESHOLD?"down":"ok":this.neverUpState(t)}neverUpState(e){return e.kind==="api"||e.dead||e.failures>=r.NEVER_UP_DOWN_THRESHOLD?"down":"starting"}startLivenessMonitor(){this.scheduleLivenessTick()}scheduleLivenessTick(){let e=this.options.livenessIntervalMs??r.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(),n=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=n.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 ${Y(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[n,i]of this.reqTimes)this.reqTimes.set(n,i.filter(s=>s>t))}async livenessTick(){this.shuttingDown||(await Promise.all([...this.apiTargets(),...this.uiTargets()].map(e=>this.probeOne(e))),this.refreshStatus())}async probeOne(e){let t=await this.healthProbe(e);this.shuttingDown||this.recordProbe(e,t)}async printReady(e,t,n,i){let s=Date.now()-n;await Promise.all(this.apiTargets().map(p=>this.probeOne(p)));let o=this.appServers.map(({app:p,alias:f})=>({tag:`${p.name}/api`,url:O({prefixUrl:p.prefixUrl,alias:f}),health:this.healthOf(`${p.name}/api`)})),a=new Map(this.appServers.map(({app:p,alias:f})=>[p.packageName,O({prefixUrl:p.prefixUrl,alias:f})]));this.proxyRoutes=Ze({uis:this.launchedUis,running:new Set(this.appServers.map(({app:p})=>p.packageName)),localOrigin:p=>a.get(p),env:m.env[ne]}),this.uiPortMap={};let l=[],u=[];for(let p of t){let f=await this.assignUiPort(p),y=`${p.name}/ui`;f!=null?l.push({tag:y,url:O({prefixUrl:"",alias:f.alias}),health:this.seedUiHealth(y),proxies:this.proxiesFor(p.name)}):u.push({tag:y,proxies:this.proxiesFor(p.name)})}let d=this.options.watch??!1,h=e.length+t.length,g=$(this.monorepoRoot).length;this.lastSummary={target:i,watch:d,release:ve(m.cwd()),elapsedMs:s,endpoints:[...o,...l],uiRefs:u,failed:this.failedApps.map(({app:p,reason:f})=>({tag:`${p.name}/api`,reason:f})),degraded:this.degradedRows(),watchSummary:`${h} app${h===1?"":"s"} \xB7 ${g} package${g===1?"":"s"}`,logPath:Y(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 vn()}catch{return null}let n=await this.registerAppAlias(e.packageName,e.path,t);return this.uiPortMap[e.packageName]={port:t,alias:n},this.uiTagByPackage.set(e.packageName,`${e.name}/ui`),{port:t,alias:n}}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 n=t.getRegisteredRoutes();this.renderer.log(` ${e.name} (${n.length}): ${n.length>0?n.join(", "):"(none)"}`)}}}reportFault(e){this.sink.write(W()??X,e,{level:"error"}),!this.shuttingDown&&this.renderer.log(e,"error",{tee:!1})}fileFault(e){this.sink.write(W()??X,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(){this.shuttingDown=!0,this.stage="starting",this.renderer.dispose(),this.intercept?.uninstall(),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)}this.intercept?.uninstall(),this.renderer.log(`\u2713 dev stopped \xB7 logs \u2192 ${Y(this.sink.dir)}`),this.sink.close(),Q===this.sink&&(Q=null),this.stage="done"}},Ft=r=>(r.tty??!!m.stdout.isTTY)&&!r.json,_n=async r=>{if(!Ft(r))return;let{PersistentInkDevUi:e}=await import("./persistent-ink-dev-ui-P65EJCC6.js"),{createSafeStream:t}=await import("./safe-stderr-ECYA6DRR.js");return new e({appendLog:Ut,verbose:r.verbose??!1,stdout:t(ut())})};async function Mt(r={}){let e=await _n(r),t=new ye(r,void 0,void 0,void 0,void 0,e);try{await t.start()}catch(n){throw await t.shutdown().catch(()=>{}),n}return t}var we=1,Mn=2e4,Hn=r=>{if(r!=null){for(let e of r)if(Re(e)!==null)throw new Error(`infra-kit dev: invalid --target "${e}" (expected "<app>/api" or "<app>/ui").`);return{apps:Object.fromEntries(r.map(e=>[e,{}]))}}},Ht=r=>{if(r==null)return null;let e=r.split(",").map(t=>t.trim()).filter(Boolean);return e.length>0?e:null},Bt=r=>({watch:r.watch??!1,include:Ht(r.app),preset:r.preset,presetDef:Hn(Ht(r.target)),cmux:r.cmux??!1,self:r.self??!1,verbose:r.verbose??!1,routes:r.routes??!1,uiHealth:r.uiHealth??!0}),Bn=r=>!r.self||r.include?r:{...r,include:[ke(P.cwd())]},jt=(r,e)=>{let t=setTimeout(r,e);return t.unref(),()=>{clearTimeout(t)}},jn=(r=jt)=>{let e=!1;return(t,n)=>{if(e)return()=>{};e=!0;let i=r(t,n);return()=>{e=!1,i()}}},Wt=(r,e,t)=>{r(),e(t)},Wn=({getRunner:r,forceReap:e=N,exit:t=s=>{P.exit(s)},setTimer:n=jt,deadlineMs:i=Mn})=>{let s=!1;return o=>{if(s)return;s=!0;let a=r();if(a==null){Wt(e,t,we);return}a.fileFault(`
33
33
  \u2717 dev-server exiting: ${o}
34
34
  `);let l=n(()=>{e(),t(we)},i);a.shutdown().finally(()=>{l(),t(we)}).catch(()=>{})}},Gn=["SIGINT","SIGTERM"],Vn=({forceReap:r=N,exit:e=i=>{P.exit(i)},register:t=(i,s)=>{P.on(i,s)},unregister:n=(i,s)=>{P.off(i,s)}}={})=>{let i=new Map;for(let s of Gn){let o=()=>{Wt(r,e,Ue(s))};i.set(s,o),t(s,o)}return{remove:()=>{for(let[s,o]of i)n(s,o)}}},be=async r=>{let e=Bn(r);if(e.cmux){if(await Fe()){await Ve(e);return}P.stdout.write(`cmux not available; falling back to single-terminal dev
35
35
  `)}let t=null,n=jn(),i=Wn({getRunner:()=>t,setTimer:n}),s=st({onDeath:(l,u)=>{i(`stdio unwritable: ${l} ${u.code}`)}}),o=Vn();try{t=await Mt({...e,onExitRequest:l=>{P.exit(l)}})}finally{o.remove()}let a=t;Ke({onFault:(l,u)=>{a.reportFault(I(l,u))},isTerminalDead:s.isDead,fileFault:(l,u)=>{a.fileFault(I(l,u,!1))},onFatal:i}),B({onSignal:async l=>{le(`
36
36
  Received ${l}, shutting down dev-server...
37
- `),await a.shutdown()},describeStall:()=>a.shutdownStage,fileReport:l=>{a.fileFault(l)},setTimer:n})},Kn=(r,e,t)=>!r.preset&&!r.app&&!r.self&&!r.cmux&&!r.watch&&!r.verbose&&!r.routes&&e&&!t,Jn=(r,e)=>({watch:r.watch,cmux:r.cmux,include:r.include??null,preset:r.preset,presetDef:r.presetDef,self:!1,verbose:!1,routes:!1,uiHealth:e.uiHealth??!0}),Ls=async(r,e,t)=>{if(Kn(r,e,t)){let{runDevWizard:n}=await import("./dev-wizard-run-AU7SZJV7.js"),i=Promise.all([import("./persistent-ink-dev-ui-QNFTO2B2.js"),import("./safe-stderr-HXDR2DNJ.js")]).catch(()=>{}),s;try{s=await n()}catch(o){if(Be(o))return;throw o}if(s==null)return;await i,await be({...Jn(s,r),tty:e,json:t});return}await be({...Bt(r),tty:e,json:t})},qn=async r=>{let e=new Un;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").option("--app <names>","Further narrow to these app folder names (comma-separated)").option("--cmux","Run each app in its own cmux pane (one workspace, N panes; falls back to single terminal if cmux is unavailable)").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(r),await be(Bt({...e.opts(),preset:e.args[0]}))};import.meta.url===Fn(P.argv[1]??"").href&&qn(P.argv).catch(r=>{console.error(r instanceof Error?r.message:String(r)),P.exit(1)});export{Wn as createFatalHandler,jn as createSharedDeadlineTimer,Vn as installBootSignalGuard,be as runDevServer,Ls as runDevServerCli,Kn as shouldRunWizard,Bt as toDevServerOptions};
37
+ `),await a.shutdown()},describeStall:()=>a.shutdownStage,fileReport:l=>{a.fileFault(l)},setTimer:n})},Kn=(r,e,t)=>!r.preset&&!r.app&&!r.self&&!r.cmux&&!r.watch&&!r.verbose&&!r.routes&&e&&!t,Jn=(r,e)=>({watch:r.watch,cmux:r.cmux,include:r.include??null,preset:r.preset,presetDef:r.presetDef,self:!1,verbose:!1,routes:!1,uiHealth:e.uiHealth??!0}),Ls=async(r,e,t)=>{if(Kn(r,e,t)){let{runDevWizard:n}=await import("./dev-wizard-run-YMH3L7GE.js"),i=Promise.all([import("./persistent-ink-dev-ui-P65EJCC6.js"),import("./safe-stderr-ECYA6DRR.js")]).catch(()=>{}),s;try{s=await n()}catch(o){if(Be(o))return;throw o}if(s==null)return;await i,await be({...Jn(s,r),tty:e,json:t});return}await be({...Bt(r),tty:e,json:t})},qn=async r=>{let e=new Un;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").option("--app <names>","Further narrow to these app folder names (comma-separated)").option("--cmux","Run each app in its own cmux pane (one workspace, N panes; falls back to single terminal if cmux is unavailable)").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(r),await be(Bt({...e.opts(),preset:e.args[0]}))};import.meta.url===Fn(P.argv[1]??"").href&&qn(P.argv).catch(r=>{console.error(r instanceof Error?r.message:String(r)),P.exit(1)});export{Wn as createFatalHandler,jn as createSharedDeadlineTimer,Vn as installBootSignalGuard,be as runDevServer,Ls as runDevServerCli,Kn as shouldRunWizard,Bt as toDevServerOptions};
38
38
  //# sourceMappingURL=dev-server.js.map