agent-dag 1.35.23 → 1.35.25

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.
@@ -69,7 +69,7 @@ Claude Code turns only. The sound is a Stop hook Claude Code runs itself when a
69
69
 
70
70
  ${n.clash} sound hook${n.clash>1?"s":""} of your own in settings.json also run${n.clash>1?"":"s"} here.`:"",l=n.parked>0?`
71
71
 
72
- ${n.parked} of your own sound hook${n.parked>1?"s were":" was"} set aside so this switch actually controls the sound. Nothing was deleted — shift-click to put ${n.parked>1?"them":"it"} back.`:"";return r+i+o+l}function $T(e){const n=Math.max(0,Math.floor(e));return`${n} event${n===1?"":"s"}`}function N5(e){return e.connected?e.paused?{tone:"paused",label:"paused",title:e.held>0?`Connected — ${$T(e.held)} held until you resume (Space)`:"Connected — updates held until you resume (Space)"}:{tone:"live",label:"live",title:"Receiving events"}:{tone:"dead",label:"offline",title:e.paused?"SSE disconnected — and the canvas is paused, so resuming will not bring events back until it reconnects":"SSE disconnected"}}function C5(e){return e.paused?e.held<=0?{label:"Resume",title:"Nothing has arrived since you paused. Resume to follow the canvas again (Space)"}:{label:`Resume · ${e.held} held`,title:`${$T(e.held)} arrived while paused and will be applied in order when you resume (Space)`}:{label:"Pause",title:"Pause live updates — events keep arriving and are applied when you resume (Space)"}}function qT(e,n){return e!==""&&n>0}function T5(e,n,r){return e===""?{active:!1,matched:n,total:r,count:null,empty:!1,message:null,dim:!1}:{active:!0,matched:n,total:r,count:`${n} of ${r}`,empty:n===0,message:n===0?`No agents match “${e}”`:null,dim:qT(e,n)}}const R5="Search agents, tools, model…";function DT(e,n){var i,o,l,u;if(!n)return!0;const r=n.toLowerCase();if(e.label.toLowerCase().includes(r)||(i=e.cwd)!=null&&i.toLowerCase().includes(r)||(o=e.cwdBasename)!=null&&o.toLowerCase().includes(r)||e.sessionId.toLowerCase().includes(r)||(l=e.firstPrompt)!=null&&l.toLowerCase().includes(r)||e.model&&(e.model.toLowerCase().includes(r)||js(e.model).toLowerCase().includes(r))||(u=e.provider)!=null&&u.toLowerCase().startsWith(r))return!0;for(const c of e.tools)if(c.name.toLowerCase().includes(r))return!0;return!1}function Lv(e){const n=Math.max(0,Math.floor(e/1e3));return n<60?"just now":n<3600?`${Math.floor(n/60)}m ago`:n<86400?`${Math.floor(n/3600)}h ago`:`${Math.floor(n/86400)}d ago`}function j5(e,n){return e.getFullYear()===n.getFullYear()&&e.getMonth()===n.getMonth()&&e.getDate()===n.getDate()}function A5(e,n,r){const i=new Date(e),o=Lv(n-e);return{label:j5(i,new Date(n))?o:`${o} · ${i.toLocaleDateString(r,{month:"short",day:"numeric"})}`,title:i.toLocaleString(r,{dateStyle:"medium",timeStyle:"medium"})}}function ua(e){return typeof window>"u"?"":getComputedStyle(document.documentElement).getPropertyValue(e).trim()||""}const I5={agent:ZP,sessionGroup:fL},FT="react-flow__node";function PE(e){var n,r;return!!e&&((r=(n=e.classList)==null?void 0:n.contains)==null?void 0:r.call(n,FT))===!0}function M5(e){try{const n=document.querySelector(`.${FT}[data-id="${CSS.escape(e)}"]`);n==null||n.focus({preventScroll:!0})}catch{}}const O5=["a[href]","button:not(:disabled)","input:not(:disabled)","select:not(:disabled)","textarea:not(:disabled)","summary","[tabindex]"].join(","),P5=420,au=18,L5=200,$5=5*6e4,q5=6,D5=2*6e4,Ey="agent-dag.layout",Ny="agent-dag.viewport",zT="agent-dag.summariesDismissed",BT="agent-dag.sessionListOpen",UT="agent-dag.detailOpen",HT="agent-dag.usagePanelOpen",LE="agent-dag.accountsPanelOpen",$E="agent-dag.versionNoticeDismissed",qE="agent-dag.oldNameNoticeDismissed",F5=15*6e4,DE={git_checkout:"this deck runs from a git checkout — pull instead:",npx:"npx runs from a cache that cannot be upgraded in place — run:",not_writable:"the install directory is not writable by this user — run:",opted_out:"installs are off (AGENTS_DECK_NO_INSTALL=1) — run:"},FE="agent-dag.autoRestart",zE="agent-dag.bundleReloadedFor";function z5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(BT)==="1"}catch{return!1}}function B5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(BT,e?"1":"0")}catch{}}function U5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(UT)==="1"}catch{return!1}}function H5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(UT,e?"1":"0")}catch{}}function W5(){const e=OC(HT);return e===null?!0:e==="1"}function V5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(HT,e?"1":"0")}catch{}}function G5(){if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(zT);if(!e)return new Set;const n=JSON.parse(e);return new Set(Array.isArray(n)?n.filter(r=>typeof r=="string"):[])}catch{return new Set}}function BE(e){if(!(typeof window>"u"))try{const n=Array.from(e),r=n.length>200?n.slice(-200):n;window.localStorage.setItem(zT,JSON.stringify(r))}catch{}}function Y5(){const e={positions:[],pins:[]};if(typeof window>"u")return e;try{const n=window.localStorage.getItem(Ey);if(!n)return e;const r=JSON.parse(n);if(!("v"in r)){const o=Object.entries(r).filter(([,l])=>l&&typeof l.x=="number"&&typeof l.y=="number");return{positions:o,pins:o.map(([l])=>l)}}return{positions:Object.entries(r.positions??{}).filter(([,o])=>o&&typeof o.x=="number"&&typeof o.y=="number"),pins:Array.isArray(r.pins)?r.pins:[]}}catch{return e}}function fv(e,n){if(!(typeof window>"u"))try{const r={};for(const[i,o]of e)r[i]=o;for(const[i,o]of n)r[i]=o;window.localStorage.setItem(Ey,JSON.stringify({v:2,positions:r,pins:Array.from(n.keys())}))}catch{}}function K5(){if(typeof window>"u")return null;try{const e=window.localStorage.getItem(Ny);if(!e)return null;const n=JSON.parse(e);return typeof(n==null?void 0:n.x)!="number"||typeof(n==null?void 0:n.y)!="number"||typeof(n==null?void 0:n.zoom)!="number"?null:n}catch{return null}}function X5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(Ny,JSON.stringify(e))}catch{}}function UE(){if(!(typeof window>"u")){try{window.localStorage.removeItem(Ey)}catch{}try{window.localStorage.removeItem(Ny)}catch{}}}function Q5(e,n){const r=e.agents.get(n);if(!r)return;const i=[];for(const d of e.agents.values())d.sessionId===n&&i.push(d);const o={schemaVersion:1,exportedAt:new Date().toISOString(),sessionId:n,label:r.label,cwd:r.cwd,startedAt:r.startedAt,endedAt:r.endedAt,model:r.model,agents:i.map(d=>({id:d.id,kind:d.kind,label:d.label,parentId:d.parentId,state:d.state,startedAt:d.startedAt,endedAt:d.endedAt,model:d.model,cwd:d.cwd,usage:d.usage,prompts:d.prompts,tools:d.tools.map(m=>({id:m.id,name:m.name,inputPreview:m.inputPreview,startedAt:m.startedAt,endedAt:m.endedAt,ok:m.ok,errorPreview:m.errorPreview,usage:m.usage}))}))},l=JSON.stringify(o,null,2),u=new Blob([l],{type:"application/json"}),c=URL.createObjectURL(u),h=document.createElement("a"),p=(r.label||"session").replace(/[^a-z0-9._-]/gi,"_");h.href=c,h.download=`${Gt}-${p}-${n.slice(0,8)}.json`,document.body.appendChild(h),h.click(),document.body.removeChild(h),setTimeout(()=>URL.revokeObjectURL(c),1e3)}const $v={file:"📁",shell:"⚡",web:"🌐",agent:"🤖",task:"📋",plan:"🧭",mcp:"🔌",other:"✨"},qv={file:"file",shell:"shell",web:"web",agent:"agent",task:"task",plan:"plan",mcp:"mcp",other:"other"},WT=EC;function Z5(e,n){if(!n)return null;const r=new Set([n]);let i=n;for(;i;){const l=e.agents.get(i);if(!(l!=null&&l.parentId)||r.has(l.parentId))break;r.add(l.parentId),i=l.parentId}let o=!0;for(;o;){o=!1;for(const l of e.agents.values())l.parentId&&r.has(l.parentId)&&!r.has(l.id)&&(r.add(l.id),o=!0)}return r}function J5(e,n,r,i,o,l,u,c,h,p,d,m,y,w,N,_,b,S,k){const E=[],T=[],I=new Set;if(l)for(const B of e.agents.values())S.has(B.id)&&DT(B,l)&&I.add(B.id);const O=qT(l,I.size);for(const B of e.agents.values()){if(!S.has(B.id))continue;const C=O&&!I.has(B.id),q=B.exitAt!=null,L=b!=null&&!b.has(B.id),re=[C?"rf-dim":"",q?"rf-exiting":"",L?"rf-spotlit-out":""].filter(Boolean).join(" ")||void 0,J=u.get(B.id);if(E.push({id:B.id,type:"agent",position:{x:0,y:0},data:{...B,now:n,onOpenContext:k},className:re,...J?{width:J.width,height:J.height}:null}),B.parentId&&S.has(B.parentId)){const W=ry(B.sessionId),Z=l&&!I.has(B.id)&&!I.has(B.parentId),M=q,G=_.size>0&&(_.has(B.id)||_.has(B.parentId)),K=b!=null&&!b.has(B.id)&&!b.has(B.parentId),$=B.state==="active"?2:1.5,Q=G?$+1.5:$,ne=Z||M?.2:K?.12:1,ae=["sess-edge",B.state==="active"?"sess-live":"sess-idle",M?"rf-edge-exiting":"",G?"rf-edge-selected":""].filter(Boolean).join(" ");T.push({id:`e:${B.parentId}->${B.id}`,source:B.parentId,target:B.id,animated:(B.state==="active"||G)&&!Z&&!M,type:"smoothstep",style:{"--session-hue":W,strokeWidth:Q,opacity:ne,transition:"var(--edge-transition)"},className:ae})}}const A=new Map;for(const B of e.agents.values())B.tools.length>0&&A.set(B.id,Math.min(4,B.tools.length));const U=`${w}#lanes:${r5(A)}`,z=E.filter(B=>p$(B.id,o,m,y));if(z.length>0||U!==N.current){if(z.length>0){const B=i5(E,T,{direction:"LR",pinned:o,measured:u,availableWidth:r,availableHeight:i,lanes:A});for(const C of B)MC(C.id,m,y)&&g$(C.id,C.position,m,y);a5(E,m,o,u,new Set(z.map(C=>C.id)),A)}o5(E,m,o,u,A),N.current=U}const P=l5(E,m,o,u,c,!p||d,A);P.length>0&&h(P),ru(m,e.agents),ru(y,e.agents),ru(o,e.agents),ru(u,h$(e.agents.values()));const D=[];let V=!1;for(const B of E){let C=o.get(B.id)??m.get(B.id);C||(C=m$(B.id,m,y),V=!0),D.push({...B,position:C})}return V&&(N.current=""),{nodes:D,edges:T}}function eF(){return g.jsx(ny,{children:g.jsx(tF,{})})}function tF(){var Va,Ga,Ya,Ka;const e=ja(),n=j.useRef(Rv()),[,r]=j.useState(0),i=j.useCallback(()=>r(H=>H+1),[]),[o,l]=j.useState(()=>new Set),[u,c]=j.useState(null),[h,p]=j.useState(null),d=j.useCallback((H,Y)=>{l(oe=>{if(!Y)return new Set([H]);const de=new Set(oe);return de.has(H)?de.delete(H):de.add(H),de}),c(oe=>Y&&oe===H?oe:H)},[]),m=j.useCallback(()=>{l(new Set),c(null)},[]),[y,w]=j.useState(null),[N,_]=j.useState(null),b=j.useCallback(H=>_(H),[]),[S,k]=j.useState(!1),E=j.useRef(G5()),[T,I]=j.useState(z5);j.useEffect(()=>{B5(T)},[T]);const[O,A]=j.useState(U5);j.useEffect(()=>{H5(O)},[O]);const[U,z]=j.useState(W5);j.useEffect(()=>{V5(U)},[U]);const[P,D]=j.useState(()=>{try{const H=window.localStorage.getItem(LE);return H===null?!0:H==="1"}catch{return!0}});j.useEffect(()=>{try{window.localStorage.setItem(LE,P?"1":"0")}catch{}},[P]);const[V,B]=j.useState(null),[C,q]=j.useState(!1),[L,re]=j.useState(0),[J,W]=j.useState(0);j.useEffect(()=>{fetch("/api/sound-hook").then(H=>H.ok?H.json():null).then(H=>{H!=null&&H.ok&&(B(H.enabled===!0),re((H.foreign??[]).filter(Y=>Y.worksHere).length),W(typeof H.parked=="number"?H.parked:0))}).catch(()=>{})},[]);const Z=j.useCallback(async()=>{q(!0);try{const Y=await(await fetch("/api/sound-hook",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:!V})})).json().catch(()=>null);Y!=null&&Y.ok&&B(Y.enabled===!0),fetch("/api/sound-hook").then(oe=>oe.ok?oe.json():null).then(oe=>{oe!=null&&oe.ok&&(re((oe.foreign??[]).filter(de=>de.worksHere).length),W(typeof oe.parked=="number"?oe.parked:0))}).catch(()=>{})}catch{}finally{q(!1)}},[V]),[M,G]=j.useState(!1),[K,$]=j.useState(null),[Q,ne]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem($E)??""}catch{return""}}),[ae,fe]=j.useState(!1),te=j.useRef(0),[ce,Ce]=j.useState(!1),ve=j.useCallback((H=!1)=>{H&&(te.current=Date.now(),Ce(!0)),fetch(H?"/api/version?refresh=1":"/api/version").then(Y=>Y.ok?Y.json():null).then(Y=>{Y&&$(Y)}).catch(()=>{}).finally(()=>{H&&Ce(!1)})},[]),je=j.useCallback(()=>{ve(Date.now()-te.current>=F5)},[ve]);j.useEffect(()=>{ve();const H=window.setInterval(je,5*6e4),Y=()=>{document.visibilityState==="visible"&&je()};return document.addEventListener("visibilitychange",Y),()=>{window.clearInterval(H),document.removeEventListener("visibilitychange",Y)}},[ve,je]),j.useEffect(()=>{M&&ve()},[M,ve]);const ye=(K==null?void 0:K.notice)??null,[Ee,Ye]=j.useState(null),[we,_e]=j.useState(Pv);j.useEffect(()=>{let H=!1;return fetch("/api/health").then(Y=>Y.ok?Y.json():null).then(Y=>{H||(_e(w5(Y)),!(!Y||typeof Y.workspace!="string")&&Ye(Y.workspace))}).catch(()=>{}),()=>{H=!0}},[M]);const Be=j.useRef(we);Be.current=we;const it=ye?`${ye.kind}:${ye.to}`:"",ft=ye!=null&&Q!==it,Ze=j.useCallback(()=>{if(!ye)return;const H=Q===it?"":it;ne(H);try{window.localStorage.setItem($E,H)}catch{}},[ye,it,Q]),[De,Je]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem(qE)??""}catch{return""}}),Xe=K!=null&&K.invokedAs&&K.invokedAs!==Gt?K.invokedAs:null,Mt=Xe!=null&&De!==Xe,lt=j.useCallback(()=>{if(Xe){Je(Xe);try{window.localStorage.setItem(qE,Xe)}catch{}}},[Xe]),Qe=((Va=K==null?void 0:K.upgrade)==null?void 0:Va.state)??"idle",Ot=n$(K==null?void 0:K.upgrade),zt=j.useCallback(async()=>{try{await fetch("/api/upgrade",{method:"POST"})}catch{}ve()},[ve]);j.useEffect(()=>{if(Qe!=="running")return;const H=window.setInterval(ve,3e3);return()=>window.clearInterval(H)},[Qe,ve]);const et=j.useCallback(async()=>{var oe;const H=K==null?void 0:K.command;if(!H)return;let Y=!1;try{Y=await Promise.race([((oe=navigator.clipboard)==null?void 0:oe.writeText(H).then(()=>!0))??Promise.resolve(!1),new Promise(de=>window.setTimeout(()=>de(!1),500))])}catch{Y=!1}if(!Y)try{const de=document.createElement("textarea");de.value=H,de.setAttribute("readonly",""),de.style.cssText="position:fixed;top:0;left:0;opacity:0",document.body.appendChild(de),de.select(),Y=document.execCommand("copy"),de.remove()}catch{Y=!1}Y&&(fe(!0),window.setTimeout(()=>fe(!1),1600))},[K==null?void 0:K.command]),bt=j.useCallback(()=>{I(H=>(H||D(!1),!H))},[]),ht=j.useCallback(()=>{D(H=>(H||I(!1),!H))},[]),[vt,hn]=j.useState(!1),[Yt,Pt]=j.useState(0),bn=j.useRef(null),[gr,Sn]=j.useState(!1),Bt=j.useRef(null),[Fn,pn]=j.useState(0),vr=j.useRef(x$()),[Hr,xi]=j.useState(!1),Wr=j.useCallback(()=>{const H=vr.current,Y=H.setPaused(!H.paused);for(const oe of Y)n.current=zx(n.current,oe);xi(H.paused)},[]),[ut,_i]=j.useState(Date.now()),[mn,Is]=j.useState(()=>{if(typeof window>"u")return!0;try{return window.localStorage.getItem(FE)!=="0"}catch{return!0}}),yr=j.useCallback(()=>{Is(H=>{const Y=!H;try{window.localStorage.setItem(FE,Y?"1":"0")}catch{}return Y})},[]),[zn,kn]=j.useState(!1),[Vr,Gr]=j.useState("restart"),[Yr,bi]=j.useState(null),sr=j.useRef(!1),Ms=j.useRef(null),En=j.useRef(0),wr=j.useCallback(async H=>{if(sr.current)return;const Y=(H==null?void 0:H.upgrade)===!0;sr.current=!0,Ms.current=Ot;const oe=++En.current;Gr(Y?"npx":"restart"),kn(!0);try{window.sessionStorage.setItem("agent-dag.restartPending",(ye==null?void 0:ye.to)??"")}catch{}try{await fetch("/api/restart",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({upgrade:Y})})}catch{}window.setTimeout(()=>{if(En.current===oe&&sr.current){sr.current=!1,kn(!1);try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}}},Y?18e4:3e4)},[ye==null?void 0:ye.to,Ot]),Os=j.useRef(null);j.useEffect(()=>{let H=!1;for(const oe of n.current.agents.values())if(oe.state==="active"){H=!0;break}const Y=s$({enabled:mn,kind:ye==null?void 0:ye.kind,canRestart:(K==null?void 0:K.canRestart)===!0,busy:H,idleSince:Os.current,now:ut});Os.current=Y.idleSince,Y.restart&&wr()},[mn,ye==null?void 0:ye.kind,K==null?void 0:K.canRestart,ut,wr]),j.useEffect(()=>{const H=K==null?void 0:K.running;let Y=null,oe=null;try{Y=window.sessionStorage.getItem("agent-dag.restartPending"),oe=window.sessionStorage.getItem(zE)}catch{return}const de=t$({bundle:"1.35.23",running:H,pending:Y,lastTried:oe});if(de==="reload"){try{window.sessionStorage.setItem(zE,H??"")}catch{return}window.location.reload();return}if(de!=="confirm")return;try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1),bi(H??null);const xe=window.setTimeout(()=>bi(null),6e3);return()=>window.clearTimeout(xe)},[K==null?void 0:K.running]),j.useEffect(()=>{if(zn&&r$({asked:Ms.current,reported:Ot})){try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1)}},[zn,Ot]);const Ps=j.useRef(Y5()).current;j.useRef(!1);const Tt=j.useRef(new Map(Ps.positions.filter(([H])=>Ps.pins.includes(H)))),xr=j.useRef(null),_r=j.useState(()=>K5())[0],[Kt,Kr]=j.useState(""),[Si,nt]=j.useState(()=>new Set),[br,Xr]=j.useState(E$),[Ls,Qr]=j.useState(!1),Zr=j.useRef(null);j.useEffect(()=>{document.documentElement.dataset.theme=br;try{window.localStorage.setItem(PC,br)}catch{}},[br]),j.useEffect(()=>{if(!_r)return;const H=window.setTimeout(()=>{try{e.setViewport(_r,{duration:0})}catch{}},60);return()=>window.clearTimeout(H)},[e,_r]);const $s=j.useRef(!0);j.useEffect(()=>{const H=new EventSource("/events"),Y=w$(i,{now:()=>Date.now(),setTimeout:(oe,de)=>window.setTimeout(oe,de),clearTimeout:oe=>window.clearTimeout(oe)});return H.addEventListener("open",()=>{G(!0),Qr(!0)}),H.addEventListener("error",()=>G(!1)),H.addEventListener("replay-end",()=>{$s.current=!1,Y.flush()}),H.addEventListener("hook",oe=>{try{const de=JSON.parse(oe.data);if(!vr.current.accept(de))return;n.current=zx(n.current,de),de.replay===!0||$s.current||Date.now()-de.receivedAt>3e4?Y.replay():Y.live()}catch{}}),()=>{H.close(),Y.cancel()}},[i]),j.useEffect(()=>{const H=setInterval(()=>{const Y=Date.now();_i(Y);let oe=gP(n.current,Y,Fx);vP(n.current,Y,Fx)&&(oe=!0),pP(n.current,Y,L5,$5)&&(oe=!0),mP(n.current,Y,q5,D5)&&(oe=!0),oe&&i()},250);return()=>clearInterval(H)},[i]);const ir=j.useRef(null),St=j.useRef(0),qs=420,pt=j.useCallback((H=500)=>{try{const Se=document.querySelector(".canvas-wrap"),Pe=Array.from(document.querySelectorAll(".react-flow__node")).filter(wt=>wt.offsetWidth>0);if(!Se||Pe.length===0)return;const Fe=Se.getBoundingClientRect(),Ge=e.getViewport();if(!Number.isFinite(Ge.zoom)||Ge.zoom<=0)return;const We=wt=>(wt-Fe.left-Ge.x)/Ge.zoom,ze=wt=>(wt-Fe.top-Ge.y)/Ge.zoom,Tn=Pe.map(wt=>wt.getBoundingClientRect()),Ys=Math.min(...Tn.map(wt=>We(wt.left))),Ao=Math.max(...Tn.map(wt=>We(wt.right))),Ks=Math.min(...Tn.map(wt=>ze(wt.top))),Io=Math.max(...Tn.map(wt=>ze(wt.bottom))),Xa=Ao-Ys,us=Io-Ks;if(!(Xa>0&&us>0))return;const Zt=Math.max(.2,Math.min(1,(Fe.width-160)/(Xa+qs)*.86,(Fe.height-160)/us*.86));e.setViewport({x:80-Ys*Zt,y:Math.max(80,(Fe.height-us*Zt)/2)-Ks*Zt,zoom:Zt},{duration:H}),St.current=Date.now(),window.setTimeout(()=>{try{const wt={x:80-Ys*Zt,y:Math.max(80,(Fe.height-us*Zt)/2)-Ks*Zt,zoom:Zt},Mo=e.getViewport();(Math.abs(Mo.zoom-Zt)>.01||Math.abs(Mo.x-wt.x)>2)&&e.setViewport(wt,{duration:0})}catch{}},H+60)}catch{}},[e]),ko=j.useRef(""),Eo=j.useRef(null),qa=j.useRef(0),Sr=j.useCallback(()=>{qa.current=Date.now()},[]),Jr="agent-dag.autoFitDisabled",gn=j.useRef((()=>{if(typeof window>"u")return!1;try{return window.localStorage.getItem(Jr)==="1"}catch{return!1}})()),[Ds,Da]=j.useState(gn.current),Fa=j.useCallback(()=>{if(!gn.current){gn.current=!0,Da(!0);try{window.localStorage.setItem(Jr,"1")}catch{}}},[]),No=j.useCallback(()=>{gn.current=!1,Da(!1);try{window.localStorage.removeItem(Jr)}catch{}pt(400)},[e,pt]);j.useEffect(()=>{const H=setInterval(()=>{if(gn.current||Date.now()-qa.current<800)return;const Y=n.current,oe=Date.now(),de=[];for(const We of Y.agents.values())Ov(We,oe)&&de.push({id:We.id});if(de.length===0)return;const xe=e.getViewport(),Se=window.innerWidth-360,Pe=window.innerHeight-52;let Fe=!1,Ge=!1;for(const{id:We}of de){const ze=or.current.get(We),Tn=Tt.current.get(We)??Xt.current.get(We);if(!ze||!Tn)continue;Ge=!0;const Ys=Tn.x*xe.zoom+xe.x,Ao=Tn.y*xe.zoom+xe.y,Ks=(Tn.x+ze.width)*xe.zoom+xe.x,Io=(Tn.y+ze.height)*xe.zoom+xe.y;if(Ks>0&&Ys<Se&&Io>0&&Ao<Pe){Fe=!0;break}}Ge&&!Fe&&pt(600)},1500);return()=>clearInterval(H)},[e]);const ki=j.useRef(!1),or=j.useRef(new Map),es=j.useRef(0),ec=j.useCallback(H=>{const Y=or.current;let oe=!1;for(const de of H.nodeInternals.values()){const xe=de.width,Se=de.height;if(xe==null||Se==null)continue;const Pe=Y.get(de.id);Pe?(Math.abs(Pe.height-Se)>4||Math.abs(Pe.width-xe)>4)&&(Y.set(de.id,{width:xe,height:Se}),oe=!0):(Y.set(de.id,{width:xe,height:Se}),oe=!0)}return oe&&(es.current+=1),es.current},[]),Ei=Ke(ec),[He,za]=j.useState(0);j.useEffect(()=>{let H=0;const Y=()=>{const de=or.current;let xe=!1;for(const Se of document.querySelectorAll(".react-flow__node[data-id]")){const Pe=Se.getAttribute("data-id");if(!Pe)continue;const Fe=Se.offsetWidth,Ge=Se.offsetHeight;if(!Fe||!Ge)continue;const We=de.get(Pe);(!We||Math.abs(We.width-Fe)>4||Math.abs(We.height-Ge)>4)&&(de.set(Pe,{width:Fe,height:Ge}),xe=!0)}xe&&za(Se=>Se+1)};if(ki.current)return;let oe=0;return document.visibilityState==="hidden"?oe=window.setTimeout(Y,32):H=requestAnimationFrame(Y),()=>{cancelAnimationFrame(H),window.clearTimeout(oe)}});const Xt=j.useRef(new Map(Ps.positions)),Co=j.useRef(new Set),Ni=j.useRef(""),kr=j.useMemo(()=>{const H=[];for(const Y of n.current.agents.values())Ov(Y,ut)&&H.push(Y.id+(Y.parentId?`>${Y.parentId}`:""));return H.sort(),`${H.join("|")}#sv${Ei}.${He}`},[n.current,n.current.lastSeq,ut,Ei,He]),ts=j.useRef(null);j.useEffect(()=>(ts.current!=null&&window.clearTimeout(ts.current),ts.current=window.setTimeout(()=>{fv(Xt.current,Tt.current)},1500),()=>{ts.current!=null&&window.clearTimeout(ts.current)}),[kr]),j.useEffect(()=>{if(ko.current===kr)return;const H=ko.current;if(ko.current=kr,!H||gn.current)return;Date.now()-St.current>1200&&pt(400),ir.current&&window.clearTimeout(ir.current),ir.current=window.setTimeout(()=>{gn.current||pt(500)},280)},[kr,e,pt]);const Fs=j.useMemo(()=>{if(o.size===0)return null;const H=new Set;for(const Y of o){const oe=Z5(n.current,Y);if(oe)for(const de of oe)H.add(de)}return H.size>0?H:null},[n.current,n.current.lastSeq,o]),Nn=j.useMemo(()=>c5(n.current,ut),[n.current,n.current.lastSeq,ut]),Bn=j.useRef(null),[vn,Un]=j.useState({w:0,h:0});j.useEffect(()=>{const H=Bn.current;if(!H||typeof ResizeObserver>"u")return;const Y=new ResizeObserver(oe=>{var xe;const de=(xe=oe[0])==null?void 0:xe.contentRect;de&&Un(Se=>Math.abs(Se.w-de.width)>40||Math.abs(Se.h-de.height)>40?{w:de.width,h:de.height}:Se)});return Y.observe(H),Un({w:H.clientWidth,h:H.clientHeight}),()=>Y.disconnect()},[]);const zs=j.useCallback(H=>{var oe,de;const Y=H.target;!(Y!=null&&Y.closest)||Y.closest(O5)!==H.currentTarget||(H.preventDefault(),(de=(oe=document.activeElement)==null?void 0:oe.blur)==null||de.call(oe))},[]),Bs=j.useRef(new Map),[Hn,tc]=j.useState(!1);j.useEffect(()=>{const H=window.setTimeout(()=>tc(!0),2500);return()=>window.clearTimeout(H)},[]);const[Ba,Er]=j.useState(!1),ar=j.useRef(null),[Ci,Us]=j.useState(!1),Ua=j.useCallback(()=>{ar.current&&(window.clearTimeout(ar.current),ar.current=null),Er(!1)},[]),nc=j.useCallback(H=>{H.length!==0&&queueMicrotask(()=>{Er(!0),ar.current&&window.clearTimeout(ar.current),ar.current=window.setTimeout(()=>Er(!1),P5+80)})},[]);j.useEffect(()=>()=>{ar.current&&window.clearTimeout(ar.current)},[]);const ns=vn.w>0?vn.w*.92:0,rs=vn.h>0?vn.h:0,{nodes:Qt,edges:Ti}=j.useMemo(()=>J5(n.current,ut,ns,rs,Tt.current,Kt,or.current,Bs.current,nc,Hn,Ci,Xt.current,Co.current,kr,Ni,o,Fs,Nn,b),[n.current,n.current.lastSeq,ut,ns,rs,Hn,Ci,Kt,kr,o,Fs,Nn,b,Yt]),Ha=j.useMemo(()=>{const H=new Map;for(const oe of Qt){const de=oe.data;if(!(de!=null&&de.sessionId)||de.exitAt!=null)continue;const xe=oe.width,Se=oe.height;if(xe==null||Se==null)continue;const Pe=oe.position.x,Fe=oe.position.y,Ge=Pe+xe,We=Fe+Se,ze=H.get(de.sessionId);ze?(ze.minX=Math.min(ze.minX,Pe),ze.minY=Math.min(ze.minY,Fe),ze.maxX=Math.max(ze.maxX,Ge),ze.maxY=Math.max(ze.maxY,We)):H.set(de.sessionId,{minX:Pe,minY:Fe,maxX:Ge,maxY:We})}const Y=[];for(const[oe,de]of H){const xe=de.maxX-de.minX+au*2,Se=de.maxY-de.minY+au*2;Y.push({id:`group:${oe}`,type:LT,position:{x:de.minX-au,y:de.minY-au},data:{sessionId:oe,w:xe,h:Se},width:xe,height:Se,style:{width:xe,height:Se},zIndex:-1,draggable:!0,selectable:!1,focusable:!1,deletable:!1,connectable:!1})}return Y},[Qt,ut]),rc=j.useMemo(()=>{const H=[...Ha,...Qt],Y=Bt.current;return!Y||Y.size===0?H:H.map(oe=>{const de=Y.get(oe.id);return de?{...oe,position:de}:oe})},[Ha,Qt,Fn]),Nr=j.useMemo(()=>{if(!Kt)return null;const H=new Set;for(const Y of n.current.agents.values())Nn.has(Y.id)&&DT(Y,Kt)&&H.add(Y.id);return H},[n.current,n.current.lastSeq,Kt,Nn]),Cn=j.useMemo(()=>T5(Kt,(Nr==null?void 0:Nr.size)??0,Nn.size),[Kt,Nr,Nn]),ss=j.useMemo(()=>{const H=new Set;for(const Y of n.current.agents.values())for(const oe of Y.tools)H.add(WT(oe.name));return Object.keys($v).filter(Y=>H.has(Y))},[n.current,n.current.lastSeq]);j.useEffect(()=>{if(ss.length<=1){Sn(!1);return}let H=0;const Y=()=>{const oe=bn.current;if(oe&&!document.hidden){const de=oe.getBoundingClientRect(),xe=Array.from(document.querySelectorAll(".react-flow__node, .tool-burst")).map(Pe=>Pe.getBoundingClientRect()),Se=f5(de,xe,8);Sn(Pe=>Pe===Se?Pe:Se)}H=window.setTimeout(Y,300)};return Y(),()=>window.clearTimeout(H)},[ss.length]);const is=j.useMemo(()=>{const H=new Map;for(const oe of n.current.agents.values())for(const de of oe.tools){if(!de.name.startsWith("mcp__"))continue;const xe=de.name.slice(5),Se=xe.indexOf("__"),Pe=Se>0?xe.slice(0,Se):xe;H.set(Pe,(H.get(Pe)??0)+1)}const Y=[];for(const[oe,de]of H){let xe=5381;for(let Se=0;Se<oe.length;Se++)xe=(xe<<5)+xe^oe.charCodeAt(Se);Y.push({server:oe,count:de,hue:Math.abs(xe)%360})}return Y.sort((oe,de)=>de.count-oe.count),Y},[n.current,n.current.lastSeq]),lr=j.useCallback(H=>{nt(Y=>{const oe=new Set(Y);return oe.has(H)?oe.delete(H):oe.add(H),oe})},[]),Rt=u?n.current.agents.get(u):null,os=h?Array.from(n.current.agents.values()).flatMap(H=>H.tools).find(H=>H.id===h)??null:null,To=j.useCallback(async()=>{try{await fetch("/api/clear",{method:"POST"})}catch{}n.current=Rv(),Tt.current.clear(),or.current.clear(),Xt.current.clear(),Ni.current="",UE(),m(),i()},[i,m]),Hs=j.useRef(S);Hs.current=S;const Ws=j.useRef(!1);Ws.current=os!=null||vt||N!=null||y!=null;const Vs=j.useCallback(H=>{const Y=o$(H,{confirmOpen:Hs.current,modalOpen:Ws.current});Y==="confirm"?k(!0):Y==="clear"&&(k(!1),To())},[To]),Lt=j.useCallback(()=>{Tt.current.clear(),Xt.current.clear(),Ni.current="",UE(),i(),window.setTimeout(()=>pt(500),80)},[i,e,pt]),Cr=j.useCallback(()=>pt(500),[pt]),as=j.useRef(Qt);as.current=Qt;const ls=j.useRef(u);ls.current=u;const Ro=j.useCallback(H=>{const Y=as.current,oe=l$(Y.map(Se=>({id:Se.id,x:Se.position.x,y:Se.position.y})),ls.current,H),de=oe?Y.find(Se=>Se.id===oe):void 0;if(!de)return;const xe=PE(document.activeElement);d(de.id,!1),window.setTimeout(()=>{try{e.fitView({padding:.35,duration:350,nodes:[de]})}catch{}St.current=Date.now(),xe&&M5(de.id)},30)},[d,e]),Ri=j.useCallback(H=>{d(H,!1),window.setTimeout(()=>{try{const Y=as.current.find(oe=>oe.id===H);Y&&e.fitView({padding:.3,duration:500,nodes:[Y]}),St.current=Date.now()}catch{}},60)},[d,e]);j.useEffect(()=>{const H=Y=>{var Fe,Ge,We;const oe=Y.target,de={tagName:oe==null?void 0:oe.tagName,isContentEditable:oe==null?void 0:oe.isContentEditable,role:(Fe=oe==null?void 0:oe.getAttribute)==null?void 0:Fe.call(oe,"role"),type:oe==null?void 0:oe.type};if(Y.key==="Escape"){const ze=LP({overlayOpen:Eu.depth()>0,typing:sy(de)});ze==="dismiss"?Eu.dismissTop():ze==="blur"?oe==null||oe.blur():(f$(de)&&(oe==null||oe.blur()),m());return}if(bC(Y))return;const xe=PE(oe)?(Ge=oe==null?void 0:oe.getAttribute)==null?void 0:Ge.call(oe,"data-id"):null,Se=xe&&as.current.some(ze=>ze.id===xe)?xe:null,Pe=c$(Y,Se);if(Pe.kind==="activate"){Y.preventDefault(),d(Pe.nodeId,Pe.additive);return}if(Pe.kind!=="node"&&!(Pe.nodeId==null&&HP(de))){if(Y.key==="/"){Y.preventDefault(),(We=Zr.current)==null||We.focus();return}Y.key===" "&&(Y.preventDefault(),Wr()),(Y.key==="c"||Y.key==="C")&&Vs("shortcut"),(Y.key==="r"||Y.key==="R")&&Lt(),(Y.key==="f"||Y.key==="F")&&Cr(),(Y.key==="l"||Y.key==="L")&&bt(),(Y.key==="h"||Y.key==="H")&&hn(ze=>!ze),(Y.key==="u"||Y.key==="U")&&z(ze=>!ze),(Y.key==="a"||Y.key==="A")&&Be.current.claude&&ht(),(Y.key==="j"||Y.key==="J")&&Ro(1),(Y.key==="k"||Y.key==="K")&&Ro(-1),(Y.key==="t"||Y.key==="T")&&Xr(ze=>ze==="dark"?"light":"dark")}};return window.addEventListener("keydown",H),()=>window.removeEventListener("keydown",H)},[Vs,Lt,Cr,m,d,Ro,Wr]);const Tr=n.current.agents.size,Gs=new Set(Array.from(n.current.agents.values()).map(H=>H.sessionId)).size,tn=j.useMemo(()=>e3(n.current.agents.values()),[n.current,n.current.lastSeq]),jo=j.useMemo(()=>t3(n.current.agents.values()),[n.current,n.current.lastSeq]),Wa=j.useRef(null);j.useEffect(()=>{const H=N$({waiting:tn.length,running:jo}),Y=Wa.current;if(Wa.current=H,(Y==null?void 0:Y.title)!==H.title&&(document.title=H.title),(Y==null?void 0:Y.icon)!==H.icon){const oe=document.querySelector('link[rel="icon"]');oe&&(oe.href=C$[H.icon])}},[tn.length,jo]);const[sc,ic]=j.useState(""),ji=R$(tn);j.useEffect(()=>{ic(H=>j$(H,ji))},[ji]);const nn=j.useMemo(()=>{let H=0,Y=0,oe=0,de=0,xe=0,Se=0,Pe=0,Fe=0,Ge=0;for(const We of n.current.agents.values()){H+=We.usage.inputTokens,Y+=We.usage.outputTokens,oe+=We.usage.cacheReadTokens,de+=We.usage.cacheCreateTokens;const ze=dn(We.usage,We.model);xe+=ze.total,Se+=ze.input,Pe+=ze.output,Fe+=ze.cacheRead,Ge+=ze.cacheWrite}return{inT:H,outT:Y,cacheR:oe,cacheC:de,sum:H+Y,cost:{total:xe,input:Se,output:Pe,cacheRead:Fe,cacheWrite:Ge}}},[n.current,n.current.lastSeq]);return g.jsxs("div",{className:"app",children:[g.jsx("a",{className:"skip-link",href:"#canvas",children:"Skip to the canvas"}),g.jsxs("header",{className:"topbar",children:[g.jsxs("div",{className:"brand",children:[g.jsx("span",{className:"logo"}),g.jsx("h1",{children:Gt}),ye?g.jsxs("button",{type:"button",className:"v stale",onClick:Ze,"aria-label":v5({...ye,open:ft}),title:ye.kind==="restart"?`Running v${ye.from}; v${ye.to} is installed on disk. Restart to pick it up.`:`Running v${ye.from}; v${ye.to} is on npm.`,children:["v",ye.from,g.jsx("span",{className:"v-dot","aria-hidden":!0})]}):(()=>{const H={running:(K==null?void 0:K.running)??"1.35.23",latest:K==null?void 0:K.latest,latestPending:K==null?void 0:K.latestPending,checkedAgo:K!=null&&K.checkedAt?Lv(ut-K.checkedAt):null,checkDisabled:K==null?void 0:K.checkDisabled,checking:ce};return g.jsxs("button",{type:"button",className:ce?"v checking":"v",onClick:()=>ve(!0),"aria-busy":ce||void 0,"aria-label":g5(H),title:m5(H),children:["v",H.running]})})()]}),Rt&&(()=>{const H=dn(Rt.usage,Rt.model),Y=Math.max(0,((Rt.endedAt??ut)-Rt.startedAt)/1e3),oe=Rt.state==="active"?ku(H.total,Y):null,de=o.size-1;return g.jsxs("button",{type:"button",className:"selected-ribbon",title:`Fit view to ${Rt.label}`,onClick:()=>{try{const xe=Qt.find(Se=>Se.id===Rt.id);xe&&e.fitView({padding:.35,duration:500,nodes:[xe]}),St.current=Date.now()}catch{}},children:[g.jsx("span",{className:`state-pill state-${Rt.state}`,children:Rt.state==="active"?"live":Rt.state}),g.jsx("span",{className:"selected-label",children:Rt.label}),H.total>0&&g.jsxs("span",{className:"selected-cost",children:[qe(H.total),oe?g.jsxs("span",{className:"selected-rate",children:[" · ",oe]}):null]}),de>0&&g.jsxs("span",{className:"selected-extra",children:["+",de]}),g.jsx("span",{"aria-hidden":!0,className:"selected-close",onClick:xe=>{xe.stopPropagation(),m()},children:"×"})]})})(),g.jsxs("div",{className:"actions",children:[g.jsxs("div",{className:"search",children:[g.jsx("span",{className:"search-icon","aria-hidden":!0,children:"⌕"}),g.jsx("input",{ref:Zr,type:"text",placeholder:R5,value:Kt,onChange:H=>Kr(H.target.value),spellCheck:!1,"aria-label":"Filter the graph"}),Kt?g.jsx("button",{className:"search-clear","aria-label":"Clear search",onClick:()=>Kr(""),children:"×"}):g.jsx("kbd",{className:"search-kbd","aria-hidden":!0,children:"/"}),Cn.count&&g.jsx("span",{className:`search-count${Cn.empty?" none":""}`,"aria-live":"polite",title:`${Cn.count} agents on the canvas match “${Kt}”`,children:Cn.count})]}),g.jsxs("span",{className:"status",children:[(()=>{const H=N5({connected:M,paused:Hr,held:vr.current.size});return g.jsx("span",{className:`pill ${H.tone}`,title:H.title,children:H.label})})(),g.jsxs("span",{className:"stat",title:b5(we),children:[g.jsx("span",{className:"count",children:Gs}),g.jsx("span",{className:"lbl",children:"sessions"})]}),g.jsxs("span",{className:"stat",title:"Total agents (root + subagents)",children:[g.jsx("span",{className:"count",children:Tr}),g.jsx("span",{className:"lbl",children:"agents"})]}),g.jsxs("span",{className:"stat",title:S5(we),children:[g.jsx("span",{className:"count",children:n.current.totalEvents}),g.jsx("span",{className:"lbl",children:"events"})]}),nn.sum>0&&g.jsxs("span",{className:"stat",title:`in:${nn.inT.toLocaleString()} out:${nn.outT.toLocaleString()} cache-r:${nn.cacheR.toLocaleString()} cache-c:${nn.cacheC.toLocaleString()}`,children:[g.jsx("span",{className:"count",children:Dt(nn.sum)}),g.jsx("span",{className:"lbl",children:"tokens"})]}),is.length>0&&g.jsxs("span",{className:"stat mcp-legend",title:`MCP servers seen this session:
72
+ ${n.parked} of your own sound hook${n.parked>1?"s were":" was"} set aside so this switch actually controls the sound. Nothing was deleted — shift-click to put ${n.parked>1?"them":"it"} back.`:"";return r+i+o+l}function $T(e){const n=Math.max(0,Math.floor(e));return`${n} event${n===1?"":"s"}`}function N5(e){return e.connected?e.paused?{tone:"paused",label:"paused",title:e.held>0?`Connected — ${$T(e.held)} held until you resume (Space)`:"Connected — updates held until you resume (Space)"}:{tone:"live",label:"live",title:"Receiving events"}:{tone:"dead",label:"offline",title:e.paused?"SSE disconnected — and the canvas is paused, so resuming will not bring events back until it reconnects":"SSE disconnected"}}function C5(e){return e.paused?e.held<=0?{label:"Resume",title:"Nothing has arrived since you paused. Resume to follow the canvas again (Space)"}:{label:`Resume · ${e.held} held`,title:`${$T(e.held)} arrived while paused and will be applied in order when you resume (Space)`}:{label:"Pause",title:"Pause live updates — events keep arriving and are applied when you resume (Space)"}}function qT(e,n){return e!==""&&n>0}function T5(e,n,r){return e===""?{active:!1,matched:n,total:r,count:null,empty:!1,message:null,dim:!1}:{active:!0,matched:n,total:r,count:`${n} of ${r}`,empty:n===0,message:n===0?`No agents match “${e}”`:null,dim:qT(e,n)}}const R5="Search agents, tools, model…";function DT(e,n){var i,o,l,u;if(!n)return!0;const r=n.toLowerCase();if(e.label.toLowerCase().includes(r)||(i=e.cwd)!=null&&i.toLowerCase().includes(r)||(o=e.cwdBasename)!=null&&o.toLowerCase().includes(r)||e.sessionId.toLowerCase().includes(r)||(l=e.firstPrompt)!=null&&l.toLowerCase().includes(r)||e.model&&(e.model.toLowerCase().includes(r)||js(e.model).toLowerCase().includes(r))||(u=e.provider)!=null&&u.toLowerCase().startsWith(r))return!0;for(const c of e.tools)if(c.name.toLowerCase().includes(r))return!0;return!1}function Lv(e){const n=Math.max(0,Math.floor(e/1e3));return n<60?"just now":n<3600?`${Math.floor(n/60)}m ago`:n<86400?`${Math.floor(n/3600)}h ago`:`${Math.floor(n/86400)}d ago`}function j5(e,n){return e.getFullYear()===n.getFullYear()&&e.getMonth()===n.getMonth()&&e.getDate()===n.getDate()}function A5(e,n,r){const i=new Date(e),o=Lv(n-e);return{label:j5(i,new Date(n))?o:`${o} · ${i.toLocaleDateString(r,{month:"short",day:"numeric"})}`,title:i.toLocaleString(r,{dateStyle:"medium",timeStyle:"medium"})}}function ua(e){return typeof window>"u"?"":getComputedStyle(document.documentElement).getPropertyValue(e).trim()||""}const I5={agent:ZP,sessionGroup:fL},FT="react-flow__node";function PE(e){var n,r;return!!e&&((r=(n=e.classList)==null?void 0:n.contains)==null?void 0:r.call(n,FT))===!0}function M5(e){try{const n=document.querySelector(`.${FT}[data-id="${CSS.escape(e)}"]`);n==null||n.focus({preventScroll:!0})}catch{}}const O5=["a[href]","button:not(:disabled)","input:not(:disabled)","select:not(:disabled)","textarea:not(:disabled)","summary","[tabindex]"].join(","),P5=420,au=18,L5=200,$5=5*6e4,q5=6,D5=2*6e4,Ey="agent-dag.layout",Ny="agent-dag.viewport",zT="agent-dag.summariesDismissed",BT="agent-dag.sessionListOpen",UT="agent-dag.detailOpen",HT="agent-dag.usagePanelOpen",LE="agent-dag.accountsPanelOpen",$E="agent-dag.versionNoticeDismissed",qE="agent-dag.oldNameNoticeDismissed",F5=15*6e4,DE={git_checkout:"this deck runs from a git checkout — pull instead:",npx:"npx runs from a cache that cannot be upgraded in place — run:",not_writable:"the install directory is not writable by this user — run:",opted_out:"installs are off (AGENTS_DECK_NO_INSTALL=1) — run:"},FE="agent-dag.autoRestart",zE="agent-dag.bundleReloadedFor";function z5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(BT)==="1"}catch{return!1}}function B5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(BT,e?"1":"0")}catch{}}function U5(){if(typeof window>"u")return!1;try{return window.localStorage.getItem(UT)==="1"}catch{return!1}}function H5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(UT,e?"1":"0")}catch{}}function W5(){const e=OC(HT);return e===null?!0:e==="1"}function V5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(HT,e?"1":"0")}catch{}}function G5(){if(typeof window>"u")return new Set;try{const e=window.localStorage.getItem(zT);if(!e)return new Set;const n=JSON.parse(e);return new Set(Array.isArray(n)?n.filter(r=>typeof r=="string"):[])}catch{return new Set}}function BE(e){if(!(typeof window>"u"))try{const n=Array.from(e),r=n.length>200?n.slice(-200):n;window.localStorage.setItem(zT,JSON.stringify(r))}catch{}}function Y5(){const e={positions:[],pins:[]};if(typeof window>"u")return e;try{const n=window.localStorage.getItem(Ey);if(!n)return e;const r=JSON.parse(n);if(!("v"in r)){const o=Object.entries(r).filter(([,l])=>l&&typeof l.x=="number"&&typeof l.y=="number");return{positions:o,pins:o.map(([l])=>l)}}return{positions:Object.entries(r.positions??{}).filter(([,o])=>o&&typeof o.x=="number"&&typeof o.y=="number"),pins:Array.isArray(r.pins)?r.pins:[]}}catch{return e}}function fv(e,n){if(!(typeof window>"u"))try{const r={};for(const[i,o]of e)r[i]=o;for(const[i,o]of n)r[i]=o;window.localStorage.setItem(Ey,JSON.stringify({v:2,positions:r,pins:Array.from(n.keys())}))}catch{}}function K5(){if(typeof window>"u")return null;try{const e=window.localStorage.getItem(Ny);if(!e)return null;const n=JSON.parse(e);return typeof(n==null?void 0:n.x)!="number"||typeof(n==null?void 0:n.y)!="number"||typeof(n==null?void 0:n.zoom)!="number"?null:n}catch{return null}}function X5(e){if(!(typeof window>"u"))try{window.localStorage.setItem(Ny,JSON.stringify(e))}catch{}}function UE(){if(!(typeof window>"u")){try{window.localStorage.removeItem(Ey)}catch{}try{window.localStorage.removeItem(Ny)}catch{}}}function Q5(e,n){const r=e.agents.get(n);if(!r)return;const i=[];for(const d of e.agents.values())d.sessionId===n&&i.push(d);const o={schemaVersion:1,exportedAt:new Date().toISOString(),sessionId:n,label:r.label,cwd:r.cwd,startedAt:r.startedAt,endedAt:r.endedAt,model:r.model,agents:i.map(d=>({id:d.id,kind:d.kind,label:d.label,parentId:d.parentId,state:d.state,startedAt:d.startedAt,endedAt:d.endedAt,model:d.model,cwd:d.cwd,usage:d.usage,prompts:d.prompts,tools:d.tools.map(m=>({id:m.id,name:m.name,inputPreview:m.inputPreview,startedAt:m.startedAt,endedAt:m.endedAt,ok:m.ok,errorPreview:m.errorPreview,usage:m.usage}))}))},l=JSON.stringify(o,null,2),u=new Blob([l],{type:"application/json"}),c=URL.createObjectURL(u),h=document.createElement("a"),p=(r.label||"session").replace(/[^a-z0-9._-]/gi,"_");h.href=c,h.download=`${Gt}-${p}-${n.slice(0,8)}.json`,document.body.appendChild(h),h.click(),document.body.removeChild(h),setTimeout(()=>URL.revokeObjectURL(c),1e3)}const $v={file:"📁",shell:"⚡",web:"🌐",agent:"🤖",task:"📋",plan:"🧭",mcp:"🔌",other:"✨"},qv={file:"file",shell:"shell",web:"web",agent:"agent",task:"task",plan:"plan",mcp:"mcp",other:"other"},WT=EC;function Z5(e,n){if(!n)return null;const r=new Set([n]);let i=n;for(;i;){const l=e.agents.get(i);if(!(l!=null&&l.parentId)||r.has(l.parentId))break;r.add(l.parentId),i=l.parentId}let o=!0;for(;o;){o=!1;for(const l of e.agents.values())l.parentId&&r.has(l.parentId)&&!r.has(l.id)&&(r.add(l.id),o=!0)}return r}function J5(e,n,r,i,o,l,u,c,h,p,d,m,y,w,N,_,b,S,k){const E=[],T=[],I=new Set;if(l)for(const B of e.agents.values())S.has(B.id)&&DT(B,l)&&I.add(B.id);const O=qT(l,I.size);for(const B of e.agents.values()){if(!S.has(B.id))continue;const C=O&&!I.has(B.id),q=B.exitAt!=null,L=b!=null&&!b.has(B.id),re=[C?"rf-dim":"",q?"rf-exiting":"",L?"rf-spotlit-out":""].filter(Boolean).join(" ")||void 0,J=u.get(B.id);if(E.push({id:B.id,type:"agent",position:{x:0,y:0},data:{...B,now:n,onOpenContext:k},className:re,...J?{width:J.width,height:J.height}:null}),B.parentId&&S.has(B.parentId)){const W=ry(B.sessionId),Z=l&&!I.has(B.id)&&!I.has(B.parentId),M=q,G=_.size>0&&(_.has(B.id)||_.has(B.parentId)),K=b!=null&&!b.has(B.id)&&!b.has(B.parentId),$=B.state==="active"?2:1.5,Q=G?$+1.5:$,ne=Z||M?.2:K?.12:1,ae=["sess-edge",B.state==="active"?"sess-live":"sess-idle",M?"rf-edge-exiting":"",G?"rf-edge-selected":""].filter(Boolean).join(" ");T.push({id:`e:${B.parentId}->${B.id}`,source:B.parentId,target:B.id,animated:(B.state==="active"||G)&&!Z&&!M,type:"smoothstep",style:{"--session-hue":W,strokeWidth:Q,opacity:ne,transition:"var(--edge-transition)"},className:ae})}}const A=new Map;for(const B of e.agents.values())B.tools.length>0&&A.set(B.id,Math.min(4,B.tools.length));const U=`${w}#lanes:${r5(A)}`,z=E.filter(B=>p$(B.id,o,m,y));if(z.length>0||U!==N.current){if(z.length>0){const B=i5(E,T,{direction:"LR",pinned:o,measured:u,availableWidth:r,availableHeight:i,lanes:A});for(const C of B)MC(C.id,m,y)&&g$(C.id,C.position,m,y);a5(E,m,o,u,new Set(z.map(C=>C.id)),A)}o5(E,m,o,u,A),N.current=U}const P=l5(E,m,o,u,c,!p||d,A);P.length>0&&h(P),ru(m,e.agents),ru(y,e.agents),ru(o,e.agents),ru(u,h$(e.agents.values()));const D=[];let V=!1;for(const B of E){let C=o.get(B.id)??m.get(B.id);C||(C=m$(B.id,m,y),V=!0),D.push({...B,position:C})}return V&&(N.current=""),{nodes:D,edges:T}}function eF(){return g.jsx(ny,{children:g.jsx(tF,{})})}function tF(){var Va,Ga,Ya,Ka;const e=ja(),n=j.useRef(Rv()),[,r]=j.useState(0),i=j.useCallback(()=>r(H=>H+1),[]),[o,l]=j.useState(()=>new Set),[u,c]=j.useState(null),[h,p]=j.useState(null),d=j.useCallback((H,Y)=>{l(oe=>{if(!Y)return new Set([H]);const de=new Set(oe);return de.has(H)?de.delete(H):de.add(H),de}),c(oe=>Y&&oe===H?oe:H)},[]),m=j.useCallback(()=>{l(new Set),c(null)},[]),[y,w]=j.useState(null),[N,_]=j.useState(null),b=j.useCallback(H=>_(H),[]),[S,k]=j.useState(!1),E=j.useRef(G5()),[T,I]=j.useState(z5);j.useEffect(()=>{B5(T)},[T]);const[O,A]=j.useState(U5);j.useEffect(()=>{H5(O)},[O]);const[U,z]=j.useState(W5);j.useEffect(()=>{V5(U)},[U]);const[P,D]=j.useState(()=>{try{const H=window.localStorage.getItem(LE);return H===null?!0:H==="1"}catch{return!0}});j.useEffect(()=>{try{window.localStorage.setItem(LE,P?"1":"0")}catch{}},[P]);const[V,B]=j.useState(null),[C,q]=j.useState(!1),[L,re]=j.useState(0),[J,W]=j.useState(0);j.useEffect(()=>{fetch("/api/sound-hook").then(H=>H.ok?H.json():null).then(H=>{H!=null&&H.ok&&(B(H.enabled===!0),re((H.foreign??[]).filter(Y=>Y.worksHere).length),W(typeof H.parked=="number"?H.parked:0))}).catch(()=>{})},[]);const Z=j.useCallback(async()=>{q(!0);try{const Y=await(await fetch("/api/sound-hook",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({enabled:!V})})).json().catch(()=>null);Y!=null&&Y.ok&&B(Y.enabled===!0),fetch("/api/sound-hook").then(oe=>oe.ok?oe.json():null).then(oe=>{oe!=null&&oe.ok&&(re((oe.foreign??[]).filter(de=>de.worksHere).length),W(typeof oe.parked=="number"?oe.parked:0))}).catch(()=>{})}catch{}finally{q(!1)}},[V]),[M,G]=j.useState(!1),[K,$]=j.useState(null),[Q,ne]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem($E)??""}catch{return""}}),[ae,fe]=j.useState(!1),te=j.useRef(0),[ce,Ce]=j.useState(!1),ve=j.useCallback((H=!1)=>{H&&(te.current=Date.now(),Ce(!0)),fetch(H?"/api/version?refresh=1":"/api/version").then(Y=>Y.ok?Y.json():null).then(Y=>{Y&&$(Y)}).catch(()=>{}).finally(()=>{H&&Ce(!1)})},[]),je=j.useCallback(()=>{ve(Date.now()-te.current>=F5)},[ve]);j.useEffect(()=>{ve();const H=window.setInterval(je,5*6e4),Y=()=>{document.visibilityState==="visible"&&je()};return document.addEventListener("visibilitychange",Y),()=>{window.clearInterval(H),document.removeEventListener("visibilitychange",Y)}},[ve,je]),j.useEffect(()=>{M&&ve()},[M,ve]);const ye=(K==null?void 0:K.notice)??null,[Ee,Ye]=j.useState(null),[we,_e]=j.useState(Pv);j.useEffect(()=>{let H=!1;return fetch("/api/health").then(Y=>Y.ok?Y.json():null).then(Y=>{H||(_e(w5(Y)),!(!Y||typeof Y.workspace!="string")&&Ye(Y.workspace))}).catch(()=>{}),()=>{H=!0}},[M]);const Be=j.useRef(we);Be.current=we;const it=ye?`${ye.kind}:${ye.to}`:"",ft=ye!=null&&Q!==it,Ze=j.useCallback(()=>{if(!ye)return;const H=Q===it?"":it;ne(H);try{window.localStorage.setItem($E,H)}catch{}},[ye,it,Q]),[De,Je]=j.useState(()=>{if(typeof window>"u")return"";try{return window.localStorage.getItem(qE)??""}catch{return""}}),Xe=K!=null&&K.invokedAs&&K.invokedAs!==Gt?K.invokedAs:null,Mt=Xe!=null&&De!==Xe,lt=j.useCallback(()=>{if(Xe){Je(Xe);try{window.localStorage.setItem(qE,Xe)}catch{}}},[Xe]),Qe=((Va=K==null?void 0:K.upgrade)==null?void 0:Va.state)??"idle",Ot=n$(K==null?void 0:K.upgrade),zt=j.useCallback(async()=>{try{await fetch("/api/upgrade",{method:"POST"})}catch{}ve()},[ve]);j.useEffect(()=>{if(Qe!=="running")return;const H=window.setInterval(ve,3e3);return()=>window.clearInterval(H)},[Qe,ve]);const et=j.useCallback(async()=>{var oe;const H=K==null?void 0:K.command;if(!H)return;let Y=!1;try{Y=await Promise.race([((oe=navigator.clipboard)==null?void 0:oe.writeText(H).then(()=>!0))??Promise.resolve(!1),new Promise(de=>window.setTimeout(()=>de(!1),500))])}catch{Y=!1}if(!Y)try{const de=document.createElement("textarea");de.value=H,de.setAttribute("readonly",""),de.style.cssText="position:fixed;top:0;left:0;opacity:0",document.body.appendChild(de),de.select(),Y=document.execCommand("copy"),de.remove()}catch{Y=!1}Y&&(fe(!0),window.setTimeout(()=>fe(!1),1600))},[K==null?void 0:K.command]),bt=j.useCallback(()=>{I(H=>(H||D(!1),!H))},[]),ht=j.useCallback(()=>{D(H=>(H||I(!1),!H))},[]),[vt,hn]=j.useState(!1),[Yt,Pt]=j.useState(0),bn=j.useRef(null),[gr,Sn]=j.useState(!1),Bt=j.useRef(null),[Fn,pn]=j.useState(0),vr=j.useRef(x$()),[Hr,xi]=j.useState(!1),Wr=j.useCallback(()=>{const H=vr.current,Y=H.setPaused(!H.paused);for(const oe of Y)n.current=zx(n.current,oe);xi(H.paused)},[]),[ut,_i]=j.useState(Date.now()),[mn,Is]=j.useState(()=>{if(typeof window>"u")return!0;try{return window.localStorage.getItem(FE)!=="0"}catch{return!0}}),yr=j.useCallback(()=>{Is(H=>{const Y=!H;try{window.localStorage.setItem(FE,Y?"1":"0")}catch{}return Y})},[]),[zn,kn]=j.useState(!1),[Vr,Gr]=j.useState("restart"),[Yr,bi]=j.useState(null),sr=j.useRef(!1),Ms=j.useRef(null),En=j.useRef(0),wr=j.useCallback(async H=>{if(sr.current)return;const Y=(H==null?void 0:H.upgrade)===!0;sr.current=!0,Ms.current=Ot;const oe=++En.current;Gr(Y?"npx":"restart"),kn(!0);try{window.sessionStorage.setItem("agent-dag.restartPending",(ye==null?void 0:ye.to)??"")}catch{}try{await fetch("/api/restart",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({upgrade:Y})})}catch{}window.setTimeout(()=>{if(En.current===oe&&sr.current){sr.current=!1,kn(!1);try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}}},Y?18e4:3e4)},[ye==null?void 0:ye.to,Ot]),Os=j.useRef(null);j.useEffect(()=>{let H=!1;for(const oe of n.current.agents.values())if(oe.state==="active"){H=!0;break}const Y=s$({enabled:mn,kind:ye==null?void 0:ye.kind,canRestart:(K==null?void 0:K.canRestart)===!0,busy:H,idleSince:Os.current,now:ut});Os.current=Y.idleSince,Y.restart&&wr()},[mn,ye==null?void 0:ye.kind,K==null?void 0:K.canRestart,ut,wr]),j.useEffect(()=>{const H=K==null?void 0:K.running;let Y=null,oe=null;try{Y=window.sessionStorage.getItem("agent-dag.restartPending"),oe=window.sessionStorage.getItem(zE)}catch{return}const de=t$({bundle:"1.35.25",running:H,pending:Y,lastTried:oe});if(de==="reload"){try{window.sessionStorage.setItem(zE,H??"")}catch{return}window.location.reload();return}if(de!=="confirm")return;try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1),bi(H??null);const xe=window.setTimeout(()=>bi(null),6e3);return()=>window.clearTimeout(xe)},[K==null?void 0:K.running]),j.useEffect(()=>{if(zn&&r$({asked:Ms.current,reported:Ot})){try{window.sessionStorage.removeItem("agent-dag.restartPending")}catch{}sr.current=!1,kn(!1)}},[zn,Ot]);const Ps=j.useRef(Y5()).current;j.useRef(!1);const Tt=j.useRef(new Map(Ps.positions.filter(([H])=>Ps.pins.includes(H)))),xr=j.useRef(null),_r=j.useState(()=>K5())[0],[Kt,Kr]=j.useState(""),[Si,nt]=j.useState(()=>new Set),[br,Xr]=j.useState(E$),[Ls,Qr]=j.useState(!1),Zr=j.useRef(null);j.useEffect(()=>{document.documentElement.dataset.theme=br;try{window.localStorage.setItem(PC,br)}catch{}},[br]),j.useEffect(()=>{if(!_r)return;const H=window.setTimeout(()=>{try{e.setViewport(_r,{duration:0})}catch{}},60);return()=>window.clearTimeout(H)},[e,_r]);const $s=j.useRef(!0);j.useEffect(()=>{const H=new EventSource("/events"),Y=w$(i,{now:()=>Date.now(),setTimeout:(oe,de)=>window.setTimeout(oe,de),clearTimeout:oe=>window.clearTimeout(oe)});return H.addEventListener("open",()=>{G(!0),Qr(!0)}),H.addEventListener("error",()=>G(!1)),H.addEventListener("replay-end",()=>{$s.current=!1,Y.flush()}),H.addEventListener("hook",oe=>{try{const de=JSON.parse(oe.data);if(!vr.current.accept(de))return;n.current=zx(n.current,de),de.replay===!0||$s.current||Date.now()-de.receivedAt>3e4?Y.replay():Y.live()}catch{}}),()=>{H.close(),Y.cancel()}},[i]),j.useEffect(()=>{const H=setInterval(()=>{const Y=Date.now();_i(Y);let oe=gP(n.current,Y,Fx);vP(n.current,Y,Fx)&&(oe=!0),pP(n.current,Y,L5,$5)&&(oe=!0),mP(n.current,Y,q5,D5)&&(oe=!0),oe&&i()},250);return()=>clearInterval(H)},[i]);const ir=j.useRef(null),St=j.useRef(0),qs=420,pt=j.useCallback((H=500)=>{try{const Se=document.querySelector(".canvas-wrap"),Pe=Array.from(document.querySelectorAll(".react-flow__node")).filter(wt=>wt.offsetWidth>0);if(!Se||Pe.length===0)return;const Fe=Se.getBoundingClientRect(),Ge=e.getViewport();if(!Number.isFinite(Ge.zoom)||Ge.zoom<=0)return;const We=wt=>(wt-Fe.left-Ge.x)/Ge.zoom,ze=wt=>(wt-Fe.top-Ge.y)/Ge.zoom,Tn=Pe.map(wt=>wt.getBoundingClientRect()),Ys=Math.min(...Tn.map(wt=>We(wt.left))),Ao=Math.max(...Tn.map(wt=>We(wt.right))),Ks=Math.min(...Tn.map(wt=>ze(wt.top))),Io=Math.max(...Tn.map(wt=>ze(wt.bottom))),Xa=Ao-Ys,us=Io-Ks;if(!(Xa>0&&us>0))return;const Zt=Math.max(.2,Math.min(1,(Fe.width-160)/(Xa+qs)*.86,(Fe.height-160)/us*.86));e.setViewport({x:80-Ys*Zt,y:Math.max(80,(Fe.height-us*Zt)/2)-Ks*Zt,zoom:Zt},{duration:H}),St.current=Date.now(),window.setTimeout(()=>{try{const wt={x:80-Ys*Zt,y:Math.max(80,(Fe.height-us*Zt)/2)-Ks*Zt,zoom:Zt},Mo=e.getViewport();(Math.abs(Mo.zoom-Zt)>.01||Math.abs(Mo.x-wt.x)>2)&&e.setViewport(wt,{duration:0})}catch{}},H+60)}catch{}},[e]),ko=j.useRef(""),Eo=j.useRef(null),qa=j.useRef(0),Sr=j.useCallback(()=>{qa.current=Date.now()},[]),Jr="agent-dag.autoFitDisabled",gn=j.useRef((()=>{if(typeof window>"u")return!1;try{return window.localStorage.getItem(Jr)==="1"}catch{return!1}})()),[Ds,Da]=j.useState(gn.current),Fa=j.useCallback(()=>{if(!gn.current){gn.current=!0,Da(!0);try{window.localStorage.setItem(Jr,"1")}catch{}}},[]),No=j.useCallback(()=>{gn.current=!1,Da(!1);try{window.localStorage.removeItem(Jr)}catch{}pt(400)},[e,pt]);j.useEffect(()=>{const H=setInterval(()=>{if(gn.current||Date.now()-qa.current<800)return;const Y=n.current,oe=Date.now(),de=[];for(const We of Y.agents.values())Ov(We,oe)&&de.push({id:We.id});if(de.length===0)return;const xe=e.getViewport(),Se=window.innerWidth-360,Pe=window.innerHeight-52;let Fe=!1,Ge=!1;for(const{id:We}of de){const ze=or.current.get(We),Tn=Tt.current.get(We)??Xt.current.get(We);if(!ze||!Tn)continue;Ge=!0;const Ys=Tn.x*xe.zoom+xe.x,Ao=Tn.y*xe.zoom+xe.y,Ks=(Tn.x+ze.width)*xe.zoom+xe.x,Io=(Tn.y+ze.height)*xe.zoom+xe.y;if(Ks>0&&Ys<Se&&Io>0&&Ao<Pe){Fe=!0;break}}Ge&&!Fe&&pt(600)},1500);return()=>clearInterval(H)},[e]);const ki=j.useRef(!1),or=j.useRef(new Map),es=j.useRef(0),ec=j.useCallback(H=>{const Y=or.current;let oe=!1;for(const de of H.nodeInternals.values()){const xe=de.width,Se=de.height;if(xe==null||Se==null)continue;const Pe=Y.get(de.id);Pe?(Math.abs(Pe.height-Se)>4||Math.abs(Pe.width-xe)>4)&&(Y.set(de.id,{width:xe,height:Se}),oe=!0):(Y.set(de.id,{width:xe,height:Se}),oe=!0)}return oe&&(es.current+=1),es.current},[]),Ei=Ke(ec),[He,za]=j.useState(0);j.useEffect(()=>{let H=0;const Y=()=>{const de=or.current;let xe=!1;for(const Se of document.querySelectorAll(".react-flow__node[data-id]")){const Pe=Se.getAttribute("data-id");if(!Pe)continue;const Fe=Se.offsetWidth,Ge=Se.offsetHeight;if(!Fe||!Ge)continue;const We=de.get(Pe);(!We||Math.abs(We.width-Fe)>4||Math.abs(We.height-Ge)>4)&&(de.set(Pe,{width:Fe,height:Ge}),xe=!0)}xe&&za(Se=>Se+1)};if(ki.current)return;let oe=0;return document.visibilityState==="hidden"?oe=window.setTimeout(Y,32):H=requestAnimationFrame(Y),()=>{cancelAnimationFrame(H),window.clearTimeout(oe)}});const Xt=j.useRef(new Map(Ps.positions)),Co=j.useRef(new Set),Ni=j.useRef(""),kr=j.useMemo(()=>{const H=[];for(const Y of n.current.agents.values())Ov(Y,ut)&&H.push(Y.id+(Y.parentId?`>${Y.parentId}`:""));return H.sort(),`${H.join("|")}#sv${Ei}.${He}`},[n.current,n.current.lastSeq,ut,Ei,He]),ts=j.useRef(null);j.useEffect(()=>(ts.current!=null&&window.clearTimeout(ts.current),ts.current=window.setTimeout(()=>{fv(Xt.current,Tt.current)},1500),()=>{ts.current!=null&&window.clearTimeout(ts.current)}),[kr]),j.useEffect(()=>{if(ko.current===kr)return;const H=ko.current;if(ko.current=kr,!H||gn.current)return;Date.now()-St.current>1200&&pt(400),ir.current&&window.clearTimeout(ir.current),ir.current=window.setTimeout(()=>{gn.current||pt(500)},280)},[kr,e,pt]);const Fs=j.useMemo(()=>{if(o.size===0)return null;const H=new Set;for(const Y of o){const oe=Z5(n.current,Y);if(oe)for(const de of oe)H.add(de)}return H.size>0?H:null},[n.current,n.current.lastSeq,o]),Nn=j.useMemo(()=>c5(n.current,ut),[n.current,n.current.lastSeq,ut]),Bn=j.useRef(null),[vn,Un]=j.useState({w:0,h:0});j.useEffect(()=>{const H=Bn.current;if(!H||typeof ResizeObserver>"u")return;const Y=new ResizeObserver(oe=>{var xe;const de=(xe=oe[0])==null?void 0:xe.contentRect;de&&Un(Se=>Math.abs(Se.w-de.width)>40||Math.abs(Se.h-de.height)>40?{w:de.width,h:de.height}:Se)});return Y.observe(H),Un({w:H.clientWidth,h:H.clientHeight}),()=>Y.disconnect()},[]);const zs=j.useCallback(H=>{var oe,de;const Y=H.target;!(Y!=null&&Y.closest)||Y.closest(O5)!==H.currentTarget||(H.preventDefault(),(de=(oe=document.activeElement)==null?void 0:oe.blur)==null||de.call(oe))},[]),Bs=j.useRef(new Map),[Hn,tc]=j.useState(!1);j.useEffect(()=>{const H=window.setTimeout(()=>tc(!0),2500);return()=>window.clearTimeout(H)},[]);const[Ba,Er]=j.useState(!1),ar=j.useRef(null),[Ci,Us]=j.useState(!1),Ua=j.useCallback(()=>{ar.current&&(window.clearTimeout(ar.current),ar.current=null),Er(!1)},[]),nc=j.useCallback(H=>{H.length!==0&&queueMicrotask(()=>{Er(!0),ar.current&&window.clearTimeout(ar.current),ar.current=window.setTimeout(()=>Er(!1),P5+80)})},[]);j.useEffect(()=>()=>{ar.current&&window.clearTimeout(ar.current)},[]);const ns=vn.w>0?vn.w*.92:0,rs=vn.h>0?vn.h:0,{nodes:Qt,edges:Ti}=j.useMemo(()=>J5(n.current,ut,ns,rs,Tt.current,Kt,or.current,Bs.current,nc,Hn,Ci,Xt.current,Co.current,kr,Ni,o,Fs,Nn,b),[n.current,n.current.lastSeq,ut,ns,rs,Hn,Ci,Kt,kr,o,Fs,Nn,b,Yt]),Ha=j.useMemo(()=>{const H=new Map;for(const oe of Qt){const de=oe.data;if(!(de!=null&&de.sessionId)||de.exitAt!=null)continue;const xe=oe.width,Se=oe.height;if(xe==null||Se==null)continue;const Pe=oe.position.x,Fe=oe.position.y,Ge=Pe+xe,We=Fe+Se,ze=H.get(de.sessionId);ze?(ze.minX=Math.min(ze.minX,Pe),ze.minY=Math.min(ze.minY,Fe),ze.maxX=Math.max(ze.maxX,Ge),ze.maxY=Math.max(ze.maxY,We)):H.set(de.sessionId,{minX:Pe,minY:Fe,maxX:Ge,maxY:We})}const Y=[];for(const[oe,de]of H){const xe=de.maxX-de.minX+au*2,Se=de.maxY-de.minY+au*2;Y.push({id:`group:${oe}`,type:LT,position:{x:de.minX-au,y:de.minY-au},data:{sessionId:oe,w:xe,h:Se},width:xe,height:Se,style:{width:xe,height:Se},zIndex:-1,draggable:!0,selectable:!1,focusable:!1,deletable:!1,connectable:!1})}return Y},[Qt,ut]),rc=j.useMemo(()=>{const H=[...Ha,...Qt],Y=Bt.current;return!Y||Y.size===0?H:H.map(oe=>{const de=Y.get(oe.id);return de?{...oe,position:de}:oe})},[Ha,Qt,Fn]),Nr=j.useMemo(()=>{if(!Kt)return null;const H=new Set;for(const Y of n.current.agents.values())Nn.has(Y.id)&&DT(Y,Kt)&&H.add(Y.id);return H},[n.current,n.current.lastSeq,Kt,Nn]),Cn=j.useMemo(()=>T5(Kt,(Nr==null?void 0:Nr.size)??0,Nn.size),[Kt,Nr,Nn]),ss=j.useMemo(()=>{const H=new Set;for(const Y of n.current.agents.values())for(const oe of Y.tools)H.add(WT(oe.name));return Object.keys($v).filter(Y=>H.has(Y))},[n.current,n.current.lastSeq]);j.useEffect(()=>{if(ss.length<=1){Sn(!1);return}let H=0;const Y=()=>{const oe=bn.current;if(oe&&!document.hidden){const de=oe.getBoundingClientRect(),xe=Array.from(document.querySelectorAll(".react-flow__node, .tool-burst")).map(Pe=>Pe.getBoundingClientRect()),Se=f5(de,xe,8);Sn(Pe=>Pe===Se?Pe:Se)}H=window.setTimeout(Y,300)};return Y(),()=>window.clearTimeout(H)},[ss.length]);const is=j.useMemo(()=>{const H=new Map;for(const oe of n.current.agents.values())for(const de of oe.tools){if(!de.name.startsWith("mcp__"))continue;const xe=de.name.slice(5),Se=xe.indexOf("__"),Pe=Se>0?xe.slice(0,Se):xe;H.set(Pe,(H.get(Pe)??0)+1)}const Y=[];for(const[oe,de]of H){let xe=5381;for(let Se=0;Se<oe.length;Se++)xe=(xe<<5)+xe^oe.charCodeAt(Se);Y.push({server:oe,count:de,hue:Math.abs(xe)%360})}return Y.sort((oe,de)=>de.count-oe.count),Y},[n.current,n.current.lastSeq]),lr=j.useCallback(H=>{nt(Y=>{const oe=new Set(Y);return oe.has(H)?oe.delete(H):oe.add(H),oe})},[]),Rt=u?n.current.agents.get(u):null,os=h?Array.from(n.current.agents.values()).flatMap(H=>H.tools).find(H=>H.id===h)??null:null,To=j.useCallback(async()=>{try{await fetch("/api/clear",{method:"POST"})}catch{}n.current=Rv(),Tt.current.clear(),or.current.clear(),Xt.current.clear(),Ni.current="",UE(),m(),i()},[i,m]),Hs=j.useRef(S);Hs.current=S;const Ws=j.useRef(!1);Ws.current=os!=null||vt||N!=null||y!=null;const Vs=j.useCallback(H=>{const Y=o$(H,{confirmOpen:Hs.current,modalOpen:Ws.current});Y==="confirm"?k(!0):Y==="clear"&&(k(!1),To())},[To]),Lt=j.useCallback(()=>{Tt.current.clear(),Xt.current.clear(),Ni.current="",UE(),i(),window.setTimeout(()=>pt(500),80)},[i,e,pt]),Cr=j.useCallback(()=>pt(500),[pt]),as=j.useRef(Qt);as.current=Qt;const ls=j.useRef(u);ls.current=u;const Ro=j.useCallback(H=>{const Y=as.current,oe=l$(Y.map(Se=>({id:Se.id,x:Se.position.x,y:Se.position.y})),ls.current,H),de=oe?Y.find(Se=>Se.id===oe):void 0;if(!de)return;const xe=PE(document.activeElement);d(de.id,!1),window.setTimeout(()=>{try{e.fitView({padding:.35,duration:350,nodes:[de]})}catch{}St.current=Date.now(),xe&&M5(de.id)},30)},[d,e]),Ri=j.useCallback(H=>{d(H,!1),window.setTimeout(()=>{try{const Y=as.current.find(oe=>oe.id===H);Y&&e.fitView({padding:.3,duration:500,nodes:[Y]}),St.current=Date.now()}catch{}},60)},[d,e]);j.useEffect(()=>{const H=Y=>{var Fe,Ge,We;const oe=Y.target,de={tagName:oe==null?void 0:oe.tagName,isContentEditable:oe==null?void 0:oe.isContentEditable,role:(Fe=oe==null?void 0:oe.getAttribute)==null?void 0:Fe.call(oe,"role"),type:oe==null?void 0:oe.type};if(Y.key==="Escape"){const ze=LP({overlayOpen:Eu.depth()>0,typing:sy(de)});ze==="dismiss"?Eu.dismissTop():ze==="blur"?oe==null||oe.blur():(f$(de)&&(oe==null||oe.blur()),m());return}if(bC(Y))return;const xe=PE(oe)?(Ge=oe==null?void 0:oe.getAttribute)==null?void 0:Ge.call(oe,"data-id"):null,Se=xe&&as.current.some(ze=>ze.id===xe)?xe:null,Pe=c$(Y,Se);if(Pe.kind==="activate"){Y.preventDefault(),d(Pe.nodeId,Pe.additive);return}if(Pe.kind!=="node"&&!(Pe.nodeId==null&&HP(de))){if(Y.key==="/"){Y.preventDefault(),(We=Zr.current)==null||We.focus();return}Y.key===" "&&(Y.preventDefault(),Wr()),(Y.key==="c"||Y.key==="C")&&Vs("shortcut"),(Y.key==="r"||Y.key==="R")&&Lt(),(Y.key==="f"||Y.key==="F")&&Cr(),(Y.key==="l"||Y.key==="L")&&bt(),(Y.key==="h"||Y.key==="H")&&hn(ze=>!ze),(Y.key==="u"||Y.key==="U")&&z(ze=>!ze),(Y.key==="a"||Y.key==="A")&&Be.current.claude&&ht(),(Y.key==="j"||Y.key==="J")&&Ro(1),(Y.key==="k"||Y.key==="K")&&Ro(-1),(Y.key==="t"||Y.key==="T")&&Xr(ze=>ze==="dark"?"light":"dark")}};return window.addEventListener("keydown",H),()=>window.removeEventListener("keydown",H)},[Vs,Lt,Cr,m,d,Ro,Wr]);const Tr=n.current.agents.size,Gs=new Set(Array.from(n.current.agents.values()).map(H=>H.sessionId)).size,tn=j.useMemo(()=>e3(n.current.agents.values()),[n.current,n.current.lastSeq]),jo=j.useMemo(()=>t3(n.current.agents.values()),[n.current,n.current.lastSeq]),Wa=j.useRef(null);j.useEffect(()=>{const H=N$({waiting:tn.length,running:jo}),Y=Wa.current;if(Wa.current=H,(Y==null?void 0:Y.title)!==H.title&&(document.title=H.title),(Y==null?void 0:Y.icon)!==H.icon){const oe=document.querySelector('link[rel="icon"]');oe&&(oe.href=C$[H.icon])}},[tn.length,jo]);const[sc,ic]=j.useState(""),ji=R$(tn);j.useEffect(()=>{ic(H=>j$(H,ji))},[ji]);const nn=j.useMemo(()=>{let H=0,Y=0,oe=0,de=0,xe=0,Se=0,Pe=0,Fe=0,Ge=0;for(const We of n.current.agents.values()){H+=We.usage.inputTokens,Y+=We.usage.outputTokens,oe+=We.usage.cacheReadTokens,de+=We.usage.cacheCreateTokens;const ze=dn(We.usage,We.model);xe+=ze.total,Se+=ze.input,Pe+=ze.output,Fe+=ze.cacheRead,Ge+=ze.cacheWrite}return{inT:H,outT:Y,cacheR:oe,cacheC:de,sum:H+Y,cost:{total:xe,input:Se,output:Pe,cacheRead:Fe,cacheWrite:Ge}}},[n.current,n.current.lastSeq]);return g.jsxs("div",{className:"app",children:[g.jsx("a",{className:"skip-link",href:"#canvas",children:"Skip to the canvas"}),g.jsxs("header",{className:"topbar",children:[g.jsxs("div",{className:"brand",children:[g.jsx("span",{className:"logo"}),g.jsx("h1",{children:Gt}),ye?g.jsxs("button",{type:"button",className:"v stale",onClick:Ze,"aria-label":v5({...ye,open:ft}),title:ye.kind==="restart"?`Running v${ye.from}; v${ye.to} is installed on disk. Restart to pick it up.`:`Running v${ye.from}; v${ye.to} is on npm.`,children:["v",ye.from,g.jsx("span",{className:"v-dot","aria-hidden":!0})]}):(()=>{const H={running:(K==null?void 0:K.running)??"1.35.25",latest:K==null?void 0:K.latest,latestPending:K==null?void 0:K.latestPending,checkedAgo:K!=null&&K.checkedAt?Lv(ut-K.checkedAt):null,checkDisabled:K==null?void 0:K.checkDisabled,checking:ce};return g.jsxs("button",{type:"button",className:ce?"v checking":"v",onClick:()=>ve(!0),"aria-busy":ce||void 0,"aria-label":g5(H),title:m5(H),children:["v",H.running]})})()]}),Rt&&(()=>{const H=dn(Rt.usage,Rt.model),Y=Math.max(0,((Rt.endedAt??ut)-Rt.startedAt)/1e3),oe=Rt.state==="active"?ku(H.total,Y):null,de=o.size-1;return g.jsxs("button",{type:"button",className:"selected-ribbon",title:`Fit view to ${Rt.label}`,onClick:()=>{try{const xe=Qt.find(Se=>Se.id===Rt.id);xe&&e.fitView({padding:.35,duration:500,nodes:[xe]}),St.current=Date.now()}catch{}},children:[g.jsx("span",{className:`state-pill state-${Rt.state}`,children:Rt.state==="active"?"live":Rt.state}),g.jsx("span",{className:"selected-label",children:Rt.label}),H.total>0&&g.jsxs("span",{className:"selected-cost",children:[qe(H.total),oe?g.jsxs("span",{className:"selected-rate",children:[" · ",oe]}):null]}),de>0&&g.jsxs("span",{className:"selected-extra",children:["+",de]}),g.jsx("span",{"aria-hidden":!0,className:"selected-close",onClick:xe=>{xe.stopPropagation(),m()},children:"×"})]})})(),g.jsxs("div",{className:"actions",children:[g.jsxs("div",{className:"search",children:[g.jsx("span",{className:"search-icon","aria-hidden":!0,children:"⌕"}),g.jsx("input",{ref:Zr,type:"text",placeholder:R5,value:Kt,onChange:H=>Kr(H.target.value),spellCheck:!1,"aria-label":"Filter the graph"}),Kt?g.jsx("button",{className:"search-clear","aria-label":"Clear search",onClick:()=>Kr(""),children:"×"}):g.jsx("kbd",{className:"search-kbd","aria-hidden":!0,children:"/"}),Cn.count&&g.jsx("span",{className:`search-count${Cn.empty?" none":""}`,"aria-live":"polite",title:`${Cn.count} agents on the canvas match “${Kt}”`,children:Cn.count})]}),g.jsxs("span",{className:"status",children:[(()=>{const H=N5({connected:M,paused:Hr,held:vr.current.size});return g.jsx("span",{className:`pill ${H.tone}`,title:H.title,children:H.label})})(),g.jsxs("span",{className:"stat",title:b5(we),children:[g.jsx("span",{className:"count",children:Gs}),g.jsx("span",{className:"lbl",children:"sessions"})]}),g.jsxs("span",{className:"stat",title:"Total agents (root + subagents)",children:[g.jsx("span",{className:"count",children:Tr}),g.jsx("span",{className:"lbl",children:"agents"})]}),g.jsxs("span",{className:"stat",title:S5(we),children:[g.jsx("span",{className:"count",children:n.current.totalEvents}),g.jsx("span",{className:"lbl",children:"events"})]}),nn.sum>0&&g.jsxs("span",{className:"stat",title:`in:${nn.inT.toLocaleString()} out:${nn.outT.toLocaleString()} cache-r:${nn.cacheR.toLocaleString()} cache-c:${nn.cacheC.toLocaleString()}`,children:[g.jsx("span",{className:"count",children:Dt(nn.sum)}),g.jsx("span",{className:"lbl",children:"tokens"})]}),is.length>0&&g.jsxs("span",{className:"stat mcp-legend",title:`MCP servers seen this session:
73
73
  ${is.map(H=>` ${H.server}: ${H.count} call${H.count===1?"":"s"}`).join(`
74
74
  `)}`,children:[is.slice(0,6).map(H=>g.jsx("span",{className:"mcp-dot",style:{"--mcp-hue":H.hue}},H.server)),is.length>6&&g.jsxs("span",{className:"mcp-more",children:["+",is.length-6]}),g.jsx("span",{className:"lbl",children:"mcp"})]}),nn.cost.total>0&&(()=>{let H=0,Y=0;for(const xe of n.current.agents.values()){if(xe.state!=="active")continue;const Se=dn(xe.usage,xe.model);H+=Se.total,Y=Math.max(Y,((xe.endedAt??ut)-xe.startedAt)/1e3)}const oe=Y>0?ku(H,Y):null,de=`input ${qe(nn.cost.input)} + output ${qe(nn.cost.output)} + cache r ${qe(nn.cost.cacheRead)} + cache w ${qe(nn.cost.cacheWrite)}${oe?`
75
75
  active burn: ${oe}`:""}`;return g.jsxs("span",{className:"stat",title:de,children:[g.jsx("span",{className:"count",children:qe(nn.cost.total)}),g.jsxs("span",{className:"lbl",children:["cost",oe?` · ${oe}`:""]})]})})()]}),g.jsx("div",{className:"vis-hidden",role:"status","aria-atomic":"true",children:sc}),tn.length>0&&g.jsxs("button",{type:"button",className:"waiting-stat",onClick:()=>Ri(tn[0].id),title:`Blocked waiting for you — click to go to the one that has been stuck longest:
