@qiaolei81/copilot-session-viewer 0.3.8 → 0.3.9
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/server.min.js +88 -63
- package/package.json +1 -1
- package/public/js/homepage.min.js +8 -8
- package/public/js/session-detail.min.js +94 -21
- package/public/js/time-analyze.min.js +18 -40
- package/views/index.ejs +8 -1
- package/views/session-vue.ejs +145 -10
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
(()=>{var{createApp:
|
|
2
|
-
`);try{await navigator.clipboard.writeText(d),$.value="\u2705 Copied!"}catch{let r=document.createElement("textarea");r.value=d,r.style.position="fixed",r.style.opacity="0",document.body.appendChild(r),r.select(),document.execCommand("copy"),document.body.removeChild(r),$.value="\u2705 Copied!"}setTimeout(()=>{$.value="\u{1F4CA} Copy as Mermaid Gantt"},2e3)},D={"tool.execution_start":{color:"#d29922",shape:"diamond",label:"Tool Start"},"tool.execution_complete":{color:"#e3b341",shape:"diamond",label:"Tool Complete"},"assistant.message":{color:"#8b949e",shape:"circle",label:"Message"},"user.message":{color:"#79c0ff",shape:"square",label:"User Message"},"session.start":{color:"#56d364",shape:"square",label:"Session Start"},"session.resume":{color:"#56d364",shape:"square",label:"Session Resume"},"session.error":{color:"#f85149",shape:"triangle",label:"Error"},"session.truncation":{color:"#f0883e",shape:"triangle",label:"Truncation"},"session.compaction_start":{color:"#a371f7",shape:"square",label:"Compaction Start"},"session.compaction_complete":{color:"#bc8cff",shape:"square",label:"Compaction End"},"session.model_change":{color:"#f778ba",shape:"square",label:"Model Change"},abort:{color:"#ff7b72",shape:"triangle",label:"Abort"}},V=new Set(Object.keys(D)),W=e=>{if(e==null||e<0)return"\u2014";if(e<1e3)return Math.round(e)+"ms";let t=e/1e3;if(t<60){let o=Math.round(t*10)/10;return(o%1===0?Math.round(o):o.toFixed(1))+"s"}let a=Math.floor(t/60),s=Math.floor(t%60);return a<60?a+"m "+s+"s":Math.floor(a/60)+"h "+a%60+"m"},qe=e=>{if(!e)return"";let t=new Date(e);return String(t.getHours()).padStart(2,"0")+":"+String(t.getMinutes()).padStart(2,"0")+":"+String(t.getSeconds()).padStart(2,"0")},Ne=e=>e?new Date(e).toLocaleString():"",A=v(()=>{if(!b.value.length)return null;for(let e of b.value){let t=e.timestamp||e.snapshot?.timestamp;if(t)return new Date(t).getTime()}return null}),G=v(()=>{if(!b.value.length)return null;for(let e=b.value.length-1;e>=0;e--){let t=b.value[e],a=t.timestamp||t.snapshot?.timestamp;if(a)return new Date(a).getTime()}return null}),_=v(()=>!A.value||!G.value?0:G.value-A.value),S=v(()=>[...b.value].sort((e,t)=>{let a=e.timestamp?new Date(e.timestamp).getTime():0,s=t.timestamp?new Date(t.timestamp).getTime():0;return a!==s?a-s:(e._fileIndex??0)-(t._fileIndex??0)})),z=v(()=>{let e=S.value,t=new Set;for(let o of e)if(o.type==="subagent.started"){let i=o.data?.toolCallId;i&&t.add(i)}let a=new Map;for(let o of e)o.id&&a.set(o.id,o);let s=new Map,n=new Map;for(let o of e){if(o.type!=="tool.execution_start")continue;let i=o.parentId,d=0;for(;i&&d<10;){let l=a.get(i);if(!l)break;if(l.type==="assistant.message"){let r=l.data?.parentToolCallId;if(r&&t.has(r)){s.set(o.id,r);let c=o.data?.toolCallId;c&&n.set(c,r)}break}i=l.parentId,d++}}for(let o of e){if(o.type!=="tool.execution_complete")continue;let i=o.data?.toolCallId;i&&n.has(i)&&s.set(o.id,n.get(i))}return s}),B=v(()=>{let e=S.value,t=[],a=[];for(let n of e)if(n.type==="subagent.started")a.push(n);else if(n.type==="subagent.completed"||n.type==="subagent.failed"){let o=n.data?.toolCallId,i=-1;if(o){for(let f=a.length-1;f>=0;f--)if(a[f].data?.toolCallId===o){i=f;break}}i<0&&a.length>0&&(i=a.length-1);let d=i>=0?a.splice(i,1)[0]:null,l=d?.data?.agentDisplayName||d?.data?.agentName||"SubAgent",r=d?new Date(d.timestamp).getTime():null,c=new Date(n.timestamp).getTime(),m=r?c-r:null,p=d?.data?.toolCallId,u=0,g=[];if(d)for(let f of e){f.type==="tool.execution_start"&&p&&z.value.get(f.id)===p&&u++;let w=new Date(f.timestamp).getTime();w>=r&&w<=c&&V.has(f.type)&&(f.type!=="tool.execution_start"&&f.type!=="tool.execution_complete"?g.push({type:f.type,timestamp:w,data:f.data}):p&&z.value.get(f.id)===p&&g.push({type:f.type,timestamp:w,data:f.data}))}let T=Q(g,r,m);t.push({name:l,status:n.type==="subagent.completed"?"completed":"failed",startTime:d?.timestamp||null,endTime:n.timestamp,duration:m,toolCalls:u,innerEventMarkers:T})}let s=e.length>0?new Date(e[e.length-1].timestamp).getTime():Date.now();for(let n of a){let o=n.data?.agentDisplayName||n.data?.agentName||"SubAgent",i=new Date(n.timestamp).getTime(),d=s-i,l=n.data?.toolCallId,r=0,c=[];for(let p of e){p.type==="tool.execution_start"&&l&&z.value.get(p.id)===l&&r++;let u=new Date(p.timestamp).getTime();u>=i&&u<=s&&V.has(p.type)&&(p.type!=="tool.execution_start"&&p.type!=="tool.execution_complete"?c.push({type:p.type,timestamp:u,data:p.data}):l&&z.value.get(p.id)===l&&c.push({type:p.type,timestamp:u,data:p.data}))}let m=Q(c,i,d);t.push({name:o,status:"incomplete",startTime:n.timestamp,endTime:e[e.length-1]?.timestamp||n.timestamp,duration:d,toolCalls:r,innerEventMarkers:m})}return t.sort((n,o)=>{let i=n.startTime?new Date(n.startTime).getTime():0,d=o.startTime?new Date(o.startTime).getTime():0;return i-d})}),Re=v(()=>Math.max(...B.value.map(e=>e.duration||0),1)),Le=v(()=>{let e=B.value,t=e.filter(r=>r.status==="completed").length,a=e.filter(r=>r.status==="failed").length,s=e.filter(r=>r.status==="incomplete").length,n=e.length?(t/e.length*100).toFixed(0):100,o=e.filter(r=>r.startTime&&r.endTime).map(r=>[new Date(r.startTime).getTime(),new Date(r.endTime).getTime()]).sort((r,c)=>r[0]-c[0]),i=[];for(let[r,c]of o)!i.length||r>=i[i.length-1].e?i.push({s:r,e:c}):c>i[i.length-1].e&&(i[i.length-1].e=c);let d=i.reduce((r,c)=>r+(c.e-c.s),0),l=e.reduce((r,c)=>r+(c.toolCalls||0),0);return{completed:t,failed:a,incomplete:s,totalTime:d,totalTools:l,successRate:n}}),Q=(e,t,a)=>{if(!e.length||!a)return[];let s=new Set(["session.start","session.resume","session.error","session.truncation","session.compaction_start","session.compaction_complete","session.model_change","abort","user.message"]),n=[],o=[];for(let u of e)s.has(u.type)?n.push(u):o.push(u);let i=n.map(u=>{let g=(u.timestamp-t)/a*100,T=D[u.type]||{};return{type:u.type,position:Math.max(0,Math.min(100,g)),color:T.color||"#8b949e",shape:T.shape||"circle",label:T.label||u.type,timestamp:u.timestamp,toolName:u.data?.toolName||null}}),d=300*1e3,l=Math.max(d,a/20),r=new Map;for(let u of o){let g=Math.floor((u.timestamp-t)/l);r.has(g)||r.set(g,[]),r.get(g).push(u)}let c=u=>{let g=Math.round(210+38*u),T=Math.round(153+-72*u),f=Math.round(34+39*u);return"rgb("+g+","+T+","+f+")"},m=u=>u.type==="tool.execution_complete"&&(u.data?.isError||!!u.data?.error),p=[];for(let[u,g]of r){let f=(t+(u+.5)*l-t)/a*100,w=Math.max(0,Math.min(100,f)),q=g.filter(m).length,pe=g.filter(y=>y.type==="tool.execution_complete").length,k=pe>0?q/pe:0;if(g.length===1){let y=g[0],N=D[y.type]||{},ge=m(y)?"#f85149":N.color||"#8b949e";p.push({type:y.type,position:w,color:ge,shape:N.shape||"circle",label:m(y)?(N.label||y.type)+" (error)":N.label||y.type,timestamp:y.timestamp,toolName:y.data?.toolName||null})}else{let y={};g.forEach(R=>{let j=(D[R.type]||{}).label||R.type;y[j]=(y[j]||0)+1}),q>0&&(y.Errors=q);let N=Object.entries(y).map(([R,O])=>O+" "+R),ge=k>0?c(k):(()=>{let R=g.reduce((O,j)=>{let Se=g.filter(tt=>tt.type===j.type).length;return Se>O.cnt?{type:j.type,cnt:Se}:O},{type:g[0].type,cnt:0}).type;return(D[R]||{}).color||"#8b949e"})();p.push({type:"cluster",position:w,color:ge,shape:"cluster",label:N.join(", "),count:g.length,items:g})}}return[...i,...p].sort((u,g)=>u.position-g.position)},F=(e,t,a)=>{let s=a-t,n=[],o={},i=0;for(let c of e){let m=new Date(c.timestamp).getTime();if(m>=t&&m<=a)if(c.type.startsWith("tool."))c.id&&z.value.has(c.id)||(V.has(c.type)&&n.push({type:c.type,timestamp:m,data:c.data}),c.type==="tool.execution_start"&&i++,o.tool=(o.tool||0)+1);else{V.has(c.type)&&n.push({type:c.type,timestamp:m,data:c.data});let p="other";c.type.startsWith("assistant.")?p="message":c.type.startsWith("user.")?p="user":c.type.startsWith("session.")&&(p="session"),o[p]=(o[p]||0)+1}}let d=[];i&&d.push(i+" tool"+(i>1?"s":"")),o.message&&d.push(o.message+" message"+(o.message>1?"s":"")),o.user&&d.push(o.user+" user msg"),o.session&&d.push(o.session+" session event"+(o.session>1?"s":"")),o.other&&d.push(o.other+" other");let l=d.length?d.join(", "):"idle",r=Q(n,t,s);return{itemType:"agent-op",name:"Main Agent",summary:l,toolCalls:i,startTime:new Date(t).toISOString(),endTime:new Date(a).toISOString(),duration:s,eventCounts:o,innerEventMarkers:r}},ee=v(()=>{let e=B.value;if(!e.length)return[];let t=S.value,a=[];for(let s=0;s<e.length;s++){let n=e[s];if(s===0&&n.startTime){let l=A.value,r=new Date(n.startTime).getTime();r-l>500&&a.push(F(t,l,r))}a.push({...n,itemType:"subagent"});let o=e[s+1],i=new Date(n.endTime).getTime(),d=o?new Date(o.startTime).getTime():G.value;d-i>500&&a.push(F(t,i,d))}return a}),te=v(()=>{try{let e=S.value,t=e.filter(s=>s.type==="assistant.message"),a=e.filter(s=>s.type==="user.message");return t.map((s,n)=>{let o=s.timestamp;if(!o)return console.warn("[turnAnalysis] Message without timestamp:",s),null;let i=new Date(o).getTime();if(isNaN(i))return console.warn("[turnAnalysis] Invalid timestamp:",o,s),null;let d=t[n+1],r=(d?new Date(d.timestamp).getTime():G.value||i)-i,c=e.indexOf(s),m=e.slice(0,c).reverse().find(f=>f.type==="user.message"),p=m?a.indexOf(m)+1:0,u="",g=s.data?.message&&s.data.message.trim()!=="";g?u=ve(s.data.message):s.data?.tools&&s.data.tools.length>0?u=`Tool calls: ${s.data.tools.map(w=>w.name||"unknown").join(", ")}`:u="(empty assistant message)";let T=s.data?.tools?.length||0;return{turnId:s.id??`msg-${n}`,userReqNumber:p,message:ve(m?.data?.message||m?.data?.content||m?.data?.transformedContent||""),displayText:u,hasText:g,startTime:s.timestamp,endTime:d?.timestamp||b.value[b.value.length-1]?.timestamp,duration:r,toolCalls:T}}).filter(s=>s!==null)}catch(e){return console.error("[turnAnalysis] Error:",e),Z.value="Error analyzing turns: "+e.message,[]}}),Pe=v(()=>Math.max(...te.value.map(e=>e.duration||0),1)),ye=v(()=>{let e=new Map;for(let t of te.value){let a=t.userReqNumber||0;e.has(a)||e.set(a,{userReqNumber:a,message:t.message,turns:[]}),e.get(a).turns.push(t)}return Array.from(e.values()).sort((t,a)=>t.userReqNumber-a.userReqNumber)}),x=v(()=>{let e=S.value,t=new Map;for(let s of e)if(s.type==="tool.execution_start"){let n=s.data?.toolCallId;n&&t.set(n,{start:s})}else if(s.type==="tool.execution_complete"){let n=s.data?.toolCallId;n&&t.has(n)&&(t.get(n).complete=s)}let a=[];return t.forEach((s,n)=>{let o=new Date(s.start.timestamp).getTime(),i=s.complete?new Date(s.complete.timestamp).getTime():null,d=i?i-o:null,l=s.start.data?.toolName||s.start.data?.tool||"unknown",r=s.start.data?.arguments||{},c=s.complete?.data?.isError||!!s.complete?.data?.error,m="";l==="Bash"||l==="bash"||l==="exec"?m=r.command||r.description||"":["Read","read","Write","write","Edit","edit"].includes(l)?m=r.file_path||r.path||"":["Glob","glob"].includes(l)||["Grep","grep"].includes(l)?m=r.pattern||"":["Task","task"].includes(l)?m=r.description||r.prompt?.substring(0,80)||"":m=r.description||r.command||r.file_path||r.path||r.query||r.url||"",m.length>120&&(m=m.substring(0,120)+"..."),a.push({toolId:n,toolName:l,description:m,startTime:s.start.timestamp,endTime:s.complete?.timestamp||null,duration:d,isError:c,isRunning:!s.complete})}),a}),Ge=v(()=>{let e=[...x.value];return e.sort((t,a)=>{if(I.value==="duration")return M.value==="asc"?(t.duration||0)-(a.duration||0):(a.duration||0)-(t.duration||0);if(I.value==="toolName"){let o=(t.toolName||"").localeCompare(a.toolName||"");return M.value==="asc"?o:-o}let s=new Date(t.startTime).getTime(),n=new Date(a.startTime).getTime();return M.value==="asc"?s-n:n-s}),e}),ze=v(()=>Math.max(...x.value.map(e=>e.duration||0),1)),be=v(()=>{let e=["view","read","write","edit","create","glob","grep","notebookedit"],t={copilot_readfile:"read",copilot_createfile:"write",copilot_createdirectory:"write",copilot_findfiles:"search",copilot_findtextinfiles:"search",copilot_listdirectory:"read",textedit:"edit",copilot_replacestring:"edit",copilot_multireplacestring:"edit"},a=[];for(let s of b.value)if(s.type==="tool.execution_start"){let n=s.data?.toolName?.toLowerCase()||"",o=s.data?.arguments||{},i=o.path||o.file||o.directory||o.pattern||"";if(e.includes(n)){if(i){let d="other";n==="view"||n==="read"?d="read":n==="write"||n==="notebookedit"||n==="create"?d="write":n==="edit"?d="edit":(n==="glob"||n==="grep")&&(d="search"),a.push({toolName:s.data?.toolName||n,opType:d,filePath:i,timestamp:s.timestamp,startTime:s.timestamp})}}else if(t[n]){let d=t[n];a.push({toolName:s.data?.toolName||n,opType:d,filePath:i||"(implicit)",timestamp:s.timestamp,startTime:s.timestamp})}}return a.sort((s,n)=>new Date(s.startTime)-new Date(n.startTime))}),Be=v(()=>{let e=be.value;return{uniqueCount:new Set(e.map(a=>a.filePath)).size,totalOps:e.length,reads:e.filter(a=>a.opType==="read").length,writes:e.filter(a=>a.opType==="write").length,edits:e.filter(a=>a.opType==="edit").length,searches:e.filter(a=>a.opType==="search").length}}),Te=v(()=>{let e={};return x.value.forEach(t=>{let a=(t.toolName||"unknown").toLowerCase(),s;["bash","exec"].includes(a)?s="Bash/Exec":["read"].includes(a)?s="Read":["write"].includes(a)?s="Write":["edit"].includes(a)?s="Edit":["glob"].includes(a)?s="Glob":["grep"].includes(a)?s="Grep":["task"].includes(a)?s="Task (SubAgent)":["web_search","websearch"].includes(a)?s="Web Search":["web_fetch","webfetch"].includes(a)?s="Web Fetch":s=t.toolName||"Other",e[s]||(e[s]={category:s,totalTime:0,count:0,errors:0}),e[s].totalTime+=t.duration||0,e[s].count++,t.isError&&e[s].errors++}),Object.values(e).sort((t,a)=>a.count-t.count)}),Fe=v(()=>Math.max(...Te.value.map(e=>e.totalTime),1)),se=v(()=>{let e=x.value.filter(n=>n.duration&&n.startTime&&n.endTime).map(n=>({start:new Date(n.startTime).getTime(),end:new Date(n.endTime).getTime()})).sort((n,o)=>n.start-o.start);if(!e.length)return 0;let t=0,a=e[0].start,s=e[0].end;for(let n=1;n<e.length;n++)e[n].start<=s?s=Math.max(s,e[n].end):(t+=s-a,a=e[n].start,s=e[n].end);return t+=s-a,t}),nt=v(()=>{let e=0,t={};for(let a of b.value)if(a.type==="tool.execution_complete"&&a.data?.toolTelemetry?.metrics){let s=a.data.toolTelemetry.metrics.resultForLlmLength||0;e+=s;let n=a.data.toolName||"unknown";t[n]||(t[n]=0),t[n]+=s}return{total:e,byCategory:t}}),ae=v(()=>{let e=S.value,t=[];for(let a=0;a<e.length-1;a++){let s=e[a],n=e[a+1],o=new Date(s.timestamp).getTime(),d=new Date(n.timestamp).getTime()-o;if(d<100)continue;let l=null,r="";s.type==="user.message"&&n.type==="assistant.turn_start"?(l="input-consumption",r=`LLM reading user input (${(s.data?.message||"").length} chars)`):s.type==="assistant.turn_start"&&n.type==="assistant.message"?(l="llm-generation",r=`LLM generating response (${(n.data?.content||"").length} chars output)`):s.type==="assistant.turn_start"&&n.type==="tool.execution_start"?(l="llm-generation",r=`LLM deciding to call ${n.data?.toolName||"unknown"}`):s.type==="assistant.message"&&n.type==="assistant.turn_start"?(l="turn-gap",r="Gap between assistant response and next turn"):s.type==="tool.execution_complete"&&d>500?(l="post-tool",r=`Processing ${s.data?.toolName||"unknown"} result`):d>5e3&&(l="idle",r=`${s.type} \u2192 ${n.type}`),l&&t.push({type:l,description:r,startTime:s.timestamp,endTime:n.timestamp,duration:d,fromEvent:s.type,toEvent:n.type,fromData:s.data,toData:n.data})}return t.sort((a,s)=>(s.duration||0)-(a.duration||0))}),Oe=v(()=>Math.max(...ae.value.map(e=>e.duration||0),1)),je=v(()=>{let e={"input-consumption":{count:0,total:0,avg:0},"llm-generation":{count:0,total:0,avg:0},"post-tool":{count:0,total:0,avg:0},"turn-gap":{count:0,total:0,avg:0},idle:{count:0,total:0,avg:0}};return ae.value.forEach(t=>{e[t.type]&&(e[t.type].count++,e[t.type].total+=t.duration)}),Object.keys(e).forEach(t=>{e[t].count>0&&(e[t].avg=e[t].total/e[t].count)}),e}),$e=v(()=>{let e=x.value.length;if(e===0)return 100;let t=x.value.filter(a=>a.isError).length;return((e-t)/e*100).toFixed(1)}),Ue=v(()=>x.value.filter(e=>e.isError).length),Ve=v(()=>{let e=S.value,t=0;for(let o=0;o<e.length-1;o++){let i=e[o],d=e[o+1];if(d.type==="user.message"&&i.type!=="user.message"){let l=new Date(d.timestamp).getTime()-new Date(i.timestamp).getTime();l>1e3&&(t+=l)}}let a=_.value||0,s=Math.max(a-t,0),n=Math.max(s-se.value,0);return{userThinkingTime:t,agentWorkingTime:s,llmTime:n,userThinkingPct:a>0?(t/a*100).toFixed(0):0,agentWorkingPct:a>0?(s/a*100).toFixed(0):0,llmPct:a>0?(n/a*100).toFixed(0):0,toolPct:a>0?(se.value/a*100).toFixed(0):0}}),ne=v(()=>x.value.length),We=v(()=>ne.value?x.value.reduce((t,a)=>t+(a.duration||0),0)/ne.value:0),He=v(()=>x.value.length?x.value.reduce((e,t)=>(t.duration||0)>(e.duration||0)?t:e):null),oe=v(()=>{let e=S.value;if(e.some(n=>n.data?.source==="vscode"))return!0;let a=e.some(n=>n.type==="assistant.message"&&n.data?.subAgentName),s=e.some(n=>n.type==="subagent.started"||n.type==="subagent.completed"||n.type==="subagent.failed");return a&&!s}),we=v(()=>{if(!oe.value)return[];let e=S.value,t=new Map;for(let a=0;a<e.length;a++){let s=e[a];if(s.type==="assistant.message"&&s.data?.subAgentName){let n=s.data.subAgentId||s.data.subAgentName;t.has(n)||t.set(n,{name:s.data.subAgentName,events:[],toolCount:0,firstIndex:a,status:"completed",subAgentId:s.data.subAgentId});let o=t.get(n);o.events.push(s),s.data.tools&&Array.isArray(s.data.tools)&&(o.toolCount+=s.data.tools.length),(s.data.error||s.data.status==="error")&&(o.status="failed")}}return Array.from(t.values()).sort((a,s)=>a.firstIndex-s.firstIndex)}),ie=v(()=>{let e=[],t=ye.value,a=B.value,s=S.value;if(oe.value){let n=we.value,o=[];for(let i=0;i<s.length;i++)s[i].type==="user.message"&&o.push({event:s[i],sortedIndex:i});if(o.length>0&&n.length>0)for(let i=0;i<o.length;i++){let{event:d,sortedIndex:l}=o[i],r=o[i+1]?o[i+1].sortedIndex:1/0,c=n.filter(u=>u.firstIndex>=l&&u.firstIndex<r),m=c.reduce((u,g)=>u+g.toolCount,0),p=d.data?.message||d.data?.content||"";e.push({rowType:"user-req",userReqNumber:i+1,message:typeof p=="string"?p.substring(0,120):String(p).substring(0,120),toolCount:m,sequenceIndex:l,isSequenceEstimated:!0,duration:m});for(let u of c)e.push({rowType:"subagent",itemType:"subagent",name:u.name,status:u.status,toolCount:u.toolCount,sequenceIndex:u.firstIndex,isSequenceEstimated:!0,duration:u.toolCount,indented:!0})}else if(n.length>0)for(let i of n)e.push({rowType:"subagent",itemType:"subagent",name:i.name,status:i.status,toolCount:i.toolCount,sequenceIndex:i.firstIndex,isSequenceEstimated:!0,duration:i.toolCount});return e}if(t.length)for(let n=0;n<t.length;n++){let o=t[n],i=o.turns;if(!i.length)continue;let d=new Date(i[0].startTime).getTime(),l=new Date(i[i.length-1].endTime).getTime();e.push({rowType:"user-req",userReqNumber:o.userReqNumber,message:o.message,startTime:i[0].startTime,endTime:i[i.length-1].endTime,duration:l-d});let r=a.filter(c=>{if(!c.startTime)return!1;let m=new Date(c.startTime).getTime();return m>=d&&m<=l});if(r.length)for(let c=0;c<r.length;c++){let m=r[c],p=c===0?d:new Date(r[c-1].endTime).getTime(),u=new Date(m.startTime).getTime();if(u-p>500){let g=F(s,p,u);g.rowType="main-agent",e.push(g)}if(e.push({...m,rowType:"subagent",itemType:"subagent"}),c===r.length-1){let g=new Date(m.endTime).getTime(),T=l;if(T-g>500){let f=F(s,g,T);f.rowType="main-agent",e.push(f)}}}else if(l-d>0){let c=F(s,d,l);c.rowType="main-agent",e.push(c)}}else if(ee.value.length)for(let n of ee.value)e.push({...n,rowType:n.itemType==="agent-op"?"main-agent":"subagent"});return e}),Ye=(e,t)=>{if(!A.value||!_.value||!e)return{left:"0%",width:"0%"};let a=new Date(e).getTime(),s=t?new Date(t).getTime():a+1e3,n=(a-A.value)/_.value*100,o=Math.max((s-a)/_.value*100,.5);return{left:n+"%",width:Math.min(o,100-n)+"%"}},re=e=>{let t=ie.value;if(t.length===0)return{left:"0%",width:"0%"};if(e.rowType==="user-req"){let c=t.findIndex(f=>f===e);if(c===-1)return{left:"0%",width:"0%"};let m=[];for(let f=c+1;f<t.length&&t[f].rowType!=="user-req";f++)t[f].rowType==="subagent"&&m.push(t[f]);if(m.length===0){let w=t.filter(k=>k.rowType!=="user-req").reduce((k,y)=>k+(y.toolCount||0),0);if(w===0)return{left:"0%",width:"0%"};let q=0;for(let k=0;k<c;k++)t[k].rowType==="subagent"&&(q+=t[k].toolCount||0);return{left:q/w*100+"%",width:Math.max(1,1/w*100)+"%"}}let p=re(m[0]),u=re(m[m.length-1]),g=parseFloat(p.left),T=parseFloat(u.left)+parseFloat(u.width);return{left:g+"%",width:T-g+"%"}}if(t.findIndex(c=>c===e)===-1)return{left:"0%",width:"0%"};let s=t.filter(c=>c.rowType!=="user-req"),n=s.reduce((c,m)=>c+(m.toolCount||0),0);if(n===0)return{left:"0%",width:"0%"};let o=s.findIndex(c=>c===e);if(o===-1)return{left:"0%",width:"0%"};let i=0;for(let c=0;c<o;c++)i+=s[c].toolCount||0;let d=i/n*100,l=e.toolCount||0,r=Math.max(l/n*100,2);return{left:d+"%",width:Math.min(r,100-d)+"%"}},Ze=e=>{I.value===e?M.value=M.value==="asc"?"desc":"asc":(I.value=e,M.value=e==="duration"?"desc":"asc")},Xe=e=>I.value!==e?"\u2195":M.value==="asc"?"\u2191":"\u2193",Ke=e=>{let t=(e||"").toLowerCase();return["bash","exec"].includes(t)?"badge-bash":t==="read"?"badge-read":t==="write"||t==="notebookedit"?"badge-write":t==="edit"?"badge-edit":t==="glob"||t==="grep"?"badge-search":t==="task"?"badge-subagent":"badge-other"},Je=e=>({read:"badge-read",write:"badge-write",edit:"badge-edit",create:"badge-create",search:"badge-search"})[e]||"badge-other";Ce(async()=>{try{let e=await fetch("/api/sessions/"+C.value+"/events");if(!e.ok)throw new Error("Failed to load events: "+e.statusText);let t=await e.json();console.log("[TIME-ANALYZE] Loaded events:",t.length),console.log("[TIME-ANALYZE] Event types:",[...new Set(t.map(a=>a.type))]),console.log("[TIME-ANALYZE] Turn starts:",t.filter(a=>a.type==="assistant.turn_start").length),console.log("[TIME-ANALYZE] User messages:",t.filter(a=>a.type==="user.message").length),b.value=t.sort((a,s)=>{let n=a.timestamp?new Date(a.timestamp).getTime():0,o=s.timestamp?new Date(s.timestamp).getTime():0;return n!==o?n-o:(a._fileIndex??0)-(s._fileIndex??0)}),console.log("[TIME-ANALYZE] Events set, length:",b.value.length)}catch(e){console.error("[TIME-ANALYZE] Error loading events:",e),Z.value=e.message}finally{E.value=!1}});let le=h("not_started"),ce=h(null),H=h(null),de=h(0),Y=null,Qe=v(()=>L.value?marked.parse(L.value):""),xe=async()=>{try{let t=await(await fetch(`/session/${C.value}/insight`)).json();le.value=t.status,t.status==="completed"?(L.value=t.report,P.value=null,J.value=t.generatedAt,me()):t.status==="generating"?(P.value=t.log||null,H.value=t.startedAt,ce.value=t.lastUpdate,de.value=t.ageMs,ue(),Vue.nextTick(()=>{let a=document.getElementById("insight-log");a&&(a.scrollTop=a.scrollHeight)})):t.status==="timeout"&&(P.value=t.log||null,H.value=t.startedAt,ce.value=t.lastUpdate,de.value=t.ageMs,ue())}catch(e){console.error("Failed to check insight:",e)}},ue=()=>{me(),Y=setInterval(xe,2e3)},me=()=>{Y&&(clearInterval(Y),Y=null)},ke=async(e=!1)=>{X.value=!0,K.value=null,P.value=null;try{let t=await fetch(`/session/${C.value}/insight`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({force:e})});if(!t.ok){let s=await t.json();throw new Error(s.error||"Failed to generate insight")}let a=await t.json();le.value=a.status,a.status==="generating"?(H.value=a.startedAt,ue()):a.status==="completed"&&(L.value=a.report,J.value=a.generatedAt)}catch(t){K.value=t.message}finally{X.value=!1}},et=async()=>{await ke(!0)};return Ce(async()=>{await xe()}),at(()=>{me()}),{sessionId:C,metadata:fe,events:b,loading:E,error:Z,activeTab:Ae,sortField:I,sortDir:M,insightReport:L,insightLog:P,insightLoading:X,insightError:K,insightGeneratedAt:J,insightStatus:le,insightLastUpdate:ce,insightStartedAt:H,insightAgeMs:de,renderedInsight:Qe,generateInsight:ke,regenerateInsight:et,formatDuration:W,formatTime:qe,formatDateTime:Ne,sessionStart:A,sessionEnd:G,totalDuration:_,subagentAnalysis:B,maxSubagentDuration:Re,subagentTimelineItems:ee,subagentStats:Le,EVENT_MARKER_CATEGORIES:D,showMarkerLegend:Ee,copyLabel:$,copyTimelineMarkdown:_e,ganttCrosshairX:U,ganttCrosshairTime:he,onGanttMouseMove:Ie,onGanttMouseLeave:De,turnAnalysis:te,maxTurnDuration:Pe,groupedTurns:ye,unifiedTimelineItems:ie,toolAnalysis:x,sortedToolAnalysis:Ge,maxToolDuration:ze,fileOperations:be,fileStats:Be,toolTimeByCategory:Te,maxCategoryTime:Fe,totalToolTime:se,totalToolCount:ne,avgToolDuration:We,longestTool:He,successRate:$e,errorCount:Ue,timeBreakdown:Ve,gapAnalysis:ae,maxGapDuration:Oe,gapStats:je,ganttPosition:Ye,ganttSequencePosition:re,toggleSort:Ze,sortIcon:Xe,getToolBadgeClass:Ke,getOpBadgeClass:Je,isVSCodeSession:oe,vsCodeSubagents:we}},template:`
|
|
1
|
+
(()=>{var it=(y,f)=>()=>(f||y((f={exports:{}}).exports,f),f.exports);var xe=it((gt,V)=>{function we(y){if(!y||typeof y!="object")return 0;let f=Number.isFinite(y.inputTokens)?y.inputTokens:0,T=Number.isFinite(y.cacheReadTokens)?y.cacheReadTokens:0,S=Number.isFinite(y.cacheWriteTokens)?y.cacheWriteTokens:0;return Math.max(f-T-S,0)}function rt(y){if(!y||typeof y!="object")return null;let f=Number.isFinite(y.cacheReadTokens)?y.cacheReadTokens:0,T=we(y)+f;return f===0||T===0?null:Math.round(f/T*100)}typeof V<"u"&&V.exports&&(V.exports={getDisplayInputTokens:we,getCacheHitRatio:rt})});var{getDisplayInputTokens:lt,getCacheHitRatio:ct}=xe(),{createApp:dt,ref:b,computed:v,onMounted:Me,onUnmounted:ut}=Vue,Se=dt({setup(){let y=b(window.__PAGE_DATA.sessionId),f=b(window.__PAGE_DATA.metadata),T=b([]),S=b(!0),Z=b(null),Ee=b("timeline"),C=b("timestamp"),E=b("asc"),L=b(null),q=b(null),X=b(!1),K=b(null),J=b(null),Ae=b(!1),O=b("\u{1F4CA} Copy as Mermaid Gantt"),me=e=>e?typeof e=="string"?e:Array.isArray(e)?e.map(t=>t.text||t.content||"").join(" "):typeof e=="object"&&e.text?e.text:String(e):"",U=b(null),pe=b(""),Ie=e=>{let t=e.currentTarget,s=t.querySelector(".gantt-bar-area");if(!s)return;let a=s.getBoundingClientRect(),n=t.getBoundingClientRect(),r=a.left-n.left,l=r+a.width,d=e.clientX-n.left;if(d>=r&&d<=l){U.value=d;let i=(d-r)/a.width,o=I.value+i*_.value,c=new Date(o),m=String(c.getHours()).padStart(2,"0"),p=String(c.getMinutes()).padStart(2,"0"),u=String(c.getSeconds()).padStart(2,"0");pe.value=m+":"+p+":"+u}else U.value=null},Ce=()=>{U.value=null},De=async()=>{let e=fe.value;if(!e.length)return;let t=i=>i?new Date(i).getTime():0,s=i=>(i||"").replace(/[`\n\r]/g,"").replace(/[:;#]/g,"-").replace(/\s+/g," ").trim().substring(0,100),a=i=>i?typeof i=="string"?i:Array.isArray(i)?i.map(o=>o.text||o.content||"").join(" "):typeof i=="object"&&i.text?i.text:String(i):"",n={},r=i=>{let o=i.replace(/[^a-zA-Z0-9]/g,"_").substring(0,30);return n[o]?(n[o]++,o+"_"+n[o]):(n[o]=1,o)},l=[];l.push("```mermaid"),l.push("gantt"),l.push(" title Session Timeline \u2013 "+s(y.value)),l.push(" dateFormat x"),l.push(" axisFormat %H:%M:%S"),l.push("");for(let i of e)if(i.rowType==="user-req"){let o=s(a(i.message)||"No message").substring(0,40),c="UserReq "+i.userReqNumber+" \u2013 "+o+" ("+W(i.duration)+")",m=r("userreq_"+i.userReqNumber),p=t(i.startTime),u=t(i.endTime);l.push(" "+c+" :milestone, "+m+", "+p+", "+u)}else if(i.rowType==="subagent"){let o=t(i.startTime),c=t(i.endTime),m=(i.toolCalls??0)+" tools",p=s(i.name)+" \u2013 "+W(i.duration)+" ("+m+")",u=r(i.name),g=i.status==="failed"?"crit, ":i.status==="incomplete"?"active, ":"";l.push(" "+p+" :"+g+u+", "+o+", "+c)}else if(i.rowType==="main-agent"){let o=t(i.startTime),c=t(i.endTime),m=s(i.summary||"idle"),p="Main Agent \u2013 "+W(i.duration)+" ("+m+")",u=r("main_agent");l.push(" "+p+" :"+u+", "+o+", "+c)}l.push("```"),l.push("");let d=l.join(`
|
|
2
|
+
`);try{await navigator.clipboard.writeText(d),O.value="\u2705 Copied!"}catch{let o=document.createElement("textarea");o.value=d,o.style.position="fixed",o.style.opacity="0",document.body.appendChild(o),o.select(),document.execCommand("copy"),document.body.removeChild(o),O.value="\u2705 Copied!"}setTimeout(()=>{O.value="\u{1F4CA} Copy as Mermaid Gantt"},2e3)},D={"tool.execution_start":{color:"#d29922",shape:"diamond",label:"Tool Start"},"tool.execution_complete":{color:"#e3b341",shape:"diamond",label:"Tool Complete"},"assistant.message":{color:"#8b949e",shape:"circle",label:"Message"},"user.message":{color:"#79c0ff",shape:"square",label:"User Message"},"session.start":{color:"#56d364",shape:"square",label:"Session Start"},"session.resume":{color:"#56d364",shape:"square",label:"Session Resume"},"session.error":{color:"#f85149",shape:"triangle",label:"Error"},"session.truncation":{color:"#f0883e",shape:"triangle",label:"Truncation"},"session.compaction_start":{color:"#a371f7",shape:"square",label:"Compaction Start"},"session.compaction_complete":{color:"#bc8cff",shape:"square",label:"Compaction End"},"session.model_change":{color:"#f778ba",shape:"square",label:"Model Change"},abort:{color:"#ff7b72",shape:"triangle",label:"Abort"}},$=new Set(Object.keys(D)),W=e=>{if(e==null||e<0)return"\u2014";if(e<1e3)return Math.round(e)+"ms";let t=e/1e3;if(t<60){let r=Math.round(t*10)/10;return(r%1===0?Math.round(r):r.toFixed(1))+"s"}let s=Math.floor(t/60),a=Math.floor(t%60);return s<60?s+"m "+a+"s":Math.floor(s/60)+"h "+s%60+"m"},_e=e=>!e||e===0?"0":e<1e3?e.toString():Math.floor(e/1e3)+"K",Re=e=>{if(!e)return"";let t=new Date(e);return String(t.getHours()).padStart(2,"0")+":"+String(t.getMinutes()).padStart(2,"0")+":"+String(t.getSeconds()).padStart(2,"0")},Ne=e=>e?new Date(e).toLocaleString():"",I=v(()=>{if(!T.value.length)return null;for(let e of T.value){let t=e.timestamp||e.snapshot?.timestamp;if(t)return new Date(t).getTime()}return null}),G=v(()=>{if(!T.value.length)return null;for(let e=T.value.length-1;e>=0;e--){let t=T.value[e],s=t.timestamp||t.snapshot?.timestamp;if(s)return new Date(s).getTime()}return null}),_=v(()=>!I.value||!G.value?0:G.value-I.value),A=v(()=>[...T.value].sort((e,t)=>{let s=e.timestamp?new Date(e.timestamp).getTime():0,a=t.timestamp?new Date(t.timestamp).getTime():0;return s!==a?s-a:(e._fileIndex??0)-(t._fileIndex??0)})),P=v(()=>{let e=A.value,t=new Set;for(let r of e)if(r.type==="subagent.started"){let l=r.data?.toolCallId;l&&t.add(l)}let s=new Map;for(let r of e)r.id&&s.set(r.id,r);let a=new Map,n=new Map;for(let r of e){if(r.type!=="tool.execution_start")continue;let l=r.parentId,d=0;for(;l&&d<10;){let i=s.get(l);if(!i)break;if(i.type==="assistant.message"){let o=i.data?.parentToolCallId;if(o&&t.has(o)){a.set(r.id,o);let c=r.data?.toolCallId;c&&n.set(c,o)}break}l=i.parentId,d++}}for(let r of e){if(r.type!=="tool.execution_complete")continue;let l=r.data?.toolCallId;l&&n.has(l)&&a.set(r.id,n.get(l))}return a}),z=v(()=>{let e=A.value,t=[],s=[];for(let n of e)if(n.type==="subagent.started")s.push(n);else if(n.type==="subagent.completed"||n.type==="subagent.failed"){let r=n.data?.toolCallId,l=-1;if(r){for(let h=s.length-1;h>=0;h--)if(s[h].data?.toolCallId===r){l=h;break}}l<0&&s.length>0&&(l=s.length-1);let d=l>=0?s.splice(l,1)[0]:null,i=d?.data?.agentDisplayName||d?.data?.agentName||"SubAgent",o=d?new Date(d.timestamp).getTime():null,c=new Date(n.timestamp).getTime(),m=o?c-o:null,p=d?.data?.toolCallId,u=0,g=[];if(d)for(let h of e){h.type==="tool.execution_start"&&p&&P.value.get(h.id)===p&&u++;let M=new Date(h.timestamp).getTime();M>=o&&M<=c&&$.has(h.type)&&(h.type!=="tool.execution_start"&&h.type!=="tool.execution_complete"?g.push({type:h.type,timestamp:M,data:h.data}):p&&P.value.get(h.id)===p&&g.push({type:h.type,timestamp:M,data:h.data}))}let w=Q(g,o,m);t.push({name:i,status:n.type==="subagent.completed"?"completed":"failed",startTime:d?.timestamp||null,endTime:n.timestamp,duration:m,toolCalls:u,innerEventMarkers:w})}let a=e.length>0?new Date(e[e.length-1].timestamp).getTime():Date.now();for(let n of s){let r=n.data?.agentDisplayName||n.data?.agentName||"SubAgent",l=new Date(n.timestamp).getTime(),d=a-l,i=n.data?.toolCallId,o=0,c=[];for(let p of e){p.type==="tool.execution_start"&&i&&P.value.get(p.id)===i&&o++;let u=new Date(p.timestamp).getTime();u>=l&&u<=a&&$.has(p.type)&&(p.type!=="tool.execution_start"&&p.type!=="tool.execution_complete"?c.push({type:p.type,timestamp:u,data:p.data}):i&&P.value.get(p.id)===i&&c.push({type:p.type,timestamp:u,data:p.data}))}let m=Q(c,l,d);t.push({name:r,status:"incomplete",startTime:n.timestamp,endTime:e[e.length-1]?.timestamp||n.timestamp,duration:d,toolCalls:o,innerEventMarkers:m})}return t.sort((n,r)=>{let l=n.startTime?new Date(n.startTime).getTime():0,d=r.startTime?new Date(r.startTime).getTime():0;return l-d})}),Le=v(()=>Math.max(...z.value.map(e=>e.duration||0),1)),qe=v(()=>{let e=z.value,t=e.filter(o=>o.status==="completed").length,s=e.filter(o=>o.status==="failed").length,a=e.filter(o=>o.status==="incomplete").length,n=e.length?(t/e.length*100).toFixed(0):100,r=e.filter(o=>o.startTime&&o.endTime).map(o=>[new Date(o.startTime).getTime(),new Date(o.endTime).getTime()]).sort((o,c)=>o[0]-c[0]),l=[];for(let[o,c]of r)!l.length||o>=l[l.length-1].e?l.push({s:o,e:c}):c>l[l.length-1].e&&(l[l.length-1].e=c);let d=l.reduce((o,c)=>o+(c.e-c.s),0),i=e.reduce((o,c)=>o+(c.toolCalls||0),0);return{completed:t,failed:s,incomplete:a,totalTime:d,totalTools:i,successRate:n}}),Q=(e,t,s)=>{if(!e.length||!s)return[];let a=new Set(["session.start","session.resume","session.error","session.truncation","session.compaction_start","session.compaction_complete","session.model_change","abort","user.message"]),n=[],r=[];for(let u of e)a.has(u.type)?n.push(u):r.push(u);let l=n.map(u=>{let g=(u.timestamp-t)/s*100,w=D[u.type]||{};return{type:u.type,position:Math.max(0,Math.min(100,g)),color:w.color||"#8b949e",shape:w.shape||"circle",label:w.label||u.type,timestamp:u.timestamp,toolName:u.data?.toolName||null}}),d=300*1e3,i=Math.max(d,s/20),o=new Map;for(let u of r){let g=Math.floor((u.timestamp-t)/i);o.has(g)||o.set(g,[]),o.get(g).push(u)}let c=u=>{let g=Math.round(210+38*u),w=Math.round(153+-72*u),h=Math.round(34+39*u);return"rgb("+g+","+w+","+h+")"},m=u=>u.type==="tool.execution_complete"&&(u.data?.isError||!!u.data?.error),p=[];for(let[u,g]of o){let h=(t+(u+.5)*i-t)/s*100,M=Math.max(0,Math.min(100,h)),de=g.filter(m).length,be=g.filter(k=>k.type==="tool.execution_complete").length,Te=be>0?de/be:0;if(g.length===1){let k=g[0],R=D[k.type]||{},ue=m(k)?"#f85149":R.color||"#8b949e";p.push({type:k.type,position:M,color:ue,shape:R.shape||"circle",label:m(k)?(R.label||k.type)+" (error)":R.label||k.type,timestamp:k.timestamp,toolName:k.data?.toolName||null})}else{let k={};g.forEach(N=>{let F=(D[N.type]||{}).label||N.type;k[F]=(k[F]||0)+1}),de>0&&(k.Errors=de);let R=Object.entries(k).map(([N,j])=>j+" "+N),ue=Te>0?c(Te):(()=>{let N=g.reduce((j,F)=>{let ke=g.filter(ot=>ot.type===F.type).length;return ke>j.cnt?{type:F.type,cnt:ke}:j},{type:g[0].type,cnt:0}).type;return(D[N]||{}).color||"#8b949e"})();p.push({type:"cluster",position:M,color:ue,shape:"cluster",label:R.join(", "),count:g.length,items:g})}}return[...l,...p].sort((u,g)=>u.position-g.position)},B=(e,t,s)=>{let a=s-t,n=[],r={},l=0;for(let c of e){let m=new Date(c.timestamp).getTime();if(m>=t&&m<=s)if(c.type.startsWith("tool."))c.id&&P.value.has(c.id)||($.has(c.type)&&n.push({type:c.type,timestamp:m,data:c.data}),c.type==="tool.execution_start"&&l++,r.tool=(r.tool||0)+1);else{$.has(c.type)&&n.push({type:c.type,timestamp:m,data:c.data});let p="other";c.type.startsWith("assistant.")?p="message":c.type.startsWith("user.")?p="user":c.type.startsWith("session.")&&(p="session"),r[p]=(r[p]||0)+1}}let d=[];l&&d.push(l+" tool"+(l>1?"s":"")),r.message&&d.push(r.message+" message"+(r.message>1?"s":"")),r.user&&d.push(r.user+" user msg"),r.session&&d.push(r.session+" session event"+(r.session>1?"s":"")),r.other&&d.push(r.other+" other");let i=d.length?d.join(", "):"idle",o=Q(n,t,a);return{itemType:"agent-op",name:"Main Agent",summary:i,toolCalls:l,startTime:new Date(t).toISOString(),endTime:new Date(s).toISOString(),duration:a,eventCounts:r,innerEventMarkers:o}},ee=v(()=>{let e=z.value;if(!e.length)return[];let t=A.value,s=[];for(let a=0;a<e.length;a++){let n=e[a];if(a===0&&n.startTime){let i=I.value,o=new Date(n.startTime).getTime();o-i>500&&s.push(B(t,i,o))}s.push({...n,itemType:"subagent"});let r=e[a+1],l=new Date(n.endTime).getTime(),d=r?new Date(r.startTime).getTime():G.value;d-l>500&&s.push(B(t,l,d))}return s}),te=v(()=>{try{let e=A.value,t=e.filter(a=>a.type==="assistant.message"),s=e.filter(a=>a.type==="user.message");return t.map((a,n)=>{let r=a.timestamp;if(!r)return console.warn("[turnAnalysis] Message without timestamp:",a),null;let l=new Date(r).getTime();if(isNaN(l))return console.warn("[turnAnalysis] Invalid timestamp:",r,a),null;let d=t[n+1],o=(d?new Date(d.timestamp).getTime():G.value||l)-l,c=e.indexOf(a),m=e.slice(0,c).reverse().find(h=>h.type==="user.message"),p=m?s.indexOf(m)+1:0,u="",g=a.data?.message&&a.data.message.trim()!=="";g?u=me(a.data.message):a.data?.tools&&a.data.tools.length>0?u=`Tool calls: ${a.data.tools.map(M=>M.name||"unknown").join(", ")}`:u="(empty assistant message)";let w=a.data?.tools?.length||0;return{turnId:a.id??`msg-${n}`,userReqNumber:p,message:me(m?.data?.message||m?.data?.content||m?.data?.transformedContent||""),displayText:u,hasText:g,startTime:a.timestamp,endTime:d?.timestamp||T.value[T.value.length-1]?.timestamp,duration:o,toolCalls:w}}).filter(a=>a!==null)}catch(e){return console.error("[turnAnalysis] Error:",e),Z.value="Error analyzing turns: "+e.message,[]}}),Ge=v(()=>Math.max(...te.value.map(e=>e.duration||0),1)),ge=v(()=>{let e=new Map;for(let t of te.value){let s=t.userReqNumber||0;e.has(s)||e.set(s,{userReqNumber:s,message:t.message,turns:[]}),e.get(s).turns.push(t)}return Array.from(e.values()).sort((t,s)=>t.userReqNumber-s.userReqNumber)}),x=v(()=>{let e=A.value,t=new Map;for(let a of e)if(a.type==="tool.execution_start"){let n=a.data?.toolCallId;n&&t.set(n,{start:a})}else if(a.type==="tool.execution_complete"){let n=a.data?.toolCallId;n&&t.has(n)&&(t.get(n).complete=a)}let s=[];return t.forEach((a,n)=>{let r=new Date(a.start.timestamp).getTime(),l=a.complete?new Date(a.complete.timestamp).getTime():null,d=l?l-r:null,i=a.start.data?.toolName||a.start.data?.tool||"unknown",o=a.start.data?.arguments||{},c=a.complete?.data?.isError||!!a.complete?.data?.error,m="";i==="Bash"||i==="bash"||i==="exec"?m=o.command||o.description||"":["Read","read","Write","write","Edit","edit"].includes(i)?m=o.file_path||o.path||"":["Glob","glob"].includes(i)||["Grep","grep"].includes(i)?m=o.pattern||"":["Task","task"].includes(i)?m=o.description||o.prompt?.substring(0,80)||"":m=o.description||o.command||o.file_path||o.path||o.query||o.url||"",m.length>120&&(m=m.substring(0,120)+"..."),s.push({toolId:n,toolName:i,description:m,startTime:a.start.timestamp,endTime:a.complete?.timestamp||null,duration:d,isError:c,isRunning:!a.complete})}),s}),Pe=v(()=>{let e=[...x.value];return e.sort((t,s)=>{if(C.value==="duration")return E.value==="asc"?(t.duration||0)-(s.duration||0):(s.duration||0)-(t.duration||0);if(C.value==="toolName"){let r=(t.toolName||"").localeCompare(s.toolName||"");return E.value==="asc"?r:-r}let a=new Date(t.startTime).getTime(),n=new Date(s.startTime).getTime();return E.value==="asc"?a-n:n-a}),e}),ze=v(()=>Math.max(...x.value.map(e=>e.duration||0),1)),Be=v(()=>{if(!f.value.usage||!f.value.usage.modelMetrics)return 0;let e=0;for(let t in f.value.usage.modelMetrics){let s=f.value.usage.modelMetrics[t].usage;s&&(e+=(s.inputTokens||0)+(s.outputTokens||0))}return e}),je=v(()=>{if(!f.value.usage||!f.value.usage.modelMetrics)return 0;let e=0;for(let t in f.value.usage.modelMetrics)e+=f.value.usage.modelMetrics[t].requests?.count||0;return e}),Fe=v(()=>!f.value.usage||!f.value.usage.modelMetrics?0:Object.keys(f.value.usage.modelMetrics).length),Oe=e=>{let t=f.value.usage?.modelMetrics[e];return!t||!t.usage?null:ct(t.usage)},Ue=e=>{let t=f.value.usage?.modelMetrics[e];return!t||!t.usage?0:lt(t.usage)},ve=v(()=>{let e={};return x.value.forEach(t=>{let s=(t.toolName||"unknown").toLowerCase(),a;["bash","exec"].includes(s)?a="Bash/Exec":["read"].includes(s)?a="Read":["write"].includes(s)?a="Write":["edit"].includes(s)?a="Edit":["glob"].includes(s)?a="Glob":["grep"].includes(s)?a="Grep":["task"].includes(s)?a="Task (SubAgent)":["web_search","websearch"].includes(s)?a="Web Search":["web_fetch","webfetch"].includes(s)?a="Web Fetch":a=t.toolName||"Other",e[a]||(e[a]={category:a,totalTime:0,count:0,errors:0}),e[a].totalTime+=t.duration||0,e[a].count++,t.isError&&e[a].errors++}),Object.values(e).sort((t,s)=>s.count-t.count)}),$e=v(()=>Math.max(...ve.value.map(e=>e.totalTime),1)),se=v(()=>{let e=x.value.filter(n=>n.duration&&n.startTime&&n.endTime).map(n=>({start:new Date(n.startTime).getTime(),end:new Date(n.endTime).getTime()})).sort((n,r)=>n.start-r.start);if(!e.length)return 0;let t=0,s=e[0].start,a=e[0].end;for(let n=1;n<e.length;n++)e[n].start<=a?a=Math.max(a,e[n].end):(t+=a-s,s=e[n].start,a=e[n].end);return t+=a-s,t}),mt=v(()=>{let e=0,t={};for(let s of T.value)if(s.type==="tool.execution_complete"&&s.data?.toolTelemetry?.metrics){let a=s.data.toolTelemetry.metrics.resultForLlmLength||0;e+=a;let n=s.data.toolName||"unknown";t[n]||(t[n]=0),t[n]+=a}return{total:e,byCategory:t}}),ae=v(()=>{let e=A.value,t=[];for(let s=0;s<e.length-1;s++){let a=e[s],n=e[s+1],r=new Date(a.timestamp).getTime(),d=new Date(n.timestamp).getTime()-r;if(d<100)continue;let i=null,o="";a.type==="user.message"&&n.type==="assistant.turn_start"?(i="input-consumption",o=`LLM reading user input (${(a.data?.message||"").length} chars)`):a.type==="assistant.turn_start"&&n.type==="assistant.message"?(i="llm-generation",o=`LLM generating response (${(n.data?.content||"").length} chars output)`):a.type==="assistant.turn_start"&&n.type==="tool.execution_start"?(i="llm-generation",o=`LLM deciding to call ${n.data?.toolName||"unknown"}`):a.type==="assistant.message"&&n.type==="assistant.turn_start"?(i="turn-gap",o="Gap between assistant response and next turn"):a.type==="tool.execution_complete"&&d>500?(i="post-tool",o=`Processing ${a.data?.toolName||"unknown"} result`):d>5e3&&(i="idle",o=`${a.type} \u2192 ${n.type}`),i&&t.push({type:i,description:o,startTime:a.timestamp,endTime:n.timestamp,duration:d,fromEvent:a.type,toEvent:n.type,fromData:a.data,toData:n.data})}return t.sort((s,a)=>(a.duration||0)-(s.duration||0))}),We=v(()=>Math.max(...ae.value.map(e=>e.duration||0),1)),He=v(()=>{let e={"input-consumption":{count:0,total:0,avg:0},"llm-generation":{count:0,total:0,avg:0},"post-tool":{count:0,total:0,avg:0},"turn-gap":{count:0,total:0,avg:0},idle:{count:0,total:0,avg:0}};return ae.value.forEach(t=>{e[t.type]&&(e[t.type].count++,e[t.type].total+=t.duration)}),Object.keys(e).forEach(t=>{e[t].count>0&&(e[t].avg=e[t].total/e[t].count)}),e}),Ye=v(()=>{let e=x.value.length;if(e===0)return 100;let t=x.value.filter(s=>s.isError).length;return((e-t)/e*100).toFixed(1)}),Ve=v(()=>x.value.filter(e=>e.isError).length),Ze=v(()=>{let e=A.value,t=0;for(let r=0;r<e.length-1;r++){let l=e[r],d=e[r+1];if(d.type==="user.message"&&l.type!=="user.message"){let i=new Date(d.timestamp).getTime()-new Date(l.timestamp).getTime();i>1e3&&(t+=i)}}let s=_.value||0,a=Math.max(s-t,0),n=Math.max(a-se.value,0);return{userThinkingTime:t,agentWorkingTime:a,llmTime:n,userThinkingPct:s>0?(t/s*100).toFixed(0):0,agentWorkingPct:s>0?(a/s*100).toFixed(0):0,llmPct:s>0?(n/s*100).toFixed(0):0,toolPct:s>0?(se.value/s*100).toFixed(0):0}}),ne=v(()=>x.value.length),Xe=v(()=>ne.value?x.value.reduce((t,s)=>t+(s.duration||0),0)/ne.value:0),Ke=v(()=>x.value.length?x.value.reduce((e,t)=>(t.duration||0)>(e.duration||0)?t:e):null),fe=v(()=>{let e=[],t=ge.value,s=z.value,a=A.value;if(t.length)for(let n=0;n<t.length;n++){let r=t[n],l=r.turns;if(!l.length)continue;let d=new Date(l[0].startTime).getTime(),i=new Date(l[l.length-1].endTime).getTime();e.push({rowType:"user-req",userReqNumber:r.userReqNumber,message:r.message,startTime:l[0].startTime,endTime:l[l.length-1].endTime,duration:i-d});let o=s.filter(c=>{if(!c.startTime)return!1;let m=new Date(c.startTime).getTime();return m>=d&&m<=i});if(o.length)for(let c=0;c<o.length;c++){let m=o[c],p=c===0?d:new Date(o[c-1].endTime).getTime(),u=new Date(m.startTime).getTime();if(u-p>500){let g=B(a,p,u);g.rowType="main-agent",e.push(g)}if(e.push({...m,rowType:"subagent",itemType:"subagent"}),c===o.length-1){let g=new Date(m.endTime).getTime(),w=i;if(w-g>500){let h=B(a,g,w);h.rowType="main-agent",e.push(h)}}}else if(i-d>0){let c=B(a,d,i);c.rowType="main-agent",e.push(c)}}else if(ee.value.length)for(let n of ee.value)e.push({...n,rowType:n.itemType==="agent-op"?"main-agent":"subagent"});return e}),Je=(e,t)=>{if(!I.value||!_.value||!e)return{left:"0%",width:"0%"};let s=new Date(e).getTime(),a=t?new Date(t).getTime():s+1e3,n=(s-I.value)/_.value*100,r=Math.max((a-s)/_.value*100,.5);return{left:n+"%",width:Math.min(r,100-n)+"%"}},Qe=e=>{C.value===e?E.value=E.value==="asc"?"desc":"asc":(C.value=e,E.value=e==="duration"?"desc":"asc")},et=e=>C.value!==e?"\u2195":E.value==="asc"?"\u2191":"\u2193",tt=e=>{let t=(e||"").toLowerCase();return["bash","exec"].includes(t)?"badge-bash":t==="read"?"badge-read":t==="write"||t==="notebookedit"?"badge-write":t==="edit"?"badge-edit":t==="glob"||t==="grep"?"badge-search":t==="task"?"badge-subagent":"badge-other"},st=e=>({read:"badge-read",write:"badge-write",edit:"badge-edit",create:"badge-create",search:"badge-search"})[e]||"badge-other";Me(async()=>{try{let e=await fetch("/api/sessions/"+y.value+"/events");if(!e.ok)throw new Error("Failed to load events: "+e.statusText);let t=await e.json();console.log("[TIME-ANALYZE] Loaded events:",t.length),console.log("[TIME-ANALYZE] Event types:",[...new Set(t.map(s=>s.type))]),console.log("[TIME-ANALYZE] Turn starts:",t.filter(s=>s.type==="assistant.turn_start").length),console.log("[TIME-ANALYZE] User messages:",t.filter(s=>s.type==="user.message").length),T.value=t.sort((s,a)=>{let n=s.timestamp?new Date(s.timestamp).getTime():0,r=a.timestamp?new Date(a.timestamp).getTime():0;return n!==r?n-r:(s._fileIndex??0)-(a._fileIndex??0)}),console.log("[TIME-ANALYZE] Events set, length:",T.value.length)}catch(e){console.error("[TIME-ANALYZE] Error loading events:",e),Z.value=e.message}finally{S.value=!1}});let oe=b("not_started"),ie=b(null),H=b(null),re=b(0),Y=null,at=v(()=>L.value?marked.parse(L.value):""),he=async()=>{try{let t=await(await fetch(`/session/${y.value}/insight`)).json();oe.value=t.status,t.status==="completed"?(L.value=t.report,q.value=null,J.value=t.generatedAt,ce()):t.status==="generating"?(q.value=t.log||null,H.value=t.startedAt,ie.value=t.lastUpdate,re.value=t.ageMs,le(),Vue.nextTick(()=>{let s=document.getElementById("insight-log");s&&(s.scrollTop=s.scrollHeight)})):t.status==="timeout"&&(q.value=t.log||null,H.value=t.startedAt,ie.value=t.lastUpdate,re.value=t.ageMs,le())}catch(e){console.error("Failed to check insight:",e)}},le=()=>{ce(),Y=setInterval(he,2e3)},ce=()=>{Y&&(clearInterval(Y),Y=null)},ye=async(e=!1)=>{X.value=!0,K.value=null,q.value=null;try{let t=await fetch(`/session/${y.value}/insight`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({force:e})});if(!t.ok){let a=await t.json();throw new Error(a.error||"Failed to generate insight")}let s=await t.json();oe.value=s.status,s.status==="generating"?(H.value=s.startedAt,le()):s.status==="completed"&&(L.value=s.report,J.value=s.generatedAt)}catch(t){K.value=t.message}finally{X.value=!1}},nt=async()=>{await ye(!0)};return Me(async()=>{await he()}),ut(()=>{ce()}),{sessionId:y,metadata:f,events:T,loading:S,error:Z,activeTab:Ee,sortField:C,sortDir:E,insightReport:L,insightLog:q,insightLoading:X,insightError:K,insightGeneratedAt:J,insightStatus:oe,insightLastUpdate:ie,insightStartedAt:H,insightAgeMs:re,renderedInsight:at,generateInsight:ye,regenerateInsight:nt,formatDuration:W,formatTime:Re,formatDateTime:Ne,sessionStart:I,sessionEnd:G,totalDuration:_,subagentAnalysis:z,maxSubagentDuration:Le,subagentTimelineItems:ee,subagentStats:qe,EVENT_MARKER_CATEGORIES:D,showMarkerLegend:Ae,copyLabel:O,copyTimelineMarkdown:De,ganttCrosshairX:U,ganttCrosshairTime:pe,onGanttMouseMove:Ie,onGanttMouseLeave:Ce,turnAnalysis:te,maxTurnDuration:Ge,groupedTurns:ge,unifiedTimelineItems:fe,toolAnalysis:x,sortedToolAnalysis:Pe,maxToolDuration:ze,fileOperations:[],fileStats:{totalOps:0,reads:0,edits:0,writes:0,searches:0},totalTokens:Be,totalRequests:je,totalModels:Fe,getModelCacheHitRatio:Oe,getDisplayUsageInputTokens:Ue,formatTokens:_e,toolTimeByCategory:ve,maxCategoryTime:$e,totalToolTime:se,totalToolCount:ne,avgToolDuration:Xe,longestTool:Ke,successRate:Ye,errorCount:Ve,timeBreakdown:Ze,gapAnalysis:ae,maxGapDuration:We,gapStats:He,ganttPosition:Je,toggleSort:Qe,sortIcon:et,getToolBadgeClass:tt,getOpBadgeClass:st}},template:`
|
|
3
3
|
<div v-if="loading" class="empty-state" style="padding: 60px;">
|
|
4
4
|
\u23F3 Loading events...
|
|
5
5
|
</div>
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</div>
|
|
34
34
|
<div class="summary-card" title="Spawned subagents (via Task tool). Shows completed/failed/incomplete counts, total wall-clock time, and tool calls attributed to subagents.">
|
|
35
35
|
<div class="summary-card-label">Sub-Agents</div>
|
|
36
|
-
<div class="summary-card-value">{{ subagentAnalysis.length
|
|
36
|
+
<div class="summary-card-value">{{ subagentAnalysis.length }}</div>
|
|
37
37
|
<div class="summary-card-sub" v-if="subagentAnalysis.length > 0">
|
|
38
38
|
<span :style="{ color: subagentStats.successRate >= 95 ? '#3fb950' : subagentStats.successRate >= 80 ? '#d29922' : '#f85149' }">{{ subagentStats.completed }}\u2713</span>
|
|
39
39
|
<span v-if="subagentStats.failed > 0" style="color: #f85149;"> \xB7 {{ subagentStats.failed }}\u2717</span>
|
|
@@ -41,10 +41,6 @@
|
|
|
41
41
|
\xB7 {{ formatDuration(subagentStats.totalTime) }}
|
|
42
42
|
\xB7 {{ subagentStats.totalTools }} tools
|
|
43
43
|
</div>
|
|
44
|
-
<div class="summary-card-sub" v-else-if="vsCodeSubagents.length > 0">
|
|
45
|
-
<span style="color: #3fb950;">{{ vsCodeSubagents.length }}\u2713</span>
|
|
46
|
-
\xB7 {{ vsCodeSubagents.reduce((s, a) => s + a.toolCount, 0) }} tools
|
|
47
|
-
</div>
|
|
48
44
|
</div>
|
|
49
45
|
<div class="summary-card" title="Estimated LLM reasoning time (total duration minus tool execution and user thinking time). Breakdown shows LLM percentage, tool wall-clock time, and user idle time.">
|
|
50
46
|
<div class="summary-card-label">Time Breakdown</div>
|
|
@@ -54,11 +50,11 @@
|
|
|
54
50
|
<span v-if="timeBreakdown.userThinkingTime > 1000"> \xB7 User {{ formatDuration(timeBreakdown.userThinkingTime) }} ({{ timeBreakdown.userThinkingPct }}%)</span>
|
|
55
51
|
</div>
|
|
56
52
|
</div>
|
|
57
|
-
<div class="summary-card" title="
|
|
58
|
-
<div class="summary-card-label">
|
|
59
|
-
<div class="summary-card-value">{{
|
|
53
|
+
<div class="summary-card" title="Token usage across all models: input, output, and cached tokens.">
|
|
54
|
+
<div class="summary-card-label">Token Usage</div>
|
|
55
|
+
<div class="summary-card-value">{{ formatTokens(totalTokens) }}</div>
|
|
60
56
|
<div class="summary-card-sub">
|
|
61
|
-
{{
|
|
57
|
+
{{ totalRequests }} reqs \xB7 {{ totalModels }} model{{ totalModels === 1 ? '' : 's' }}
|
|
62
58
|
</div>
|
|
63
59
|
</div>
|
|
64
60
|
</div>
|
|
@@ -127,23 +123,6 @@
|
|
|
127
123
|
</template>
|
|
128
124
|
</div>
|
|
129
125
|
|
|
130
|
-
<!-- VS Code Session Banner -->
|
|
131
|
-
<div v-if="isVSCodeSession" style="
|
|
132
|
-
background: rgba(88, 166, 255, 0.1);
|
|
133
|
-
border: 1px solid rgba(88, 166, 255, 0.3);
|
|
134
|
-
border-radius: 6px;
|
|
135
|
-
padding: 12px 16px;
|
|
136
|
-
margin-bottom: 16px;
|
|
137
|
-
display: flex;
|
|
138
|
-
align-items: center;
|
|
139
|
-
gap: 8px;
|
|
140
|
-
color: #58a6ff;
|
|
141
|
-
font-size: 13px;
|
|
142
|
-
">
|
|
143
|
-
<span style="font-size: 16px;">\u24D8</span>
|
|
144
|
-
<span>Sequence layout \u2014 bar widths represent tool count, not elapsed time</span>
|
|
145
|
-
</div>
|
|
146
|
-
|
|
147
126
|
<div class="gantt-container" @mousemove="onGanttMouseMove" @mouseleave="onGanttMouseLeave">
|
|
148
127
|
<!-- Crosshair -->
|
|
149
128
|
<div v-if="ganttCrosshairX !== null" class="gantt-crosshair" :style="{ left: ganttCrosshairX + 'px' }">
|
|
@@ -165,16 +144,16 @@
|
|
|
165
144
|
<div class="gantt-bar-area">
|
|
166
145
|
<div
|
|
167
146
|
class="gantt-bar user-req"
|
|
168
|
-
:style="
|
|
169
|
-
:title="
|
|
147
|
+
:style="ganttPosition(item.startTime, item.endTime)"
|
|
148
|
+
:title="'UserReq ' + item.userReqNumber + ' \u2014 ' + formatDuration(item.duration)"
|
|
170
149
|
>
|
|
171
|
-
{{
|
|
150
|
+
{{ formatDuration(item.duration) }}
|
|
172
151
|
</div>
|
|
173
152
|
</div>
|
|
174
153
|
</div>
|
|
175
154
|
|
|
176
|
-
<!-- Sub-Agent row
|
|
177
|
-
<div v-else-if="item.rowType === 'subagent'" :class="['gantt-row',
|
|
155
|
+
<!-- Sub-Agent row -->
|
|
156
|
+
<div v-else-if="item.rowType === 'subagent'" :class="['gantt-row', 'indented']">
|
|
178
157
|
<div class="gantt-label" :title="item.name">
|
|
179
158
|
<a
|
|
180
159
|
:href="'/session/' + sessionId + '?eventType=subagent.started&eventName=' + encodeURIComponent(item.name) + '&eventTimestamp=' + encodeURIComponent(item.startTime || '')"
|
|
@@ -191,16 +170,15 @@
|
|
|
191
170
|
<div
|
|
192
171
|
:class="[
|
|
193
172
|
'gantt-bar',
|
|
194
|
-
item.isSequenceEstimated ? 'sequence-estimated' : '',
|
|
195
173
|
item.status === 'completed' ? 'subagent' : item.status === 'failed' ? 'subagent-failed' : 'subagent-incomplete'
|
|
196
174
|
]"
|
|
197
|
-
:style="
|
|
198
|
-
:title="item.
|
|
175
|
+
:style="ganttPosition(item.startTime, item.endTime)"
|
|
176
|
+
:title="item.name + ' \u2014 ' + formatDuration(item.duration)"
|
|
199
177
|
>
|
|
200
|
-
{{
|
|
178
|
+
{{ formatDuration(item.duration) }}
|
|
201
179
|
|
|
202
|
-
<!-- Event markers
|
|
203
|
-
<template v-if="
|
|
180
|
+
<!-- Event markers -->
|
|
181
|
+
<template v-if="item.innerEventMarkers && item.innerEventMarkers.length">
|
|
204
182
|
<span
|
|
205
183
|
v-for="(marker, midx) in item.innerEventMarkers"
|
|
206
184
|
:key="'m-' + midx"
|
|
@@ -515,4 +493,4 @@
|
|
|
515
493
|
</div>
|
|
516
494
|
</div>
|
|
517
495
|
</div>
|
|
518
|
-
`});
|
|
496
|
+
`});Se.config.errorHandler=(y,f,T)=>{console.error("[Vue Error]",y,T);let S=document.createElement("div");S.style.cssText="position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background: #f85149; color: white; padding: 20px; border-radius: 6px; z-index: 9999; max-width: 80%; font-family: monospace; font-size: 14px;",S.innerHTML=`<strong>Vue Error:</strong><br>${y.message}<br><br><small>${T}</small>`,document.body.appendChild(S)};Se.mount("#app");})();
|
package/views/index.ejs
CHANGED
|
@@ -414,6 +414,12 @@
|
|
|
414
414
|
color: #79c0ff;
|
|
415
415
|
text-decoration: underline;
|
|
416
416
|
}
|
|
417
|
+
.import-formats-hint {
|
|
418
|
+
font-size: 11px;
|
|
419
|
+
color: #6e7681;
|
|
420
|
+
margin-left: 6px;
|
|
421
|
+
vertical-align: middle;
|
|
422
|
+
}
|
|
417
423
|
.import-status {
|
|
418
424
|
margin-bottom: 12px;
|
|
419
425
|
padding: 10px 12px;
|
|
@@ -524,6 +530,7 @@
|
|
|
524
530
|
Sessions
|
|
525
531
|
</div>
|
|
526
532
|
<a class="import-link" id="importLink">Import session from zip</a>
|
|
533
|
+
<span class="import-formats-hint">Supports: GitHub Copilot, Claude, Pi-Mono</span>
|
|
527
534
|
</div>
|
|
528
535
|
<div class="filter-pills">
|
|
529
536
|
<button class="filter-pill active" data-source="copilot">Copilot CLI</button>
|
|
@@ -536,7 +543,7 @@
|
|
|
536
543
|
<input
|
|
537
544
|
type="file"
|
|
538
545
|
id="fileInput"
|
|
539
|
-
name="
|
|
546
|
+
name="zipFile"
|
|
540
547
|
accept=".zip"
|
|
541
548
|
style="display: none;"
|
|
542
549
|
>
|
package/views/session-vue.ejs
CHANGED
|
@@ -844,27 +844,121 @@
|
|
|
844
844
|
display: flex;
|
|
845
845
|
align-items: center;
|
|
846
846
|
gap: 8px;
|
|
847
|
+
position: relative;
|
|
847
848
|
}
|
|
848
849
|
|
|
849
|
-
.subagent-dropdown {
|
|
850
|
-
|
|
850
|
+
.subagent-dropdown-trigger {
|
|
851
|
+
display: flex;
|
|
852
|
+
align-items: center;
|
|
853
|
+
gap: 6px;
|
|
854
|
+
padding: 4px 10px;
|
|
851
855
|
background: #161b22;
|
|
852
856
|
border: 1px solid #30363d;
|
|
853
857
|
border-radius: 6px;
|
|
854
858
|
color: #c9d1d9;
|
|
855
859
|
font-size: 13px;
|
|
856
860
|
cursor: pointer;
|
|
857
|
-
max-width:
|
|
861
|
+
max-width: 280px;
|
|
858
862
|
}
|
|
863
|
+
.subagent-dropdown-trigger:hover { border-color: #58a6ff; }
|
|
864
|
+
.subagent-trigger-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
865
|
+
.subagent-trigger-arrow { font-size: 10px; opacity: 0.6; }
|
|
859
866
|
|
|
860
|
-
.subagent-dropdown
|
|
861
|
-
|
|
867
|
+
.subagent-dropdown-panel {
|
|
868
|
+
position: absolute;
|
|
869
|
+
top: calc(100% + 4px);
|
|
870
|
+
right: 0;
|
|
871
|
+
z-index: 100;
|
|
872
|
+
min-width: 320px;
|
|
873
|
+
max-width: 420px;
|
|
874
|
+
background: #161b22;
|
|
875
|
+
border: 1px solid #30363d;
|
|
876
|
+
border-radius: 8px;
|
|
877
|
+
box-shadow: 0 8px 24px rgba(0,0,0,0.4);
|
|
878
|
+
overflow: hidden;
|
|
862
879
|
}
|
|
863
880
|
|
|
864
|
-
.subagent-
|
|
881
|
+
.subagent-search-input {
|
|
882
|
+
width: 100%;
|
|
883
|
+
padding: 8px 12px;
|
|
884
|
+
background: #0d1117;
|
|
885
|
+
border: none;
|
|
886
|
+
border-bottom: 1px solid #30363d;
|
|
887
|
+
color: #c9d1d9;
|
|
888
|
+
font-size: 13px;
|
|
865
889
|
outline: none;
|
|
866
|
-
|
|
867
|
-
|
|
890
|
+
box-sizing: border-box;
|
|
891
|
+
}
|
|
892
|
+
.subagent-search-input::placeholder { color: #484f58; }
|
|
893
|
+
|
|
894
|
+
.subagent-dropdown-list {
|
|
895
|
+
max-height: 320px;
|
|
896
|
+
overflow-y: auto;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.subagent-dropdown-item {
|
|
900
|
+
display: flex;
|
|
901
|
+
align-items: flex-start;
|
|
902
|
+
gap: 8px;
|
|
903
|
+
padding: 8px 12px;
|
|
904
|
+
cursor: pointer;
|
|
905
|
+
border-bottom: 1px solid #21262d;
|
|
906
|
+
}
|
|
907
|
+
.subagent-dropdown-item:last-child { border-bottom: none; }
|
|
908
|
+
.subagent-dropdown-item:hover { background: #1c2129; }
|
|
909
|
+
.subagent-dropdown-item.active { background: rgba(88, 166, 255, 0.1); }
|
|
910
|
+
|
|
911
|
+
.subagent-item-color {
|
|
912
|
+
width: 4px;
|
|
913
|
+
min-height: 20px;
|
|
914
|
+
border-radius: 2px;
|
|
915
|
+
flex-shrink: 0;
|
|
916
|
+
margin-top: 2px;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.subagent-item-body { flex: 1; min-width: 0; }
|
|
920
|
+
|
|
921
|
+
.subagent-item-name {
|
|
922
|
+
font-size: 13px;
|
|
923
|
+
color: #c9d1d9;
|
|
924
|
+
font-weight: 500;
|
|
925
|
+
white-space: nowrap;
|
|
926
|
+
overflow: hidden;
|
|
927
|
+
text-overflow: ellipsis;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
.subagent-item-meta {
|
|
931
|
+
display: flex;
|
|
932
|
+
gap: 6px;
|
|
933
|
+
margin-top: 2px;
|
|
934
|
+
flex-wrap: wrap;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
.subagent-meta-tag {
|
|
938
|
+
font-size: 11px;
|
|
939
|
+
color: #8b949e;
|
|
940
|
+
background: #21262d;
|
|
941
|
+
padding: 1px 6px;
|
|
942
|
+
border-radius: 4px;
|
|
943
|
+
}
|
|
944
|
+
.subagent-meta-tag.dim { opacity: 0.7; }
|
|
945
|
+
|
|
946
|
+
.subagent-item-desc {
|
|
947
|
+
font-size: 11px;
|
|
948
|
+
color: #6e7681;
|
|
949
|
+
margin-top: 3px;
|
|
950
|
+
line-height: 1.4;
|
|
951
|
+
display: -webkit-box;
|
|
952
|
+
-webkit-line-clamp: 2;
|
|
953
|
+
-webkit-box-orient: vertical;
|
|
954
|
+
overflow: hidden;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
.subagent-dropdown-empty {
|
|
958
|
+
padding: 12px;
|
|
959
|
+
text-align: center;
|
|
960
|
+
color: #484f58;
|
|
961
|
+
font-size: 13px;
|
|
868
962
|
}
|
|
869
963
|
|
|
870
964
|
.subagent-usage-badge {
|
|
@@ -1040,6 +1134,7 @@
|
|
|
1040
1134
|
.badge-reasoning { background: #a371f7; color: #fff; }
|
|
1041
1135
|
.badge-turn { background: #8250df; color: #fff; }
|
|
1042
1136
|
.badge-tool { background: #9e6a03; color: #fff; }
|
|
1137
|
+
.badge-hook { background: #484f58; color: #c9d1d9; }
|
|
1043
1138
|
.badge-subagent { background: #8957e5; color: #fff; }
|
|
1044
1139
|
.badge-skill { background: #bf3989; color: #fff; }
|
|
1045
1140
|
.badge-session { background: #6e7681; color: #fff; }
|
|
@@ -1290,6 +1385,35 @@
|
|
|
1290
1385
|
margin-right: 3px;
|
|
1291
1386
|
}
|
|
1292
1387
|
|
|
1388
|
+
/* Hook event styles */
|
|
1389
|
+
.hook-content { font-size: 13px; }
|
|
1390
|
+
.hook-summary { color: #8b949e; }
|
|
1391
|
+
.hook-section { margin-top: 4px; }
|
|
1392
|
+
.hook-section-header {
|
|
1393
|
+
cursor: pointer;
|
|
1394
|
+
display: inline-flex;
|
|
1395
|
+
align-items: center;
|
|
1396
|
+
gap: 4px;
|
|
1397
|
+
padding: 2px 0;
|
|
1398
|
+
user-select: none;
|
|
1399
|
+
}
|
|
1400
|
+
.hook-section-header:hover { color: #c9d1d9; }
|
|
1401
|
+
.hook-section-body {
|
|
1402
|
+
margin-top: 2px;
|
|
1403
|
+
padding: 6px 10px;
|
|
1404
|
+
background: #161b22;
|
|
1405
|
+
border: 1px solid #21262d;
|
|
1406
|
+
border-radius: 4px;
|
|
1407
|
+
overflow-x: auto;
|
|
1408
|
+
}
|
|
1409
|
+
.hook-section-body pre {
|
|
1410
|
+
margin: 0;
|
|
1411
|
+
font-size: 12px;
|
|
1412
|
+
color: #c9d1d9;
|
|
1413
|
+
white-space: pre-wrap;
|
|
1414
|
+
word-break: break-word;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1293
1417
|
/* Turn divider - Design 3: Slack Style (居中对称) */
|
|
1294
1418
|
.turn-divider {
|
|
1295
1419
|
display: flex;
|
|
@@ -1364,6 +1488,11 @@
|
|
|
1364
1488
|
color: #58a6ff;
|
|
1365
1489
|
background: rgba(88, 166, 255, 0.1);
|
|
1366
1490
|
}
|
|
1491
|
+
.subagent-divider-model {
|
|
1492
|
+
font-weight: 400;
|
|
1493
|
+
opacity: 0.8;
|
|
1494
|
+
font-size: 11px;
|
|
1495
|
+
}
|
|
1367
1496
|
.subagent-divider-line-left,
|
|
1368
1497
|
.subagent-divider-line-right {
|
|
1369
1498
|
display: none;
|
|
@@ -1493,10 +1622,16 @@
|
|
|
1493
1622
|
min-width: 0;
|
|
1494
1623
|
font-size: 12px;
|
|
1495
1624
|
}
|
|
1496
|
-
.subagent-dropdown {
|
|
1497
|
-
max-width:
|
|
1625
|
+
.subagent-dropdown-trigger {
|
|
1626
|
+
max-width: 160px;
|
|
1498
1627
|
font-size: 12px;
|
|
1499
1628
|
}
|
|
1629
|
+
.subagent-dropdown-panel {
|
|
1630
|
+
min-width: 260px;
|
|
1631
|
+
max-width: calc(100vw - 32px);
|
|
1632
|
+
right: 0;
|
|
1633
|
+
left: auto;
|
|
1634
|
+
}
|
|
1500
1635
|
.subagent-usage-badge {
|
|
1501
1636
|
display: none;
|
|
1502
1637
|
}
|