daimon 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js ADDED
@@ -0,0 +1,75 @@
1
+ import Ts from"react";import{render as ks}from"ink";import{pathToFileURL as xs}from"node:url";import J from"node:fs";import G from"node:path";import tt from"node:os";import{fileURLToPath as Er}from"node:url";var Tr=Er(import.meta.url),ce=G.dirname(Tr);function pe(){return{searchRoots:[],portRange:[4200,4299],apiPort:4999,overrides:{},autoStart:[],profiles:{},tags:{},autoRestart:{enabled:!1,maxAttempts:5,windowMs:3e5},healthProbe:{enabled:!0,intervalMs:3e4,timeoutMs:2e3,path:"/",host:null,scheme:null,rejectUnauthorized:!1,fallbackHosts:["127.0.0.1","::1"]},logs:{enabled:!1,dir:G.join(tt.homedir(),".daimon","logs"),maxFiles:5,maxBytesPerFile:1e7},depends:{},cascadeRestart:!1,history:{enabled:!0,path:G.join(tt.homedir(),".daimon","history.db"),retentionDays:30},notifications:{enabled:!0,onError:!0,onUnhealthy:!0,tray:!1},staleDetect:{enabled:!0,silentMs:3e4},headless:!1,envFiles:{},requestLog:{enabled:!1,portOffset:1e3},metrics:{enabled:!1},editor:{scheme:"vscode"},apiToken:null}}function le(n){return n.startsWith("~/")||n.startsWith("~\\")?G.join(tt.homedir(),n.slice(2)):n==="~"?tt.homedir():n}function Pt(n,t){return Rt(n,t)}function Rt(n,t){if(!n||typeof n!="object")throw new Error(`Config at ${t} is not a JSON object`);let e=n,r=pe();if(e.searchRoots!==void 0){if(!Array.isArray(e.searchRoots)||!e.searchRoots.every(s=>typeof s=="string"||s&&typeof s=="object"&&typeof s.path=="string"))throw new Error(`Config "searchRoots" must be an array of strings or { path, viteSubfolders? } objects (${t})`);r.searchRoots=e.searchRoots}if(e.portRange!==void 0){if(!Array.isArray(e.portRange)||e.portRange.length!==2||typeof e.portRange[0]!="number"||typeof e.portRange[1]!="number"||e.portRange[0]>e.portRange[1])throw new Error(`Config "portRange" must be [min, max] numbers (${t})`);r.portRange=[e.portRange[0],e.portRange[1]]}if(e.apiPort!==void 0){if(typeof e.apiPort!="number")throw new Error(`Config "apiPort" must be a number (${t})`);r.apiPort=e.apiPort}if(e.overrides!==void 0){if(typeof e.overrides!="object"||e.overrides===null||Array.isArray(e.overrides))throw new Error(`Config "overrides" must be an object (${t})`);r.overrides=e.overrides}if(e.autoStart!==void 0){if(!Array.isArray(e.autoStart)||!e.autoStart.every(s=>typeof s=="string"))throw new Error(`Config "autoStart" must be an array of strings (${t})`);r.autoStart=e.autoStart}if(e.profiles!==void 0){if(typeof e.profiles!="object"||e.profiles===null||Array.isArray(e.profiles))throw new Error(`Config "profiles" must be an object (${t})`);for(let[s,o]of Object.entries(e.profiles))if(!Array.isArray(o)||!o.every(i=>typeof i=="string"))throw new Error(`Config "profiles.${s}" must be an array of strings (${t})`);r.profiles=e.profiles}if(e.tags!==void 0){if(typeof e.tags!="object"||e.tags===null||Array.isArray(e.tags))throw new Error(`Config "tags" must be an object (${t})`);r.tags=e.tags}if(e.autoRestart&&typeof e.autoRestart=="object"&&(r.autoRestart={...r.autoRestart,...e.autoRestart}),e.healthProbe&&typeof e.healthProbe=="object"&&(r.healthProbe={...r.healthProbe,...e.healthProbe}),e.logs&&typeof e.logs=="object"&&(r.logs={...r.logs,...e.logs},r.logs.dir=le(r.logs.dir)),e.depends&&typeof e.depends=="object"&&!Array.isArray(e.depends)){for(let[s,o]of Object.entries(e.depends))if(!Array.isArray(o)||!o.every(i=>typeof i=="string"))throw new Error(`Config "depends.${s}" must be an array of strings (${t})`);r.depends=e.depends}if(typeof e.cascadeRestart=="boolean"&&(r.cascadeRestart=e.cascadeRestart),e.history&&typeof e.history=="object"&&(r.history={...r.history,...e.history},r.history.path=le(r.history.path)),e.notifications&&typeof e.notifications=="object"&&(r.notifications={...r.notifications,...e.notifications}),e.staleDetect&&typeof e.staleDetect=="object"&&(r.staleDetect={...r.staleDetect,...e.staleDetect}),typeof e.headless=="boolean"&&(r.headless=e.headless),e.envFiles&&typeof e.envFiles=="object"&&!Array.isArray(e.envFiles)&&(r.envFiles=e.envFiles),e.requestLog&&typeof e.requestLog=="object"&&(r.requestLog={...r.requestLog,...e.requestLog}),e.metrics&&typeof e.metrics=="object"&&(r.metrics={...r.metrics,...e.metrics}),e.editor&&typeof e.editor=="object"){let s=e.editor.scheme;typeof s=="string"&&s.trim()&&(r.editor={scheme:s.trim()})}return(typeof e.apiToken=="string"||e.apiToken===null)&&(r.apiToken=e.apiToken),r}function Ot(){return{local:G.join(process.cwd(),"daimon.config.json"),user:G.join(tt.homedir(),".daimon","config.json")}}function ue(){let{local:n,user:t}=Ot();if(J.existsSync(n)){let s=JSON.parse(J.readFileSync(n,"utf8"));return{kind:"loaded",config:Rt(s,n),path:n}}if(J.existsSync(t)){let s=JSON.parse(J.readFileSync(t,"utf8"));return{kind:"loaded",config:Rt(s,t),path:t}}let r=[G.resolve(ce,"..","daimon.config.example.json"),G.resolve(ce,"..","..","daimon.config.example.json")].find(s=>J.existsSync(s));return J.mkdirSync(G.dirname(t),{recursive:!0}),r?J.copyFileSync(r,t):J.writeFileSync(t,JSON.stringify(pe(),null,2)+`
2
+ `,"utf8"),{kind:"stub-created",path:t}}import et from"node:fs";import F from"node:path";import Nt from"fast-glob";function fe(n){try{return JSON.parse(et.readFileSync(n,"utf8"))}catch{return null}}function de(n){return!n||typeof n!="object"?!1:!!(n.targets?.serve||n.architect?.serve)}function me(n){if(!n||typeof n!="object")return[];let t=n.targets??n.architect??{};return Object.keys(t).filter(e=>e!=="serve").sort()}function $t(n){return n.replace(/\\/g,"/")}function ot(n,t={}){let e=new Map,r=t.warnings??[],s=t.warnings===void 0;for(let o of n.searchRoots){let i=typeof o=="string"?o:o.path,a=typeof o=="string"?!1:!!o.viteSubfolders,l=typeof o=="string"?void 0:o.label,c=F.resolve(i);if(!et.existsSync(c)){r.push(`searchRoot does not exist: ${c}`);continue}let f=F.join(c,"nx.json"),u=F.join(c,"angular.json");if(et.existsSync(f)){let m=Nt.sync("**/project.json",{cwd:$t(c),ignore:["**/node_modules/**","**/dist/**","**/.nx/**","**/.git/**"],absolute:!0,dot:!1});for(let g of m){let d=fe(g);if(!d||!de(d))continue;let v=d.name||F.basename(F.dirname(g));if(v){if(e.has(v)){r.push(`duplicate project name "${v}" \u2014 keeping first`);continue}e.set(v,{name:v,workspaceRoot:c,workspaceType:"nx",command:`npx nx serve ${v}`,hidden:!1,tags:[],tasks:me(d),workspaceLabel:l})}}continue}if(et.existsSync(u)){let g=fe(u)?.projects||{};for(let[d,v]of Object.entries(g))if(de(v)){if(e.has(d)){r.push(`duplicate project name "${d}" \u2014 keeping first`);continue}e.set(d,{name:d,workspaceRoot:c,workspaceType:"angular",command:`npx ng serve ${d}`,hidden:!1,tags:[],tasks:me(v),workspaceLabel:l})}continue}let y=Nt.sync("vite.config.{ts,js,mjs,cjs}",{cwd:$t(c),absolute:!0,deep:1}),b=et.existsSync(F.join(c,".storybook")),p=!1;if(y.length>0){let m=F.basename(c);if(e.has(m)||e.set(m,{name:m,workspaceRoot:c,workspaceType:"vite",command:"npx vite",hidden:!1,tags:[],workspaceLabel:l}),p=!0,a){let g=Nt.sync("*/vite.config.{ts,js,mjs,cjs}",{cwd:$t(c),absolute:!0});for(let d of g){let v=F.dirname(d),A=F.basename(v);A===m||e.has(A)||e.set(A,{name:A,workspaceRoot:v,workspaceType:"vite",command:"npx vite",hidden:!1,tags:[],workspaceLabel:l})}}}if(b){let m=`${F.basename(c)}-storybook`;e.has(m)||e.set(m,{name:m,workspaceRoot:c,workspaceType:"storybook",command:"npx storybook dev --no-open",hidden:!1,tags:[],workspaceLabel:l}),p=!0}p||r.push(`searchRoot has none of nx.json/angular.json/vite.config.*/.storybook: ${c}`)}for(let[o,i]of Object.entries(n.overrides||{})){let a=e.get(o);a?(i.command&&(a.command=i.command),typeof i.hidden=="boolean"&&(a.hidden=i.hidden),typeof i.port=="number"&&(a.pinnedPort=i.port),i.env&&(a.env=i.env)):i.command&&e.set(o,{name:o,workspaceRoot:process.cwd(),workspaceType:"nx",command:i.command,hidden:i.hidden??!1,pinnedPort:i.port,env:i.env,tags:[]})}for(let o of e.values())o.tags=n.tags?.[o.name]??[];if(s&&r.length)for(let o of r)process.stderr.write(`[daimon] warning: ${o}
3
+ `);return[...e.values()].filter(o=>!o.hidden)}import{EventEmitter as an}from"node:events";import{spawn as Gr}from"node:child_process";import ge from"tree-kill";import Jr from"strip-ansi";import kr from"node:crypto";var xr=[/Local:\s+http/i,/Application bundle generation complete/i,/compiled successfully/i,/webpack compiled/i,/Angular Live Development Server is listening/i],Ar=[/Building\.\.\./i,/Compilation started/i,/Initial chunk files/i,/Compiling/i],Cr=[/^\s*ERROR\b/,/\berror TS\d+/,/✘/,/\[ERROR\]/,/Cannot find module/i],Rr=/\berror TS(\d+)/,Pr=/✘\s*\[ERROR\]\s*TS(\d+)/,Or=/([A-Z]:[\\/][^\s:()]+|[^\s:()]+\.(?:tsx?|jsx?|mjs|cjs|vue|svelte)):(\d+):(\d+)/,Nr=/Local:\s+(https?:\/\/\S+)/i,$r=/Server running at\s+(https?:\/\/\S+)/i,Lr=/listening on\s+(https?:\/\/\S+)/i,jr=/(?:listening|listen)\s+(https?:\/\/\S+)/i,Mr=/Initial chunk files/i,_r=/Lazy chunk files/i,Dr=/(Initial total|Lazy total)\s*\|?\s*([\d.]+)\s*(kB|MB|B)\b/i,Ir=/^\s*\|?\s*([^\s|][^|]*?)\s*\|\s*([^|]+?)\s*\|\s*([\d.]+)\s*(kB|MB|B)\b/i;function Fr(n){return kr.createHash("sha1").update(n).digest("hex").slice(0,16)}function Br(n){let t={message:n},e=n.match(Pr)||n.match(Rr);e&&(t.code=`TS${e[1]}`);let r=n.match(Or);return r&&(t.file=r[1],t.line=Number(r[2]),t.col=Number(r[3])),t}function Hr(n,t){try{let e=new URL(n);return e.hostname==="0.0.0.0"||e.hostname==="[::]"?(e.hostname=t.includes(":")?`[${t}]`:t,e.toString().replace(/\/$/,"")):n.replace(/\/$/,"")}catch{return n}}function Ur(n,t="127.0.0.1"){let e=n.match(Nr)||n.match($r)||n.match(Lr)||n.match(jr);if(!e)return null;let r=e[1].replace(/[),.;]+$/,"");return Hr(r,t)}function Wr(n,t){if(Mr.test(t))return n.bundle||(n.bundle={initialKB:0,lazyKB:0,files:[]}),n._bundleSection="initial",!1;if(_r.test(t))return n.bundle||(n.bundle={initialKB:0,lazyKB:0,files:[]}),n._bundleSection="lazy",!1;let e=t.match(Dr);if(e&&n.bundle){let s=parseFloat(e[2]),o=e[3].toUpperCase(),i=Math.round(o==="MB"?s*1024:o==="B"?s/1024:s);return/Initial/i.test(e[1])?n.bundle.initialKB=i:n.bundle.lazyKB=i,!0}let r=t.match(Ir);if(r&&n.bundle){let s=r[1].trim();if(/^(Initial|Lazy)\s+(total|chunk)/i.test(s))return!1;let o=r[4].toUpperCase(),i=parseFloat(r[3]),a=o==="MB"?i*1024:o==="B"?i/1024:i;return n.bundle.files.push({name:s,sizeKB:Math.round(a*10)/10}),!1}return!1}function he(n,t){let e=t.trim();if(!e)return null;let r=n.status,s=!1,o,i=Ur(e);i&&!n.announcedUrl&&(n.announcedUrl=i,o=i);let a=Wr(n,e),l;if(xr.some(f=>f.test(e))){let f=n.status==="error"||!!n.recoveringFromError;if(n.status==="compiling"||n.status==="starting"||n.status==="error"){let u=Date.now();n.compileStartedAt!=null?(l=u-n.compileStartedAt,n.lastCompileMs=l,n.lastCompileAt=u,n.compileStartedAt=null,n.compileHistory.push(l),n.compileHistory.length>20&&n.compileHistory.splice(0,n.compileHistory.length-20)):n.lastCompileAt=u}n.status="serving",f&&(n.errors.clear(),n.recoveringFromError=!1)}else Ar.some(f=>f.test(e))&&(n.status==="starting"||n.status==="serving"||n.status==="error")&&(n.status==="error"&&(n.recoveringFromError=!0),n.compileStartedAt=Date.now(),n.status="compiling");let c;if(Cr.some(f=>f.test(e))){let f=Fr(e),u=Date.now(),y=n.errors.get(f),b=!1,p;y?(y.count+=1,y.lastSeen=u,p=y):(p={message:e,count:1,firstSeen:u,lastSeen:u,parsed:Br(e)},n.errors.set(f,p),b=!0),c={entry:p,isNew:b},n.status="error"}return s=n.status!==r,{statusChanged:s,error:c,announcedUrl:o,bundleUpdated:a,compileMs:l}}var ye=500,it=class{child=null;stdoutBuf="";stderrBuf="";deps;stopping=!1;constructor(t){this.deps=t}isRunning(){return this.child!==null&&this.child.exitCode===null&&!this.stopping}start(){if(this.isRunning())return;let{app:t,port:e,state:r}=this.deps,s=Date.now();r.status="starting",r.startedAt=s,r.compileStartedAt=s,r.lastCompileMs=null,r.lastCompileAt=null,r.errors.clear(),r.logBuffer.length=0,r.lastStatusMessage=void 0;let i=`${this.deps.commandOverride||t.command} --port ${e}`,a={...process.env,...t.env||{},...this.deps.envOverride||{},PORT:String(e),FORCE_COLOR:"0"},l=Gr(i,[],{cwd:t.workspaceRoot,shell:!0,env:a,windowsHide:!0});this.child=l,r.pid=l.pid??null,r.port=e,l.stdout?.on("data",c=>this.handleChunk(c,"stdout")),l.stderr?.on("data",c=>this.handleChunk(c,"stderr")),l.on("exit",(c,f)=>{let u=r.status,y=this.stopping;y?(r.status="stopped",r.lastStatusMessage=`stopped (code=${c??"null"}${f?`, ${f}`:""})`):c!==0?(r.status="error",r.lastStatusMessage=`process exited with code ${c}${f?` (${f})`:""}`):r.status="stopped",r.pid=null,r.health="unknown",this.child=null,this.stopping=!1,u!==r.status&&this.deps.onStatusChange?.(u,r.status,r.lastStatusMessage),this.deps.onExit?.(c,f,y),this.deps.onStateChange()}),l.on("error",c=>{r.status="error",r.lastStatusMessage=`spawn error: ${c.message}`,this.deps.onStateChange()}),this.deps.onStateChange()}handleChunk(t,e){let r=t.toString("utf8"),s=this[e==="stdout"?"stdoutBuf":"stderrBuf"]+=r,o=s.lastIndexOf(`
4
+ `);if(o<0)return;let i=s.slice(0,o),a=s.slice(o+1);e==="stdout"?this.stdoutBuf=a:this.stderrBuf=a;let{state:l}=this.deps,c=!1;for(let f of i.split(/\r?\n/)){if(!f.length)continue;let u=Jr(f),y=Date.now();l.lastLogTs=y,l.stale&&(l.stale=!1),l.logBuffer.push({ts:y,line:u}),l.logBuffer.length>ye&&l.logBuffer.splice(0,l.logBuffer.length-ye),this.deps.onLogLine?.(u);let b=l.status,p=he(l,u);p?.statusChanged&&(c=!0,this.deps.onStatusChange?.(b,l.status)),p?.error&&this.deps.onErrorRecorded?.(p.error.entry,p.error.isNew),p?.compileMs!=null&&this.deps.onCompile?.(p.compileMs),p?.bundleUpdated&&this.deps.onBundleUpdate?.()}(c||i.length>0)&&this.deps.onStateChange()}async stop(){if(!this.child||this.stopping)return;this.stopping=!0;let t=this.child.pid;if(!t){this.child=null,this.stopping=!1;return}await new Promise(e=>{let r=!1,s=()=>{r||(r=!0,e())},o=()=>s();this.child?.once("exit",o),ge(t,"SIGTERM",()=>{});let i=setTimeout(()=>{ge(t,"SIGKILL",()=>{})},2e3),a=setTimeout(()=>{clearTimeout(i),s()},3e3);this.child?.once("exit",()=>{clearTimeout(i),clearTimeout(a),s()})})}};import qr from"node:net";var z=class{assigned=new Map;min;max;onChange;constructor(t,e={}){if(this.min=t[0],this.max=t[1],this.onChange=e.onChange,e.initial){let r=new Set;for(let[s,o]of Object.entries(e.initial))typeof o=="number"&&(o<this.min||o>this.max||r.has(o)||(r.add(o),this.assigned.set(s,o)))}}snapshot(){return Object.fromEntries(this.assigned)}getAssigned(t){return this.assigned.get(t)}pin(t,e){this.assigned.set(t,e),this.onChange?.(this.snapshot())}async allocate(t,e){let r=this.assigned.get(t);if(e!==void 0)return this.assigned.set(t,e),this.onChange?.(this.snapshot()),e;if(r!==void 0)return r;let s=new Set(this.assigned.values());for(let o=this.min;o<=this.max;o++){if(s.has(o))continue;if(await at(o))return this.assigned.set(t,o),this.onChange?.(this.snapshot()),o}throw new Error(`No free ports in range ${this.min}-${this.max}`)}async isPortAvailableForUse(t){return at(t)}};function at(n){return new Promise(t=>{let e=qr.createServer();e.unref(),e.once("error",()=>t(!1)),e.listen({port:n,host:"127.0.0.1",exclusive:!0},()=>{e.close(()=>t(!0))})})}import B from"node:fs";import Xr from"node:path";var ct=class{constructor(t,e){this.appName=t;this.cfg=e;this.filePath=Xr.join(e.dir,`${t}.log`),this.open()}appName;cfg;fd=null;bytes=0;warned=!1;filePath;open(){try{B.mkdirSync(this.cfg.dir,{recursive:!0});try{this.bytes=B.statSync(this.filePath).size}catch{this.bytes=0}this.fd=B.openSync(this.filePath,"a")}catch(t){this.warn(`open failed: ${t.message}`),this.fd=null}}write(t){if(this.fd!=null)try{let e=`${new Date().toISOString()} ${t}
5
+ `,r=Buffer.from(e,"utf8");B.writeSync(this.fd,r),this.bytes+=r.length,this.bytes>=this.cfg.maxBytesPerFile&&this.rotate()}catch(e){this.warn(`write failed: ${e.message}`)}}close(){if(this.fd!=null){try{B.closeSync(this.fd)}catch{}this.fd=null}}rotate(){try{this.close();for(let t=this.cfg.maxFiles-1;t>=1;t--){let e=`${this.filePath}.${t}`,r=`${this.filePath}.${t+1}`;if(t+1>this.cfg.maxFiles-1){try{B.rmSync(e,{force:!0})}catch{}continue}try{B.existsSync(e)&&B.renameSync(e,r)}catch{}}try{let t=`${this.filePath}.1`;B.existsSync(this.filePath)&&B.renameSync(this.filePath,t)}catch{}this.open()}catch(t){this.warn(`rotate failed: ${t.message}`)}}warn(t){this.warned||(this.warned=!0,process.stderr.write(`[daimon] warning: diskLogger(${this.appName}) ${t}
6
+ `))}};function ve(n){let s=new Map,o=new Map,i=null,a=l=>{if(!i){s.set(l,1);for(let c of n[l]||[]){let f=s.get(c)??0;if(f===1){let u=[c,l],y=o.get(l);for(;y&&y!==c;)u.push(y),y=o.get(y);y===c&&u.push(c),i=u.reverse();return}if(f===0&&(o.set(c,l),a(c),i))return}s.set(l,2)}};for(let l of Object.keys(n))if((s.get(l)??0)===0&&(o.set(l,null),a(l),i))return i;return null}function we(n,t){let e=new Set,r=[t];for(;r.length;){let s=r.pop();if(!e.has(s)){e.add(s);for(let o of n[s]||[])r.push(o)}}return[...e]}function be(n,t){let e=new Set(t),r=new Map,s=new Map;for(let a of t)r.set(a,0),s.set(a,[]);for(let a of t)for(let l of n[a]||[])e.has(l)&&(s.get(l).push(a),r.set(a,(r.get(a)??0)+1));let o=[],i=t.filter(a=>(r.get(a)??0)===0);for(;i.length;){o.push([...i].sort());let a=[];for(let l of i)for(let c of s.get(l)??[])r.set(c,(r.get(c)??1)-1),r.get(c)===0&&a.push(c);i=a}return o}function Se(n,t){let e=[];for(let[r,s]of Object.entries(n))s.includes(t)&&e.push(r);return e}import{spawn as Te}from"node:child_process";import Ee from"tree-kill";import ke from"strip-ansi";var Kr=/Tests:\s+(?:(\d+)\s+failed,\s+)?(\d+)\s+passed(?:,\s+(\d+)\s+total)?/,Yr=/Executed (\d+) of (\d+)(?:\s*\((\d+)\s*FAILED\))?/,zr=/(\d+)\s+passed(?:.*?(\d+)\s+failed)?/i;function Vr(n){let t=n.match(Kr);if(t){let s=t[1]?Number(t[1]):0,o=Number(t[2]),i=t[3]?Number(t[3]):o+s;return{passed:o,failed:s,total:i}}let e=n.match(Yr);if(e){let s=Number(e[1]),o=Number(e[2]),i=e[3]?Number(e[3]):0;return{passed:s-i,failed:i,total:o}}let r=n.match(zr);if(r){let s=Number(r[1]),o=r[2]?Number(r[2]):0;return{passed:s,failed:o,total:s+o}}return null}function xe(n,t,e){let r=e.length?" -- "+e.join(" "):"";return n.workspaceType==="nx"?`npx nx run ${n.name}:${t}${r}`:n.workspaceType==="angular"?`npx ng run ${n.name}:${t}${r}`:`npx ${t}${r}`}function Ae(n,t,e=[]){return new Promise(r=>{let s=Date.now(),o=xe(n,t,e),i=Te(o,[],{cwd:n.workspaceRoot,shell:!0,env:{...process.env,...n.env||{},FORCE_COLOR:"0"},windowsHide:!0}),a=[],l="",c=f=>{l+=f.toString("utf8");let u=l.lastIndexOf(`
7
+ `);if(u<0)return;let y=l.slice(0,u);l=l.slice(u+1);for(let b of y.split(/\r?\n/)){if(!b.length)continue;let p=ke(b);a.push(p),a.length>1e3&&a.splice(0,a.length-1e3)}};i.stdout?.on("data",c),i.stderr?.on("data",c),i.on("exit",f=>{let u=Date.now()-s,y=a.join(`
8
+ `)+(l?`
9
+ `+l:""),b=Vr(y);r({app:n.name,task:t,exitCode:f,durationMs:u,summary:b,outputTail:a.slice(-50)})}),i.on("error",()=>{r({app:n.name,task:t,exitCode:-1,durationMs:Date.now()-s,summary:null,outputTail:[...a,"[daimon] task spawn error"]})})})}function Ce(n,t,e=[]){let r=xe(n,t,e),s=Te(r,[],{cwd:n.workspaceRoot,shell:!0,env:{...process.env,...n.env||{},FORCE_COLOR:"0"},windowsHide:!0}),o=[],i="",a=c=>{i+=c.toString("utf8");let f=i.lastIndexOf(`
10
+ `);if(f<0)return;let u=i.slice(0,f);i=i.slice(f+1);for(let y of u.split(/\r?\n/))y.length&&(o.push(ke(y)),o.length>500&&o.splice(0,o.length-500))};return s.stdout?.on("data",a),s.stderr?.on("data",a),{app:n.name,task:t,pid:s.pid??null,child:s,startedAt:Date.now(),logs:o,stop:()=>new Promise(c=>{if(!s.pid){c();return}let f=!1,u=()=>{f||(f=!0,c())};s.once("exit",u),Ee(s.pid,"SIGTERM",()=>{}),setTimeout(()=>{s.pid&&Ee(s.pid,"SIGKILL",()=>{})},2e3),setTimeout(u,3500)})}}import{spawnSync as Lt}from"node:child_process";import so from"tree-kill";function Re(n){if(process.platform==="win32"){let o=Lt("powershell",["-NoProfile","-Command",`Get-NetTCPConnection -LocalPort ${n} -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty OwningProcess`],{encoding:"utf8",windowsHide:!0});if(o.status!==0)return null;let i=Number((o.stdout||"").trim().split(/\s+/)[0]);if(!Number.isFinite(i)||i<=0)return null;let a=Lt("powershell",["-NoProfile","-Command",`Get-CimInstance Win32_Process -Filter "ProcessId=${i}" | Select-Object -Property Name,CommandLine | ConvertTo-Json -Compress`],{encoding:"utf8",windowsHide:!0}),l,c;try{let f=JSON.parse((a.stdout||"").trim()||"{}");l=typeof f.Name=="string"?f.Name:void 0,c=typeof f.CommandLine=="string"?f.CommandLine:void 0}catch{}return{pid:i,name:l,cmd:c}}let t=Lt("lsof",["-nP","-iTCP:"+n,"-sTCP:LISTEN"],{encoding:"utf8"});if(t.status!==0)return null;let e=(t.stdout||"").split(/\r?\n/).filter(o=>o.trim()&&!o.startsWith("COMMAND"));if(!e.length)return null;let r=e[0].split(/\s+/);return{pid:Number(r[1]),name:r[0]}}function Pe(n,t){if(!t)return`port ${n} already in use`;let e=[`port ${n} in use by`];return t.name&&e.push(t.name),e.push(`(pid ${t.pid}`),t.cmd&&(e[e.length-1]+=`, cmd: ${t.cmd.slice(0,120)}`),e[e.length-1]+=")",e.join(" ")}import Ne from"node:fs";import Oe from"node:path";function $e(n){let t={},e;try{e=Ne.readFileSync(n,"utf8")}catch{return t}for(let r of e.split(/\r?\n/)){let s=r.trim();if(!s||s.startsWith("#"))continue;let o=s.indexOf("=");if(o<0)continue;let i=s.slice(0,o).trim(),a=s.slice(o+1).trim();(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),i&&(t[i]=a)}return t}function jt(n,t){return Oe.isAbsolute(t)?t:Oe.join(n,t)}function Mt(n,t){return t.filter(e=>Ne.existsSync(jt(n,e)))}import rn from"node:fs";import nn from"node:path";import pt from"node:fs";import je from"node:path";import en from"node:os";import Qr from"node:fs";import _t from"node:path";import{fileURLToPath as Zr}from"node:url";var Le=_t.dirname(Zr(import.meta.url));function tn(){let n=[_t.resolve(Le,"..","package.json"),_t.resolve(Le,"..","..","package.json")];for(let t of n)try{return JSON.parse(Qr.readFileSync(t,"utf8"))}catch{}return{}}var lt=tn().version||"0.0.0";var It=je.join(en.homedir(),".daimon"),Dt=je.join(It,"daemon.lock");function q(){return It}function Me(n){pt.mkdirSync(It,{recursive:!0});let t=Dt+"."+process.pid+".tmp";pt.writeFileSync(t,JSON.stringify(n)),pt.renameSync(t,Dt)}function _e(){try{pt.unlinkSync(Dt)}catch{}}function De(n,t){return{pid:process.pid,apiPort:n,version:lt,startedAt:Date.now(),headless:t}}function sn(){return nn.join(q(),"secrets.json")}function Ie(){try{let n=rn.readFileSync(sn(),"utf8");n.charCodeAt(0)===65279&&(n=n.slice(1));let t=JSON.parse(n);if(!t||typeof t!="object")return{};let e={};for(let[r,s]of Object.entries(t))typeof s=="string"&&(e[r]=s);return e}catch{return{}}}function Fe(n,t){let e={};for(let[r,s]of Object.entries(n))e[r]=s.replace(/\$\{([A-Z_][A-Z0-9_]*)\}/gi,(o,i)=>t[i]??`\${${i}}`);return e}import Ft from"node:fs";import on from"node:os";import Be from"node:path";var ut=class{file=null;startTs=0;isRecording(){return this.file!=null}start(){if(this.file)return{path:this.file};let t=Be.join(on.homedir(),".daimon","sessions");Ft.mkdirSync(t,{recursive:!0});let e=Be.join(t,`${new Date().toISOString().replace(/[:.]/g,"-")}.jsonl`);return Ft.writeFileSync(e,""),this.file=e,this.startTs=Date.now(),{path:e}}stop(){let t={path:this.file};return this.file=null,this.startTs=0,t}append(t){if(!this.file)return;let e=JSON.stringify({ts:Date.now()-this.startTs,...t})+`
11
+ `;try{Ft.appendFileSync(this.file,e)}catch{}}};var He=500,ft=class extends an{entries=new Map;portAlloc;config;eventBuffer=[];history=null;watchTasks=new Map;sessionRecorder=new ut;constructor(t,e,r){super(),this.config=t,this.portAlloc=r??new z(t.portRange);for(let s of e)this.entries.set(s.name,{app:s,state:this.freshState(s.name,s.tags,s.workspaceLabel??null),proc:null})}getConfig(){return this.config}addDiscoveredApp(t){this.entries.has(t.name)||(this.entries.set(t.name,{app:t,state:this.freshState(t.name,t.tags,t.workspaceLabel??null),proc:null}),this.emit("change"))}updateDiscoveredApp(t){let e=this.entries.get(t.name);e&&(e.app=t,e.state.tags=t.tags,e.state.workspaceLabel=t.workspaceLabel??null,e.state.dependsOn=this.config.depends?.[t.name]??[],this.emit("change"))}getPortAllocator(){return this.portAlloc}setHistory(t){this.history=t}getHistory(){return this.history}freshState(t,e,r=null){return{name:t,status:"stopped",port:null,pid:null,startedAt:null,compileStartedAt:null,lastCompileMs:null,lastCompileAt:null,logBuffer:[],errors:new Map,compileHistory:[],health:"unknown",lastHealthAt:null,cpu:null,memMB:null,restartAttempts:0,restartWindowStart:null,nextRestartAt:null,tags:e,announcedUrl:null,lastHealthError:null,cachedProbeHost:null,lastLogTs:null,stale:!1,bundle:null,bundleRegressionPct:null,activeEnvFile:null,sessionOverrides:null,dependsOn:this.config.depends?.[t]??[],workspaceLabel:r}}names(){return[...this.entries.keys()]}list(){return this.names().map(t=>this.summary(t))}summary(t){let e=this.entries.get(t);if(!e)return null;let r=e.state,s=r.startedAt&&(r.status==="serving"||r.status==="compiling"||r.status==="starting")?Date.now()-r.startedAt:null,i=this.config.overrides?.[t]?.url||e.resolvedUrl||r.announcedUrl||(r.port?`http://127.0.0.1:${r.port}`:null);return{name:r.name,status:r.status,port:r.port,url:i,errorCount:[...r.errors.values()].reduce((a,l)=>a+l.count,0),uptimeMs:s,lastCompileMs:r.lastCompileMs,health:r.health,lastHealthAt:r.lastHealthAt,cpu:r.cpu,memMB:r.memMB,compileHistoryMs:[...r.compileHistory],tags:[...r.tags],restartAttempts:r.restartAttempts,nextRestartAt:r.nextRestartAt,announcedUrl:r.announcedUrl,lastHealthError:r.lastHealthError,stale:r.stale,bundle:r.bundle,bundleRegressionPct:r.bundleRegressionPct,dependsOn:[...r.dependsOn],activeEnvFile:r.activeEnvFile,workspaceLabel:r.workspaceLabel}}getState(t){return this.entries.get(t)?.state??null}getApp(t){return this.entries.get(t)?.app??null}errors(t){let e=this.getState(t);return e?[...e.errors.values()].sort((r,s)=>s.lastSeen-r.lastSeen):null}errorsSince(t,e){let r=this.getState(t);return r?[...r.errors.values()].filter(s=>s.lastSeen>e).sort((s,o)=>o.lastSeen-s.lastSeen):null}logs(t,e={}){let r=this.getState(t);if(!r)return null;let s=r.logBuffer;if(e.sinceMs&&e.sinceMs>0){let o=Date.now()-e.sinceMs;s=s.filter(i=>i.ts>=o)}return e.tail&&e.tail>0&&(s=s.slice(-e.tail)),s.map(o=>o.line)}events(t={}){let e=t.sinceMs&&t.sinceMs>0?Date.now()-t.sinceMs:0;return this.eventBuffer.filter(r=>r.ts>=e&&(!t.app||r.app===t.app))}recordEvent(t){let e={ts:t.ts??Date.now(),...t};this.eventBuffer.push(e),this.eventBuffer.length>He&&this.eventBuffer.splice(0,this.eventBuffer.length-He),this.history?.recordEvent(e),this.emit("event",e)}setHealth(t,e){let r=this.entries.get(t);if(!r)return;let s=r.state;if(s.lastHealthAt=Date.now(),s.health===e)return;let o=s.health;s.health=e,e==="healthy"&&(r.prevHealthyAt=Date.now(),r.cascadeArmed&&(r.cascadeArmed=!1,this.triggerCascadeRestart(t))),this.recordEvent({app:t,type:"health",from:o,to:e}),this.emit("change")}armCascade(t){let e=this.entries.get(t);e&&this.config.cascadeRestart&&e.prevHealthyAt!=null&&(e.cascadeArmed=!0)}setLastHealthError(t,e){let r=this.getState(t);r&&r.lastHealthError!==e&&(r.lastHealthError=e,this.emit("change"))}setResolvedUrl(t,e){let r=this.entries.get(t);r&&r.resolvedUrl!==e&&(r.resolvedUrl=e,this.emit("change"))}setCachedProbeHost(t,e){let r=this.getState(t);r&&(r.cachedProbeHost=e)}setStale(t,e){let r=this.getState(t);r&&r.stale!==e&&(r.stale=e,this.emit("change"))}setSessionOverride(t,e){let r=this.getState(t);r&&(r.sessionOverrides=e,this.emit("change"))}setActiveEnvFile(t,e){let r=this.getState(t);r&&(r.activeEnvFile=e,this.emit("change"))}async start(t){this.sessionRecorder.append({kind:"start",app:t});let e=this.entries.get(t);if(!e)return{ok:!1,status:"unknown",error:"unknown app"};if(e.proc?.isRunning())return{ok:!0,status:e.state.status};let r=e.state.status,s;try{s=await this.portAlloc.allocate(t,e.app.pinnedPort)}catch(b){return e.state.status="error",e.state.lastStatusMessage=b.message,this.recordEvent({app:t,type:"status",from:r,to:"error",message:b.message}),this.emit("change"),{ok:!1,status:"error",error:b.message}}if(!await at(s)){let b=Re(s),p=Pe(s,b);return e.state.status="error",e.state.port=s,e.state.lastStatusMessage=p,this.recordEvent({app:t,type:"status",from:r,to:"error",message:p}),this.emit("change"),{ok:!1,status:"error",error:p}}e.state.health="unknown",e.state.lastHealthAt=null,e.state.announcedUrl=null,e.state.lastHealthError=null,e.state.cachedProbeHost=null,e.state.stale=!1,e.state.lastLogTs=null,e.resolvedUrl=void 0,!e.logger&&this.config.logs.enabled&&(e.logger=new ct(t,this.config.logs));let i=e.state.sessionOverrides,a=this.config.envFiles?.[t]??[],l={};if(a.length){let b=e.state.activeEnvFile;(!b||!Mt(e.app.workspaceRoot,[b]).length)&&(b=Mt(e.app.workspaceRoot,a)[0]??null,b&&(e.state.activeEnvFile=b)),b&&(l=$e(jt(e.app.workspaceRoot,b)))}let c={...l,...this.config.overrides?.[t]?.env??{},...i?.env??{}},f=Ie(),u=Fe(c,f),y=new it({state:e.state,app:e.app,port:s,envOverride:Object.keys(u).length?u:void 0,commandOverride:i?.command,onStateChange:()=>this.emit("change"),onStatusChange:(b,p,m)=>{this.recordEvent({app:t,type:"status",from:b,to:p,message:m}),(p==="stopped"||p==="error")&&(b==="serving"||b==="compiling")&&this.armCascade(t)},onErrorRecorded:(b,p)=>this.recordEvent({app:t,type:p?"error-new":"error-recur",message:b.message}),onExit:(b,p,m)=>this.emit("childExit",{name:t,code:b,signal:p,stopping:m}),onLogLine:b=>{e.logger?.write(b),this.emit("log",{name:t,ts:Date.now(),line:b})},onCompile:b=>{this.history?.recordCompile(t,b);let p=this.getState(t),m=e.lastBundleInitialKB;if(p.bundle&&p.bundle.initialKB>0){if(m&&m>0){let g=(p.bundle.initialKB-m)/m*100;p.bundleRegressionPct=Math.round(g*10)/10,g>10&&this.recordEvent({app:t,type:"bundle-regression",message:`initialKB +${p.bundleRegressionPct}% (${m}->${p.bundle.initialKB})`})}else p.bundleRegressionPct=null;e.lastBundleInitialKB=p.bundle.initialKB}this.checkCompileRegression(t,b),this.emit("compile",{name:t,ms:b})},onBundleUpdate:()=>this.emit("bundleUpdate",{name:t})});return e.proc=y,this.recordEvent({app:t,type:"status",from:r,to:"starting"}),y.start(),{ok:!0,status:e.state.status}}async stop(t){this.sessionRecorder.append({kind:"stop",app:t});let e=this.entries.get(t);if(!e)return{ok:!1,status:"unknown",error:"unknown app"};if(this.emit("userStop",{name:t}),!e.proc||!e.proc.isRunning())return e.state.status!=="stopped"&&this.recordEvent({app:t,type:"status",from:e.state.status,to:"stopped"}),e.state.status="stopped",e.state.pid=null,e.state.health="unknown",this.emit("change"),{ok:!0,status:"stopped"};let r=e.state.status;return await e.proc.stop(),e.proc=null,e.state.status!==r&&this.recordEvent({app:t,type:"status",from:r,to:e.state.status}),{ok:!0,status:e.state.status}}async restart(t){return this.sessionRecorder.append({kind:"restart",app:t}),await this.stop(t),this.start(t)}async startWithDeps(t,e={}){if(!this.entries.has(t))return{ok:!1,results:[{name:t,status:"unknown",health:"unknown",error:"unknown app"}]};let r=we(this.config.depends??{},t).filter(a=>this.entries.has(a)),s=be(this.config.depends??{},r),o=[],i=e.waitMs??6e4;for(let a of s){let l=await Promise.all(a.map(f=>this.start(f)));for(let f=0;f<a.length;f++){let u=l[f];if(!u.ok)return o.push({name:a[f],status:u.status,health:"unknown",error:u.error}),{ok:!1,results:o}}let c=await Promise.all(a.map(f=>this.waitFor(f,"healthy",i)));for(let f=0;f<a.length;f++){let u=c[f],y=!u.timedOut&&u.status==="serving"&&u.health==="healthy";if(o.push({name:u.name,status:u.status,health:u.health,error:y?void 0:u.timedOut?"timeout waiting for healthy":"did not reach healthy"}),!y)return{ok:!1,results:o}}}return{ok:!0,results:o}}triggerCascadeRestart(t){if(!this.config.cascadeRestart)return;let e=Se(this.config.depends??{},t);for(let r of e){let s=this.getState(r);s&&(s.status==="serving"||s.status==="compiling"||s.status==="starting")&&this.restart(r)}}async stopAll(t=3e3){let e=[];for(let r of this.entries.values())r.proc?.isRunning()&&e.push(r.proc.stop());for(let r of this.watchTasks.values())e.push(r.stop());await Promise.race([Promise.all(e),new Promise(r=>setTimeout(r,t))]);for(let r of this.entries.values())r.logger?.close()}listTasks(t){let e=this.getApp(t);return e?[...e.tasks??[]]:null}async runTask(t,e,r=[]){this.sessionRecorder.append({kind:"run",app:t,task:e,args:r});let s=this.getApp(t);if(!s)return{error:"unknown app"};let o=await Ae(s,e,r);return this.history?.recordTaskRun(t,e,o.exitCode,o.durationMs,o.summary),this.recordEvent({app:t,type:"task-run",message:`${e} exit=${o.exitCode} duration=${o.durationMs}ms`}),this.emit("taskRun",{name:t,task:e,result:o}),o}startWatchTask(t,e,r=[]){let s=this.getApp(t);if(!s)return{ok:!1,error:"unknown app"};let o=`${t}::${e}`;if(this.watchTasks.has(o))return{ok:!0,pid:this.watchTasks.get(o).pid};let i=Ce(s,e,r);return this.watchTasks.set(o,i),i.child.on("exit",()=>this.watchTasks.delete(o)),{ok:!0,pid:i.pid}}async stopWatchTask(t,e){let r=`${t}::${e}`,s=this.watchTasks.get(r);return s?(await s.stop(),this.watchTasks.delete(r),{ok:!0}):{ok:!0}}listWatchTasks(t){let e=[];for(let r of this.watchTasks.values())t&&r.app!==t||e.push({app:r.app,task:r.task,pid:r.pid,startedAt:r.startedAt});return e}checkCompileRegression(t,e){let r=this.history;if(!r)return;let o=r.queryCompiles({app:t,limit:31}).filter(l=>l.ms!==e).slice(0,30).map(l=>l.ms);if(o.length<10)return;let i=[...o].sort((l,c)=>l-c),a=i[Math.floor((i.length-1)*.5)];e>2*a&&this.recordEvent({app:t,type:"compile-regression",message:`${(e/1e3).toFixed(1)}s vs p50 ${(a/1e3).toFixed(1)}s`})}watchTaskLogs(t,e,r){let s=this.watchTasks.get(`${t}::${e}`);if(!s)return null;let o=s.logs;return r?o.slice(-r):[...o]}waitFor(t,e,r){return new Promise(s=>{let o=Date.now(),i=this.entries.get(t),a=()=>{if(!i)return!0;let u=i.state;return e==="serving"&&u.status==="serving"||e==="healthy"&&u.status==="serving"&&u.health==="healthy"||e==="stopped"&&u.status==="stopped"||e==="error"&&u.status==="error"},l=u=>{this.off("change",c),clearTimeout(f);let y=i?.state;s({name:t,status:y?.status??"unknown",health:y?.health??"unknown",timedOut:u,waitedMs:Date.now()-o})},c=()=>{a()&&l(!1)};if(a()){s({name:t,status:i.state.status,health:i.state.health,timedOut:!1,waitedMs:0});return}let f=setTimeout(()=>l(!0),r);this.on("change",c)})}};import Tn from"node:http";import kn from"node:crypto";import Kt from"node:fs";import Xt from"node:path";import{fileURLToPath as xn}from"node:url";import Ut from"node:fs";import Ue from"node:path";import cn from"node:os";var Wt=Ue.join(cn.homedir(),".daimon","cursors.json");function ln(){try{let n=Ut.readFileSync(Wt,"utf8"),t=JSON.parse(n);if(t&&typeof t=="object"&&t.errors&&typeof t.errors=="object")return{errors:t.errors}}catch{}return{errors:{}}}var Bt=null,Ht=null;function pn(n){Ht=n,!Bt&&(Bt=setTimeout(()=>{Bt=null;let t=Ht;if(Ht=null,!!t)try{Ut.mkdirSync(Ue.dirname(Wt),{recursive:!0}),Ut.writeFileSync(Wt,JSON.stringify(t),"utf8")}catch(e){process.stderr.write(`[daimon] warning: cursor write failed: ${e.message}
12
+ `)}},500))}var dt=class{data=ln();getErrorCursor(t,e){return this.data.errors[`${t}:${e}`]??0}setErrorCursor(t,e,r){this.data.errors[`${t}:${e}`]=r,pn(this.data)}};import We from"node:fs";import un from"node:os";import Ge from"node:path";var fn=/key|secret|token|password|api[-_]?key/i;function dn(n){let t={};for(let[e,r]of Object.entries(n))typeof r=="string"&&(t[e]=fn.test(e)?"***":r);return t}function Gt(n,t){let e=n.summary(t);if(!e)return null;let r=n.getState(t),s=n.getApp(t),o=n.getConfig(),i=o.overrides?.[t]??{},a={...process.env,...s.env??{},...r.sessionOverrides?.env??{}},l=n.getHistory(),c=l?l.queryEvents({app:t,limit:50}):[];return{takenAt:new Date().toISOString(),summary:e,logs:r.logBuffer.slice(-500).map(f=>({ts:f.ts,line:f.line})),errors:[...r.errors.entries()].map(([f,u])=>({hash:f,message:u.message,count:u.count,firstSeen:u.firstSeen,lastSeen:u.lastSeen})),env:dn(a),configSlice:{command:r.sessionOverrides?.command??i.command??s.command,port:r.sessionOverrides?.port??i.port??null,workspaceRoot:s.workspaceRoot,workspaceType:s.workspaceType,tags:s.tags,depends:o.depends?.[t]??[],envFiles:o.envFiles?.[t]??[]},events:c}}function Je(n,t){let e=Gt(n,t);if(!e)return null;let r=Ge.join(un.homedir(),".daimon","snapshots");We.mkdirSync(r,{recursive:!0});let s=e.takenAt.replace(/[:.]/g,"-"),o=Ge.join(r,`${t}-${s}.json`);return We.writeFileSync(o,JSON.stringify(e,null,2)),{path:o,payload:e}}import mt from"node:fs";import qe from"node:path";var mn=["dist",".angular/cache","tmp","out-tsc"],hn=["node_modules"];function Xe(n){let t=0;try{let e=mt.readdirSync(n,{withFileTypes:!0});for(let r of e){let s=qe.join(n,r.name);try{r.isDirectory()?t+=Xe(s):r.isFile()&&(t+=mt.statSync(s).size)}catch{}}}catch{}return t}function Jt(n,t,e){let r=n.getApp(t);if(!r)return null;let s=n.getState(t),o=s?s.status==="serving"||s.status==="compiling"||s.status==="starting":!1,a=[...mn,...e?hn:[]].map(l=>{let c=qe.join(r.workspaceRoot,l),f=mt.existsSync(c);return{path:c,exists:f,sizeBytes:f?Xe(c):0}});return{app:t,workspace:r.workspaceRoot,targets:a,ranOnServing:o}}function Ke(n,t,e){let r=Jt(n,t,e);if(!r)return{error:"unknown app"};if(r.ranOnServing)return{error:"app is currently running; stop it first"};let s=[],o=[];for(let i of r.targets)if(i.exists)try{mt.rmSync(i.path,{recursive:!0,force:!0}),s.push(i.path)}catch(a){o.push({path:i.path,error:a?.message||String(a)})}return{ok:o.length===0,removed:s,failed:o}}function rt(n){return n.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n")}var gn=["stopped","starting","compiling","serving","error"];function Ye(n){let t=[];t.push("# HELP daimon_up daimon daemon up"),t.push("# TYPE daimon_up gauge"),t.push("daimon_up 1"),t.push("# HELP daimon_app_status app status one-hot"),t.push("# TYPE daimon_app_status gauge");let e=n.list();for(let r of e)for(let s of gn)t.push(`daimon_app_status{name="${rt(r.name)}",status="${s}"} ${r.status===s?1:0}`);t.push("# HELP daimon_compile_seconds last successful compile duration in seconds"),t.push("# TYPE daimon_compile_seconds gauge");for(let r of e)r.lastCompileMs!=null&&t.push(`daimon_compile_seconds{name="${rt(r.name)}"} ${(r.lastCompileMs/1e3).toFixed(3)}`);t.push("# HELP daimon_error_total cumulative deduped error count"),t.push("# TYPE daimon_error_total counter");for(let r of e)t.push(`daimon_error_total{name="${rt(r.name)}"} ${r.errorCount}`);t.push("# HELP daimon_cpu_percent app CPU percent"),t.push("# TYPE daimon_cpu_percent gauge");for(let r of e)r.cpu!=null&&t.push(`daimon_cpu_percent{name="${rt(r.name)}"} ${r.cpu}`);t.push("# HELP daimon_mem_mb app resident memory MB"),t.push("# TYPE daimon_mem_mb gauge");for(let r of e)r.memMB!=null&&t.push(`daimon_mem_mb{name="${rt(r.name)}"} ${r.memMB}`);return t.join(`
13
+ `)+`
14
+ `}import nt from"node:fs";import yn from"node:crypto";import ze from"node:path";var vn=1e6;function wn(){return ze.join(q(),"audit.log")}function bn(n){try{if(nt.statSync(n).size>vn){let e=n+".1";try{nt.unlinkSync(e)}catch{}nt.renameSync(n,e)}}catch{}}function Ve(n,t,e,r){let s=wn();nt.mkdirSync(ze.dirname(s),{recursive:!0}),bn(s);let o=JSON.stringify({prev:t,next:e}),i=yn.createHash("sha1").update(o).digest("hex").slice(0,12),a=`${new Date().toISOString()} ${n} ${i} ${r.join(",")}
15
+ `;try{nt.appendFileSync(s,a)}catch{}}import ht from"node:fs";import gt from"node:path";import{fileURLToPath as Sn}from"node:url";var Qe=gt.dirname(Sn(import.meta.url));function En(){let n=[gt.resolve(Qe,"templates","presets"),gt.resolve(Qe,"..","src","templates","presets")];for(let t of n)if(ht.existsSync(t))return t;return n[0]}function Ze(){let n=En();if(!ht.existsSync(n))return[];let t=ht.readdirSync(n).filter(r=>r.endsWith(".json")),e=[];for(let r of t)try{let s=ht.readFileSync(gt.join(n,r),"utf8");s.charCodeAt(0)===65279&&(s=s.slice(1)),e.push(JSON.parse(s))}catch{}return e}import yt from"node:fs";import tr from"node:path";function er(){return tr.join(q(),"state-handoff.json")}function rr(n){let t=[];for(let s of n.names()){let o=n.getState(s);o&&(o.status==="serving"||o.status==="compiling"||o.status==="starting")&&o.port&&t.push({name:s,port:o.port})}let e={ts:Date.now(),apps:t},r=er();return yt.mkdirSync(tr.dirname(r),{recursive:!0}),yt.writeFileSync(r,JSON.stringify(e)),r}function nr(n=6e4){let t=er();try{let e=yt.readFileSync(t,"utf8"),r=JSON.parse(e);return yt.unlinkSync(t),!r||typeof r.ts!="number"||Date.now()-r.ts>n?null:r}catch{return null}}var An=xn(import.meta.url),sr=Xt.dirname(An);function Cn(){return[Xt.resolve(sr,"dashboard.html"),Xt.resolve(sr,"..","src","dashboard.html")].find(t=>Kt.existsSync(t))??null}function w(n,t,e){let r=JSON.stringify(e);n.writeHead(t,{"content-type":"application/json; charset=utf-8","content-length":Buffer.byteLength(r)}),n.end(r)}function V(n){if(!n)return;let t=n.match(/^(\d+)(ms|s|m|h)?$/);if(!t)return;let e=Number(t[1]);switch(t[2]||"ms"){case"ms":return e;case"s":return e*1e3;case"m":return e*60*1e3;case"h":return e*60*60*1e3}}function Rn(n){if(!n)return{};if(/^\d{10,}$/.test(n))return{sinceTs:Number(n)};let t=V(n);return t!=null?{sinceMs:t}:{}}var Pn=/key|secret|token|password|pass/i;function On(n){let t=JSON.parse(JSON.stringify(n));if(t.apiToken&&(t.apiToken="***"),t.overrides&&typeof t.overrides=="object")for(let e of Object.keys(t.overrides)){let r=t.overrides[e]?.env;if(r&&typeof r=="object")for(let s of Object.keys(r))Pn.test(s)&&(r[s]="***")}return t}function qt(n){if(!n)return"";try{let t=Kt.readFileSync(n);return kn.createHash("sha1").update(t).digest("hex")}catch{return""}}function or(n,t,e={}){let r=new dt,s=Tn.createServer(async(o,i)=>{try{let a=new URL(o.url||"/","http://127.0.0.1"),l=o.method||"GET",c=a.pathname.replace(/\/$/,"").split("/").filter(Boolean),f=()=>{let m=(e.getConfig?e.getConfig():null)?.apiToken??null;if(!m)return!0;let g=o.headers.authorization;return typeof g=="string"&&g.toLowerCase().startsWith("bearer ")&&g.slice(7).trim()===m?!0:(w(i,401,{error:"unauthorized"}),!1)};if(l==="POST"&&a.pathname==="/api/shutdown"){if(!f())return;w(i,200,{ok:!0}),e.onShutdown&&setImmediate(()=>{try{e.onShutdown()}catch{}});return}if(a.pathname==="/api/config"&&e.getConfig){if(l==="GET"){let p=e.getConfig(),m=qt(e.configPath);i.writeHead(200,{"content-type":"application/json; charset=utf-8",etag:m}),i.end(JSON.stringify({etag:m,config:On(p)}));return}if(l==="PATCH"&&e.patchConfig){if(!f())return;let p=o.headers["if-match"]?.trim(),m=qt(e.configPath);if(!p||p!==m){w(i,412,{error:"etag mismatch",current:m});return}let g={};o.headers["content-length"]&&o.headers["content-length"]!=="0"&&await new Promise(A=>{let $=[];o.on("data",S=>$.push(S)),o.on("end",()=>{try{g=JSON.parse(Buffer.concat($).toString("utf8"))}catch{}A()})});let d=e.patchConfig(g);if(!d.ok){w(i,400,{error:d.error});return}let v=qt(e.configPath);try{let A=o.socket.remoteAddress||"127.0.0.1";Ve(A,g,g,d.applied)}catch{}i.writeHead(200,{"content-type":"application/json; charset=utf-8",etag:v}),i.end(JSON.stringify({etag:v,applied:d.applied,addedApps:d.addedApps,removedApps:d.removedApps,restartRequired:d.restartRequired}));return}w(i,405,{error:"method not allowed"});return}if(a.pathname==="/api/presets"&&l==="GET"){w(i,200,Ze());return}if(a.pathname==="/api/snapshot-state"&&l==="POST"){if(!f())return;let p=rr(n);w(i,200,{ok:!0,path:p});return}if(a.pathname==="/api/config/reload"&&l==="POST"&&e.reloadConfig){if(!f())return;try{let p=await e.reloadConfig();w(i,200,p)}catch(p){w(i,400,{error:p?.message||String(p)})}return}if(l==="GET"&&a.pathname==="/metrics"&&e.metricsEnabled){let p=Ye(n);i.writeHead(200,{"content-type":"text/plain; version=0.0.4","content-length":Buffer.byteLength(p)}),i.end(p);return}if(l!=="GET"&&a.pathname.startsWith("/api/")&&a.pathname!=="/api/shutdown"&&a.pathname!=="/api/config"&&a.pathname!=="/api/config/reload"&&!f())return;if(l==="GET"&&a.pathname==="/"){let p=Cn();if(!p){i.writeHead(404).end("dashboard not found");return}let m=Kt.readFileSync(p);i.writeHead(200,{"content-type":"text/html; charset=utf-8","content-length":m.length}),i.end(m);return}if(c[0]==="api"&&c[1]==="events"&&c.length===2){if(l!=="GET"){w(i,405,{error:"method not allowed"});return}let p=V(a.searchParams.get("since")),m=a.searchParams.get("app")||void 0,g=n.events({sinceMs:p,app:m}),d=n.getHistory();if(d&&p&&g.length<500){let v=Date.now()-p,A=d.queryEvents({app:m,since:v,limit:1e3}),$=new Set(g.map(S=>`${S.ts}|${S.app}|${S.type}|${S.from??""}|${S.to??""}|${S.message??""}`));for(let S of A){let L=`${S.ts}|${S.app}|${S.type}|${S.from_state??""}|${S.to_state??""}|${S.message??""}`;$.has(L)||g.push({ts:S.ts,app:S.app,type:S.type,from:S.from_state??void 0,to:S.to_state??void 0,message:S.message??void 0})}g.sort((S,L)=>S.ts-L.ts)}w(i,200,g);return}if(c[0]==="api"&&c[1]==="session"){if(c[2]==="record"&&l==="POST"){let p=a.searchParams.get("action")||"toggle";if(p==="start"||p==="toggle"&&!n.sessionRecorder.isRecording()){let m=n.sessionRecorder.start();w(i,200,{recording:!0,path:m.path});return}if(p==="stop"||p==="toggle"&&n.sessionRecorder.isRecording()){let m=n.sessionRecorder.stop();w(i,200,{recording:!1,path:m.path});return}w(i,400,{error:"invalid action"});return}if(c[2]==="status"&&l==="GET"){w(i,200,{recording:n.sessionRecorder.isRecording()});return}w(i,404,{error:"not found"});return}if(c[0]==="api"&&c[1]==="history"){if(l!=="GET"){w(i,405,{error:"method not allowed"});return}let p=n.getHistory();if(!p){w(i,200,[]);return}let m=c[2],g=a.searchParams.get("app")||void 0,d=a.searchParams.get("since"),v=a.searchParams.get("until"),A=a.searchParams.get("limit"),$=d?/^\d{10,}$/.test(d)?Number(d):Date.now()-(V(d)??0):void 0,S=v?/^\d{10,}$/.test(v)?Number(v):Date.now()-(V(v)??0):void 0,L=A?Number(A):void 0;if(m==="events"){w(i,200,p.queryEvents({app:g,since:$,until:S,type:a.searchParams.get("type")||void 0,limit:L}));return}if(m==="compile-times"){w(i,200,p.queryCompiles({app:g,since:$,until:S,limit:L}));return}if(m==="tasks"){w(i,200,p.queryTasks({app:g,task:a.searchParams.get("task")||void 0,since:$,limit:L}));return}if(m==="summary"&&c.length>=4){let U=decodeURIComponent(c[3]);w(i,200,p.summary(U));return}if(m==="why"&&c.length>=4){let U=decodeURIComponent(c[3]);w(i,200,p.why(U));return}w(i,404,{error:"not found"});return}if(c[0]!=="api"||c[1]!=="apps"){w(i,404,{error:"not found"});return}if(c.length===2){if(l!=="GET"){w(i,405,{error:"method not allowed"});return}w(i,200,n.list());return}let u=decodeURIComponent(c[2]),y=c[3],b=c[4];if(!y){if(l!=="GET"){w(i,405,{error:"method not allowed"});return}let p=n.summary(u);if(!p){w(i,404,{error:"unknown app"});return}w(i,200,p);return}if(y==="errors"&&b==="since-last"&&l==="GET"){let p=a.searchParams.get("client")||"default",m=r.getErrorCursor(p,u),g=n.errorsSince(u,m);if(g==null){w(i,404,{error:"unknown app"});return}let d=g.reduce((v,A)=>Math.max(v,A.lastSeen),m);d>m&&r.setErrorCursor(p,u,d),w(i,200,g);return}if(y==="errors"&&!b&&l==="GET"){let p=a.searchParams.get("since");if(p){let{sinceMs:g,sinceTs:d}=Rn(p),v=d??(g!=null?Date.now()-g:0),A=n.errorsSince(u,v);if(A==null){w(i,404,{error:"unknown app"});return}w(i,200,A);return}let m=n.errors(u);if(m==null){w(i,404,{error:"unknown app"});return}w(i,200,m);return}if(y==="logs"&&c[4]==="stream"&&l==="GET"){if(!n.summary(u)){w(i,404,{error:"unknown app"});return}i.writeHead(200,{"content-type":"text/event-stream","cache-control":"no-cache",connection:"keep-alive"});let p=n.logs(u,{tail:50})??[];for(let $ of p)i.write(`data: ${JSON.stringify({ts:Date.now(),line:$})}
16
+
17
+ `);let m=[],g=0,d=()=>{for(;m.length&&i.write(m.shift()););},v=$=>{$.name===u&&(m.length>=200&&(g++,m.shift()),m.push(`data: ${JSON.stringify({ts:$.ts,line:$.line})}
18
+
19
+ `),d())};n.on("log",v);let A=setInterval(()=>i.write(`: ping
20
+
21
+ `),3e4);o.on("close",()=>{n.off("log",v),clearInterval(A)});return}if(y==="logs"&&l==="GET"){let p=a.searchParams.get("tail"),m=a.searchParams.get("since"),g=n.logs(u,{tail:p?Number(p):void 0,sinceMs:V(m)});if(g==null){w(i,404,{error:"unknown app"});return}w(i,200,{lines:g});return}if(y==="wait"&&l==="GET"){if(!n.summary(u)){w(i,404,{error:"unknown app"});return}let p=(a.searchParams.get("until")||"serving").toLowerCase();if(!["serving","healthy","stopped","error"].includes(p)){w(i,400,{error:"until must be one of serving|healthy|stopped|error"});return}let m=a.searchParams.get("timeout"),g=m?Number(m):120;(!Number.isFinite(g)||g<=0)&&(g=120),g=Math.min(g,600);let d=await n.waitFor(u,p,g*1e3);w(i,200,d);return}if(y==="start"&&l==="POST"){if(a.searchParams.get("withDeps")==="1"){let g=await n.startWithDeps(u);w(i,g.ok?200:400,g);return}let m=await n.start(u);w(i,m.ok?200:400,m);return}if(y==="start-with-deps"&&l==="POST"){let p=await n.startWithDeps(u);w(i,p.ok?200:400,p);return}if(y==="tasks"&&l==="GET"&&!b){let p=n.listTasks(u);if(p==null){w(i,404,{error:"unknown app"});return}w(i,200,{tasks:p,watching:n.listWatchTasks(u)});return}if(y==="run"&&b&&l==="POST"){let p={};o.headers["content-length"]&&o.headers["content-length"]!=="0"&&await new Promise(d=>{let v=[];o.on("data",A=>v.push(A)),o.on("end",()=>{try{p=JSON.parse(Buffer.concat(v).toString("utf8"))}catch{}d()})});let m=Array.isArray(p.args)?p.args.map(String):[];if(p.watch){let d=n.startWatchTask(u,b,m);w(i,d.ok?200:400,d);return}let g=await n.runTask(u,b,m);if("error"in g){w(i,404,g);return}w(i,200,g);return}if(y==="run-stop"&&b&&l==="POST"){let p=await n.stopWatchTask(u,b);w(i,200,p);return}if(y==="env"&&l==="GET"){let m=n.getConfig().envFiles?.[u]??[],g=n.getState(u);w(i,200,{candidates:m,active:g?.activeEnvFile??null});return}if(y==="env"&&l==="POST"){let p={};o.headers["content-length"]&&o.headers["content-length"]!=="0"&&await new Promise(g=>{let d=[];o.on("data",v=>d.push(v)),o.on("end",()=>{try{p=JSON.parse(Buffer.concat(d).toString("utf8"))}catch{}g()})}),n.setActiveEnvFile(u,p.use??null);let m=n.getState(u);w(i,200,{active:m?.activeEnvFile??null});return}if(y==="requests"&&l==="GET"){if(!e.requestLog){w(i,200,[]);return}let p=V(a.searchParams.get("since"));w(i,200,e.requestLog.requests(u,p));return}if(y==="clean"&&l==="POST"){let p=a.searchParams.get("deep")==="1",m=a.searchParams.get("yes")==="1",g=Jt(n,u,p);if(!g){w(i,404,{error:"unknown app"});return}if(g.ranOnServing){w(i,409,{error:"refusing: app is currently running",plan:g});return}if(!m){w(i,200,{plan:g,hint:"pass --yes to delete"});return}let d=Ke(n,u,p);w(i,200,d);return}if(y==="snapshot"&&l==="POST"){if(a.searchParams.get("write")==="1"){let g=Je(n,u);if(!g){w(i,404,{error:"unknown app"});return}w(i,200,{snapshot:g.path});return}let m=Gt(n,u);if(!m){w(i,404,{error:"unknown app"});return}w(i,200,m);return}if(y==="stop"&&l==="POST"){let p=await n.stop(u);w(i,p.ok?200:400,p);return}if(y==="restart"&&l==="POST"){let p=await n.restart(u);w(i,p.ok?200:400,p);return}w(i,404,{error:"not found"})}catch(a){w(i,500,{error:a?.message||String(a)})}});return s.listen(t,"127.0.0.1"),s}import Nn from"node:http";import $n from"node:https";var Ln=1e3,jn=500;function Mn(n,t,e,r,s){if(t)return[t];let o=n.path||"/",i=n.fallbackHosts&&n.fallbackHosts.length?n.fallbackHosts:["127.0.0.1"];if(n.host||n.scheme){let l=e?Yt(e):null,c=n.scheme||l?.protocol?.replace(":","")||"http",f=n.host||l?.hostname||(r?i[0]:"127.0.0.1"),u=r??(l?.port?Number(l.port):null);return[ir(c,f,u,o)]}if(e){let l=Yt(e);if(l)return l.pathname=o,[l.toString()]}let a=[];s&&a.push(s);for(let l of i)a.includes(l)||a.push(l);return a.map(l=>ir("http",l,r,o))}function Yt(n){try{return new URL(n)}catch{return null}}function ir(n,t,e,r){let s=t.includes(":")&&!t.startsWith("[")?`[${t}]`:t,o=e?`:${e}`:"";return`${n}://${s}${o}${r.startsWith("/")?r:"/"+r}`}var vt=class{constructor(t,e,r){this.registry=t;this.cfg=e;this.fullConfig=r;if(e.enabled){t.on("change",this.onChange);for(let s of t.names())this.evaluate(s)}}registry;cfg;fullConfig;timers=new Map;starting=new Map;freshness=new Map;stopped=!1;stop(){this.stopped=!0,this.registry.off("change",this.onChange);for(let t of this.timers.values())clearInterval(t);for(let t of this.starting.values())clearTimeout(t);this.timers.clear(),this.starting.clear()}onChange=()=>{if(!this.stopped)for(let t of this.registry.names())this.evaluate(t)};evaluate(t){let e=this.registry.getState(t);if(e)if(e.status==="serving"){if(this.timers.has(t)||this.starting.has(t))return;this.freshness.set(t,{retried:!1});let r=setTimeout(()=>{this.starting.delete(t),this.probe(t);let s=setInterval(()=>{this.probe(t)},this.cfg.intervalMs);this.timers.set(t,s)},jn);this.starting.set(t,r)}else{let r=this.timers.get(t);r&&(clearInterval(r),this.timers.delete(t));let s=this.starting.get(t);s&&(clearTimeout(s),this.starting.delete(t)),this.freshness.delete(t),e.health!=="unknown"&&(e.status==="stopped"||e.status==="error")&&this.registry.setHealth(t,"unknown")}}async probe(t){let e=this.registry.getState(t);if(!e||e.status!=="serving")return;let r=this.fullConfig?.overrides?.[t]?.url,s=Mn(this.cfg,r,e.announcedUrl,e.port,e.cachedProbeHost);if(s.length===0){this.registry.setLastHealthError(t,"no probe URL available"),this.registry.setHealth(t,"unhealthy");return}let o=null;for(let a of s){let l=await this.tryProbe(a);if(l.ok){let c=Yt(a);c&&this.registry.setCachedProbeHost(t,c.hostname.replace(/^\[|\]$/g,"")),this.registry.setResolvedUrl(t,a),this.registry.setLastHealthError(t,null),this.registry.setHealth(t,"healthy");return}o||(o=`${l.error} ${a}`)}let i=this.freshness.get(t);if(i&&!i.retried){i.retried=!0,setTimeout(()=>{this.probe(t)},Ln);return}this.registry.setLastHealthError(t,o||"unknown probe failure"),this.registry.setHealth(t,"unhealthy")}tryProbe(t){return new Promise(e=>{let r=!1,s=l=>{r||(r=!0,e(l))},o=t.startsWith("https://"),i=o?$n:Nn,a={timeout:this.cfg.timeoutMs};o&&(a.rejectUnauthorized=!!this.cfg.rejectUnauthorized);try{let l=i.get(t,a,c=>{let f=c.statusCode??0;c.resume(),f>=200&&f<500?s({ok:!0}):s({ok:!1,error:`http ${f}`})});l.on("timeout",()=>l.destroy(new Error("timeout"))),l.on("error",c=>s({ok:!1,error:c?.code||c?.message||"error"}))}catch(l){s({ok:!1,error:l?.message||"throw"})}})}};import _n from"pidusage";var wt=class{constructor(t,e=2e3){this.registry=t;this.intervalMs=e;this.timer=setInterval(()=>this.tick(),e)}registry;intervalMs;timer=null;stopped=!1;stop(){this.stopped=!0,this.timer&&(clearInterval(this.timer),this.timer=null)}async tick(){if(this.stopped)return;let t=[];for(let r of this.registry.names()){let s=this.registry.getState(r);s?.pid&&t.push({name:r,pid:s.pid})}if(!t.length)return;let e=!1;await Promise.all(t.map(async({name:r,pid:s})=>{try{let o=await _n(s),i=this.registry.getState(r);if(!i)return;let a=Math.round(o.cpu*10)/10,l=Math.round(o.memory/(1024*1024));(i.cpu!==a||i.memMB!==l)&&(i.cpu=a,i.memMB=l,e=!0)}catch{let o=this.registry.getState(r);o&&(o.cpu!=null||o.memMB!=null)&&(o.cpu=null,o.memMB=null,e=!0)}})),e&&this.registry.emit("change")}};var bt=class{constructor(t,e){this.registry=t;this.cfg=e}registry;cfg;timers=new Map;stopped=!1;stop(){this.stopped=!0;for(let t of this.timers.values())clearTimeout(t);this.timers.clear()}onExit(t,e,r,s){if(this.stopped||s||!this.cfg.enabled||e===0&&!r)return;let o=this.registry.getState(t);if(!o)return;let i=Date.now();if((o.restartWindowStart==null||i-o.restartWindowStart>this.cfg.windowMs)&&(o.restartWindowStart=i,o.restartAttempts=0),o.restartAttempts+=1,o.restartAttempts>this.cfg.maxAttempts){o.lastStatusMessage=`auto-restart aborted (${o.restartAttempts-1}/${this.cfg.maxAttempts} within window)`,o.nextRestartAt=null,this.registry.recordEvent({app:t,type:"restart-scheduled",message:o.lastStatusMessage}),this.registry.emit("change");return}let a=Math.min(2**(o.restartAttempts-1)*1e3,3e4);o.nextRestartAt=i+a,o.lastStatusMessage=`restarting in ${Math.round(a/1e3)}s (attempt ${o.restartAttempts}/${this.cfg.maxAttempts})`,this.registry.recordEvent({app:t,type:"restart-scheduled",message:o.lastStatusMessage}),this.registry.emit("change");let l=setTimeout(()=>{this.timers.delete(t);let c=this.registry.getState(t);c&&(c.nextRestartAt=null),this.registry.start(t)},a);this.timers.set(t,l)}onUserStop(t){let e=this.timers.get(t);e&&(clearTimeout(e),this.timers.delete(t));let r=this.registry.getState(t);r&&(r.restartAttempts=0,r.restartWindowStart=null,r.nextRestartAt=null)}};import Qt from"node:fs";import ar from"node:path";import Dn from"node:os";var Zt=ar.join(Dn.homedir(),".daimon","state.json");function cr(){try{let n=Qt.readFileSync(Zt,"utf8"),t=JSON.parse(n);if(t&&typeof t=="object"&&t.ports&&typeof t.ports=="object")return{ports:t.ports}}catch{}return{ports:{}}}var zt=null,Vt=null;function lr(n){Vt=n,!zt&&(zt=setTimeout(()=>{zt=null;let t=Vt;if(Vt=null,!!t)try{Qt.mkdirSync(ar.dirname(Zt),{recursive:!0}),Qt.writeFileSync(Zt,JSON.stringify(t),"utf8")}catch(e){process.stderr.write(`[daimon] warning: state write failed: ${e.message}
22
+ `)}},500))}import In from"node:fs";import Fn from"node:path";import{createRequire as Bn}from"node:module";var Hn=Bn(import.meta.url),Un=200,Wn=360*60*1e3,Gn=1e4,St=class{constructor(t){this.cfg=t;if(t.enabled)try{In.mkdirSync(Fn.dirname(t.path),{recursive:!0});let e=Hn("better-sqlite3");this.db=new e(t.path),this.db.pragma("journal_mode = WAL"),this.migrate(),this.flushTimer=setInterval(()=>this.flush(),Un),this.retentionStart=setTimeout(()=>this.runRetention(),Gn),this.retentionTimer=setInterval(()=>this.runRetention(),Wn)}catch(e){this.warnOnce(`failed to open history db: ${e?.message||e}`),this.db=null}}cfg;db=null;queue=[];flushTimer=null;retentionTimer=null;retentionStart=null;warned=!1;warnOnce(t){this.warned||(this.warned=!0,process.stderr.write(`[daimon] history: ${t}
23
+ `))}migrate(){this.db&&this.db.exec(`
24
+ CREATE TABLE IF NOT EXISTS events (
25
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
26
+ ts INTEGER NOT NULL,
27
+ app TEXT NOT NULL,
28
+ type TEXT NOT NULL,
29
+ from_state TEXT,
30
+ to_state TEXT,
31
+ message TEXT
32
+ );
33
+ CREATE INDEX IF NOT EXISTS events_ts_app ON events(ts, app);
34
+ CREATE TABLE IF NOT EXISTS compile_times (
35
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
36
+ ts INTEGER NOT NULL,
37
+ app TEXT NOT NULL,
38
+ ms INTEGER NOT NULL
39
+ );
40
+ CREATE INDEX IF NOT EXISTS compile_app_ts ON compile_times(app, ts);
41
+ CREATE TABLE IF NOT EXISTS task_runs (
42
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
43
+ ts INTEGER NOT NULL,
44
+ app TEXT NOT NULL,
45
+ task TEXT NOT NULL,
46
+ exit_code INTEGER,
47
+ duration_ms INTEGER,
48
+ summary TEXT
49
+ );
50
+ CREATE INDEX IF NOT EXISTS task_runs_app_ts ON task_runs(app, ts);
51
+ `)}recordEvent(t){this.db&&this.queue.push({kind:"event",row:{ts:t.ts,app:t.app,type:t.type,from_state:t.from??null,to_state:t.to??null,message:t.message??null}})}recordCompile(t,e,r=Date.now()){this.db&&this.queue.push({kind:"compile",row:{ts:r,app:t,ms:e}})}recordTaskRun(t,e,r,s,o,i=Date.now()){this.db&&this.queue.push({kind:"task",row:{ts:i,app:t,task:e,exit_code:r,duration_ms:s,summary:o==null?null:JSON.stringify(o)}})}flush(){if(!this.db||this.queue.length===0)return;let t=this.queue;this.queue=[];try{let e=this.db.prepare("INSERT INTO events (ts,app,type,from_state,to_state,message) VALUES (?,?,?,?,?,?)"),r=this.db.prepare("INSERT INTO compile_times (ts,app,ms) VALUES (?,?,?)"),s=this.db.prepare("INSERT INTO task_runs (ts,app,task,exit_code,duration_ms,summary) VALUES (?,?,?,?,?,?)");this.db.transaction(i=>{for(let a of i)a.kind==="event"?e.run(a.row.ts,a.row.app,a.row.type,a.row.from_state,a.row.to_state,a.row.message):a.kind==="compile"?r.run(a.row.ts,a.row.app,a.row.ms):s.run(a.row.ts,a.row.app,a.row.task,a.row.exit_code,a.row.duration_ms,a.row.summary)})(t)}catch(e){this.warnOnce(`history write failed: ${e?.message||e}`)}}runRetention(){if(this.db)try{let t=Date.now()-this.cfg.retentionDays*864e5;this.db.prepare("DELETE FROM events WHERE ts < ?").run(t),this.db.prepare("DELETE FROM compile_times WHERE ts < ?").run(t),this.db.prepare("DELETE FROM task_runs WHERE ts < ?").run(t)}catch(t){this.warnOnce(`retention failed: ${t?.message||t}`)}}queryEvents(t){if(!this.db)return[];let e=[],r=[];t.app&&(e.push("app = ?"),r.push(t.app)),t.since!=null&&(e.push("ts >= ?"),r.push(t.since)),t.until!=null&&(e.push("ts <= ?"),r.push(t.until)),t.type&&(e.push("type = ?"),r.push(t.type));let s=`SELECT * FROM events ${e.length?"WHERE "+e.join(" AND "):""} ORDER BY ts DESC LIMIT ?`;return r.push(t.limit??500),this.db.prepare(s).all(...r)}queryCompiles(t){if(!this.db)return[];let e=[],r=[];t.app&&(e.push("app = ?"),r.push(t.app)),t.since!=null&&(e.push("ts >= ?"),r.push(t.since)),t.until!=null&&(e.push("ts <= ?"),r.push(t.until));let s=`SELECT * FROM compile_times ${e.length?"WHERE "+e.join(" AND "):""} ORDER BY ts DESC LIMIT ?`;return r.push(t.limit??1e3),this.db.prepare(s).all(...r)}queryTasks(t){if(!this.db)return[];let e=[],r=[];t.app&&(e.push("app = ?"),r.push(t.app)),t.task&&(e.push("task = ?"),r.push(t.task)),t.since!=null&&(e.push("ts >= ?"),r.push(t.since));let s=`SELECT * FROM task_runs ${e.length?"WHERE "+e.join(" AND "):""} ORDER BY ts DESC LIMIT ?`;return r.push(t.limit??200),this.db.prepare(s).all(...r)}summary(t){if(!this.db)return{uptimePct24h:0,restartCount24h:0,compileP50:null,compileP95:null,topErrors:[]};let e=Date.now()-24*3600*1e3,r=this.queryEvents({app:t,since:e,limit:5e3}),s=0,o=e,i=!1,a=null,l=[...r].sort((d,v)=>d.ts-v.ts);for(let d of l)d.type==="status"&&(d.to_state==="serving"&&!i?(i=!0,a=d.ts):i&&d.to_state!=="serving"&&a!=null&&(s+=d.ts-a,i=!1,a=null));i&&a!=null&&(s+=Date.now()-a);let c=Math.round(s/(24*3600*1e3)*1e3)/10,f=r.filter(d=>d.type==="status"&&d.to_state==="starting"&&(d.from_state==="serving"||d.from_state==="error"||d.from_state==="compiling")).length,u=this.queryCompiles({app:t,since:e,limit:1e3}).map(d=>d.ms).sort((d,v)=>d-v),y=(d,v)=>{if(d.length===0)return null;let A=Math.min(d.length-1,Math.floor((d.length-1)*v));return d[A]},b=y(u,.5),p=y(u,.95),m=new Map;for(let d of r)if(d.type==="error-new"||d.type==="error-recur"){let v=d.message??"";if(!v)continue;m.set(v,(m.get(v)??0)+1)}let g=[...m.entries()].sort((d,v)=>v[1]-d[1]).slice(0,5).map(([d,v])=>({message:d,count:v}));return{uptimePct24h:c,restartCount24h:f,compileP50:b,compileP95:p,topErrors:g}}why(t){let e=this.queryEvents({app:t,limit:200}),r=e.find(a=>a.type==="status"&&(a.to_state==="error"||a.from_state==="error"||a.to_state==="serving")),s=r?{ts:r.ts,app:r.app,type:r.type,from:r.from_state??void 0,to:r.to_state??void 0,message:r.message??void 0}:null,o=s?s.ts:Date.now(),i=e.filter(a=>a.ts<o).slice(0,5);return{trigger:s,preceding:i.map(a=>({ts:a.ts,app:a.app,type:a.type,from:a.from_state??void 0,to:a.to_state??void 0,message:a.message??void 0}))}}quickCheck(){if(!this.db)return!1;try{return this.db.prepare("PRAGMA quick_check").get()?.quick_check==="ok"}catch{return!1}}close(){if(this.flushTimer&&clearInterval(this.flushTimer),this.retentionTimer&&clearInterval(this.retentionTimer),this.retentionStart&&clearTimeout(this.retentionStart),this.flush(),this.db){try{this.db.close()}catch{}this.db=null}}};import pr from"node:fs";import Jn from"node:os";import ur from"node:path";import{createRequire as qn}from"node:module";var Xn=qn(import.meta.url),Kn=6e4,Et=class{constructor(t,e){this.registry=t;this.cfg=e;this.logFile=ur.join(Jn.homedir(),".daimon","notifications.log");try{pr.mkdirSync(ur.dirname(this.logFile),{recursive:!0})}catch{}if(!e.enabled){this.audit("init","disabled by config");return}try{let r=Xn("node-notifier");if(this.notifier=r,process.platform==="win32")try{let s=r.WindowsToaster;s&&(this.toaster=new s({withFallback:!0}))}catch(s){this.audit("init",`WindowsToaster unavailable: ${s?.message||s}`)}this.audit("init",`node-notifier loaded${this.toaster?" (+WindowsToaster fallback)":""}`)}catch(r){this.warnOnce(`node-notifier unavailable: ${r?.message||r}`),this.audit("init",`node-notifier load failed: ${r?.message||r}`);return}t.on("event",this.onEvent)}registry;cfg;notifier=null;toaster=null;lastSent=new Map;warned=!1;logFile;audit(t,e){let r=`${new Date().toISOString()} ${t} ${e}
52
+ `;try{pr.appendFileSync(this.logFile,r)}catch{}}warnOnce(t){this.warned||(this.warned=!0,process.stderr.write(`[daimon] notifier: ${t}
53
+ `))}stop(){this.registry.off("event",this.onEvent)}onEvent=t=>{this.notifier&&(t.type==="status"&&t.to==="error"&&this.cfg.onError?this.fire(t.app,"error",`${t.app} \u2192 error`,t.message||"app entered error state"):t.type==="health"&&t.to==="unhealthy"&&this.cfg.onUnhealthy?this.fire(t.app,"unhealthy",`${t.app} unhealthy`,"health probe failing"):t.type==="stale"?this.fire(t.app,"stale",`${t.app} stale`,t.message||"no output despite source changes"):t.type==="compile-regression"?this.fire(t.app,"compile-regression",`${t.app} slow compile`,t.message||"compile time regression"):t.type==="bundle-regression"?this.fire(t.app,"bundle-regression",`${t.app} bundle grew`,t.message||"bundle size regression"):t.type==="task-run"&&/exit=[1-9]/.test(t.message||"")&&this.fire(t.app,"task-fail",`${t.app} task failed`,t.message||""))};fire(t,e,r,s){if(!this.notifier)return;let o=`${t}::${e}`,i=this.lastSent.get(o)??0,a=Date.now();if(a-i<Kn){this.audit("throttled",`${o}`);return}this.lastSent.set(o,a);let l={title:`daimon: ${r}`,message:s,wait:!1,appID:"daimon"},c=(f,u)=>{f?(this.audit("fail",`${o} :: ${f?.message||f}`),this.warnOnce(`notify failed: ${f?.message||f}`)):this.audit("ok",`${o} :: ${r} :: ${u??"(no response)"}`)};try{this.audit("attempt",`${o} :: ${r}`),(this.toaster??this.notifier).notify(l,c)}catch(f){this.audit("throw",`${o} :: ${f?.message||f}`),this.warnOnce(`notify threw: ${f?.message||f}`)}}};import fr from"node:fs";import te from"node:path";var Yn=5e3,zn=3e4,Vn=new Set(["node_modules","dist",".angular",".nx",".git","tmp","out-tsc","coverage"]),Qn=new Set([".ts",".tsx",".html",".scss",".css",".js",".jsx",".json"]),Tt=class{constructor(t,e){this.registry=t;this.cfg=e;e.enabled&&(this.timer=setInterval(()=>this.tick(),Yn),t.on("compile",this.onCompile))}registry;cfg;timer=null;caches=new Map;stop(){this.timer&&clearInterval(this.timer),this.registry.off("compile",this.onCompile)}onCompile=t=>{let e=this.registry.getApp(t.name);e&&this.caches.delete(e.workspaceRoot)};tick(){for(let t of this.registry.names())this.evaluate(t)}evaluate(t){let e=this.registry.getState(t),r=this.registry.getApp(t);if(!e||!r)return;if(e.status!=="serving"){e.stale&&this.registry.setStale(t,!1);return}if(e.startedAt==null)return;let s=e.lastLogTs??e.startedAt,o=Date.now()-s;if(o<this.cfg.silentMs){e.stale&&this.registry.setStale(t,!1);return}let i=e.lastCompileAt??e.startedAt;this.hasSourceChange(r.workspaceRoot,i,e.lastCompileAt)&&(e.stale||(this.registry.setStale(t,!0),this.registry.recordEvent({app:t,type:"stale",message:`no output in ${Math.round(o/1e3)}s despite source changes`})))}hasSourceChange(t,e,r){let s=this.caches.get(t);if(!s||Date.now()-s.ts>zn||r!=null&&s.ts<r){let a=this.scan(t);this.caches.set(t,{ts:Date.now(),files:a})}return this.caches.get(t).files.some(a=>a.mtime>e)}scan(t){let e=[],r=(s,o)=>{if(o>8||e.length>4e3)return;let i;try{i=fr.readdirSync(s,{withFileTypes:!0})}catch{return}for(let a of i)if(!a.name.startsWith(".git")){if(a.isDirectory()){if(Vn.has(a.name))continue;r(te.join(s,a.name),o+1)}else if(a.isFile()){let l=te.extname(a.name);if(!Qn.has(l))continue;try{let c=te.join(s,a.name),f=fr.statSync(c);e.push({path:c,mtime:f.mtimeMs})}catch{}}}};return r(t,0),e}};import dr from"node:http";var kt=200,xt=class{constructor(t,e){this.registry=t;this.cfg=e;e.enabled&&(t.on("change",this.onChange),this.tick())}registry;cfg;proxies=new Map;stopped=!1;stop(){this.stopped=!0,this.registry.off("change",this.onChange);for(let t of this.proxies.values())try{t.server.close()}catch{}this.proxies.clear()}onChange=()=>{this.stopped||this.tick()};tick(){for(let t of this.registry.names()){let e=this.registry.getState(t);if(!e)continue;let r=this.proxies.has(t);e.status==="serving"&&e.port&&!r?this.startProxy(t,e.port):e.status!=="serving"&&r&&this.stopProxy(t)}}stopProxy(t){let e=this.proxies.get(t);if(e){try{e.server.close()}catch{}this.proxies.delete(t)}}startProxy(t,e){let r=e+this.cfg.portOffset,s=[],o=dr.createServer((i,a)=>{let l=Date.now(),c={hostname:"127.0.0.1",port:e,method:i.method,path:i.url,headers:{...i.headers,host:`127.0.0.1:${e}`}},f=dr.request(c,u=>{a.writeHead(u.statusCode||502,u.headers),u.pipe(a);let y=()=>{s.push({ts:Date.now(),method:i.method||"GET",path:i.url||"/",status:u.statusCode||0,durationMs:Date.now()-l}),s.length>kt&&s.splice(0,s.length-kt)};u.on("end",y),u.on("error",y)});f.on("error",()=>{a.writeHead(502).end("upstream error"),s.push({ts:Date.now(),method:i.method||"GET",path:i.url||"/",status:502,durationMs:Date.now()-l}),s.length>kt&&s.splice(0,s.length-kt)}),i.pipe(f)});o.on("error",i=>{i?.code==="EADDRINUSE"&&process.stderr.write(`[daimon] requestLog: port ${r} in use for ${t}; disabling proxy
54
+ `),this.proxies.delete(t)}),o.listen(r,"127.0.0.1",()=>{this.proxies.set(t,{app:t,proxyPort:r,server:o,buffer:s})})}requests(t,e){let r=this.proxies.get(t);if(!r)return[];if(e){let s=Date.now()-e;return r.buffer.filter(o=>o.ts>=s)}return[...r.buffer]}proxyPortFor(t){return this.proxies.get(t)?.proxyPort??null}};import ee from"node:fs";var Zn=new Set(["command","port","env","url"]);function mr(n){let t=ee.readFileSync(n,"utf8");t.charCodeAt(0)===65279&&(t=t.slice(1));let e=JSON.parse(t);if(!e||typeof e!="object"||Array.isArray(e))throw new Error("config must be a JSON object");return e}function hr(n,t){if(t===null)return null;if(typeof t!="object"||Array.isArray(t))return t;let e=n&&typeof n=="object"&&!Array.isArray(n)?{...n}:{};for(let[r,s]of Object.entries(t))s===null?delete e[r]:e[r]=hr(e[r],s);return e}function ts(n,t){let e=n+"."+process.pid+".tmp";ee.writeFileSync(e,t,"utf8"),ee.renameSync(e,n)}function es(n,t){let e=new Set;for(let r of Object.keys(t))JSON.stringify(n?.[r])!==JSON.stringify(t[r])&&e.add(r);for(let r of Object.keys(n||{}))r in t||e.add(r);return[...e]}function gr(n){let t=mr(n.configPath),e=hr(t,n.patch);if(!e||typeof e!="object")throw new Error("patch produced non-object config");let r=Pt(e,n.configPath);return ts(n.configPath,JSON.stringify(e,null,2)+`
55
+ `),{config:r,raw:e,applied:es(t,e),prevRaw:t}}function re(n){let t=mr(n.configPath),e=Pt(t,n.configPath);return rs(n.registry,e)}function rs(n,t){let e=n.getConfig();for(let c of Object.keys(e))e[c]=void 0;Object.assign(e,t);let r=new Set(n.names()),s=ot(e),o=new Set(s.map(c=>c.name)),i=[],a=[];for(let c of s)r.has(c.name)?n.updateDiscoveredApp(c):(n.addDiscoveredApp(c),i.push(c.name));for(let c of r)o.has(c)||a.push(c);let l=[];for(let c of n.names()){let f=n.getState(c);if(f&&(f.status==="serving"||f.status==="compiling")){let u=e.overrides?.[c];if(!u)continue;for(let y of Zn)if(y in u){l.push(c);break}}}return{addedApps:i,removedApps:a,restartRequired:l,config:e}}import yr from"node:fs";import ns from"node:os";import vr from"node:path";var ss=/key|secret|token|password|pass/i;function os(n){if(!n)return null;let t=JSON.parse(JSON.stringify(n));if(t.apiToken&&(t.apiToken="***"),t.overrides)for(let e of Object.keys(t.overrides)){let r=t.overrides[e]?.env;if(r)for(let s of Object.keys(r))ss.test(s)&&(r[s]="***")}return t}function is(n,t=200){if(!n)return[];let e=[];for(let r of n.names()){let s=n.getState(r);if(s)for(let o of s.logBuffer)e.push({ts:o.ts,line:`[${r}] ${o.line}`})}return e.sort((r,s)=>r.ts-s.ts),e.slice(-t).map(r=>r.line)}function as(){let n=vr.join(q(),"crashes");return yr.mkdirSync(n,{recursive:!0}),n}function cs(n,t,e){let r=new Date().toISOString().replace(/[:.]/g,"-"),s=vr.join(as(),`${r}.txt`),o=n,i=[`daimon crash dump @ ${new Date().toISOString()}`,`version: ${lt}`,`node: ${process.version}`,`platform: ${process.platform} ${ns.release()}`,`cwd: ${process.cwd()}`,`pid: ${process.pid}`,"","ERROR:",o?.stack||String(o),"","CONFIG (redacted):",JSON.stringify(os(e),null,2),"","RECENT LOG (last 200 lines across apps):",...is(t,200)];try{yr.writeFileSync(s,i.join(`
56
+ `))}catch{}return s}function wr(n){let t=e=>{let r=null;try{r=cs(e,n.getRegistry(),n.getConfig())}catch{}try{process.stderr.write(`[daimon] fatal: ${e?.stack||e}
57
+ `)}catch{}if(r)try{process.stderr.write(`[daimon] crash dump: ${r}
58
+ `)}catch{}process.exit(1)};process.on("uncaughtException",t),process.on("unhandledRejection",t)}import E,{useEffect as ms,useState as H}from"react";import se from"node:fs";import hs from"node:os";import gs from"node:path";import{Box as I,Text as k,useApp as ys,useInput as vs,useStdout as ws}from"ink";import oe from"ink-text-input";import{spawn as ie,spawnSync as bs}from"node:child_process";import j,{useEffect as ls,useMemo as ps,useState as Q}from"react";import{Box as st,Text as D,useInput as us,useStdout as fs}from"ink";import ds from"ink-text-input";function ne({registry:n,appName:t,onExit:e}){let{stdout:r}=fs(),[s,o]=Q(0),[i,a]=Q(!1),[l,c]=Q(""),[f,u]=Q(""),[y,b]=Q(0),[p,m]=Q(0);ls(()=>{let h=()=>o(N=>N+1);n.on("change",h);let C=setInterval(()=>o(N=>N+1),500);return()=>{n.off("change",h),clearInterval(C)}},[n]);let d=n.getState(t)?.logBuffer.map(h=>h.line)??[],v=(r.rows||30)-4,A=ps(()=>{if(!f)return[];let h=f.toLowerCase();return d.reduce((C,N,_)=>(N.toLowerCase().includes(h)&&C.push(_),C),[])},[d,f,s]);us((h,C)=>{if(i){if(C.escape){a(!1),c("");return}return}if(h==="q"||C.escape){e();return}if(h==="/"){a(!0);return}if(h==="g"){b(Math.max(0,d.length-v));return}if(h==="G"){b(0);return}if(C.pageUp){b(N=>Math.min(Math.max(0,d.length-v),N+v));return}if(C.pageDown){b(N=>Math.max(0,N-v));return}if(C.upArrow){b(N=>Math.min(Math.max(0,d.length-v),N+1));return}if(C.downArrow){b(N=>Math.max(0,N-1));return}if((h==="n"||h==="N")&&A.length){let N=h==="n"?(p+1)%A.length:(p-1+A.length)%A.length;m(N);let _=A[N],Y=d.length-y,T=Y-v;(_<T||_>=Y)&&b(Math.max(0,d.length-_-Math.floor(v/2)));return}});let $=h=>{u(h),a(!1),c(""),m(0)},S=d.length-y,L=Math.max(0,S-v),U=d.slice(L,S),x=(h,C)=>{if(!f)return j.createElement(D,{key:C},j.createElement(D,{dimColor:!0},String(C+1).padStart(5)," "),h);let N=f,_=h.toLowerCase(),Y=N.toLowerCase(),T=[],P=0,R=0;for(;P<h.length;){let M=_.indexOf(Y,P);if(M<0){T.push(j.createElement(D,{key:R++},h.slice(P)));break}M>P&&T.push(j.createElement(D,{key:R++},h.slice(P,M))),T.push(j.createElement(D,{key:R++,backgroundColor:"yellow",color:"black"},h.slice(M,M+N.length))),P=M+N.length}let O=A[p]===C;return j.createElement(D,{key:C},j.createElement(D,{color:O?"cyan":void 0,dimColor:!O},String(C+1).padStart(5)," "),T)};return j.createElement(st,{flexDirection:"column"},j.createElement(st,null,j.createElement(D,{bold:!0},"full log: ",j.createElement(D,{color:"cyan"},t)),j.createElement(D,{dimColor:!0}," (",d.length," lines",f?`, ${A.length} matches for "${f}"`:"",", scroll=",y,")")),j.createElement(st,{flexDirection:"column"},U.length===0?j.createElement(D,{dimColor:!0},"(no log yet)"):U.map((h,C)=>x(h,L+C))),j.createElement(st,null,i?j.createElement(st,null,j.createElement(D,null,"/"),j.createElement(ds,{value:l,onChange:c,onSubmit:$})):j.createElement(D,{dimColor:!0},"[/] search [n/N] next/prev [g/G] bottom/top [PgUp/PgDn] [\u2191\u2193] [q/Esc] back")))}function Ss(n){try{process.platform==="win32"?ie("cmd",["/c","start","",n],{detached:!0,stdio:"ignore",windowsHide:!0}).unref():process.platform==="darwin"?ie("open",[n],{detached:!0,stdio:"ignore"}).unref():ie("xdg-open",[n],{detached:!0,stdio:"ignore"}).unref()}catch{}}var br={stopped:"gray",starting:"yellow",compiling:"yellow",serving:"green",error:"red"},Sr={healthy:"green",unhealthy:"red",unknown:"gray"};function Es(n){if(n==null)return"";let t=Math.floor(n/1e3);if(t<60)return`${t}s`;let e=Math.floor(t/60);return e<60?`${e}m ${t%60}s`:`${Math.floor(e/60)}h ${e%60}m`}function ae({registry:n,apiPort:t,onQuit:e}){let{exit:r}=ys(),{stdout:s}=ws(),[o,i]=H(n.list()),[a,l]=H(0),[c,f]=H(!1),[u,y]=H(0),[b,p]=H(!1),[m,g]=H([]),[d,v]=H(!1),[A,$]=H(""),[S,L]=H(null),[,U]=H(0);ms(()=>{let T=()=>i(n.list());n.on("change",T);let P=setInterval(()=>{i(n.list()),U(R=>R+1)},1e3);return()=>{n.off("change",T),clearInterval(P)}},[n]),vs((T,P)=>{if(b)return;if(S){if(P.escape){L(null);return}if(P.tab){let O=S.field==="command"?"port":S.field==="port"?"env":"command";L({...S,field:O});return}return}if(d){if(P.escape){v(!1),$("");return}if(P.return){let O=A.trim();g(O?O.split(/[\s,]+/).filter(Boolean):[]),v(!1),$("");return}if(P.backspace||P.delete){$(O=>O.slice(0,-1));return}T&&!P.ctrl&&$(O=>O+T);return}if(T==="q"||P.ctrl&&T==="c"){e(),r();return}if(o.length===0)return;if(P.upArrow){l(O=>Math.max(0,O-1)),y(0);return}if(P.downArrow){l(O=>Math.min(o.length-1,O+1)),y(0);return}let R=o[a];if(R)if(T==="s")n.start(R.name);else if(T==="x")n.stop(R.name);else if(T==="r")n.restart(R.name);else if(T==="L")p(!0);else if(T==="t")v(!0),$(m.join(" "));else if(T==="e"){let O=n.getConfig(),M=n.getApp(R.name),W=n.getState(R.name)?.sessionOverrides??null,Z=W?.env??O.overrides?.[R.name]?.env??{},X=Object.entries(Z).map(([At,Ct])=>`${At}=${Ct}`).join(`
59
+ `);L({name:R.name,field:"command",cmd:W?.command??M?.command??"",port:String(W?.port??O.overrides?.[R.name]?.port??R.port??""),env:X})}else if(T==="E"){let M=n.getConfig().envFiles?.[R.name]??[];if(!M.length)return;let W=n.getState(R.name)?.activeEnvFile??null,Z=W?M.indexOf(W):-1,X=M[(Z+1)%M.length];n.setActiveEnvFile(R.name,X)}else if(T==="V"){let O=process.env.EDITOR||(process.platform==="win32"?"notepad":"vi"),M=gs.join(hs.tmpdir(),`daimon-${R.name}-${Date.now()}.json`),W=n.getConfig(),Z=n.getApp(R.name),X=n.getState(R.name)?.sessionOverrides??null,At={command:X?.command??Z?.command,port:X?.port??W.overrides?.[R.name]?.port??null,env:X?.env??W.overrides?.[R.name]?.env??{}};try{se.writeFileSync(M,JSON.stringify(At,null,2)),bs(O,[M],{stdio:"inherit",shell:!0});let Ct=se.readFileSync(M,"utf8"),K=JSON.parse(Ct);n.setSessionOverride(R.name,{command:typeof K.command=="string"?K.command:void 0,port:typeof K.port=="number"?K.port:void 0,env:K.env&&typeof K.env=="object"?K.env:void 0}),se.unlinkSync(M)}catch{}}else T==="l"?f(O=>!O):T==="o"?R.url&&Ss(R.url):P.pageUp?y(O=>O+5):P.pageDown&&y(O=>Math.max(0,O-5))});let x=m.length===0?o:o.filter(T=>m.every(P=>T.tags.includes(P))),h=x[Math.min(a,Math.max(0,x.length-1))],C=h?n.getState(h.name):null,N=C?C.logBuffer.slice(Math.max(0,C.logBuffer.length-12-u),C.logBuffer.length-u).map(T=>T.line):[],_=s.columns||100,Y=Math.min(36,Math.floor(_*.4));return b&&h?E.createElement(ne,{registry:n,appName:h.name,onExit:()=>p(!1)}):E.createElement(I,{flexDirection:"column",width:_},E.createElement(I,{borderStyle:"round",borderColor:"cyan",paddingX:1},E.createElement(k,{bold:!0,color:"cyan"},"daimon"),E.createElement(k,{dimColor:!0}," \u2022 api http://127.0.0.1:",t)),E.createElement(I,{flexDirection:"row"},E.createElement(I,{flexDirection:"column",width:Y,borderStyle:"single",borderColor:"gray",paddingX:1},E.createElement(k,{bold:!0},"Apps ",m.length?E.createElement(k,{dimColor:!0},"(tags: ",m.join(", "),")"):null),x.length===0?E.createElement(k,{dimColor:!0},o.length===0?"(no apps discovered)":"(no apps match tag filter)"):x.map((T,P)=>{let R=P===a;return E.createElement(I,{key:T.name},E.createElement(k,{color:R?"cyan":void 0},R?"\u25B8 ":" "),E.createElement(k,{color:R?"cyan":void 0},((n.getState(T.name)?.sessionOverrides?"*":"")+T.name).padEnd(20).slice(0,20)),E.createElement(k,{color:br[T.status]}," ",T.status.padEnd(9)),E.createElement(k,{color:Sr[T.health]},T.status==="serving"?"\u25CF":" "),E.createElement(k,{dimColor:!0},T.port?` :${T.port}`:""),_>=100&&T.cpu!=null?E.createElement(k,{dimColor:!0}," ",String(T.cpu).padStart(5),"% ",String(T.memMB??0).padStart(5),"MB"):null)})),E.createElement(I,{flexDirection:"column",flexGrow:1,borderStyle:"single",borderColor:"gray",paddingX:1},h&&C?E.createElement(E.Fragment,null,E.createElement(k,null,"Selected: ",E.createElement(k,{bold:!0},h.name)),E.createElement(k,null,"Status: ",E.createElement(k,{color:br[h.status]},h.status)," ",E.createElement(k,{color:Sr[h.health]},"\u25CF")," ",E.createElement(k,{dimColor:!0},h.health)),E.createElement(k,null,"Port: ",h.port??"-"),E.createElement(k,null,"URL: ",h.url??"-"),h.announcedUrl&&h.announcedUrl!==h.url?E.createElement(k,{dimColor:!0},"Announced: ",h.announcedUrl):null,h.lastHealthError?E.createElement(k,{color:"red"},"HealthErr: ",h.lastHealthError):null,h.stale?E.createElement(k,{color:"yellow"},"\u26A0 stale (best guess)"):null,E.createElement(k,null,"Errors: ",E.createElement(k,{color:h.errorCount?"red":void 0},h.errorCount)),E.createElement(k,null,"Uptime: ",Es(h.uptimeMs)),h.cpu!=null||h.memMB!=null?E.createElement(k,null,"Usage: ",h.cpu??"-","% ",h.memMB??"-"," MB"):null,h.compileHistoryMs.length>0?E.createElement(k,null,"Recent compile: ",h.compileHistoryMs.slice(-5).map(T=>(T/1e3).toFixed(1)+"s").join(" \xB7 ")):null,h.bundle?E.createElement(k,null,"Bundle: ",h.bundle.initialKB,"KB initial \xB7 ",h.bundle.lazyKB,"KB lazy",h.bundleRegressionPct!=null&&h.bundleRegressionPct>10?E.createElement(k,{color:"red"}," (+",h.bundleRegressionPct,"% \u26A0)"):null):null,C.lastStatusMessage?E.createElement(k,{dimColor:!0},"Note: ",C.lastStatusMessage):null,E.createElement(k,null,"\u2500\u2500\u2500\u2500 recent log ",c?"(focused)":""," \u2500\u2500\u2500\u2500"),N.length===0?E.createElement(k,{dimColor:!0},"(no output yet)"):N.map((T,P)=>E.createElement(k,{key:P,wrap:"truncate-end"},T))):E.createElement(k,{dimColor:!0},"No app selected."))),E.createElement(I,{flexDirection:"column"},d?E.createElement(k,null,"tag filter (space-separated, Enter to apply, Esc to cancel): ",E.createElement(k,{color:"cyan"},A)):null,S?E.createElement(I,{flexDirection:"column",borderStyle:"round",borderColor:"yellow",paddingX:1},E.createElement(k,{bold:!0,color:"yellow"},"edit ",S.name," (session-only) Tab=next field Enter=save Esc=cancel"),E.createElement(I,null,E.createElement(k,null,S.field==="command"?"> ":" ","command: "),S.field==="command"?E.createElement(oe,{value:S.cmd,onChange:T=>L({...S,cmd:T}),onSubmit:()=>L({...S,field:"port"})}):E.createElement(k,{dimColor:!0},S.cmd)),E.createElement(I,null,E.createElement(k,null,S.field==="port"?"> ":" ","port: "),S.field==="port"?E.createElement(oe,{value:S.port,onChange:T=>L({...S,port:T}),onSubmit:()=>L({...S,field:"env"})}):E.createElement(k,{dimColor:!0},S.port)),E.createElement(I,null,E.createElement(k,null,S.field==="env"?"> ":" ","env (k=v;): "),S.field==="env"?E.createElement(oe,{value:S.env.replace(/\n/g,";"),onChange:T=>L({...S,env:T.replace(/;/g,`
60
+ `)}),onSubmit:()=>{let T=Number(S.port),P={};for(let R of S.env.split(/\n/)){let O=R.match(/^\s*([^=]+)=(.*)$/);O&&(P[O[1].trim()]=O[2])}n.setSessionOverride(S.name,{command:S.cmd||void 0,port:Number.isFinite(T)&&T>0?T:void 0,env:Object.keys(P).length?P:void 0}),L(null)}}):E.createElement(k,{dimColor:!0},S.env))):null,E.createElement(k,{dimColor:!0},"[s] start [x] stop [r] restart [o] open URL [t] tag filter [e] edit [E] cycle env [V] $EDITOR [l] log focus [Shift+L] full log [PgUp/PgDn] scroll [q] quit")))}async function As(n={}){let t=null,e=null;wr({getRegistry:()=>t,getConfig:()=>e});let r;try{r=ue()}catch(x){process.stderr.write(`[daimon] config error: ${x.message}
61
+ `),process.exit(1)}if(r.kind==="stub-created"){let x=Ot();process.stdout.write(`[daimon] no config found. Created stub at:
62
+ ${r.path}
63
+ `),process.stdout.write(`[daimon] Edit it to add "searchRoots" pointing at your Nx/Angular workspace, then run again.
64
+ `),process.stdout.write(`[daimon] (Local override path: ${x.local})
65
+ `),process.exit(0)}let{config:s,path:o}=r;if(process.stdout.write(`[daimon] config: ${o}
66
+ `),s.depends&&Object.keys(s.depends).length){let x=ve(s.depends);x&&(process.stderr.write(`[daimon] config error: depends graph has a cycle: ${x.join(" -> ")}
67
+ `),process.exit(1))}let i=ot(s);i.length===0&&process.stdout.write(`[daimon] no serveable projects discovered in: ${s.searchRoots.join(", ")||"(none)"}
68
+ `);let a=cr(),l=new z(s.portRange,{initial:a.ports,onChange:x=>lr({ports:x})}),c=new ft(s,i,l);t=c,e=s;let f=new St(s.history);c.setHistory(f);let u=new vt(c,s.healthProbe,s),y=new wt(c),b=new bt(c,s.autoRestart),p=new Et(c,s.notifications),m=new Tt(c,s.staleDetect),g=new xt(c,s.requestLog);c.on("childExit",({name:x,code:h,signal:C,stopping:N})=>b.onExit(x,h,C,N)),c.on("userStop",({name:x})=>b.onUserStop(x));let d=nr();if(d&&d.apps.length){process.stdout.write(`[daimon] state-handoff: restoring ${d.apps.map(x=>x.name).join(", ")}
69
+ `);for(let x of d.apps)l.pin(x.name,x.port);for(let x of d.apps)c.names().includes(x.name)&&c.start(x.name)}if(s.autoStart&&s.autoStart.length){let x=new Set(c.names());for(let h of s.autoStart){if(!x.has(h)){process.stderr.write(`[daimon] warning: autoStart references unknown app "${h}"
70
+ `);continue}s.depends&&s.depends[h]&&s.depends[h].length?c.startWithDeps(h):c.start(h)}}let v=process.env.DAIMON_PORT?Number(process.env.DAIMON_PORT):s.apiPort,A=!!n.headless||!!s.headless||process.argv.includes("--headless"),$=!1,S=async()=>{if(!$){$=!0;try{u.stop()}catch{}try{y.stop()}catch{}try{b.stop()}catch{}try{p.stop()}catch{}try{m.stop()}catch{}try{g.stop()}catch{}try{f.close()}catch{}try{await c.stopAll(3e3)}catch{}try{L.close()}catch{}try{_e()}catch{}process.exit(0)}},L=or(c,v,{metricsEnabled:s.metrics.enabled,requestLog:g,onShutdown:()=>{S()},configPath:o,getConfig:()=>c.getConfig(),patchConfig:x=>{try{let h=gr({configPath:o,patch:x}),C=re({configPath:o,registry:c});return{ok:!0,applied:h.applied,addedApps:C.addedApps,removedApps:C.removedApps,restartRequired:C.restartRequired}}catch(h){return{ok:!1,error:h?.message||String(h)}}},reloadConfig:async()=>{let x=re({configPath:o,registry:c});return{ok:!0,addedApps:x.addedApps,removedApps:x.removedApps,restartRequired:x.restartRequired}}});process.stdout.write(`[daimon] api: http://127.0.0.1:${v}
71
+ `);try{Me(De(v,A))}catch(x){process.stderr.write(`[daimon] warning: could not write daemon.lock: ${x?.message||x}
72
+ `)}if(process.on("SIGINT",()=>{S()}),process.on("SIGTERM",()=>{S()}),process.on("beforeExit",()=>{S()}),A){process.stdout.write(`[daimon] headless mode \u2014 TUI suppressed. Dashboard: http://127.0.0.1:${v}
73
+ `);let x="",h=setInterval(()=>{let C=c.list().map(_=>({name:_.name,status:_.status,health:_.health,port:_.port})),N=JSON.stringify(C);N!==x&&(process.stderr.write(N+`
74
+ `),x=N)},6e4);await new Promise(()=>{}),clearInterval(h);return}await ks(Ts.createElement(ae,{registry:c,apiPort:v,onQuit:()=>{S()}})).waitUntilExit(),await S()}var Cs=(()=>{try{return import.meta.url===xs(process.argv[1]||"").href}catch{return!1}})();Cs&&As().catch(n=>{process.stderr.write(`[daimon] fatal: ${n?.stack||n}
75
+ `),process.exit(1)});export{As as startInProcess};
package/dist/mcp.js ADDED
@@ -0,0 +1,3 @@
1
+ import{McpServer as V}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as W}from"@modelcontextprotocol/sdk/server/stdio.js";import{z as a}from"zod";import f from"node:fs";import c from"node:path";import m from"node:os";import{fileURLToPath as I}from"node:url";var $=I(import.meta.url),A=c.dirname($);function j(){return{searchRoots:[],portRange:[4200,4299],apiPort:4999,overrides:{},autoStart:[],profiles:{},tags:{},autoRestart:{enabled:!1,maxAttempts:5,windowMs:3e5},healthProbe:{enabled:!0,intervalMs:3e4,timeoutMs:2e3,path:"/",host:null,scheme:null,rejectUnauthorized:!1,fallbackHosts:["127.0.0.1","::1"]},logs:{enabled:!1,dir:c.join(m.homedir(),".daimon","logs"),maxFiles:5,maxBytesPerFile:1e7},depends:{},cascadeRestart:!1,history:{enabled:!0,path:c.join(m.homedir(),".daimon","history.db"),retentionDays:30},notifications:{enabled:!0,onError:!0,onUnhealthy:!0,tray:!1},staleDetect:{enabled:!0,silentMs:3e4},headless:!1,envFiles:{},requestLog:{enabled:!1,portOffset:1e3},metrics:{enabled:!1},editor:{scheme:"vscode"},apiToken:null}}function P(r){return r.startsWith("~/")||r.startsWith("~\\")?c.join(m.homedir(),r.slice(2)):r==="~"?m.homedir():r}function x(r,n){if(!r||typeof r!="object")throw new Error(`Config at ${n} is not a JSON object`);let t=r,e=j();if(t.searchRoots!==void 0){if(!Array.isArray(t.searchRoots)||!t.searchRoots.every(o=>typeof o=="string"||o&&typeof o=="object"&&typeof o.path=="string"))throw new Error(`Config "searchRoots" must be an array of strings or { path, viteSubfolders? } objects (${n})`);e.searchRoots=t.searchRoots}if(t.portRange!==void 0){if(!Array.isArray(t.portRange)||t.portRange.length!==2||typeof t.portRange[0]!="number"||typeof t.portRange[1]!="number"||t.portRange[0]>t.portRange[1])throw new Error(`Config "portRange" must be [min, max] numbers (${n})`);e.portRange=[t.portRange[0],t.portRange[1]]}if(t.apiPort!==void 0){if(typeof t.apiPort!="number")throw new Error(`Config "apiPort" must be a number (${n})`);e.apiPort=t.apiPort}if(t.overrides!==void 0){if(typeof t.overrides!="object"||t.overrides===null||Array.isArray(t.overrides))throw new Error(`Config "overrides" must be an object (${n})`);e.overrides=t.overrides}if(t.autoStart!==void 0){if(!Array.isArray(t.autoStart)||!t.autoStart.every(o=>typeof o=="string"))throw new Error(`Config "autoStart" must be an array of strings (${n})`);e.autoStart=t.autoStart}if(t.profiles!==void 0){if(typeof t.profiles!="object"||t.profiles===null||Array.isArray(t.profiles))throw new Error(`Config "profiles" must be an object (${n})`);for(let[o,i]of Object.entries(t.profiles))if(!Array.isArray(i)||!i.every(s=>typeof s=="string"))throw new Error(`Config "profiles.${o}" must be an array of strings (${n})`);e.profiles=t.profiles}if(t.tags!==void 0){if(typeof t.tags!="object"||t.tags===null||Array.isArray(t.tags))throw new Error(`Config "tags" must be an object (${n})`);e.tags=t.tags}if(t.autoRestart&&typeof t.autoRestart=="object"&&(e.autoRestart={...e.autoRestart,...t.autoRestart}),t.healthProbe&&typeof t.healthProbe=="object"&&(e.healthProbe={...e.healthProbe,...t.healthProbe}),t.logs&&typeof t.logs=="object"&&(e.logs={...e.logs,...t.logs},e.logs.dir=P(e.logs.dir)),t.depends&&typeof t.depends=="object"&&!Array.isArray(t.depends)){for(let[o,i]of Object.entries(t.depends))if(!Array.isArray(i)||!i.every(s=>typeof s=="string"))throw new Error(`Config "depends.${o}" must be an array of strings (${n})`);e.depends=t.depends}if(typeof t.cascadeRestart=="boolean"&&(e.cascadeRestart=t.cascadeRestart),t.history&&typeof t.history=="object"&&(e.history={...e.history,...t.history},e.history.path=P(e.history.path)),t.notifications&&typeof t.notifications=="object"&&(e.notifications={...e.notifications,...t.notifications}),t.staleDetect&&typeof t.staleDetect=="object"&&(e.staleDetect={...e.staleDetect,...t.staleDetect}),typeof t.headless=="boolean"&&(e.headless=t.headless),t.envFiles&&typeof t.envFiles=="object"&&!Array.isArray(t.envFiles)&&(e.envFiles=t.envFiles),t.requestLog&&typeof t.requestLog=="object"&&(e.requestLog={...e.requestLog,...t.requestLog}),t.metrics&&typeof t.metrics=="object"&&(e.metrics={...e.metrics,...t.metrics}),t.editor&&typeof t.editor=="object"){let o=t.editor.scheme;typeof o=="string"&&o.trim()&&(e.editor={scheme:o.trim()})}return(typeof t.apiToken=="string"||t.apiToken===null)&&(e.apiToken=t.apiToken),e}function E(){return{local:c.join(process.cwd(),"daimon.config.json"),user:c.join(m.homedir(),".daimon","config.json")}}function C(){let{local:r,user:n}=E();if(f.existsSync(r)){let o=JSON.parse(f.readFileSync(r,"utf8"));return{kind:"loaded",config:x(o,r),path:r}}if(f.existsSync(n)){let o=JSON.parse(f.readFileSync(n,"utf8"));return{kind:"loaded",config:x(o,n),path:n}}let e=[c.resolve(A,"..","daimon.config.example.json"),c.resolve(A,"..","..","daimon.config.example.json")].find(o=>f.existsSync(o));return f.mkdirSync(c.dirname(n),{recursive:!0}),e?f.copyFileSync(e,n):f.writeFileSync(n,JSON.stringify(j(),null,2)+`
2
+ `,"utf8"),{kind:"stub-created",path:n}}import L from"node:fs";import h from"node:path";import U from"node:os";import{spawn as q}from"node:child_process";import{fileURLToPath as J}from"node:url";import _ from"node:fs";import R from"node:path";import{fileURLToPath as F}from"node:url";var O=R.dirname(F(import.meta.url));function M(){let r=[R.resolve(O,"..","package.json"),R.resolve(O,"..","..","package.json")];for(let n of r)try{return JSON.parse(_.readFileSync(n,"utf8"))}catch{}return{}}var S=M().version||"0.0.0";var G=h.join(U.homedir(),".daimon"),N=h.join(G,"daemon.lock");function B(r){try{return process.kill(r,0),!0}catch(n){return n&&n.code==="EPERM"}}function b(){try{let r=L.readFileSync(N,"utf8"),n=JSON.parse(r);if(!n||typeof n.pid!="number")return null;if(!B(n.pid)){try{L.unlinkSync(N)}catch{}return null}return n}catch{return null}}function H(){let r=h.dirname(J(import.meta.url));return h.join(r,"main.js")}async function D(r={}){let n={...process.env};r.port&&(n.DAIMON_PORT=String(r.port)),q(process.execPath,[H(),"--headless"],{detached:!0,stdio:"ignore",env:n,windowsHide:!0}).unref();let e=Date.now();for(;Date.now()-e<5e3;){let o=b();if(o&&(!r.port||o.apiPort===r.port))return o;await new Promise(i=>setTimeout(i,100))}throw new Error("daemon failed to start within 5s")}function z(){if(process.env.DAIMON_PORT){let n=Number(process.env.DAIMON_PORT);if(Number.isFinite(n)&&n>0)return n}let r=b();if(r)return r.apiPort;try{let n=C();if(n.kind==="loaded")return n.config.apiPort}catch{}return 4999}var K=()=>`http://127.0.0.1:${z()}`,T=!1;async function Q(){if(!T&&(T=!0,process.env.DAIMON_NO_SPAWN!=="1"&&!b()))try{let r=process.env.DAIMON_PORT?Number(process.env.DAIMON_PORT):void 0;await D({port:Number.isFinite(r)&&r>0?r:void 0})}catch{}}async function l(r,n="GET"){await Q();try{let t=await fetch(K()+r,{method:n}),e=await t.text();try{return{status:t.status,body:JSON.parse(e)}}catch{return{status:t.status,body:e}}}catch{return{status:0,body:{error:"daimon is not running \u2014 start it with: daimon daemon start --detach"}}}}function d(r){return{content:[{type:"text",text:JSON.stringify(r)}]}}function p(r){return{content:[{type:"text",text:JSON.stringify({error:r})}],isError:!0}}async function X(){let r=new V({name:"daimon",version:S});r.registerTool("list_apps",{description:"List all known apps with current status, port, health, etc.",inputSchema:{}},async()=>{let t=await l("/api/apps");return t.status===0?p(t.body?.error||"unknown"):d(t.body)}),r.registerTool("get_status",{description:"Get the current status of one app.",inputSchema:{name:a.string()}},async({name:t})=>{let e=await l(`/api/apps/${encodeURIComponent(t)}`);return e.status===0?p(e.body?.error||"unknown"):e.status===404?p("unknown app"):d(e.body)}),r.registerTool("get_errors",{description:"Get errors for an app. Supports --since duration, --since-last cursor, optional structured form.",inputSchema:{name:a.string(),since:a.string().optional(),sinceLast:a.boolean().optional(),client:a.string().optional(),structured:a.boolean().optional()}},async({name:t,since:e,sinceLast:o,client:i,structured:s})=>{let u=`/api/apps/${encodeURIComponent(t)}/errors`,w=new URLSearchParams;o?(u+="/since-last",i&&w.set("client",i)):e&&w.set("since",e);let v=w.toString(),g=await l(u+(v?"?"+v:""));if(g.status===0)return p(g.body?.error||"unknown");if(g.status===404)return p("unknown app");let y=g.body;return s&&Array.isArray(y)&&(y=y.map(k=>k.parsed??{message:k.message})),d(y)}),r.registerTool("get_logs",{description:"Get recent log lines for an app.",inputSchema:{name:a.string(),tail:a.number().int().positive().optional(),since:a.string().optional()}},async({name:t,tail:e,since:o})=>{let i=new URLSearchParams;e&&i.set("tail",String(e)),o&&i.set("since",o);let s=i.toString(),u=await l(`/api/apps/${encodeURIComponent(t)}/logs${s?"?"+s:""}`);return u.status===0?p(u.body?.error||"unknown"):u.status===404?p("unknown app"):d(u.body)});for(let t of["start","stop","restart"])r.registerTool(`${t}_app`,{description:`${t} an app.`,inputSchema:{name:a.string()}},async({name:e})=>{let o=await l(`/api/apps/${encodeURIComponent(e)}/${t}`,"POST");return o.status===0?p(o.body?.error||"unknown"):d(o.body)});r.registerTool("wait_for_app",{description:"Block until app reaches the given state or timeout (max 600s).",inputSchema:{name:a.string(),until:a.enum(["serving","healthy","stopped","error"]).optional(),timeout:a.number().int().positive().max(600).optional()}},async({name:t,until:e,timeout:o})=>{let i=new URLSearchParams;i.set("until",e||"serving"),i.set("timeout",String(Math.min(o??120,600)));let s=await l(`/api/apps/${encodeURIComponent(t)}/wait?${i.toString()}`);return s.status===0?p(s.body?.error||"unknown"):s.status===404?p("unknown app"):d(s.body)});let n=new W;await r.connect(n)}X().catch(r=>{process.stderr.write(`[daimon-mcp] fatal: ${r?.stack||r}
3
+ `),process.exit(1)});
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "daimon",
3
+ "version": "0.4.2",
4
+ "description": "Local dev-server manager for Angular/Nx/Vite/Storybook — TUI, loopback HTTP API, JSON CLI, and MCP server for Claude Code",
5
+ "license": "SEE LICENSE IN LICENSE",
6
+ "author": "Yosi Azulay (https://flycotech.com)",
7
+ "homepage": "https://github.com/Yosi-Azulay/daimon#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/Yosi-Azulay/daimon.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/Yosi-Azulay/daimon/issues"
14
+ },
15
+ "keywords": [
16
+ "dev-server",
17
+ "angular",
18
+ "nx",
19
+ "vite",
20
+ "storybook",
21
+ "process-manager",
22
+ "tui",
23
+ "mcp",
24
+ "claude-code",
25
+ "ai-tools",
26
+ "cli"
27
+ ],
28
+ "type": "module",
29
+ "bin": {
30
+ "daimon": "dist/cli.js"
31
+ },
32
+ "files": [
33
+ "dist",
34
+ "src/dashboard.html",
35
+ "src/templates",
36
+ "README.md",
37
+ "LICENSE"
38
+ ],
39
+ "scripts": {
40
+ "build": "tsc",
41
+ "start": "npm run build && node dist/main.js",
42
+ "cli": "node dist/cli.js",
43
+ "mcp": "node dist/mcp.js",
44
+ "test": "node --test test/depends.test.mjs test/bundle.test.mjs test/notifier.test.mjs test/regression.test.mjs",
45
+ "clean:dist": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
46
+ "build:bundle": "npm run clean:dist && esbuild src/cli.ts src/main.ts src/mcp.ts --bundle --platform=node --target=node20 --format=esm --minify --legal-comments=none --outdir=dist --packages=external",
47
+ "prepublishOnly": "npm run build && npm test && npm run build:bundle"
48
+ },
49
+ "engines": {
50
+ "node": ">=20"
51
+ },
52
+ "dependencies": {
53
+ "@modelcontextprotocol/sdk": "^1.29.0",
54
+ "better-sqlite3": "^12.10.0",
55
+ "fast-glob": "^3.3.2",
56
+ "ink": "^5.0.1",
57
+ "ink-select-input": "^6.0.0",
58
+ "ink-text-input": "^6.0.0",
59
+ "node-notifier": "^10.0.1",
60
+ "pidusage": "^4.0.1",
61
+ "react": "^18.3.1",
62
+ "strip-ansi": "^7.1.0",
63
+ "tree-kill": "^1.2.2",
64
+ "zod": "^4.4.3"
65
+ },
66
+ "devDependencies": {
67
+ "@types/better-sqlite3": "^7.6.13",
68
+ "@types/node": "^20.14.0",
69
+ "@types/react": "^18.3.3",
70
+ "esbuild": "^0.28.0",
71
+ "typescript": "^5.5.4"
72
+ }
73
+ }