@@ -40,7 +40,7 @@
40
40
  document.documentElement.setAttribute("data-theme", stored === "light" ? "light" : "dark");
41
41
  })();
42
42
  </script>
43
- <script type="module" crossorigin src="/assets/index-jfKKRYet.js"></script>
43
+ <script type="module" crossorigin src="/assets/index-DE0KYVY3.js"></script>
44
44
  <link rel="stylesheet" crossorigin href="/assets/index-hLBidJXz.css">
45
45
  </head>
46
46
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-dag",
3
- "version": "1.35.23",
3
+ "version": "1.35.25",
4
4
  "description": "Live deck of Claude Code and Codex agents — watch tool calls, token spend and every Claude Code subagent on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,6 +18,13 @@
18
18
  // rather than pasted together. Getting this wrong is not a degraded feature:
19
19
  // the throw escaped the retry path and took the whole process down on Windows
20
20
  // before the server ever started.
21
+ //
22
+ // Going through cmd.exe then raises a question a direct spawn never has to ask:
23
+ // under what NAME. A `.cmd` shim finds its own payload relative to `%~dp0`, so a
24
+ // bare name — which carries no directory — makes it look under the deck's
25
+ // working directory instead of its own. Every batch candidate is therefore
26
+ // launched by its full path where one can be found; see shimPath and
27
+ // candidateSpec.
21
28
  import { execFile, spawn } from "node:child_process";
