infra-kit 0.1.132 → 0.1.133

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.
@@ -1,5 +1,5 @@
1
1
  import{d as M,h as ae,l as ue,m as ce,n as de,q as he}from"./chunk-RSF5XAQJ.js";import{A as ee,B as S,C as re,D as te,E as ne,G as ie,H as oe,K as se,Q as O,v as b,w as P,x as R,y as Z,z as C}from"./chunk-V37MZDFR.js";import"./chunk-6FU2TRU5.js";import{d as le,m as pe}from"./chunk-CHETBZ6M.js";import{a as _,b as F,c as k}from"./chunk-LTKR3F4N.js";import{b as j,c as ge}from"./chunk-JD5T4VCB.js";import{Command as at}from"commander";import w from"node:process";import{pathToFileURL as lt}from"node:url";import*as Pe from"node:path";import ur from"node:process";var Ke=t=>({pane:{surfaces:[{type:"terminal",command:t}]}}),H=(t,e)=>{if(t.length===1)return Ke(t[0]);let r=Math.ceil(t.length/2),n=t.slice(0,r),i=t.slice(r);return{direction:e%2===0?"horizontal":"vertical",split:Math.round(r/t.length*100)/100,children:[H(n,e+1),H(i,e+1)]}},me=t=>{if(t.length===0)throw new Error("buildCmuxLayout: at least one command is required");return H(t,0)};import{constants as nr}from"node:os";import V from"node:process";import{execFileSync as ze}from"node:child_process";import D from"node:process";var qe=5e3,Ye=100,Xe=2e3,Qe="/bin/ps",Ze=t=>t.split(`
2
- `).flatMap(e=>{let[r,n,i]=e.trim().split(/\s+/);if(r==null||n==null||i==null)return[];let o=Number(r),s=Number(n),a=Number(i);return!Number.isInteger(o)||!Number.isInteger(s)||!Number.isInteger(a)?[]:[{pid:o,ppid:s,pgid:a}]}),er=(t,e,r)=>{let n=new Map;for(let a of e){let l=n.get(a.ppid);l?l.push(a):n.set(a.ppid,[a])}let i=new Set([t]),o=new Set([t]),s=[t];for(let a=0;a<s.length;a+=1)for(let l of n.get(s[a]??-1)??[])o.has(l.pid)||(o.add(l.pid),i.add(l.pgid),s.push(l.pid));return[...i].filter(a=>a>1&&a!==r)},W=()=>{try{return Ze(ze(Qe,["-eo","pid=,ppid=,pgid="],{encoding:"utf8",maxBuffer:8<<20}))}catch{return[]}},rr=(t,e,r)=>r.some(n=>n.pid===t&&n.ppid===e),B=(t,e)=>{let r=e.find(n=>n.pid===D.pid)?.pgid;return er(t,e,r)},ve=t=>{try{return D.kill(-t,0),!0}catch{return!1}},G=(t,e)=>{for(let r of t)try{D.kill(-r,e)}catch{}},ye=()=>{G(B(D.pid,W()),"SIGKILL")},tr=async t=>new Promise(e=>{setTimeout(e,t)}),fe=async(t,e)=>{let r=Date.now()+e,n=t;for(;n.length>0&&Date.now()<r&&(n=n.filter(ve),n.length!==0);)await tr(Ye);return n};function T(t,e=qe,r){t.unref();let n=!1,i=o=>{n||r?.(o)};return t.on("exit",(o,s)=>{i(`exited unexpectedly (code=${o??"null"}, signal=${s??"null"})`)}),t.on("error",o=>{i(`failed to spawn: ${o.message}`)}),{kill:async()=>{n=!0;let o=t.pid;if(o==null||t.exitCode!==null||t.signalCode!==null)return;let s=W();if(s.length>0&&!rr(o,D.pid,s))return;let a=B(o,s);G(a,"SIGTERM");let l=await fe(a,e);if(l.length===0)return;let u=B(o,W()),d=[...new Set([...l,...u])].filter(ve);G(d,"SIGKILL"),await fe(d,Xe)}}}var ir=["SIGINT","SIGTERM"],or=nr.signals,sr=2,we=t=>128+(or[t]??sr),ar=t=>{V.exit(t)},lr=(t,e)=>{V.on(t,e)},be=t=>{try{V.stderr.write(t)}catch{}},pr=(t,e)=>{let r=e instanceof Error?`${e.message}
2
+ `).flatMap(e=>{let[r,n,i]=e.trim().split(/\s+/);if(r==null||n==null||i==null)return[];let o=Number(r),s=Number(n),a=Number(i);return!Number.isInteger(o)||!Number.isInteger(s)||!Number.isInteger(a)?[]:[{pid:o,ppid:s,pgid:a}]}),er=(t,e,r)=>{let n=new Map;for(let a of e){let l=n.get(a.ppid);l?l.push(a):n.set(a.ppid,[a])}let i=new Set([t]),o=new Set([t]),s=[t];for(let a=0;a<s.length;a+=1)for(let l of n.get(s[a]??-1)??[])o.has(l.pid)||(o.add(l.pid),i.add(l.pgid),s.push(l.pid));return[...i].filter(a=>a>1&&a!==r)},W=()=>{try{return Ze(ze(Qe,["-eo","pid=,ppid=,pgid="],{encoding:"utf8",maxBuffer:8<<20}))}catch{return[]}},rr=(t,e,r)=>r.some(n=>n.pid===t&&n.ppid===e),B=(t,e)=>{let r=e.find(n=>n.pid===D.pid)?.pgid;return er(t,e,r)},ve=t=>{try{return D.kill(-t,0),!0}catch{return!1}},G=(t,e)=>{for(let r of t)try{D.kill(-r,e)}catch{}},ye=()=>{G(B(D.pid,W()),"SIGKILL")},tr=async t=>new Promise(e=>{setTimeout(e,t)}),fe=async(t,e)=>{let r=Date.now()+e,n=t;for(;n.length>0&&Date.now()<r&&(n=n.filter(ve),n.length!==0);)await tr(Ye);return n};function T(t,e=qe,r){t.unref();let n=!1,i=o=>{n||r?.(o)};return t.on("exit",(o,s)=>{i(`exited unexpectedly (code=${o??"null"}, signal=${s??"null"})`)}),t.on("error",o=>{i(`failed to spawn: ${o.message}`)}),{kill:async()=>{n=!0;let o=t.pid;if(o==null||t.exitCode!==null||t.signalCode!==null)return;let s=W();if(s.length>0&&!rr(o,D.pid,s))return;let a=B(o,s);G(a,"SIGTERM");let l=await fe(a,e);if(l.length===0)return;let u=B(o,W()),d=[...new Set([...l,...u])].filter(ve);G(d,"SIGKILL"),await fe(d,Xe)}}}var ir=["SIGINT","SIGTERM","SIGHUP"],or=nr.signals,sr=2,we=t=>128+(or[t]??sr),ar=t=>{V.exit(t)},lr=(t,e)=>{V.on(t,e)},be=t=>{try{V.stderr.write(t)}catch{}},pr=(t,e)=>{let r=e instanceof Error?`${e.message}
3
3
  ${e.stack??"(no stack)"}`:String(e);be(`
4
4
  \u2717 Teardown failed while handling ${t}: ${r}
5
5
  `)},$=({onSignal:t,exit:e=ar,register:r=lr,forceReap:n=ye})=>{let i=null,o=s=>{if(i!==null){if(s!==i)return;be(`
@@ -20,7 +20,7 @@ ${e.stack??"(no stack)"}`:String(e);fr(`
20
20
  sudo portless service install
21
21
  Then trust its local CA (no sudo needed):
22
22
  portless trust
23
- \`infra-kit doctor\` checks both.`)}async registerAppAlias(e,r,n){let i=z(r),o=_(e);if(o==="")throw new Error(`infra-kit dev: package name "${e}" has no letters or digits to build a hostname from.`);let s=`${i}.${o}`;if(!await this.proxy.registerAlias(s,n))throw new Error(`infra-kit dev: portless refused the alias "${s}" \u2192 127.0.0.1:${n}.`);return this.registeredAliases.add(s),`${s}.localhost`}async startOneApp(e){this.renderer.narrate(`\u{1F504} Starting ${e.name}...`);let r=new I({controllersPath:e.path,prefixUrl:e.prefixUrl,port:e.preferredPort,appName:e.name,onRequestLog:({method:o,path:s,status:a,ms:l})=>{s!=="/__health"&&this.renderer.event({tag:`${e.name}/api`,text:`${o} ${s} ${a} ${l}ms`})}}),n=await r.start(),i;try{i=await this.registerAppAlias(e.packageName,e.path,n)}catch(o){throw await r.close().catch(()=>{}),o}try{this.writeDevContextFragment(e,n,i)}catch(o){this.renderer.log(`\u26A0\uFE0F Failed to write dev-context fragment for ${e.name}: ${String(o)}`,"warn")}return this.renderer.narrate(`\u2705 ${e.name} started on port ${n}`),{server:r,boundPort:n,alias:i}}writeDevContextFragment(e,r,n){let i={package:e.packageName,port:r,pid:g.pid,writtenAt:Date.now(),release:z(e.path),alias:n,origin:`https://${n}`},o=h.join(this.devContextDir,`${e.name}.json`),s=h.join(this.devContextDir,`${e.name}.json.${g.pid}.tmp`);c.mkdirSync(this.devContextDir,{recursive:!0}),c.writeFileSync(s,JSON.stringify(i,null,2)),c.renameSync(s,o)}removeDevContextFragment(e){c.rmSync(h.join(this.devContextDir,`${e.name}.json`),{force:!0})}scheduleRestartWork(e){let r=this.restartWorkChain.then(()=>e(),()=>e());return this.restartWorkChain=r.catch(()=>{}),r}async delayPortRelease(){await new Promise(e=>setTimeout(e,t.PORT_RELEASE_DELAY_MS))}restart(e){return this.shuttingDown?Promise.resolve():this.scheduleRestartWork(()=>this.shuttingDown?Promise.resolve():this.runRestart(e))}resolveRestartTargets(e){return e.map(r=>({idx:this.appServers.findIndex(n=>n.app.name===r.name),app:r})).filter(r=>r.idx>=0)}async runRestart(e){let r=this.resolveRestartTargets(e);if(r.length===0)return;let n=r.length===1?r[0].app.name:`${r.length} apps`;this.renderer.log(`\u{1F504} Restarting ${n}...`),await Promise.all(r.map(async({idx:a})=>{try{await this.appServers[a].server.close()}catch(l){this.renderer.log(` Close warning: ${String(l)}`,"debug")}})),await this.delayPortRelease();let i=await Promise.all(r.map(async({idx:a,app:l})=>{try{let u=await this.startOneApp(l);if(u){let d={app:l,...u};return this.appServers[a]=d,{app:l,entry:d}}return{app:l,entry:null}}catch(u){return this.renderer.log(`\u274C Failed to restart ${l.name}: ${String(u)}`,"error"),{app:l,entry:null}}})),o=await Promise.all(i.map(async({app:a,entry:l})=>{let u=l?await this.healthProbe(t.healthUrl(l.boundPort)):!1;return{label:`${l?`${a.name}:${l.boundPort}`:a.name} ${u?"\u25CF up":"\u25CF down"}`,healthy:u}})),s=o.every(a=>a.healthy);this.renderer.log(`${s?"\u2705":"\u26A0\uFE0F "} Restarted ${o.map(a=>a.label).join(", ")}`)}async buildClosureMapSafe(e){try{return await Ee(this.monorepoRoot,e,this.dryRunner)}catch(r){return this.renderer.log(`\u26A0\uFE0F Dependency-closure map unavailable (${String(r)}); package changes restart all apps`,"warn"),null}}reportEngineDeath(e,r,n){this.shuttingDown||this.renderer.log(`\u26A0\uFE0F ${e} ${n} \u2014 ${r}. Restart \`infra-kit dev\`.`,"warn")}setupWatch(e,r){this.turboWatch=this.turboWatchFactory({depInclusive:e.map(l=>l.packageName),depClosure:r.map(l=>l.packageName),cwd:g.cwd(),logFile:f,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=re(e),i=S(this.monorepoRoot),o=[...n,...i];if(o.length===0){this.renderer.log("\u26A0\uFE0F No app or package dist directories found to watch (were they built?)","warn");return}let s=g.env.DEV_SERVER_CHOKIDAR_POLL==="1",a=Vr.watch(o,{ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:200,pollInterval:100},ignored:l=>l.endsWith(".tsbuildinfo")||l.endsWith(".map"),...s?{usePolling:!0,interval:400}:{}});this.watcher=a,s&&this.renderer.log("\u{1F440} chokidar: usePolling enabled (DEV_SERVER_CHOKIDAR_POLL=1)","debug"),a.on("change",l=>{this.handleDistChange(l,e,n,i)}),this.renderer.narrate(`\u{1F440} Watching ${n.length} app dist + ${i.length} package dist dir(s) for changes...`)}handleDistChange(e,r,n,i){this.renderer.log(`\u{1F440} dist change detected: ${e}`,"debug");let o=te(e,n,i);if(o.kind==="package"){let a=Ce(r,this.closureMap,o.packageDir);if(a===null){this.scheduleDebounced("__packages__",()=>this.restart(r));return}a.length>0&&o.packageDir!==void 0&&this.scheduleDebounced(Re(o.packageDir),()=>this.restart(a));return}let s=r.find(a=>h.join(a.path,"dist")===o.app);s&&this.scheduleDebounced(s.name,()=>this.restart([s]))}scheduleDebounced(e,r){if(this.shuttingDown)return;let n=this.watchDebounceTimers.get(e);n&&clearTimeout(n);let i=setTimeout(()=>{this.watchDebounceTimers.delete(e),!this.shuttingDown&&r().catch(o=>{this.renderer.log(`Restart error (${e}): ${String(o)}`,"error")})},t.WATCH_DEBOUNCE_MS);this.watchDebounceTimers.set(e,i)}static healthUrl(e){return`http://127.0.0.1:${e}/__health`}startLivenessMonitor(){this.scheduleLivenessTick()}scheduleLivenessTick(){let e=this.options.livenessIntervalMs??t.LIVENESS_INTERVAL_MS;this.livenessTimer=setTimeout(()=>{this.livenessTick().finally(()=>{this.shuttingDown||this.scheduleLivenessTick()}).catch(()=>{})},e),this.livenessTimer.unref()}async livenessTick(){this.shuttingDown||await Promise.all(this.appServers.map(async({app:e,boundPort:r})=>{let n=await this.healthProbe(t.healthUrl(r));if(this.shuttingDown)return;let i=this.livenessFailures.get(e.name)??0;if(n){i>=t.LIVENESS_FAILURE_THRESHOLD&&this.renderer.log(`\u2705 ${e.name}/api recovered`),this.livenessFailures.set(e.name,0);return}let o=i+1;this.livenessFailures.set(e.name,o),o===t.LIVENESS_FAILURE_THRESHOLD&&this.renderer.log(`\u26A0\uFE0F ${e.name}/api unhealthy (/__health not responding)`,"warn")}))}async printReady(e,r,n,i){let o=Date.now()-n,s=await Promise.all(this.appServers.map(({boundPort:m})=>this.healthProbe(t.healthUrl(m)))),a=this.appServers.map(({app:m,alias:y},N)=>({tag:`${m.name}/api`,url:j({prefixUrl:m.prefixUrl,alias:y}),healthy:s[N]??null}));this.uiPortMap={};let l=[],u=[];for(let m of r){let y=await this.assignUiPort(m);y!=null?l.push({tag:`${m.name}/ui`,url:j({prefixUrl:"",alias:y.alias}),healthy:null}):u.push({tag:`${m.name}/ui`})}let d=this.options.watch??!1,v=e.length+r.length,p=S(this.monorepoRoot).length;this.renderer.ready({target:i,watch:d,hasUiChild:r.length>0,release:z(g.cwd()),elapsedMs:o,endpoints:[...a,...l],uiRefs:u,failed:this.failedApps.map(({app:m,reason:y})=>({tag:`${m.name}/api`,reason:y})),watchSummary:`${v} app${v===1?"":"s"} \xB7 ${p} package${p===1?"":"s"}`,logPath:Me(f),logHref:f})}async assignUiPort(e){if(!e.managedPort)return null;let r;try{r=await et()}catch{return null}let n=await this.registerAppAlias(e.packageName,e.path,r);return this.uiPortMap[e.packageName]={port:r,alias:n},{port:r,alias:n}}printRouteDump(){if(this.appServers.length!==0){this.renderer.log("\u{1F5FA}\uFE0F Registered routes:");for(let{app:e,server:r}of this.appServers){let n=r.getRegisteredRoutes();this.renderer.log(` ${e.name} (${n.length}): ${n.length>0?n.join(", "):"(none)"}`)}}}async shutdown(){this.shuttingDown=!0,this.renderer.dispose(),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&&(await this.watcher.close(),this.watcher=null),await this.restartWorkChain,await this.closureBuild,await Promise.all([...this.registeredAliases].map(e=>this.proxy.removeAlias(e))),this.registeredAliases.clear(),this.turboWatch&&(await this.turboWatch.kill(),this.turboWatch=null),this.uiDev&&(await this.uiDev.kill(),this.uiDev=null),this.uiLogStream&&(this.uiLogStream.end(),this.uiLogStream=null);for(let{app:e,server:r}of this.appServers){try{await r.close()}catch{}this.removeDevContextFragment(e)}this.renderer.log(`\u2713 dev stopped \xB7 logs \u2192 ${Me(f)}`)}},st=async t=>{if(!(t.tty??!!g.stdout.isTTY)||t.json)return;let{PersistentInkDevUi:r}=await import("./persistent-ink-dev-ui-LRTJBSCH.js");return new r({appendLog:We,verbose:t.verbose??!1})};async function Be(t={}){let e=await st(t),r=new q(t,void 0,void 0,void 0,void 0,e);try{await r.start()}catch(n){throw await r.shutdown().catch(()=>{}),n}return r}var pt=t=>{if(t!=null){for(let e of t)if(ne(e)!==null)throw new Error(`infra-kit dev: invalid --target "${e}" (expected "<app>/api" or "<app>/ui").`);return{apps:Object.fromEntries(t.map(e=>[e,{}]))}}},Ge=t=>{if(t==null)return null;let e=t.split(",").map(r=>r.trim()).filter(Boolean);return e.length>0?e:null},Ve=t=>({watch:t.watch??!1,include:Ge(t.app),preset:t.preset,presetDef:pt(Ge(t.target)),cmux:t.cmux??!1,self:t.self??!1,verbose:t.verbose??!1,routes:t.routes??!1}),ut=t=>!t.self||t.include?t:{...t,include:[ee(w.cwd())]},Y=async t=>{let e=ut(t);if(e.cmux){if(await ue()){await Se(e);return}w.stdout.write(`cmux not available; falling back to single-terminal dev
23
+ \`infra-kit doctor\` checks both.`)}async registerAppAlias(e,r,n){let i=z(r),o=_(e);if(o==="")throw new Error(`infra-kit dev: package name "${e}" has no letters or digits to build a hostname from.`);let s=`${i}.${o}`;if(!await this.proxy.registerAlias(s,n))throw new Error(`infra-kit dev: portless refused the alias "${s}" \u2192 127.0.0.1:${n}.`);return this.registeredAliases.add(s),`${s}.localhost`}async startOneApp(e){this.renderer.narrate(`\u{1F504} Starting ${e.name}...`);let r=new I({controllersPath:e.path,prefixUrl:e.prefixUrl,port:e.preferredPort,appName:e.name,onRequestLog:({method:o,path:s,status:a,ms:l})=>{s!=="/__health"&&this.renderer.event({tag:`${e.name}/api`,text:`${o} ${s} ${a} ${l}ms`})}}),n=await r.start(),i;try{i=await this.registerAppAlias(e.packageName,e.path,n)}catch(o){throw await r.close().catch(()=>{}),o}try{this.writeDevContextFragment(e,n,i)}catch(o){this.renderer.log(`\u26A0\uFE0F Failed to write dev-context fragment for ${e.name}: ${String(o)}`,"warn")}return this.renderer.narrate(`\u2705 ${e.name} started on port ${n}`),{server:r,boundPort:n,alias:i}}writeDevContextFragment(e,r,n){let i={package:e.packageName,port:r,pid:g.pid,writtenAt:Date.now(),release:z(e.path),alias:n,origin:`https://${n}`},o=h.join(this.devContextDir,`${e.name}.json`),s=h.join(this.devContextDir,`${e.name}.json.${g.pid}.tmp`);c.mkdirSync(this.devContextDir,{recursive:!0}),c.writeFileSync(s,JSON.stringify(i,null,2)),c.renameSync(s,o)}removeDevContextFragment(e){c.rmSync(h.join(this.devContextDir,`${e.name}.json`),{force:!0})}scheduleRestartWork(e){let r=this.restartWorkChain.then(()=>e(),()=>e());return this.restartWorkChain=r.catch(()=>{}),r}async delayPortRelease(){await new Promise(e=>setTimeout(e,t.PORT_RELEASE_DELAY_MS))}restart(e){return this.shuttingDown?Promise.resolve():this.scheduleRestartWork(()=>this.shuttingDown?Promise.resolve():this.runRestart(e))}resolveRestartTargets(e){return e.map(r=>({idx:this.appServers.findIndex(n=>n.app.name===r.name),app:r})).filter(r=>r.idx>=0)}async runRestart(e){let r=this.resolveRestartTargets(e);if(r.length===0)return;let n=r.length===1?r[0].app.name:`${r.length} apps`;this.renderer.log(`\u{1F504} Restarting ${n}...`),await Promise.all(r.map(async({idx:a})=>{try{await this.appServers[a].server.close()}catch(l){this.renderer.log(` Close warning: ${String(l)}`,"debug")}})),await this.delayPortRelease();let i=await Promise.all(r.map(async({idx:a,app:l})=>{try{let u=await this.startOneApp(l);if(u){let d={app:l,...u};return this.appServers[a]=d,{app:l,entry:d}}return{app:l,entry:null}}catch(u){return this.renderer.log(`\u274C Failed to restart ${l.name}: ${String(u)}`,"error"),{app:l,entry:null}}})),o=await Promise.all(i.map(async({app:a,entry:l})=>{let u=l?await this.healthProbe(t.healthUrl(l.boundPort)):!1;return{label:`${l?`${a.name}:${l.boundPort}`:a.name} ${u?"\u25CF up":"\u25CF down"}`,healthy:u}})),s=o.every(a=>a.healthy);this.renderer.log(`${s?"\u2705":"\u26A0\uFE0F "} Restarted ${o.map(a=>a.label).join(", ")}`)}async buildClosureMapSafe(e){try{return await Ee(this.monorepoRoot,e,this.dryRunner)}catch(r){return this.renderer.log(`\u26A0\uFE0F Dependency-closure map unavailable (${String(r)}); package changes restart all apps`,"warn"),null}}reportEngineDeath(e,r,n){this.shuttingDown||this.renderer.log(`\u26A0\uFE0F ${e} ${n} \u2014 ${r}. Restart \`infra-kit dev\`.`,"warn")}setupWatch(e,r){this.turboWatch=this.turboWatchFactory({depInclusive:e.map(l=>l.packageName),depClosure:r.map(l=>l.packageName),cwd:g.cwd(),logFile:f,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=re(e),i=S(this.monorepoRoot),o=[...n,...i];if(o.length===0){this.renderer.log("\u26A0\uFE0F No app or package dist directories found to watch (were they built?)","warn");return}let s=g.env.DEV_SERVER_CHOKIDAR_POLL==="1",a=Vr.watch(o,{ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:200,pollInterval:100},ignored:l=>l.endsWith(".tsbuildinfo")||l.endsWith(".map"),...s?{usePolling:!0,interval:400}:{}});this.watcher=a,s&&this.renderer.log("\u{1F440} chokidar: usePolling enabled (DEV_SERVER_CHOKIDAR_POLL=1)","debug"),a.on("change",l=>{this.handleDistChange(l,e,n,i)}),this.renderer.narrate(`\u{1F440} Watching ${n.length} app dist + ${i.length} package dist dir(s) for changes...`)}handleDistChange(e,r,n,i){this.renderer.log(`\u{1F440} dist change detected: ${e}`,"debug");let o=te(e,n,i);if(o.kind==="package"){let a=Ce(r,this.closureMap,o.packageDir);if(a===null){this.scheduleDebounced("__packages__",()=>this.restart(r));return}a.length>0&&o.packageDir!==void 0&&this.scheduleDebounced(Re(o.packageDir),()=>this.restart(a));return}let s=r.find(a=>h.join(a.path,"dist")===o.app);s&&this.scheduleDebounced(s.name,()=>this.restart([s]))}scheduleDebounced(e,r){if(this.shuttingDown)return;let n=this.watchDebounceTimers.get(e);n&&clearTimeout(n);let i=setTimeout(()=>{this.watchDebounceTimers.delete(e),!this.shuttingDown&&r().catch(o=>{this.renderer.log(`Restart error (${e}): ${String(o)}`,"error")})},t.WATCH_DEBOUNCE_MS);this.watchDebounceTimers.set(e,i)}static healthUrl(e){return`http://127.0.0.1:${e}/__health`}startLivenessMonitor(){this.scheduleLivenessTick()}scheduleLivenessTick(){let e=this.options.livenessIntervalMs??t.LIVENESS_INTERVAL_MS;this.livenessTimer=setTimeout(()=>{this.livenessTick().finally(()=>{this.shuttingDown||this.scheduleLivenessTick()}).catch(()=>{})},e),this.livenessTimer.unref()}async livenessTick(){this.shuttingDown||await Promise.all(this.appServers.map(async({app:e,boundPort:r})=>{let n=await this.healthProbe(t.healthUrl(r));if(this.shuttingDown)return;let i=this.livenessFailures.get(e.name)??0;if(n){i>=t.LIVENESS_FAILURE_THRESHOLD&&this.renderer.log(`\u2705 ${e.name}/api recovered`),this.livenessFailures.set(e.name,0);return}let o=i+1;this.livenessFailures.set(e.name,o),o===t.LIVENESS_FAILURE_THRESHOLD&&this.renderer.log(`\u26A0\uFE0F ${e.name}/api unhealthy (/__health not responding)`,"warn")}))}async printReady(e,r,n,i){let o=Date.now()-n,s=await Promise.all(this.appServers.map(({boundPort:m})=>this.healthProbe(t.healthUrl(m)))),a=this.appServers.map(({app:m,alias:y},N)=>({tag:`${m.name}/api`,url:j({prefixUrl:m.prefixUrl,alias:y}),healthy:s[N]??null}));this.uiPortMap={};let l=[],u=[];for(let m of r){let y=await this.assignUiPort(m);y!=null?l.push({tag:`${m.name}/ui`,url:j({prefixUrl:"",alias:y.alias}),healthy:null}):u.push({tag:`${m.name}/ui`})}let d=this.options.watch??!1,v=e.length+r.length,p=S(this.monorepoRoot).length;this.renderer.ready({target:i,watch:d,hasUiChild:r.length>0,release:z(g.cwd()),elapsedMs:o,endpoints:[...a,...l],uiRefs:u,failed:this.failedApps.map(({app:m,reason:y})=>({tag:`${m.name}/api`,reason:y})),watchSummary:`${v} app${v===1?"":"s"} \xB7 ${p} package${p===1?"":"s"}`,logPath:Me(f),logHref:f})}async assignUiPort(e){if(!e.managedPort)return null;let r;try{r=await et()}catch{return null}let n=await this.registerAppAlias(e.packageName,e.path,r);return this.uiPortMap[e.packageName]={port:r,alias:n},{port:r,alias:n}}printRouteDump(){if(this.appServers.length!==0){this.renderer.log("\u{1F5FA}\uFE0F Registered routes:");for(let{app:e,server:r}of this.appServers){let n=r.getRegisteredRoutes();this.renderer.log(` ${e.name} (${n.length}): ${n.length>0?n.join(", "):"(none)"}`)}}}async shutdown(){this.shuttingDown=!0,this.renderer.dispose(),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&&(await this.watcher.close(),this.watcher=null),await this.restartWorkChain,await this.closureBuild,await Promise.all([...this.registeredAliases].map(e=>this.proxy.removeAlias(e))),this.registeredAliases.clear(),this.turboWatch&&(await this.turboWatch.kill(),this.turboWatch=null),this.uiDev&&(await this.uiDev.kill(),this.uiDev=null),this.uiLogStream&&(this.uiLogStream.end(),this.uiLogStream=null);for(let{app:e,server:r}of this.appServers){try{await r.close()}catch{}this.removeDevContextFragment(e)}this.renderer.log(`\u2713 dev stopped \xB7 logs \u2192 ${Me(f)}`)}},st=async t=>{if(!(t.tty??!!g.stdout.isTTY)||t.json)return;let{PersistentInkDevUi:r}=await import("./persistent-ink-dev-ui-FUJQDFNY.js");return new r({appendLog:We,verbose:t.verbose??!1})};async function Be(t={}){let e=await st(t),r=new q(t,void 0,void 0,void 0,void 0,e);try{await r.start()}catch(n){throw await r.shutdown().catch(()=>{}),n}return r}var pt=t=>{if(t!=null){for(let e of t)if(ne(e)!==null)throw new Error(`infra-kit dev: invalid --target "${e}" (expected "<app>/api" or "<app>/ui").`);return{apps:Object.fromEntries(t.map(e=>[e,{}]))}}},Ge=t=>{if(t==null)return null;let e=t.split(",").map(r=>r.trim()).filter(Boolean);return e.length>0?e:null},Ve=t=>({watch:t.watch??!1,include:Ge(t.app),preset:t.preset,presetDef:pt(Ge(t.target)),cmux:t.cmux??!1,self:t.self??!1,verbose:t.verbose??!1,routes:t.routes??!1}),ut=t=>!t.self||t.include?t:{...t,include:[ee(w.cwd())]},Y=async t=>{let e=ut(t);if(e.cmux){if(await ue()){await Se(e);return}w.stdout.write(`cmux not available; falling back to single-terminal dev
24
24
  `)}let r=await Be(e);xe(),$({onSignal:async n=>{w.stdout.write(`
25
25
  Received ${n}, shutting down dev-server...
26
26
  `),await r.shutdown()}})},ct=(t,e,r)=>!t.preset&&!t.app&&!t.self&&!t.cmux&&!t.watch&&!t.verbose&&!t.routes&&e&&!r,dt=t=>({watch:t.watch,cmux:t.cmux,include:t.include??null,preset:t.preset,presetDef:t.presetDef,self:!1,verbose:!1,routes:!1}),Cn=async(t,e,r)=>{if(ct(t,e,r)){let{runDevWizard:n}=await import("./dev-wizard-run-TNA5YI7P.js"),i;try{i=await n()}catch(o){if(he(o))return;throw o}if(i==null)return;await Y({...dt(i),tty:e,json:r});return}await Y({...Ve(t),tty:e,json:r})},ht=async t=>{let e=new at;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(t),await Y(Ve({...e.opts(),preset:e.args[0]}))};import.meta.url===lt(w.argv[1]??"").href&&ht(w.argv).catch(t=>{console.error(t instanceof Error?t.message:String(t)),w.exit(1)});export{Y as runDevServer,Cn as runDevServerCli,ct as shouldRunWizard,Ve as toDevServerOptions};