22
29
  import { existsSync } from "node:fs";
23
30
 
@@ -29,8 +36,17 @@ const WIN_EXTS = [".exe", ".cmd", ".bat", ""];
29
36
  // free, and these run on a poll.
30
37
  const resolved = new Map();
31
38
 
32
- function candidates(cmd) {
33
- if (process.platform !== "win32") return [cmd];
39
+ /**
40
+ * The spellings to try for `cmd`, best first.
41
+ *
42
+ * Exported with the platform as a parameter for the reason everything else in
43
+ * this file is: the Windows answer decides which candidate becomes a batch one,
44
+ * and a batch candidate is the only kind #457 touches — so a test that wants to
45
+ * follow a caller's bare name all the way to the command line cmd.exe receives
46
+ * has to be able to ask for the Windows list from a machine that is not Windows.
47
+ */
48
+ export function candidates(cmd, platform = process.platform) {
49
+ if (platform !== "win32") return [cmd];
34
50
  // An explicit extension is respected as given.
35
51
  if (/\.[a-z]+$/i.test(cmd)) return [cmd];
36
52
  const known = resolved.get(cmd);
@@ -184,6 +200,46 @@ export function shimPath(name, {
184
200
  export const spawnSpec = (file, args, platform = process.platform) =>
185
201
  isBatch(file, platform) ? viaCmd(file, args) : { file, args, opts: {} };
186
202
 
203
+ /**
204
+ * The same thing for ONE CANDIDATE SPELLING out of the list above — which on
205
+ * Windows means deciding the NAME the shim is launched under before deciding
206
+ * how, because those are not the same question.
207
+ *
208
+ * `spawnSpec` answers "how". This answers what #457 put in front of it. A batch
209
+ * candidate runs THROUGH cmd.exe (see viaCmd), and a `.cmd` shim locates its own
210
+ * payload relative to `%~dp0` — the drive and path of the command token cmd.exe
211
+ * was handed. A bare `claude.cmd` carries no directory at all, so `%~dp0` came
212
+ * out as the deck's WORKING DIRECTORY and the shim went hunting for its
213
+ * JavaScript under whatever folder the deck happened to be started from. #456
214
+ * proved exactly that for ccusage's `npm.cmd` and `npx.cmd`; it left the three
215
+ * helpers below alone, and they carry the shims the panels depend on — the
216
+ * `claude.cmd` behind the quota poll and the sign-in, and whatever `.cmd` a
217
+ * Python installer left for cswap. Same defect, same machine, wider blast
218
+ * radius.
219
+ *
220
+ * `?? raw` is the whole safety story and is not optional: when shimPath can see
221
+ * no layout it answers null, and the candidate stays the bare name today's code
222
+ * already uses, so nothing that works now can start failing. It is the same
223
+ * `?? name` ccusage.mjs and npx.mjs spell, so the repo has one rule rather than
224
+ * three. shimPath also refuses any name that already carries a directory, which
225
+ * is what keeps a caller's own absolute candidate — quotaClaudeBin's
226
+ * `%APPDATA%\npm\claude.cmd`, cswapCandidates' `~/.local/bin/cswap.exe` — from
227
+ * being re-rooted somewhere else entirely.
228
+ *
229
+ * `launch` comes back beside the spec because looksMissing has to be told the
230
+ * spelling cmd.exe was ACTUALLY GIVEN rather than the one the loop started
231
+ * from; its own header explains what breaks otherwise, and that coupling is the
232
+ * reason #456 stopped short of doing this.
233
+ *
234
+ * On POSIX `isBatch` is false, so no lookup happens, no filesystem is touched,
235
+ * `launch` is `raw`, and the spec is the object spawnSpec always returned —
236
+ * byte-identical, which is the point.
237
+ */
238
+ export function candidateSpec(raw, args, platform = process.platform, deps) {
239
+ const launch = isBatch(raw, platform) ? (shimPath(raw, deps) ?? raw) : raw;
240
+ return { ...spawnSpec(launch, args, platform), launch };
241
+ }
242
+
187
243
  /**
188
244
  * Stop a child AND everything it started.
189
245
  *
@@ -277,8 +333,30 @@ const sameCommand = (quoted, name) => {
277
333
  * command it could not find, that name must be the candidate we asked for — a
278
334
  * tool that shells out itself can forward the message about some other command.
279
335
  *
280
- * `name` is the candidate spelling that produced the output. Callers that only
281
- * have the text (failureText) omit it and get the shape rules alone.
336
+ * `name` is the spelling cmd.exe was ACTUALLY GIVEN which since #457 is the
337
+ * shim's absolute path whenever shimPath found one, not the bare candidate the
338
+ * loop started from. That distinction is the coupling #456 named as its reason
339
+ * for stopping short, and it is a one-way trap rather than a detail: cmd.exe
340
+ * echoes the command token back exactly as it received it, so a check against
341
+ * the bare name stops matching the instant the token becomes a path. What that
342
+ * costs is not a cosmetic mismatch — it is the honesty of the whole answer. A
343
+ * shim that shimPath saw and that is gone by the time cmd.exe looks for it (a
344
+ * stale memo, an uninstall mid-session, a network drive that dropped, a roaming
345
+ * profile still syncing) would come back as an ordinary exit 1 whose stderr is
346
+ * cmd.exe's two-line "is not recognized / operable program or batch file."
347
+ * instead of the `code: "ENOENT"` every panel keys its "not installed" message
348
+ * off. The user would be told their CLI failed, and shown half a sentence about
349
+ * batch files, when the truthful answer is that it is not there.
350
+ *
351
+ * Feeding it the launch spelling keeps the comparison EXACT, which is what the
352
+ * paragraph above is protecting: matching loosely — on the basename, say —
353
+ * would let a tool that shells out itself have its own child's "is not
354
+ * recognized" read as the tool's absence, re-running a command that may be
355
+ * `cswap remove 3`. So the rule is not "compare less", it is "compare against
356
+ * what was actually asked for".
357
+ *
358
+ * Callers that only have the text (failureText) omit it and get the shape rules
359
+ * alone.
282
360
  */
283
361
  export function looksMissing(text, name = "") {
284
362
  const lines = String(text ?? "").split(/\r?\n/).map(l => l.trim()).filter(Boolean);
@@ -324,9 +402,10 @@ export function run(cmd, args, { timeout = 20_000, maxBuffer = 4 << 20, env } =
324
402
  return resolve({ ok: false, code: "ENOENT", killed: false, timedOut: false, stdout: "", stderr: "" });
325
403
  }
326
404
  const raw = tries[i];
327
- const { file, args: argv, opts } = isBatch(raw)
328
- ? viaCmd(raw, args)
329
- : { file: raw, args, opts: {} };
405
+ // `launch` is what cmd.exe is handed and `raw` is what the loop is
406
+ // reasoning about; on Windows those differ for a batch candidate whose
407
+ // shim was found (#457) and are the same everywhere else.
408
+ const { file, args: argv, opts, launch } = candidateSpec(raw, args);
330
409
 
331
410
  const tree = isBatch(raw);
332
411
  let timer = null, timedOut = false;
@@ -354,8 +433,14 @@ export function run(cmd, args, { timeout = 20_000, maxBuffer = 4 << 20, env } =
354
433
  // be a shell's verdict rather than the tool's own words — spawned
355
434
  // directly, a missing file is a plain ENOENT and anything printed came
356
435
  // from a tool that ran.
357
- const missing = Boolean(err) && tree && looksMissing(`${stderr ?? ""}\n${stdout ?? ""}`, raw);
436
+ const missing = Boolean(err) && tree && looksMissing(`${stderr ?? ""}\n${stdout ?? ""}`, launch);
358
437
  if (err && (tryNext(err) || missing) && i + 1 < tries.length) return attempt(i + 1);
438
+ // The CANDIDATE is what gets remembered, never the resolved path. The
439
+ // memo is the only entry `candidates` offers afterwards, so recording an
440
+ // absolute path would pin this process to one install location for its
441
+ // whole life — an upgrade that moves the shim would then fail forever
442
+ // where today it simply gets found again. Re-running the lookup per
443
+ // attempt costs a handful of stats against a process spawn.
359
444
  if (!err) resolved.set(cmd, raw);
360
445
  resolve({
361
446
  ok: !err,
@@ -475,7 +560,10 @@ export function runInteractive(cmd, args, { timeout = 300_000, maxOutput = 256 <
475
560
  const attempt = (i) => {
476
561
  if (i >= tries.length) return finish(-1, { code: "ENOENT" });
477
562
  const raw = tries[i];
478
- const { file, args: argv, opts } = isBatch(raw) ? viaCmd(raw, args) : { file: raw, args, opts: {} };
563
+ // Same split as in `run`: `launch` is the spelling cmd.exe receives an
564
+ // absolute `.cmd` once shimPath can see one — and `raw` stays the candidate
565
+ // the loop and the memo are about.
566
+ const { file, args: argv, opts, launch } = candidateSpec(raw, args);
479
567
  let proc;
480
568
  try {
481
569
  proc = spawn(file, argv, { stdio: ["pipe", "pipe", "pipe"], shell: false, windowsHide: true, ...opts });
@@ -523,7 +611,7 @@ export function runInteractive(cmd, args, { timeout = 300_000, maxOutput = 256 <
523
611
  // batch candidate, which is the only kind launched through a shell, and
524
612
  // to output that is cmd.exe's message alone — everything below re-runs
525
613
  // the whole command, and these commands remove accounts.
526
- if (code !== 0 && isBatch(raw) && looksMissing(`${stderr}\n${stdout}`, raw)) {
614
+ if (code !== 0 && isBatch(raw) && looksMissing(`${stderr}\n${stdout}`, launch)) {
527
615
  if (i + 1 < tries.length) {
528
616
  stdout = ""; stderr = ""; pending = "";
529
617
  child = null;
@@ -569,9 +657,11 @@ export function runDetached(cmd, args) {
569
657
  const attempt = (i) => {
570
658
  if (i >= tries.length) return;
571
659
  const raw = tries[i];
572
- const { file, args: argv, opts } = isBatch(raw)
573
- ? viaCmd(raw, args)
574
- : { file: raw, args, opts: {} };
660
+ // Nothing here reads output, so there is no looksMissing call to keep
661
+ // honest — but the shim still has to be launched by its full path, or the
662
+ // detached `cswap list` this exists for computes `%~dp0` from the deck's cwd
663
+ // exactly like every other caller.
664
+ const { file, args: argv, opts } = candidateSpec(raw, args);
575
665
  try {
576
666
  const child = spawn(file, argv, { stdio: "ignore", shell: false, windowsHide: true, ...opts });
577
667
  child.on("error", (err) => { if (tryNext(err)) attempt(i + 1); });
@@ -66,6 +66,16 @@ let persistPath = null; // absolute path to events.jsonl, or null
66
66
  // same way. A session is recorded unless we have been told someone else owns
67
67
  // it, so a lone deck — and a deck the hook is too old to flag — still writes
68
68
  // everything.
69
+ //
70
+ // THIS COVERS THE CLAUDE SIDE ONLY, and that is worth stating because reading it
71
+ // as the general answer is what produced #447. The only thing that ever fills
72
+ // the set is noteLogWriter, called from handleEventIngest — a hook POST. Codex
73
+ // events are read off the rollout files inside this process and never reach an
74
+ // HTTP handler, and Codex hooks are not installed any more, so a Codex session
75
+ // id cannot get in here and writesLogFor answers "mine" for every one of them on
76
+ // every deck. The Codex half is decided by writesCodexLog in the watcher's scan
77
+ // loop instead, and every event derived from a rollout — including the memory
78
+ // scan's ContextObserved — has to carry that verdict explicitly.
69
79
  const foreignSessions = new Set(); // session ids another deck is logging
70
80
  const MAX_FOREIGN_SESSIONS = 512; // bound: insertion order = oldest first
71
81
 
@@ -738,8 +748,27 @@ const pendingCodexMemoryReads = new Set();
738
748
  * session happened first, on a panel whose whole purpose is to say what is in
739
749
  * the window. ContextModal says so in the slot those counts would have used;
740
750
  * see codex-approval.ts for the same move on a different unanswerable question.
751
+ *
752
+ * WHY `persist` IS A PARAMETER (#447). Every other event the rollout watcher
753
+ * produces goes out through emitCodexEvent, which carries the per-batch verdict
754
+ * of writesCodexLog: several decks tailing one rollout all DRAW it, and exactly
755
+ * one of them appends it to the events.jsonl they share. This function pushed
756
+ * with no opts at all, so pushEvent fell back to writesLogFor — and that answers
757
+ * from `foreignSessions`, a set only ever filled by noteLogWriter off an
758
+ * incoming hook POST marked `?persist=0`. A Codex rollout never touches an HTTP
759
+ * handler and Codex hooks are not installed any more (installer.mjs keeps the
760
+ * provider for uninstall only), so a Codex session id can never appear in that
761
+ * set and every deck answered "yes, mine" for this one event. The caller already
762
+ * holds the verdict for the whole batch, so it is threaded in rather than
763
+ * re-derived: recomputing it here would cost a second directory listing and
764
+ * could disagree with the roots and tool calls the same batch just emitted.
765
+ *
766
+ * Omitting the argument keeps the old behaviour — write. That is the same
767
+ * fail-safe writesCodexLog itself takes when a deck cannot find its own
768
+ * discovery record: a line written twice is recoverable, a deck that quietly
769
+ * records nothing is not.
741
770
  */
742
- function maybeResolveCodexMemory(sid, cwd) {
771
+ function maybeResolveCodexMemory(sid, cwd, persist) {
743
772
  if (!sid || !cwd) return;
744
773
  if (pendingCodexMemoryReads.has(sid)) return;
745
774
  const now = Date.now();
@@ -754,12 +783,16 @@ function maybeResolveCodexMemory(sid, cwd) {
754
783
  // would only ever overwrite a real one with nothing. A repo that grows its
755
784
  // first AGENTS.md mid-session is picked up by the next throttled pass.
756
785
  if (!memoryFiles.length) return;
786
+ // `persist` false means another deck tailing this same rollout was elected
787
+ // to record it. The event is still buffered and broadcast from here, so
788
+ // every deck's context modal lists the AGENTS.md files — it is only the
789
+ // second copy on disk that is dropped, exactly as emitCodexEvent does it.
757
790
  pushEvent({
758
791
  hook_event_name: "ContextObserved",
759
792
  session_id: sid,
760
793
  provider: "codex",
761
794
  context: { memoryFiles },
762
- }, "internal");
795
+ }, "internal", { persist });
763
796
  })
764
797
  .catch(() => {})
765
798
  .finally(() => pendingCodexMemoryReads.delete(sid));
@@ -1452,7 +1485,13 @@ async function codexScanOnce(firstRun) {
1452
1485
  // existing so a session the deck has decided not to draw does not cost a
1453
1486
  // directory walk, and repeated rather than done once at root creation so
1454
1487
  // an AGENTS.md written after the session started is still found (#399).
1455
- if (state.rootEmitted) maybeResolveCodexMemory(state.sid, state.cwd);
1488
+ //
1489
+ // Carries the same `persist` verdict as every emit in the loop above, and
1490
+ // for the same reason: this is one more event about this batch of appended
1491
+ // lines, and a batch whose roots and tool calls went to one deck's log
1492
+ // while its memory list went to every deck's is the split the election
1493
+ // exists to prevent (#447).
1494
+ if (state.rootEmitted) maybeResolveCodexMemory(state.sid, state.cwd, persist);
1456
1495
  }
1457
1496
 
1458
1497
  // Rollout files fall out of the newest-2-days listing and never come back,