@qiaolei81/copilot-session-viewer 0.3.7 → 0.3.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@qiaolei81/copilot-session-viewer",
3
- "version": "0.3.7",
3
+ "version": "0.3.8",
4
4
  "description": "Web UI for viewing GitHub Copilot CLI session logs",
5
5
  "author": "Lei Qiao <qiaolei81@gmail.com>",
6
6
  "license": "MIT",
@@ -1,4 +1,4 @@
1
- (()=>{var y=window.__PAGE_DATA||{},A=y.sessions||[],G=y.totalSessions||0,D=y.hasMore||!1,k=y.sourceHints||{},m=[...A],u={};u.copilot={offset:A.length,hasMore:D};var f=!1,S="sessionViewer.sourceFilter",$;try{$=localStorage.getItem(S)}catch{$=null}var i=$||"copilot";function g(){return u[i]||(u[i]={offset:0,hasMore:!0}),u[i]}async function B(){let e=g();if(f||!e.hasMore)return;f=!0;let t=document.getElementById("loading-indicator");t.style.display="block",window.trackClick("LoadMoreClicked",{currentPage:Math.floor(e.offset/20)+1,offset:e.offset,source:i});try{let s=await fetch(`/api/sessions/load-more?offset=${g().offset}&limit=20&source=${encodeURIComponent(i)}`);if(!s.ok)throw new Error("Failed to load more sessions");let o=await s.json(),n=new Set(m.map(r=>r.id)),a=[];for(let r of o.sessions)n.has(r.id)||(m.push(r),a.push(r));g().offset+=o.sessions.length,g().hasMore=o.hasMore,await C(a),E()}catch(s){console.error("Error loading more sessions:",s)}finally{f=!1,t.style.display="none"}}function F(){return m.filter(e=>e.source===i)}function E(){let e=document.getElementById("sessions-container");e.innerHTML="";let t=F();if(t.length===0){e.innerHTML='<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">No sessions found for this filter.</div>';return}let s=O(t);Object.keys(s).sort((n,a)=>a.localeCompare(n)).forEach(n=>{let a=document.createElement("div");a.className="date-group-header",a.textContent=z(s[n][0].createdAt),e.appendChild(a);let r=document.createElement("div");r.className="recent-list",s[n].forEach(h=>{r.innerHTML+=R(h)}),e.appendChild(r)})}function P(){let e=window.pageYOffset||document.documentElement.scrollTop,t=window.innerHeight,s=document.documentElement.scrollHeight;e+t>=s-500&&g().hasMore&&!f&&B()}var w;function Z(){w||(w=setTimeout(()=>{P(),w=null},100))}function _(e){e.preventDefault();let t=document.getElementById("sessionInput").value.trim();t&&(window.location.href=`/session/${t}`)}document.getElementById("sessionForm").addEventListener("submit",_);var M=document.getElementById("fileInput"),d=document.getElementById("importLink"),L=document.getElementById("importStatus");d.addEventListener("click",e=>{e.preventDefault(),M.click()});M.addEventListener("change",async e=>{let t=e.target.files[0];if(t){if(!t.name.endsWith(".zip")){p("error","\u274C Please select a .zip file");return}d.style.pointerEvents="none",d.style.opacity="0.5",d.textContent="Importing...",p("loading","Uploading and extracting session...");try{let s=new FormData;s.append("sessionZip",t);let o=await fetch("/session/import",{method:"POST",body:s}),n=await o.json();o.ok?(p("success",`\u2705 Session ${n.sessionId} imported successfully!`),setTimeout(()=>{window.location.reload()},1500)):(p("error",`\u274C Import failed: ${n.error}`),d.style.pointerEvents="auto",d.style.opacity="1",d.textContent="Import session from zip")}catch(s){p("error",`\u274C Import failed: ${s.message}`),d.style.pointerEvents="auto",d.style.opacity="1",d.textContent="Import session from zip"}finally{M.value=""}}});function p(e,t){L.className=`import-status ${e}`,L.textContent=t}function N(e){if(!e||e<0)return"\u2014";let t=Math.floor(e/1e3),s=Math.floor(t/60),o=Math.floor(s/60);if(o>0){let n=s%60;return`${o}h ${n}m`}else if(s>0){let n=t%60;return`${s}m ${n}s`}else return`${t}s`}function z(e){let t=new Date(e),s=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${s}/${o}/${n}`}function j(e){if(!e)return"Unknown";let t=new Date(e),s=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${s}-${o}-${n}`}function O(e){let t={};return e.forEach(s=>{let o=j(s.createdAt);t[o]||(t[o]=[]),t[o].push(s)}),t}function R(e){let t="",s=e.sourceBadgeClass||"source-copilot",o=e.sourceName||"Copilot";if(t+=`<span class="status-badge ${s}" title="${o}">${o}</span>`,e.sessionStatus==="wip"&&(t+='<span class="status-badge wip" title="Session in progress">\u{1F504} WIP</span>'),e.isImported&&(t+='<span class="status-badge imported" title="Imported session">\u{1F4E5}</span>'),e.hasInsight&&(t+='<span class="status-badge insight" title="Has Agent Review">\u{1F4A1}</span>'),e.selectedModel){let v=e.selectedModel.replace("claude-","").replace("gpt-","").replace("gemini-",""),l="model-other";e.selectedModel.includes("claude")?l="model-claude":e.selectedModel.includes("gpt")?l="model-gpt":e.selectedModel.includes("gemini")&&(l="model-gemini"),t+=`<span class="status-badge model ${l}" title="Model: ${c(e.selectedModel)}">${c(v)}</span>`}e.copilotVersion&&(t+=`<span class="status-badge version" title="CLI version">${c(e.copilotVersion)}</span>`);let n="";if(e.summary&&e.summary!=="No summary"&&e.summary!=="Legacy session"){let v=e.summary.replace(/"/g,"&quot;"),l=c(e.summary).replace(/\n+/g," ");n=`<div class="session-summary" title="${v}">${l}</div>`}else n='<div class="session-summary" style="color: #6e7681; font-style: italic;">No summary available</div>';let a="";e.workspace&&e.workspace.cwd&&(a=`
1
+ (()=>{var y=window.__PAGE_DATA||{},A=y.sessions||[],G=y.totalSessions||0,D=y.hasMore||!1,k=y.sourceHints||{},m=[...A],u={};u.copilot={offset:A.length,hasMore:D};var f=!1,S="sessionViewer.sourceFilter",$;try{$=localStorage.getItem(S)}catch{$=null}var i=$||"copilot";function g(){return u[i]||(u[i]={offset:0,hasMore:!0}),u[i]}async function B(){let e=g();if(f||!e.hasMore)return;f=!0;let t=document.getElementById("loading-indicator");t.style.display="block",window.trackClick("LoadMoreClicked",{currentPage:Math.floor(e.offset/20)+1,offset:e.offset,source:i});try{let s=await fetch(`/api/sessions/load-more?offset=${g().offset}&limit=20&source=${encodeURIComponent(i)}`);if(!s.ok)throw new Error("Failed to load more sessions");let o=await s.json(),n=new Set(m.map(r=>r.id)),a=[];for(let r of o.sessions)n.has(r.id)||(m.push(r),a.push(r));g().offset+=o.sessions.length,g().hasMore=o.hasMore,await C(a),E()}catch(s){console.error("Error loading more sessions:",s)}finally{f=!1,t.style.display="none"}}function F(){return m.filter(e=>e.source===i)}function E(){let e=document.getElementById("sessions-container");e.innerHTML="";let t=F();if(t.length===0){e.innerHTML='<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">No sessions found for this filter.</div>';return}let s=O(t);Object.keys(s).sort((n,a)=>a.localeCompare(n)).forEach(n=>{let a=document.createElement("div");a.className="date-group-header",a.textContent=N(s[n][0].createdAt),e.appendChild(a);let r=document.createElement("div");r.className="recent-list",s[n].forEach(h=>{r.innerHTML+=R(h)}),e.appendChild(r)})}function z(){let e=window.pageYOffset||document.documentElement.scrollTop,t=window.innerHeight,s=document.documentElement.scrollHeight;e+t>=s-500&&g().hasMore&&!f&&B()}var w;function P(){w||(w=setTimeout(()=>{z(),w=null},100))}function Z(e){e.preventDefault();let t=document.getElementById("sessionInput").value.trim();t&&(window.location.href=`/session/${t}`)}document.getElementById("sessionForm").addEventListener("submit",Z);var M=document.getElementById("fileInput"),d=document.getElementById("importLink"),L=document.getElementById("importStatus");d.addEventListener("click",e=>{e.preventDefault(),M.click()});M.addEventListener("change",async e=>{let t=e.target.files[0];if(t){if(!t.name.endsWith(".zip")){p("error","\u274C Please select a .zip file");return}d.style.pointerEvents="none",d.style.opacity="0.5",d.textContent="Importing...",p("loading","Uploading and extracting session...");try{let s=new FormData;s.append("sessionZip",t);let o=await fetch("/session/import",{method:"POST",body:s}),n=await o.json();o.ok?(p("success",`\u2705 Session ${n.sessionId} imported successfully!`),setTimeout(()=>{window.location.reload()},1500)):(p("error",`\u274C Import failed: ${n.error}`),d.style.pointerEvents="auto",d.style.opacity="1",d.textContent="Import session from zip")}catch(s){p("error",`\u274C Import failed: ${s.message}`),d.style.pointerEvents="auto",d.style.opacity="1",d.textContent="Import session from zip"}finally{M.value=""}}});function p(e,t){L.className=`import-status ${e}`,L.textContent=t}function _(e){if(!e||e<0)return"\u2014";let t=Math.floor(e/1e3),s=Math.floor(t/60),o=Math.floor(s/60);if(o>0){let n=s%60;return`${o}h ${n}m`}else if(s>0){let n=t%60;return`${s}m ${n}s`}else return`${t}s`}function N(e){let t=new Date(e),s=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${s}/${o}/${n}`}function j(e){if(!e)return"Unknown";let t=new Date(e),s=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0");return`${s}-${o}-${n}`}function O(e){let t={};return e.forEach(s=>{let o=j(s.createdAt);t[o]||(t[o]=[]),t[o].push(s)}),t}function R(e){let t="",s=e.sourceBadgeClass||"source-copilot",o=e.sourceName||"Copilot";if(t+=`<span class="status-badge ${s}" title="${o}">${o}</span>`,e.sessionStatus==="wip"&&(t+='<span class="status-badge wip" title="Session in progress">\u{1F504} WIP</span>'),e.isImported&&(t+='<span class="status-badge imported" title="Imported session">\u{1F4E5}</span>'),e.hasInsight&&(t+='<span class="status-badge insight" title="Has Agent Review">\u{1F4A1}</span>'),e.selectedModel){let v=e.selectedModel.replace("claude-","").replace("gpt-","").replace("gemini-",""),l="model-other";e.selectedModel.includes("claude")?l="model-claude":e.selectedModel.includes("gpt")?l="model-gpt":e.selectedModel.includes("gemini")&&(l="model-gemini"),t+=`<span class="status-badge model ${l}" title="Model: ${c(e.selectedModel)}">${c(v)}</span>`}e.source==="modernize"&&e.modernizeVersion?t+=`<span class="status-badge version" title="Modernize version">${c(e.modernizeVersion)}</span>`:e.copilotVersion&&(t+=`<span class="status-badge version" title="CLI version">${c(e.copilotVersion)}</span>`);let n="";if(e.summary&&e.summary!=="No summary"&&e.summary!=="Legacy session"){let v=e.summary.replace(/"/g,"&quot;"),l=c(e.summary).replace(/\n+/g," ");n=`<div class="session-summary" title="${v}">${l}</div>`}else n='<div class="session-summary" style="color: #6e7681; font-style: italic;">No summary available</div>';let a="";e.workspace&&e.workspace.cwd&&(a=`
2
2
  <div class="session-info-item workspace" title="${c(e.workspace.cwd)}">
3
3
  <svg viewBox="0 0 16 16" fill="currentColor"><path d="M1.75 1A1.75 1.75 0 000 2.75v10.5C0 14.216.784 15 1.75 15h12.5A1.75 1.75 0 0016 13.25v-8.5A1.75 1.75 0 0014.25 3H7.5a.25.25 0 01-.2-.1l-.9-1.2C6.07 1.26 5.55 1 5 1H1.75z"></path></svg>
4
4
  <span class="session-info-value">${c(e.workspace.cwd)}</span>
@@ -6,9 +6,9 @@
6
6
  `);let r=e.createdAt?new Date(e.createdAt).toLocaleString("en-US",{month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hour12:!1}):"unknown",h="";e.duration&&(h=`
7
7
  <div class="session-info-item">
8
8
  <svg viewBox="0 0 16 16" fill="currentColor"><path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8Zm8-6.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13ZM7.25 12.5v-5A.75.75 0 0 1 8 6.75h2.5a.75.75 0 0 1 0 1.5H8.75v4.25a.75.75 0 0 1-1.5 0Z"></path></svg>
9
- <span class="session-info-value">${N(e.duration)}</span>
9
+ <span class="session-info-value">${_(e.duration)}</span>
10
10
  </div>
11
- `);let T=e.sessionStatus==="wip"?" recent-item-wip":"",I="";return e.tags&&e.tags.length>0&&(I=`<div class="session-tags">${e.tags.map(l=>`<span class="session-tag" style="background-color: ${U(l)}" title="${c(l)}">${c(l)}</span>`).join("")}</div>`),`
11
+ `);let T=e.sessionStatus==="wip"?" recent-item-wip":"",I="";return e.tags&&e.tags.length>0&&(I=`<div class="session-tags">${e.tags.map(l=>`<span class="session-tag" style="background-color: ${V(l)}" title="${c(l)}">${c(l)}</span>`).join("")}</div>`),`
12
12
  <a href="/session/${e.id}" class="recent-item${T}" onclick="trackClick('SessionCardClicked', { sessionId: '${c(e.id)}', source: '${c(e.source||"unknown")}' })">
13
13
  <div class="session-id">
14
14
  <span class="session-id-text" title="${c(e.id)}">${c(e.id)}</span>
@@ -32,4 +32,4 @@
32
32
  </div>
33
33
  </div>
34
34
  </a>
35
- `}function c(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}var H=["#3b82f6","#10b981","#f59e0b","#ef4444","#8b5cf6","#ec4899","#06b6d4","#f97316"];function U(e){let t=0;for(let s=0;s<e.length;s++)t=e.charCodeAt(s)+((t<<5)-t);return H[Math.abs(t)%H.length]}async function V(e){try{let t=e.map(n=>fetch(`/api/sessions/${n}/tags`).then(a=>a.ok?a.json():{tags:[]}).then(a=>({id:n,tags:a.tags||[]})).catch(()=>({id:n,tags:[]}))),s=await Promise.all(t),o={};return s.forEach(({id:n,tags:a})=>{o[n]=a}),o}catch(t){return console.error("Error loading session tags:",t),{}}}async function C(e){let t=e.map(o=>o.id),s=await V(t);e.forEach(o=>{o.tags=s[o.id]||[]})}function b(e){let t=document.getElementById("sourceHint");t&&k[e]?t.innerHTML='Sessions from <span class="hint-code">'+k[e]+"</span>":t&&(t.textContent="")}async function x(e){if(u[e]||(u[e]={offset:0,hasMore:!0}),u[e].offset===0&&!f){f=!0;let t=document.getElementById("sessions-container");t.innerHTML='<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">\u23F3 Loading...</div>',document.getElementById("loading-indicator").style.display="none";try{let s=await fetch(`/api/sessions/load-more?offset=0&limit=20&source=${encodeURIComponent(e)}`);if(s.ok){let o=await s.json(),n=new Set(m.map(r=>r.id)),a=[];for(let r of o.sessions||[])n.has(r.id)||(m.push(r),a.push(r));u[e].offset=(o.sessions||[]).length,u[e].hasMore=o.hasMore,await C(a)}}catch(s){console.error("Failed to load sessions for source:",e,s)}finally{f=!1}}E()}function Y(){let e=document.querySelectorAll(".filter-pill");if(!new Set([...e].map(s=>s.getAttribute("data-source"))).has(i)){i="copilot";try{localStorage.setItem(S,i)}catch{}}e.forEach(s=>{s.classList.toggle("active",s.getAttribute("data-source")===i)}),b(i),e.forEach(s=>{s.addEventListener("click",async()=>{e.forEach(o=>o.classList.remove("active")),s.classList.add("active"),i=s.getAttribute("data-source");try{localStorage.setItem(S,i)}catch{}b(i),window.trackClick("FilterPillClicked",{pillName:s.textContent.trim(),dataSource:i}),await x(i)})})}document.addEventListener("DOMContentLoaded",async function(){await C(m),window.addEventListener("scroll",Z),Y(),i==="copilot"?E():await x(i)});})();
35
+ `}function c(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}var b=["#3b82f6","#10b981","#f59e0b","#ef4444","#8b5cf6","#ec4899","#06b6d4","#f97316"];function V(e){let t=0;for(let s=0;s<e.length;s++)t=e.charCodeAt(s)+((t<<5)-t);return b[Math.abs(t)%b.length]}async function U(e){try{let t=e.map(n=>fetch(`/api/sessions/${n}/tags`).then(a=>a.ok?a.json():{tags:[]}).then(a=>({id:n,tags:a.tags||[]})).catch(()=>({id:n,tags:[]}))),s=await Promise.all(t),o={};return s.forEach(({id:n,tags:a})=>{o[n]=a}),o}catch(t){return console.error("Error loading session tags:",t),{}}}async function C(e){let t=e.map(o=>o.id),s=await U(t);e.forEach(o=>{o.tags=s[o.id]||[]})}function H(e){let t=document.getElementById("sourceHint");t&&k[e]?t.innerHTML='Sessions from <span class="hint-code">'+k[e]+"</span>":t&&(t.textContent="")}async function x(e){if(u[e]||(u[e]={offset:0,hasMore:!0}),u[e].offset===0&&!f){f=!0;let t=document.getElementById("sessions-container");t.innerHTML='<div style="text-align: center; color: #6e7681; padding: 40px; font-size: 14px;">\u23F3 Loading...</div>',document.getElementById("loading-indicator").style.display="none";try{let s=await fetch(`/api/sessions/load-more?offset=0&limit=20&source=${encodeURIComponent(e)}`);if(s.ok){let o=await s.json(),n=new Set(m.map(r=>r.id)),a=[];for(let r of o.sessions||[])n.has(r.id)||(m.push(r),a.push(r));u[e].offset=(o.sessions||[]).length,u[e].hasMore=o.hasMore,await C(a)}}catch(s){console.error("Failed to load sessions for source:",e,s)}finally{f=!1}}E()}function Y(){let e=document.querySelectorAll(".filter-pill");if(!new Set([...e].map(s=>s.getAttribute("data-source"))).has(i)){i="copilot";try{localStorage.setItem(S,i)}catch{}}e.forEach(s=>{s.classList.toggle("active",s.getAttribute("data-source")===i)}),H(i),e.forEach(s=>{s.addEventListener("click",async()=>{e.forEach(o=>o.classList.remove("active")),s.classList.add("active"),i=s.getAttribute("data-source");try{localStorage.setItem(S,i)}catch{}H(i),window.trackClick("FilterPillClicked",{pillName:s.textContent.trim(),dataSource:i}),await x(i)})})}document.addEventListener("DOMContentLoaded",async function(){await C(m),window.addEventListener("scroll",P),Y(),i==="copilot"?E():await x(i)});})();
@@ -1,13 +1,13 @@
1
- (()=>{(function(){if(typeof Vue>"u"){console.error("Vue is not loaded");return}if(typeof window.VueVirtualScroller>"u"){console.error("VueVirtualScroller is not loaded");return}console.log("Initializing Vue app...");let{createApp:fe,ref:u,computed:v,onMounted:X,onBeforeUnmount:be,watch:$}=Vue,{DynamicScroller:Te,DynamicScrollerItem:he}=window.VueVirtualScroller,Y=fe({components:{DynamicScroller:Te,DynamicScrollerItem:he},setup(){let m=u(window.__PAGE_DATA.sessionId),b=u(window.__PAGE_DATA.metadata),j=u(!1),Z=()=>window.innerWidth<=640,q=u(Z()?!0:localStorage.getItem("sidebarCollapsed")==="true");$(q,e=>{Z()||localStorage.setItem("sidebarCollapsed",e.toString())});let k=u({}),w=u({}),U=50,Q=()=>{let e=Object.keys(k.value);e.length>U&&e.slice(0,e.length-U).forEach(s=>delete k.value[s]);let t=Object.keys(w.value);t.length>U&&t.slice(0,t.length-U).forEach(s=>delete w.value[s])},E=u("all"),F=u(""),M=u(""),ee=u(0),g=u(null),te=u({start:0,end:0}),L=null;$(F,e=>{clearTimeout(L),L=setTimeout(()=>{M.value=e,e.trim()&&window.trackClick&&window.trackClick("SearchUsed",{query:e.substring(0,50),resultCount:N.value.length,sessionId:m.value})},300)}),$(E,()=>{Q()}),$(M,()=>{Q()});let C=u([]),ae=u(!0),se=u(null),T=v(()=>C.value.filter(t=>t.type!=="assistant.turn_end"&&t.type!=="assistant.turn_complete").sort((t,a)=>{let s=t.timestamp?new Date(t.timestamp).getTime():0,n=a.timestamp?new Date(a.timestamp).getTime():0;return s!==n?s-n:(t._fileIndex??0)-(a._fileIndex??0)}).map((t,a)=>({...t,virtualIndex:a,stableId:t.id||`${t.timestamp}-${t.type}-${a}`}))),ye=e=>{if(!M.value.trim())return!0;let t=M.value.toLowerCase();return[e.data?.message,e.data?.text,e.data?.content,e.data?.reason,e.data?.reasoningText,e.data?.errorType,e.data?.previousModel,e.data?.newModel].filter(Boolean).join(" ").toLowerCase().includes(t)},N=v(()=>{let e=a=>{let s=a.type||"";return s!=="tool.execution_start"&&s!=="tool.execution_complete"},t=T.value.filter(e);return M.value.trim()&&(t=t.filter(ye)),t}),A=v(()=>{let e=N.value;E.value!=="all"&&(e=e.filter(s=>s.type===E.value));let t=["assistant.turn_start","subagent.started","subagent.completed","subagent.failed"],a=e.length;return e.map((s,n)=>{let i=e[n+1],o=n===a-1,r=i&&t.includes(i.type);return{...s,filteredIndex:n,filteredTotal:a,isLastEvent:o||r}})}),xe=v(()=>{let e={};return N.value.forEach(t=>{t.type&&(e[t.type]=(e[t.type]||0)+1)}),e}),ke=v(()=>{if(!M.value.trim())return null;let e=N.value.length;return e>0?`${e} result${e!==1?"s":""}`:"No matches"}),we=v(()=>{let e=Object.keys(k.value).filter(a=>k.value[a]).length,t=Object.keys(w.value).filter(a=>w.value[a]).length;return e+t}),oe=v(()=>{let e=N.value.length,t=[{type:"all",label:`All (${e})`,count:e}],a={};N.value.forEach(n=>{n.type&&(a[n.type]=(a[n.type]||0)+1)});let s=Object.entries(a).sort((n,i)=>i[1]-n[1]).map(([n,i])=>({type:n,label:`${n} (${i})`,count:i,disabled:!1}));return[...t,...s]}),D=v(()=>{let e=T.value.filter(a=>a.type==="assistant.turn_start"),t=T.value.filter(a=>a.type==="user.message");return e.map((a,s)=>{let n=s,i=new Date(a.timestamp).getTime(),o,r=e.indexOf(a)+1;r<e.length?o=new Date(e[r].timestamp).getTime():o=Date.now();let c=o-i,l=Math.floor(c/1e3),d=Math.floor(l/60),p=l%60,J=d>0?`${d}m ${p}s`:`${p}s`,R=T.value.slice(0,T.value.indexOf(a)).reverse().find(f=>f.type==="user.message"),B=R?t.indexOf(R)+1:0;return{id:n,index:a.virtualIndex,originalTurnId:a.data?.turnId,timestamp:a.timestamp,duration:J,message:R?.data?.content||R?.data?.transformedContent||"",userReqNumber:B}})}),Ce=v(()=>{let e=[],t=new Map;return D.value.forEach(a=>{let s=a.userReqNumber||0;if(!t.has(s)){let n={reqNumber:s,message:a.message,turns:[]};t.set(s,n),e.push(n)}t.get(s).turns.push(a)}),e}),Se=(e,t)=>e?e.length<=t?e:e.substring(0,t)+"\u2026":"",Ie=v(()=>{let e=T.value,t=new Map,a=new Map,s=0;for(let o of e)if(o.type==="subagent.started"){let r=o.data?.toolCallId;r&&a.set(r,{name:o.data?.agentDisplayName||o.data?.agentName||"SubAgent",colorIndex:s++})}for(let o of e)if(o.type==="assistant.message"&&o.data?.subAgentName&&o.data?.subAgentId){let r=o.data.subAgentId;a.has(r)||a.set(r,{name:o.data.subAgentName,colorIndex:s++}),t.set(o.stableId,r)}if(a.size===0)return{ownerMap:t,subagentInfo:a};let n=new Map;for(let o of e)o.id&&n.set(o.id,o);for(let o of e)if(o.type==="assistant.message"){let r=o.data?.parentToolCallId;r&&a.has(r)&&t.set(o.stableId,r)}for(let o of e){if(o.type!=="reasoning")continue;let r=o.parentId,c=0;for(;r&&c<10;){let l=n.get(r);if(!l)break;if(l.type==="assistant.message"){let d=l.data?.parentToolCallId;d&&a.has(d)&&t.set(o.stableId,d);break}r=l.parentId,c++}}let i=new Map;for(let o of e){if(o.type!=="tool.execution_start")continue;let r=o.parentId,c=0;for(;r&&c<10;){let l=n.get(r);if(!l)break;if(l.type==="assistant.message"){let d=l.data?.parentToolCallId;if(d&&a.has(d)){t.set(o.stableId,d);let p=o.data?.toolCallId;p&&i.set(p,d)}break}r=l.parentId,c++}}for(let o of e){if(o.type!=="tool.execution_complete")continue;let r=o.data?.toolCallId;r&&i.has(r)&&t.set(o.stableId,i.get(r))}for(let o of e){if(o.type!=="tool.invocation")continue;let r=o.data?.parentToolCallId;r&&a.has(r)&&t.set(o.stableId,r)}return{ownerMap:t,subagentInfo:a}}),Ee=e=>{if(!e)return"";let t=new Date(e),a=String(t.getHours()).padStart(2,"0"),s=String(t.getMinutes()).padStart(2,"0"),n=String(t.getSeconds()).padStart(2,"0");return`${a}:${s}:${n}`},Me=e=>{if(!e)return"";let t=new Date(e),a=String(t.getHours()).padStart(2,"0"),s=String(t.getMinutes()).padStart(2,"0"),n=String(t.getSeconds()).padStart(2,"0"),i=String(t.getMilliseconds()).padStart(3,"0");return`${a}:${s}:${n}.${i}`},h=new Map,ne=200,Ne=e=>{if(!e)return"";if(h.has(e))return h.get(e);try{let t=e.replace(/\\r\\n/g,`
1
+ (()=>{var Ae=(d,g)=>()=>(g||d((g={exports:{}}).exports,g),g.exports);var Le=Ae((Bt,oe)=>{function qt(d){let g=new Map,f=new Map,y=0;for(let o of d)if(o.type==="subagent.started"){let u=o.data?.toolCallId;u&&f.set(u,{name:o.data?.agentDisplayName||o.data?.agentName||"SubAgent",colorIndex:y++})}for(let o of d)if(o.type==="assistant.message"&&o.data?.subAgentName&&o.data?.subAgentId){let u=o.data.subAgentId;f.has(u)||f.set(u,{name:o.data.subAgentName,colorIndex:y++}),g.set(o.stableId,u)}for(let o of d)if(o._subagent?.id){let u=o._subagent.id;f.has(u)||f.set(u,{name:o._subagent.name||"SubAgent",colorIndex:y++}),g.set(o.stableId,u)}if(f.size===0)return{ownerMap:g,subagentInfo:f};let B=new Map;for(let o of d)o.id&&B.set(o.id,o);for(let o of d)if(o.type==="assistant.message"){let u=o.data?.parentToolCallId;u&&f.has(u)&&g.set(o.stableId,u)}for(let o of d){if(o.type!=="reasoning")continue;let u=o.parentId,M=0;for(;u&&M<10;){let w=B.get(u);if(!w)break;if(w.type==="assistant.message"){let R=w.data?.parentToolCallId;R&&f.has(R)&&g.set(o.stableId,R);break}u=w.parentId,M++}}let m=new Map;for(let o of d){if(o.type!=="tool.execution_start")continue;let u=o.parentId,M=0;for(;u&&M<10;){let w=B.get(u);if(!w)break;if(w.type==="assistant.message"){let R=w.data?.parentToolCallId;if(R&&f.has(R)){g.set(o.stableId,R);let P=o.data?.toolCallId;P&&m.set(P,R)}break}u=w.parentId,M++}}for(let o of d){if(o.type!=="tool.execution_complete")continue;let u=o.data?.toolCallId;u&&m.has(u)&&g.set(o.stableId,m.get(u))}for(let o of d){if(o.type!=="tool.invocation")continue;let u=o.data?.parentToolCallId;u&&f.has(u)&&g.set(o.stableId,u)}let v=null;for(let o of d)o.type==="subagent.started"&&o.data?.toolCallId&&f.has(o.data.toolCallId)?v=o.data.toolCallId:(o.type==="subagent.completed"||o.type==="subagent.failed")&&o.data?.toolCallId===v?v=null:v&&!g.has(o.stableId)&&g.set(o.stableId,v);return{ownerMap:g,subagentInfo:f}}function Ft(d,g,f){return g?d.filter(y=>(y.type==="subagent.started"||y.type==="subagent.completed"||y.type==="subagent.failed")&&y.data?.toolCallId===g||f.get(y.stableId)===g||y._subagent?.id===g||y.data?.subAgentId===g):d}typeof oe<"u"&&oe.exports&&(oe.exports={computeSubagentOwnership:qt,filterBySubagent:Ft})});var Oe=Ae((Pt,ie)=>{function De(d){if(!d||typeof d!="object")return 0;let g=Number.isFinite(d.inputTokens)?d.inputTokens:0,f=Number.isFinite(d.cacheReadTokens)?d.cacheReadTokens:0,y=Number.isFinite(d.cacheWriteTokens)?d.cacheWriteTokens:0;return Math.max(g-f-y,0)}function Ut(d){if(!d||typeof d!="object")return null;let g=Number.isFinite(d.cacheReadTokens)?d.cacheReadTokens:0,f=De(d)+g;return g===0||f===0?null:Math.round(g/f*100)}typeof ie<"u"&&ie.exports&&(ie.exports={getDisplayInputTokens:De,getCacheHitRatio:Ut})});(function(){let{computeSubagentOwnership:d,filterBySubagent:g}=Le(),{getDisplayInputTokens:f,getCacheHitRatio:y}=Oe();if(typeof Vue>"u"){console.error("Vue is not loaded");return}if(typeof window.VueVirtualScroller>"u"){console.error("VueVirtualScroller is not loaded");return}console.log("Initializing Vue app...");let{createApp:B,ref:m,computed:v,onMounted:o,onBeforeUnmount:u,watch:M}=Vue,{DynamicScroller:w,DynamicScrollerItem:R}=window.VueVirtualScroller,P=B({components:{DynamicScroller:w,DynamicScrollerItem:R},setup(){let p=m(window.__PAGE_DATA.sessionId),x=m(window.__PAGE_DATA.metadata),re=m(!1),me=()=>window.innerWidth<=640,X=m(me()?!0:localStorage.getItem("sidebarCollapsed")==="true");M(X,t=>{me()||localStorage.setItem("sidebarCollapsed",t.toString())});let L=m({}),D=m({}),Y=50,ge=()=>{let t=Object.keys(L.value);t.length>Y&&t.slice(0,t.length-Y).forEach(s=>delete L.value[s]);let e=Object.keys(D.value);e.length>Y&&e.slice(0,e.length-Y).forEach(s=>delete D.value[s])},N=m("all"),H=m(""),F=m(""),pe=m(0),h=m(null),ve=m({start:0,end:0}),A=m(null),le=m(!1),_e=v(()=>{let t=0;return N.value!=="all"&&t++,A.value&&t++,H.value.trim()&&t++,t}),$e=()=>{N.value="all",A.value=null,H.value="",F.value="",le.value=!1},j=null,Z=null;M(H,t=>{clearTimeout(j),j=setTimeout(()=>{F.value=t,t.trim()&&window.trackClick&&window.trackClick("SearchUsed",{query:t.substring(0,50),resultCount:z.value.length,sessionId:p.value})},300)}),M(N,()=>{ge()}),M(F,()=>{ge()});let O=m([]),fe=m(!0),be=m(null),k=v(()=>O.value.filter(e=>e.type!=="assistant.turn_end"&&e.type!=="assistant.turn_complete").sort((e,a)=>{let s=e.timestamp?new Date(e.timestamp).getTime():0,n=a.timestamp?new Date(a.timestamp).getTime():0;return s!==n?s-n:(e._fileIndex??0)-(a._fileIndex??0)}).map((e,a)=>({...e,virtualIndex:a,stableId:e.id||`${e.timestamp}-${e.type}-${a}`}))),qe=t=>{if(!F.value.trim())return!0;let e=F.value.toLowerCase();return[t.data?.message,t.data?.text,t.data?.content,t.data?.reason,t.data?.reasoningText,t.data?.errorType,t.data?.previousModel,t.data?.newModel].filter(Boolean).join(" ").toLowerCase().includes(e)},z=v(()=>{let t=a=>{let s=a.type||"";return s!=="tool.execution_start"&&s!=="tool.execution_complete"},e=k.value.filter(t);return F.value.trim()&&(e=e.filter(qe)),e}),W=v(()=>{let t=z.value;if(A.value){let{ownerMap:s}=Q.value;t=g(t,A.value,s)}N.value!=="all"&&(t=t.filter(s=>s.type===N.value));let e=["assistant.turn_start","subagent.started","subagent.completed","subagent.failed"],a=t.length;return t.map((s,n)=>{let i=t[n+1],r=n===a-1,l=i&&e.includes(i.type);return{...s,filteredIndex:n,filteredTotal:a,isLastEvent:r||l}})}),Fe=v(()=>{let t={};return z.value.forEach(e=>{e.type&&(t[e.type]=(t[e.type]||0)+1)}),t}),Ue=v(()=>{if(!F.value.trim())return null;let t=z.value.length;return t>0?`${t} result${t!==1?"s":""}`:"No matches"}),ze=v(()=>{let t=Object.keys(L.value).filter(a=>L.value[a]).length,e=Object.keys(D.value).filter(a=>D.value[a]).length;return t+e}),Te=v(()=>{let t=z.value.length,e=[{type:"all",label:`All (${t})`,count:t}],a={};z.value.forEach(n=>{n.type&&(a[n.type]=(a[n.type]||0)+1)});let s=Object.entries(a).sort((n,i)=>i[1]-n[1]).map(([n,i])=>({type:n,label:`${n} (${i})`,count:i,disabled:!1}));return[...e,...s]}),G=v(()=>{let t=k.value.filter(a=>a.type==="assistant.turn_start"),e=k.value.filter(a=>a.type==="user.message");return t.map((a,s)=>{let n=s,i=new Date(a.timestamp).getTime(),r,l=t.indexOf(a)+1;l<t.length?r=new Date(t[l].timestamp).getTime():r=Date.now();let c=r-i,b=Math.floor(c/1e3),T=Math.floor(b/60),$=b%60,q=T>0?`${T}m ${$}s`:`${$}s`,V=k.value.slice(0,k.value.indexOf(a)).reverse().find(C=>C.type==="user.message"),te=V?e.indexOf(V)+1:0;return{id:n,index:a.virtualIndex,originalTurnId:a.data?.turnId,timestamp:a.timestamp,duration:q,message:V?.data?.content||V?.data?.transformedContent||"",userReqNumber:te}})}),Ve=v(()=>{let t=[],e=new Map;return G.value.forEach(a=>{let s=a.userReqNumber||0;if(!e.has(s)){let n={reqNumber:s,message:a.message,turns:[]};e.set(s,n),t.push(n)}e.get(s).turns.push(a)}),t}),Be=(t,e)=>t?t.length<=e?t:t.substring(0,e)+"\u2026":"",Q=v(()=>d(k.value)),Pe=v(()=>{let{subagentInfo:t}=Q.value;if(t.size===0)return[];let e=[];for(let[a,s]of t)e.push({toolCallId:a,name:s.name,colorIndex:s.colorIndex});return e}),He=v(()=>{if(!A.value)return null;let{ownerMap:t,subagentInfo:e}=Q.value,a=A.value;if(!e.has(a))return null;let s=0,n=null,i=null;for(let l of k.value){let c=(l.type==="subagent.started"||l.type==="subagent.completed"||l.type==="subagent.failed")&&l.data?.toolCallId===a,b=t.get(l.stableId)===a,T=l._subagent?.id===a,$=l.data?.subAgentId===a;if((c||b||T||$)&&(s++,l.timestamp!==null&&l.timestamp!==void 0)){let q=new Date(l.timestamp).getTime();(n===null||q<n)&&(n=q),(i===null||q>i)&&(i=q)}}let r=n===null||i===null?0:i-n;return{eventCount:s,durationMs:r}}),je=t=>{if(!t)return"";let e=new Date(t),a=String(e.getHours()).padStart(2,"0"),s=String(e.getMinutes()).padStart(2,"0"),n=String(e.getSeconds()).padStart(2,"0");return`${a}:${s}:${n}`},We=t=>{if(!t)return"";let e=new Date(t),a=String(e.getHours()).padStart(2,"0"),s=String(e.getMinutes()).padStart(2,"0"),n=String(e.getSeconds()).padStart(2,"0"),i=String(e.getMilliseconds()).padStart(3,"0");return`${a}:${s}:${n}.${i}`},S=new Map,he=200,Ge=t=>{if(!t)return"";if(S.has(t))return S.get(t);try{let e=t.replace(/\\r\\n/g,`
2
2
  `).replace(/\\n/g,`
3
- `).replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),a={ALLOWED_TAGS:["p","br","strong","em","code","pre","a","ul","ol","li","h1","h2","h3","h4","h5","h6","blockquote","table","thead","tbody","tr","th","td","hr","del","span","div","mark"],ALLOWED_ATTR:["href","style","class"],ALLOW_DATA_ATTR:!1,ALLOWED_URI_REGEXP:/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i},s=t.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(s){let o=s[1],r=s[2],c=o.split(`
4
- `),l=[],d=0;for(;d<c.length;){let f=c[d];if(!f.trim()||!f.includes(":")){d++;continue}let z=f.indexOf(":"),H=f.substring(0,z).trim(),V=f.substring(z+1).trim();if(V==="|"||V===">"){let pe=[];for(d++;d<c.length&&(c[d].startsWith(" ")||c[d].startsWith(" ")||c[d].trim()==="");)pe.push(c[d].trim()),d++;let vt=V===">"?" ":`
5
- `;l.push({key:H,value:pe.filter(pt=>pt).join(vt)})}else l.push({key:H,value:V}),d++}let p='<table style="margin-bottom: 16px; border-collapse: collapse; width: 100%;"><tbody>';l.forEach(f=>{let z=DOMPurify.sanitize(f.key,{ALLOWED_TAGS:[]}),H=DOMPurify.sanitize(f.value,{ALLOWED_TAGS:[]});p+=`<tr><td style="padding: 4px 12px; border: 1px solid #30363d; font-weight: 600; color: #7d8590;">${z}</td><td style="padding: 4px 12px; border: 1px solid #30363d;">${H}</td></tr>`}),p+="</tbody></table>";let J=marked.parse(r),R=DOMPurify.sanitize(J,a),B=p+R;if(h.size>=ne){let f=h.keys().next().value;h.delete(f)}return h.set(e,B),B}let n=marked.parse(t),i=DOMPurify.sanitize(n,a);if(h.size>=ne){let o=h.keys().next().value;h.delete(o)}return h.set(e,i),i}catch{return e}},Re=e=>{let t={...k.value},a=!!t[e];t[e]?delete t[e]:t[e]=!0,k.value=t,window.trackClick&&window.trackClick("EventExpanded",{eventType:"tool",action:a?"collapse":"expand",sessionId:m.value})},Le=(e,t)=>{if(!t||!t.trim()||!e)return e;let a=t.trim(),s=ce(a).replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=document.createElement("div");n.innerHTML=e;let i=o=>{if(o.nodeType===Node.TEXT_NODE){let r=o.textContent,c=new RegExp(`(${s})`,"gi");if(c.test(r)){let l=r.replace(c,'<mark class="search-highlight">$1</mark>'),d=document.createElement("span");d.innerHTML=l,o.parentNode.replaceChild(d,o)}}else o.nodeType===Node.ELEMENT_NODE&&o.tagName!=="SCRIPT"&&o.tagName!=="STYLE"&&Array.from(o.childNodes).forEach(i)};return Array.from(n.childNodes).forEach(i),n.innerHTML},Ae=e=>{let t={...w.value},a=!!t[e];t[e]?delete t[e]:t[e]=!0,w.value=t,window.trackClick&&window.trackClick("EventExpanded",{eventType:"content",action:a?"collapse":"expand",sessionId:m.value})},De=e=>e?e.split(`
6
- `).length>20||e.length>2e3:!1,Oe=e=>{let t=e.split(`
7
- `);return t.length<=20?e:t.slice(0,20).join(`
3
+ `).replace(/\\t/g," ").replace(/\\"/g,'"').replace(/\\\\/g,"\\"),a={ALLOWED_TAGS:["p","br","strong","em","code","pre","a","ul","ol","li","h1","h2","h3","h4","h5","h6","blockquote","table","thead","tbody","tr","th","td","hr","del","span","div","mark"],ALLOWED_ATTR:["href","style","class"],ALLOW_DATA_ATTR:!1,ALLOWED_URI_REGEXP:/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i},s=e.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);if(s){let r=s[1],l=s[2],c=r.split(`
4
+ `),b=[],T=0;for(;T<c.length;){let C=c[T];if(!C.trim()||!C.includes(":")){T++;continue}let ae=C.indexOf(":"),se=C.substring(0,ae).trim(),ne=C.substring(ae+1).trim();if(ne==="|"||ne===">"){let Ne=[];for(T++;T<c.length&&(c[T].startsWith(" ")||c[T].startsWith(" ")||c[T].trim()==="");)Ne.push(c[T].trim()),T++;let _t=ne===">"?" ":`
5
+ `;b.push({key:se,value:Ne.filter($t=>$t).join(_t)})}else b.push({key:se,value:ne}),T++}let $='<table style="margin-bottom: 16px; border-collapse: collapse; width: 100%;"><tbody>';b.forEach(C=>{let ae=DOMPurify.sanitize(C.key,{ALLOWED_TAGS:[]}),se=DOMPurify.sanitize(C.value,{ALLOWED_TAGS:[]});$+=`<tr><td style="padding: 4px 12px; border: 1px solid #30363d; font-weight: 600; color: #7d8590;">${ae}</td><td style="padding: 4px 12px; border: 1px solid #30363d;">${se}</td></tr>`}),$+="</tbody></table>";let q=marked.parse(l),V=DOMPurify.sanitize(q,a),te=$+V;if(S.size>=he){let C=S.keys().next().value;S.delete(C)}return S.set(t,te),te}let n=marked.parse(e),i=DOMPurify.sanitize(n,a);if(S.size>=he){let r=S.keys().next().value;S.delete(r)}return S.set(t,i),i}catch{return t}},Ke=t=>{let e={...L.value},a=!!e[t];e[t]?delete e[t]:e[t]=!0,L.value=e,window.trackClick&&window.trackClick("EventExpanded",{eventType:"tool",action:a?"collapse":"expand",sessionId:p.value})},Je=(t,e)=>{if(!e||!e.trim()||!t)return t;let a=e.trim(),s=Ce(a).replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),n=document.createElement("div");n.innerHTML=t;let i=r=>{if(r.nodeType===Node.TEXT_NODE){let l=r.textContent,c=new RegExp(`(${s})`,"gi");if(c.test(l)){let b=l.replace(c,'<mark class="search-highlight">$1</mark>'),T=document.createElement("span");T.innerHTML=b,r.parentNode.replaceChild(T,r)}}else r.nodeType===Node.ELEMENT_NODE&&r.tagName!=="SCRIPT"&&r.tagName!=="STYLE"&&Array.from(r.childNodes).forEach(i)};return Array.from(n.childNodes).forEach(i),n.innerHTML},Xe=t=>{let e={...D.value},a=!!e[t];e[t]?delete e[t]:e[t]=!0,D.value=e,window.trackClick&&window.trackClick("EventExpanded",{eventType:"content",action:a?"collapse":"expand",sessionId:p.value})},Ye=t=>t?t.split(`
6
+ `).length>20||t.length>2e3:!1,Ze=t=>{let e=t.split(`
7
+ `);return e.length<=20?t:e.slice(0,20).join(`
8
8
  `)+`
9
9
 
10
- ...`},_e=(e,t)=>{if(t?.data?.badgeLabel&&t?.data?.badgeClass)return{label:t.data.badgeLabel,class:t.data.badgeClass};if(e==="message"&&t?.data?.role==="toolResult")return{label:"TOOL RESULT",class:"badge-tool"};if(e==="session.model_change")return{label:"MODEL CHANGE",class:"badge-session"};if(e==="session.truncation")return{label:"TRUNCATION",class:"badge-truncation"};if(e==="session.compaction_start"||e==="session.compaction_complete")return{label:"COMPACTION",class:"badge-compaction"};if(e==="system.notification")return{label:"SYSTEM",class:"badge-system"};let s=(e||"").split(".")[0]||"unknown";return{user:{label:"USER",class:"badge-user"},assistant:{label:"ASSISTANT",class:"badge-assistant"},reasoning:{label:"REASONING",class:"badge-reasoning"},turn:{label:"TURN",class:"badge-turn"},tool:{label:"TOOL",class:"badge-tool"},subagent:{label:"SUBAGENT",class:"badge-subagent"},skill:{label:"SKILL",class:"badge-skill"},session:{label:"SESSION",class:"badge-session"},error:{label:"ERROR",class:"badge-error"},abort:{label:"ABORT",class:"badge-error"}}[s]||{label:s.toUpperCase(),class:"badge-info"}},$e=e=>{if(!e.complete)return{icon:"\u23F3",color:"tool-status-running",text:""};let t=e.complete.data||{};return t.error||t.isError?{icon:"\u274C",color:"tool-status-error",text:""}:{icon:"\u2713",color:"tool-status-success",text:""}},qe=e=>{if(!e.complete?.data?.error)return"";let t=e.complete.data.error;if(typeof t=="object"&&t.message)return t.message;if(typeof t=="string"){try{let a=JSON.parse(t);if(a.message)return a.message}catch{}return t}return String(t)},Ue=e=>{if(!e.complete)return"";let t=new Date(e.start.timestamp).getTime(),s=new Date(e.complete.timestamp).getTime()-t;return s>=100?`${parseFloat((s/1e3).toPrecision(3))}s`:""},ft=e=>{let t={};if(e.start?.timestamp&&(t.startTime=e.start.timestamp),e.complete?.timestamp&&(t.endTime=e.complete.timestamp),t.startTime&&t.endTime){let a=new Date(t.endTime).getTime()-new Date(t.startTime).getTime();a>=0&&(t.duration=`${parseFloat((a/1e3).toPrecision(3))}s (${a}ms)`)}return t},Pe=e=>{if(!e.start)return"";let t=e.start.data?.arguments||{},a=e.start.data?.toolName||e.tool||"",s="";if(a==="bash"||a==="exec")s=t.command||t.description||"";else if(a==="ask_user")s=t.question||t.message||"";else if(a==="read"||a==="write"||a==="edit")s=t.file_path||t.path||"";else if(a==="view")s=t.path||t.file||"";else if(a==="create")s=t.path||t.name||"";else if(a==="report_intent")s=t.intent||t.message||"";else if(a==="web_search")s=t.query||"";else if(a==="web_fetch")s=t.url||"";else if(a==="browser"){let n=t.action||"",i=t.targetUrl||t.url||"";s=i?`${n} ${i}`:n}else s=t.description||t.command||t.message||t.path||t.file_path||t.query||"";return s&&s.length>200&&(s=s.substring(0,200)+"..."),s},Be=e=>e.data?.tools&&e.data.tools.length>0,ze=e=>e.data?.tools&&Array.isArray(e.data.tools)?e.data.tools.filter(t=>t&&typeof t=="object"&&t.name).map(t=>{let a=t.result!==void 0||t.status==="completed"||t.status==="error",s={};if(t.startTime&&(s.startTime=t.startTime),t.endTime&&(s.endTime=t.endTime),s.startTime&&s.endTime){let n=new Date(s.endTime).getTime()-new Date(s.startTime).getTime();n>=0&&(s.duration=`${parseFloat((n/1e3).toPrecision(3))}s (${n}ms)`)}return{tool:t.name,timing:s,start:{timestamp:t.startTime,data:{toolName:t.name,arguments:t.input||t.arguments||{}}},complete:a?{timestamp:t.endTime,data:{result:t.result,error:t.status==="error"?t.error:null}}:null}}):[],ie=["#58a6ff","#f0883e","#a371f7","#3fb950","#f778ba","#79c0ff","#d29922","#56d4dd"],He=e=>{let t=0;for(let a=0;a<e.length;a++){let s=e.charCodeAt(a);t=(t<<5)-t+s,t=t&t}return t},re=e=>{let{ownerMap:t,subagentInfo:a}=Ie.value;if(e.type==="subagent.started"||e.type==="subagent.completed"||e.type==="subagent.failed"){let i=e.data?.toolCallId;if(i&&a.has(i)){let o=a.get(i);return{name:o.name,toolCallId:i,colorIndex:o.colorIndex}}return null}if(e._subagent){let i=e._subagent.id,o=e._subagent.name;if(a.has(i)){let r=a.get(i);return{name:r.name,toolCallId:i,colorIndex:r.colorIndex}}return{name:o,toolCallId:i,colorIndex:Math.abs(He(i))}}if(e.data?.subAgentId){let i=e.data.subAgentId,o=a.get(i);if(o)return{name:o.name,toolCallId:i,colorIndex:o.colorIndex}}let s=t.get(e.stableId);if(!s)return null;let n=a.get(s);return n?{name:n.name,toolCallId:s,colorIndex:n.colorIndex}:null},Ve=e=>{let t=re(e);return t?ie[t.colorIndex%ie.length]:null},je=e=>{if(window.trackClick){let t=oe.value.find(a=>a.type===e);window.trackClick("EventFilterClicked",{filterType:e,filterLabel:t?t.label:e,sessionId:m.value})}E.value=e},le=e=>{F.value="",E.value="all",ee.value=e.id,Vue.nextTick(()=>{if(g.value){let t=A.value.findIndex(a=>a.virtualIndex===e.index);if(t>=0){let a=s=>{s<=0||!g.value||(g.value.scrollToItem(t),setTimeout(()=>a(s-1),100))};setTimeout(()=>a(3),50)}}})},Fe=()=>{if(!g.value)return;let e=t=>{t<=0||!g.value||(g.value.scrollToItem(0),setTimeout(()=>e(t-1),100))};e(3)},We=()=>{if(!g.value)return;let e=A.value.length-1,t=a=>{a<=0||!g.value||(g.value.scrollToItem(e),setTimeout(()=>t(a-1),100))};t(5)},de=e=>{window.trackClick&&window.trackClick("TurnClicked",{turnNumber:e,sessionId:m.value});let t=D.value.find(a=>a.id===e);if(t){let a=`UserReq${t.userReqNumber}_Turn${t.id}`,s=`${window.location.pathname}?eventType=assistant.turn_start&eventName=${a}`;window.history.pushState({},"",s),le(t)}},Ge=e=>{if(!e)return"";let t=e.replace(/\/$/,"").split("/");return t[t.length-1]||e},Ke=e=>{let t=D.value.find(s=>s.index===e);if(!t)return"?";let a=t.originalTurnId??t.id;return t.userReqNumber>0?`${t.userReqNumber} - Turn ${a}`:`Turn ${a}`},Je=e=>D.value.find(a=>a.index===e)?.duration||null,ce=e=>{let t=document.createElement("div");return t.textContent=e,t.innerHTML},Xe=e=>e?new Date(e).toLocaleString():"N/A",Ye=async()=>{console.log("[Export] exportSession called"),window.trackClick&&window.trackClick("ExportClicked",{sessionId:m.value}),j.value=!0;try{console.log("[Export] Fetching:",`/session/${m.value}/export`);let e=await fetch(`/session/${m.value}/export`);if(console.log("[Export] Response received:",e.status,e.ok),console.log("[Export] Response received:",e.status,e.ok),!e.ok)throw new Error("Share failed");console.log("[Export] Creating blob...");let t=await e.blob();console.log("[Export] Blob size:",t.size,"type:",t.type);let a=window.URL.createObjectURL(t);console.log("[Export] Creating download link...");let s=document.createElement("a");s.href=a,s.download=`session-${m.value}.zip`,document.body.appendChild(s),s.click(),console.log("[Export] Download triggered"),window.URL.revokeObjectURL(a),document.body.removeChild(s),console.log("[Export] Showing success feedback...");let n="\u{1F4E4} Share Session",i="\u2713 Downloaded!",o=document.querySelector(".export-btn");o&&(o.textContent=i,o.style.background="#238636",console.log("[Export] Button text updated to:",o.textContent),setTimeout(()=>{o.textContent=n,o.style.background="",console.log("[Export] Button text restored")},2e3))}catch(e){console.error("[Export] Share session error:",e),alert("Failed to share session: "+e.message)}finally{j.value=!1,console.log("[Export] Export complete")}};X(async()=>{try{console.log("[Navigation] Starting event loading...");let a=await fetch(`/api/sessions/${m.value}/events`);if(!a.ok)throw new Error(`Failed to load events: ${a.statusText}`);let s=await a.json();if(Array.isArray(s))C.value=s;else if(s.events&&Array.isArray(s.events))C.value=s.events,console.log("[Navigation] Pagination:",s.pagination);else throw new Error("Invalid response format");if(console.log("[Navigation] Events loaded:",C.value.length),C.value.length>0){let c=C.value[C.value.length-1],l=c.timestamp||c.time||c.data?.timestamp;l&&(b.value.updated=new Date(l))}let n=new URLSearchParams(window.location.search),i=n.get("eventType"),o=n.get("eventName"),r=n.get("eventTimestamp");console.log("[Navigation] URL params:",i,o,r),i&&o&&(console.log("[Navigation] Waiting for Vue to render..."),Vue.nextTick(()=>{console.log("[Navigation] nextTick - flatEvents count:",T.value?.length);let c=null;if(i==="assistant.turn_start"){let l=o.match(/UserReq(\d+)_Turn(\d+)/);if(l){let d=parseInt(l[2],10);if(!isNaN(d)){console.log("[Navigation] Jumping to turn:",d),de(d);return}}}else i==="subagent.started"?(console.log("[Navigation] Searching for subagent:",o,"timestamp:",r),r&&(c=T.value.find(l=>l.type==="subagent.started"&&l.timestamp===r)),c||(c=T.value.find(l=>l.type==="subagent.started"&&(l.data?.agentDisplayName===o||l.data?.agentName===o||l.data?.label===o))),console.log("[Navigation] Target event found:",c?"YES":"NO","virtualIndex:",c?.virtualIndex)):c=T.value.find(l=>l.type===i);if(c){let l=A.value.findIndex(d=>d.virtualIndex===c.virtualIndex);if(console.log("[Navigation] Target in filteredEvents at index:",l),l>=0&&g.value){console.log("[Navigation] Scrolling to index:",l);let d=p=>{p<=0||!g.value||(g.value.scrollToItem(l),setTimeout(()=>d(p-1),100))};setTimeout(()=>d(3),50)}else console.log("[Navigation] Failed - targetIndex:",l,"scrollerRef:",!!g.value)}else console.log("[Navigation] Target event not found")}))}catch(a){console.error("Error loading events:",a),se.value=a.message}finally{ae.value=!1}window.addEventListener("keydown",a=>{a.ctrlKey&&a.key==="b"&&(a.preventDefault(),q.value=!q.value)}),window.marked&&marked.setOptions({breaks:!0,gfm:!0});let e=()=>{if(!g.value)return;let a=null;if(g.value.$el&&typeof g.value.$el.querySelector=="function"?a=g.value.$el.querySelector(".vue-recycle-scroller"):g.value.querySelector&&typeof g.value.querySelector=="function"&&(a=g.value.querySelector(".vue-recycle-scroller")),a||(a=document.querySelector(".vue-recycle-scroller")),a){let s=a.scrollTop,n=a.clientHeight,i=80,o=Math.floor(s/i),r=Math.ceil(n/i),c=Math.min(o+r,A.value.length),l=Math.max(1,o+1),d=Math.max(1,c);te.value={start:Math.min(l,d),end:d}}},t=null;setTimeout(()=>{e();let a=document.querySelector(".vue-recycle-scroller");a&&(a.addEventListener("scroll",e),t=()=>{a.removeEventListener("scroll",e)})},500),be(()=>{L&&(clearTimeout(L),L=null),t&&t(),k.value={},w.value={},h.clear()})});let O=u([]),W=u([]),_=u(!1),y=u([]),S=u(""),G=u(null),x=u(""),I=u(!1),P=u([]),ue=u(0),K=u(!1),Ze=e=>!e||e===0?"0":e<1e3?e.toString():Math.floor(e/1e3)+"K",Qe=e=>{if(!e||e===0)return"0s";let t=Math.floor(e/1e3);if(t<60)return(e/1e3).toFixed(1)+"s";let a=Math.floor(t/60),s=t%60;return`${a}m ${s}s`},et=v(()=>{if(!b.value.usage||!b.value.usage.modelMetrics)return 0;let e=0;for(let t in b.value.usage.modelMetrics){let a=b.value.usage.modelMetrics[t].usage;a&&(e+=(a.inputTokens||0)+(a.outputTokens||0))}return e}),tt=v(()=>{if(!b.value.usage||!b.value.usage.modelMetrics)return 0;let e=0;for(let t in b.value.usage.modelMetrics)e+=b.value.usage.modelMetrics[t].requests?.count||0;return e}),at=e=>{let t=b.value.usage?.modelMetrics[e];if(!t||!t.usage)return null;let a=t.usage.cacheReadTokens||0,s=t.usage.inputTokens||0;return s===0?null:Math.round(a/s*100)},st=e=>e==null?"":e+" premium",ot=()=>{K.value=!K.value},me=["#3b82f6","#10b981","#f59e0b","#ef4444","#8b5cf6","#ec4899","#06b6d4","#f97316"],nt=e=>{let t=0;for(let a=0;a<e.length;a++)t=e.charCodeAt(a)+((t<<5)-t);return me[Math.abs(t)%me.length]},it=async()=>{try{let e=await fetch(`/api/sessions/${m.value}/tags`);if(e.ok){let t=await e.json();O.value=t.tags||[]}}catch(e){console.error("Error loading tags:",e)}},ge=async()=>{try{let e=await fetch("/api/tags");if(e.ok){let t=await e.json();W.value=t.tags||[]}}catch(e){console.error("Error loading all tags:",e)}},rt=async e=>{try{window.trackClick&&e.filter(s=>!O.value.includes(s)).forEach(s=>{window.trackClick("TagAdded",{sessionId:m.value,tag:s})});let t=await fetch(`/api/sessions/${m.value}/tags`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({tags:e})});if(t.ok){let a=await t.json();return O.value=a.tags||[],x.value="",!0}else{let a=await t.json();return x.value=a.error||"Failed to save tags",!1}}catch(t){return console.error("Error saving tags:",t),x.value="Network error",!1}},lt=()=>{y.value=[...O.value],_.value=!0,x.value="",setTimeout(()=>{G.value&&G.value.focus()},10)},dt=()=>{_.value=!1,y.value=[],S.value="",I.value=!1,x.value=""},ve=()=>{let e=S.value.trim().toLowerCase();if(e){if(e.length>30){x.value="Tag must be 30 characters or less";return}if(y.value.length>=10){x.value="Maximum 10 tags per session";return}if(y.value.includes(e)){x.value="Tag already added",S.value="";return}y.value.push(e),S.value="",I.value=!1,x.value=""}},ct=e=>{y.value=y.value.filter(t=>t!==e),x.value=""},ut=()=>{let e=S.value.trim().toLowerCase();if(!e){I.value=!1,P.value=[];return}let t=W.value.filter(a=>a.toLowerCase().includes(e)&&!y.value.includes(a)).slice(0,5);t.length>0?(I.value=!0,P.value=t,ue.value=0):(I.value=!1,P.value=[])},mt=e=>{S.value=e,ve()},gt=async()=>{setTimeout(async()=>{if(!_.value)return;await rt(y.value)&&(_.value=!1,y.value=[],S.value="",I.value=!1,await ge())},200)};return X(async()=>{await it(),await ge()}),{sessionId:m,metadata:b,exporting:j,sidebarCollapsed:q,expandedTools:k,expandedContent:w,expansionCount:we,currentFilter:E,searchText:F,currentTurnIndex:ee,scrollerRef:g,visibleRange:te,loadedEvents:C,eventsLoading:ae,eventsError:se,flatEvents:T,filteredEvents:A,eventCounts:xe,filters:oe,turns:D,userReqs:Ce,truncateText:Se,formatTime:Ee,formatToolTime:Me,formatDateTime:Xe,renderMarkdown:Ne,highlightSearchText:Le,toggleTool:Re,toggleContent:Ae,isContentTooLong:De,truncateContent:Oe,getBadgeInfo:_e,getToolStatus:$e,getToolErrorMessage:qe,getToolDuration:Ue,getToolCommand:Pe,hasTools:Be,getToolGroups:ze,getSubagentInfo:re,getSubagentColor:Ve,setFilter:je,scrollToTurn:le,scrollToTop:Fe,scrollToBottom:We,jumpToTurn:de,getTurnNumber:Ke,getTurnDuration:Je,repoBasename:Ge,escapeHtml:ce,exportSession:Ye,searchResultCount:ke,sessionTags:O,allTags:W,tagsEditing:_,editingTags:y,tagInputValue:S,tagInputRef:G,tagsError:x,showAutocomplete:I,autocompleteOptions:P,autocompleteSelectedIndex:ue,getTagColor:nt,startEditTags:lt,cancelEditTags:dt,addTag:ve,removeTagFromEdit:ct,updateAutocomplete:ut,selectAutocompleteOption:mt,saveTagsOnBlur:gt,usageExpanded:K,toggleUsage:ot,formatTokens:Ze,formatDuration:Qe,formatCost:st,totalTokens:et,totalRequests:tt,getCacheHitRatio:at}},template:`
10
+ ...`},Qe=(t,e)=>{if(e?.data?.badgeLabel&&e?.data?.badgeClass)return{label:e.data.badgeLabel,class:e.data.badgeClass};if(t==="message"&&e?.data?.role==="toolResult")return{label:"TOOL RESULT",class:"badge-tool"};if(t==="session.model_change")return{label:"MODEL CHANGE",class:"badge-session"};if(t==="session.truncation")return{label:"TRUNCATION",class:"badge-truncation"};if(t==="session.compaction_start"||t==="session.compaction_complete")return{label:"COMPACTION",class:"badge-compaction"};if(t==="system.notification")return{label:"SYSTEM",class:"badge-system"};let s=(t||"").split(".")[0]||"unknown";return{user:{label:"USER",class:"badge-user"},assistant:{label:"ASSISTANT",class:"badge-assistant"},reasoning:{label:"REASONING",class:"badge-reasoning"},turn:{label:"TURN",class:"badge-turn"},tool:{label:"TOOL",class:"badge-tool"},subagent:{label:"SUBAGENT",class:"badge-subagent"},skill:{label:"SKILL",class:"badge-skill"},session:{label:"SESSION",class:"badge-session"},error:{label:"ERROR",class:"badge-error"},abort:{label:"ABORT",class:"badge-error"}}[s]||{label:s.toUpperCase(),class:"badge-info"}},et=t=>{if(!t.complete)return{icon:"\u23F3",color:"tool-status-running",text:""};let e=t.complete.data||{};return e.error||e.isError?{icon:"\u274C",color:"tool-status-error",text:""}:{icon:"\u2713",color:"tool-status-success",text:""}},tt=t=>{if(!t.complete?.data?.error)return"";let e=t.complete.data.error;if(typeof e=="object"&&e.message)return e.message;if(typeof e=="string"){try{let a=JSON.parse(e);if(a.message)return a.message}catch{}return e}return String(e)},at=t=>{if(!t.complete)return"";let e=new Date(t.start.timestamp).getTime(),s=new Date(t.complete.timestamp).getTime()-e;return s>=100?`${parseFloat((s/1e3).toPrecision(3))}s`:""},zt=t=>{let e={};if(t.start?.timestamp&&(e.startTime=t.start.timestamp),t.complete?.timestamp&&(e.endTime=t.complete.timestamp),e.startTime&&e.endTime){let a=new Date(e.endTime).getTime()-new Date(e.startTime).getTime();a>=0&&(e.duration=`${parseFloat((a/1e3).toPrecision(3))}s (${a}ms)`)}return e},st=t=>{if(!t.start)return"";let e=t.start.data?.arguments||{},a=t.start.data?.toolName||t.tool||"",s="";if(a==="bash"||a==="exec")s=e.command||e.description||"";else if(a==="ask_user")s=e.question||e.message||"";else if(a==="read"||a==="write"||a==="edit")s=e.file_path||e.path||"";else if(a==="view")s=e.path||e.file||"";else if(a==="create")s=e.path||e.name||"";else if(a==="report_intent")s=e.intent||e.message||"";else if(a==="web_search")s=e.query||"";else if(a==="web_fetch")s=e.url||"";else if(a==="browser"){let n=e.action||"",i=e.targetUrl||e.url||"";s=i?`${n} ${i}`:n}else s=e.description||e.command||e.message||e.path||e.file_path||e.query||"";return s&&s.length>200&&(s=s.substring(0,200)+"..."),s},nt=t=>t.data?.tools&&t.data.tools.length>0,ot=t=>t.data?.tools&&Array.isArray(t.data.tools)?t.data.tools.filter(e=>e&&typeof e=="object"&&e.name).map(e=>{let a=e.result!==void 0||e.status==="completed"||e.status==="error",s={};if(e.startTime&&(s.startTime=e.startTime),e.endTime&&(s.endTime=e.endTime),s.startTime&&s.endTime){let n=new Date(s.endTime).getTime()-new Date(s.startTime).getTime();n>=0&&(s.duration=`${parseFloat((n/1e3).toPrecision(3))}s (${n}ms)`)}return{tool:e.name,timing:s,start:{timestamp:e.startTime,data:{toolName:e.name,arguments:e.input||e.arguments||{}}},complete:a?{timestamp:e.endTime,data:{result:e.result,error:e.status==="error"?e.error:null}}:null}}):[],ce=["#58a6ff","#f0883e","#a371f7","#3fb950","#f778ba","#79c0ff","#d29922","#56d4dd"],it=t=>{let e=0;for(let a=0;a<t.length;a++){let s=t.charCodeAt(a);e=(e<<5)-e+s,e=e&e}return e},ye=t=>{let{ownerMap:e,subagentInfo:a}=Q.value;if(t.type==="subagent.started"||t.type==="subagent.completed"||t.type==="subagent.failed"){let i=t.data?.toolCallId;if(i&&a.has(i)){let r=a.get(i);return{name:r.name,toolCallId:i,colorIndex:r.colorIndex}}return null}if(t._subagent){let i=t._subagent.id,r=t._subagent.name;if(a.has(i)){let l=a.get(i);return{name:l.name,toolCallId:i,colorIndex:l.colorIndex}}return{name:r,toolCallId:i,colorIndex:Math.abs(it(i))}}if(t.data?.subAgentId){let i=t.data.subAgentId,r=a.get(i);if(r)return{name:r.name,toolCallId:i,colorIndex:r.colorIndex}}let s=e.get(t.stableId);if(!s)return null;let n=a.get(s);return n?{name:n.name,toolCallId:s,colorIndex:n.colorIndex}:null},rt=t=>{let e=ye(t);return e?ce[e.colorIndex%ce.length]:null},lt=t=>{if(window.trackClick){let e=Te.value.find(a=>a.type===t);window.trackClick("EventFilterClicked",{filterType:t,filterLabel:e?e.label:t,sessionId:p.value})}N.value=t},ct=t=>{A.value=t,t&&(N.value="all"),window.trackClick&&window.trackClick("SubagentSelected",{subagent:t,sessionId:p.value})},xe=t=>{H.value="",N.value="all",A.value=null,pe.value=t.id,Vue.nextTick(()=>{if(h.value){let e=W.value.findIndex(a=>a.virtualIndex===t.index);if(e>=0){let a=s=>{s<=0||!h.value||(h.value.scrollToItem(e),setTimeout(()=>a(s-1),100))};setTimeout(()=>a(3),50)}}})},dt=()=>{if(!h.value)return;let t=e=>{e<=0||!h.value||(h.value.scrollToItem(0),setTimeout(()=>t(e-1),100))};t(3)},ut=()=>{if(!h.value)return;let t=W.value.length-1,e=a=>{a<=0||!h.value||(h.value.scrollToItem(t),setTimeout(()=>e(a-1),100))};e(5)},ke=t=>{window.trackClick&&window.trackClick("TurnClicked",{turnNumber:t,sessionId:p.value});let e=G.value.find(a=>a.id===t);if(e){let a=`UserReq${e.userReqNumber}_Turn${e.id}`,s=`${window.location.pathname}?eventType=assistant.turn_start&eventName=${a}`;window.history.pushState({},"",s),xe(e)}},mt=t=>{if(!t)return"";let e=t.replace(/\/$/,"").split("/");return e[e.length-1]||t},gt=t=>{let e=G.value.find(s=>s.index===t);if(!e)return"?";let a=e.originalTurnId??e.id;return e.userReqNumber>0?`${e.userReqNumber} - Turn ${a}`:`Turn ${a}`},pt=t=>G.value.find(a=>a.index===t)?.duration||null,Ce=t=>{let e=document.createElement("div");return e.textContent=t,e.innerHTML},vt=t=>t?new Date(t).toLocaleString():"N/A",ft=async()=>{console.log("[Export] exportSession called"),window.trackClick&&window.trackClick("ExportClicked",{sessionId:p.value}),re.value=!0;try{console.log("[Export] Fetching:",`/session/${p.value}/export`);let t=await fetch(`/session/${p.value}/export`);if(console.log("[Export] Response received:",t.status,t.ok),console.log("[Export] Response received:",t.status,t.ok),!t.ok)throw new Error("Share failed");console.log("[Export] Creating blob...");let e=await t.blob();console.log("[Export] Blob size:",e.size,"type:",e.type);let a=window.URL.createObjectURL(e);console.log("[Export] Creating download link...");let s=document.createElement("a");s.href=a,s.download=`session-${p.value}.zip`,document.body.appendChild(s),s.click(),console.log("[Export] Download triggered"),window.URL.revokeObjectURL(a),document.body.removeChild(s),console.log("[Export] Showing success feedback...");let n="\u{1F4E4} Share Session",i="\u2713 Downloaded!",r=document.querySelector(".export-btn");r&&(r.textContent=i,r.style.background="#238636",console.log("[Export] Button text updated to:",r.textContent),setTimeout(()=>{r.textContent=n,r.style.background="",console.log("[Export] Button text restored")},2e3))}catch(t){console.error("[Export] Share session error:",t),alert("Failed to share session: "+t.message)}finally{re.value=!1,console.log("[Export] Export complete")}},we=t=>{let e=document.querySelector(".filter-type-wrapper");e&&!e.contains(t.target)&&(le.value=!1)},Se=t=>{t.ctrlKey&&t.key==="b"&&(t.preventDefault(),X.value=!X.value)};u(()=>{document.removeEventListener("click",we),window.removeEventListener("keydown",Se),j&&(clearTimeout(j),j=null),Z&&(Z(),Z=null),L.value={},D.value={},S.clear()}),o(async()=>{document.addEventListener("click",we);try{console.log("[Navigation] Starting event loading...");let e=await fetch(`/api/sessions/${p.value}/events`);if(!e.ok)throw new Error(`Failed to load events: ${e.statusText}`);let a=await e.json();if(Array.isArray(a))O.value=a;else if(a.events&&Array.isArray(a.events))O.value=a.events,console.log("[Navigation] Pagination:",a.pagination);else throw new Error("Invalid response format");if(console.log("[Navigation] Events loaded:",O.value.length),O.value.length>0){let l=O.value[O.value.length-1],c=l.timestamp||l.time||l.data?.timestamp;c&&(x.value.updated=new Date(c))}let s=new URLSearchParams(window.location.search),n=s.get("eventType"),i=s.get("eventName"),r=s.get("eventTimestamp");console.log("[Navigation] URL params:",n,i,r),n&&i&&(console.log("[Navigation] Waiting for Vue to render..."),Vue.nextTick(()=>{console.log("[Navigation] nextTick - flatEvents count:",k.value?.length);let l=null;if(n==="assistant.turn_start"){let c=i.match(/UserReq(\d+)_Turn(\d+)/);if(c){let b=parseInt(c[2],10);if(!isNaN(b)){console.log("[Navigation] Jumping to turn:",b),ke(b);return}}}else n==="subagent.started"?(console.log("[Navigation] Searching for subagent:",i,"timestamp:",r),r&&(l=k.value.find(c=>c.type==="subagent.started"&&c.timestamp===r)),l||(l=k.value.find(c=>c.type==="subagent.started"&&(c.data?.agentDisplayName===i||c.data?.agentName===i||c.data?.label===i))),console.log("[Navigation] Target event found:",l?"YES":"NO","virtualIndex:",l?.virtualIndex)):l=k.value.find(c=>c.type===n);if(l){let c=W.value.findIndex(b=>b.virtualIndex===l.virtualIndex);if(console.log("[Navigation] Target in filteredEvents at index:",c),c>=0&&h.value){console.log("[Navigation] Scrolling to index:",c);let b=T=>{T<=0||!h.value||(h.value.scrollToItem(c),setTimeout(()=>b(T-1),100))};setTimeout(()=>b(3),50)}else console.log("[Navigation] Failed - targetIndex:",c,"scrollerRef:",!!h.value)}else console.log("[Navigation] Target event not found")}))}catch(e){console.error("Error loading events:",e),be.value=e.message}finally{fe.value=!1}window.addEventListener("keydown",Se),window.marked&&marked.setOptions({breaks:!0,gfm:!0});let t=()=>{if(!h.value)return;let e=null;if(h.value.$el&&typeof h.value.$el.querySelector=="function"?e=h.value.$el.querySelector(".vue-recycle-scroller"):h.value.querySelector&&typeof h.value.querySelector=="function"&&(e=h.value.querySelector(".vue-recycle-scroller")),e||(e=document.querySelector(".vue-recycle-scroller")),e){let a=e.scrollTop,s=e.clientHeight,n=80,i=Math.floor(a/n),r=Math.ceil(s/n),l=Math.min(i+r,W.value.length),c=Math.max(1,i+1),b=Math.max(1,l);ve.value={start:Math.min(c,b),end:b}}};setTimeout(()=>{t();let e=document.querySelector(".vue-recycle-scroller");e&&(e.addEventListener("scroll",t),Z=()=>{e.removeEventListener("scroll",t)})},500)});let K=m([]),de=m([]),J=m(!1),I=m([]),_=m(""),ue=m(null),E=m(""),U=m(!1),ee=m([]),Ie=m(0),bt=t=>!t||t===0?"0":t<1e3?t.toString():Math.floor(t/1e3)+"K",Tt=t=>{if(!t||t===0)return"0s";let e=Math.floor(t/1e3);if(e<60)return(t/1e3).toFixed(1)+"s";let a=Math.floor(e/60),s=e%60;return`${a}m ${s}s`},ht=v(()=>{if(!x.value.usage||!x.value.usage.modelMetrics)return 0;let t=0;for(let e in x.value.usage.modelMetrics){let a=x.value.usage.modelMetrics[e].usage;a&&(t+=(a.inputTokens||0)+(a.outputTokens||0))}return t}),yt=v(()=>{if(!x.value.usage||!x.value.usage.modelMetrics)return 0;let t=0;for(let e in x.value.usage.modelMetrics)t+=x.value.usage.modelMetrics[e].requests?.count||0;return t}),xt=v(()=>!x.value.usage||!x.value.usage.modelMetrics?0:Object.keys(x.value.usage.modelMetrics).length),kt=t=>{let e=x.value.usage?.modelMetrics[t];return!e||!e.usage?null:y(e.usage)},Ct=t=>{let e=x.value.usage?.modelMetrics[t];return!e||!e.usage?0:f(e.usage)},wt=v(()=>{let t=new Map;for(let e of k.value)if(e.data?.tools&&Array.isArray(e.data.tools))for(let a of e.data.tools)a&&a.name&&t.set(a.name,(t.get(a.name)||0)+1);return Array.from(t,([e,a])=>({name:e,count:a})).sort((e,a)=>a.count-e.count)}),St=t=>t==null?"":t+" premium",Ee=["#3b82f6","#10b981","#f59e0b","#ef4444","#8b5cf6","#ec4899","#06b6d4","#f97316"],It=t=>{let e=0;for(let a=0;a<t.length;a++)e=t.charCodeAt(a)+((e<<5)-e);return Ee[Math.abs(e)%Ee.length]},Et=async()=>{try{let t=await fetch(`/api/sessions/${p.value}/tags`);if(t.ok){let e=await t.json();K.value=e.tags||[]}}catch(t){console.error("Error loading tags:",t)}},Me=async()=>{try{let t=await fetch("/api/tags");if(t.ok){let e=await t.json();de.value=e.tags||[]}}catch(t){console.error("Error loading all tags:",t)}},Mt=async t=>{try{window.trackClick&&t.filter(s=>!K.value.includes(s)).forEach(s=>{window.trackClick("TagAdded",{sessionId:p.value,tag:s})});let e=await fetch(`/api/sessions/${p.value}/tags`,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify({tags:t})});if(e.ok){let a=await e.json();return K.value=a.tags||[],E.value="",!0}else{let a=await e.json();return E.value=a.error||"Failed to save tags",!1}}catch(e){return console.error("Error saving tags:",e),E.value="Network error",!1}},Rt=()=>{I.value=[...K.value],J.value=!0,E.value="",setTimeout(()=>{ue.value&&ue.value.focus()},10)},Nt=()=>{J.value=!1,I.value=[],_.value="",U.value=!1,E.value=""},Re=()=>{let t=_.value.trim().toLowerCase();if(t){if(t.length>30){E.value="Tag must be 30 characters or less";return}if(I.value.length>=10){E.value="Maximum 10 tags per session";return}if(I.value.includes(t)){E.value="Tag already added",_.value="";return}I.value.push(t),_.value="",U.value=!1,E.value=""}},At=t=>{I.value=I.value.filter(e=>e!==t),E.value=""},Lt=()=>{let t=_.value.trim().toLowerCase();if(!t){U.value=!1,ee.value=[];return}let e=de.value.filter(a=>a.toLowerCase().includes(t)&&!I.value.includes(a)).slice(0,5);e.length>0?(U.value=!0,ee.value=e,Ie.value=0):(U.value=!1,ee.value=[])},Dt=t=>{_.value=t,Re()},Ot=async()=>{setTimeout(async()=>{if(!J.value)return;await Mt(I.value)&&(J.value=!1,I.value=[],_.value="",U.value=!1,await Me())},200)};return o(async()=>{await Et(),await Me()}),{sessionId:p,metadata:x,exporting:re,sidebarCollapsed:X,expandedTools:L,expandedContent:D,expansionCount:ze,currentFilter:N,searchText:H,currentTurnIndex:pe,scrollerRef:h,visibleRange:ve,loadedEvents:O,eventsLoading:fe,eventsError:be,flatEvents:k,filteredEvents:W,eventCounts:Fe,filters:Te,turns:G,userReqs:Ve,truncateText:Be,formatTime:je,formatToolTime:We,formatDateTime:vt,renderMarkdown:Ge,highlightSearchText:Je,toggleTool:Ke,toggleContent:Xe,isContentTooLong:Ye,truncateContent:Ze,getBadgeInfo:Qe,getToolStatus:et,getToolErrorMessage:tt,getToolDuration:at,getToolCommand:st,hasTools:nt,getToolGroups:ot,getSubagentInfo:ye,getSubagentColor:rt,setFilter:lt,selectSubagent:ct,selectedSubagent:A,subagentList:Pe,subagentTokenUsage:He,SUBAGENT_COLORS:ce,typeFilterOpen:le,activeFilterCount:_e,clearAllFilters:$e,scrollToTurn:xe,scrollToTop:dt,scrollToBottom:ut,jumpToTurn:ke,getTurnNumber:gt,getTurnDuration:pt,repoBasename:mt,escapeHtml:Ce,exportSession:ft,searchResultCount:Ue,sessionTags:K,allTags:de,tagsEditing:J,editingTags:I,tagInputValue:_,tagInputRef:ue,tagsError:E,showAutocomplete:U,autocompleteOptions:ee,autocompleteSelectedIndex:Ie,getTagColor:It,startEditTags:Rt,cancelEditTags:Nt,addTag:Re,removeTagFromEdit:At,updateAutocomplete:Lt,selectAutocompleteOption:Dt,saveTagsOnBlur:Ot,formatTokens:bt,formatDuration:Tt,formatCost:St,totalTokens:ht,totalRequests:yt,totalModels:xt,getDisplayUsageInputTokens:Ct,getModelCacheHitRatio:kt,toolCallingSummary:wt}},template:`
11
11
  <div class="container">
12
12
  <div class="header">
13
13
  <a href="/" class="home-btn">\u2190 Back to Home</a>
@@ -33,7 +33,6 @@
33
33
  <div class="sidebar-section">
34
34
  <div class="sidebar-section-title">Session Info</div>
35
35
  <div class="session-info">
36
- <div v-if="metadata.summary" class="session-summary-block">{{ metadata.summary }}</div>
37
36
  <table class="session-info-table">
38
37
  <tbody>
39
38
  <tr v-if="metadata.source">
@@ -45,7 +44,15 @@
45
44
  </span>
46
45
  </td>
47
46
  </tr>
48
- <tr v-if="metadata.copilotVersion">
47
+ <tr v-if="metadata.modernizeVersion">
48
+ <td>Version</td>
49
+ <td>{{ metadata.modernizeVersion }}</td>
50
+ </tr>
51
+ <tr v-if="metadata.source === 'modernize' && metadata.copilotVersion">
52
+ <td>Copilot SDK</td>
53
+ <td>{{ metadata.copilotVersion }}</td>
54
+ </tr>
55
+ <tr v-if="metadata.copilotVersion && metadata.source !== 'modernize'">
49
56
  <td>Version</td>
50
57
  <td>{{ metadata.copilotVersion }}</td>
51
58
  </tr>
@@ -80,34 +87,66 @@
80
87
 
81
88
  <!-- Usage Section -->
82
89
  <div v-if="metadata.usage" class="sidebar-section">
83
- <div class="sidebar-section-title">Usage</div>
90
+ <div class="sidebar-section-title">Token Usage</div>
84
91
  <div class="usage-container">
85
- <!-- Compact view (always visible) -->
86
- <div class="usage-compact" @click="toggleUsage">
87
- {{ totalRequests }} reqs \xB7 {{ formatTokens(totalTokens) }} tokens \xB7 {{ formatDuration(metadata.usage.totalApiDurationMs) }}
88
- <span class="usage-expand-icon">{{ usageExpanded ? '\u25B2' : '\u25BC' }}</span>
92
+ <div class="usage-summary">
93
+ <div class="usage-summary-eyebrow">Overview</div>
94
+ <div class="usage-summary-total">
95
+ {{ formatTokens(totalTokens) }} <span class="usage-summary-total-unit">tokens</span>
96
+ </div>
97
+ <div class="usage-summary-caption">
98
+ Usage captured across {{ totalModels }} model{{ totalModels === 1 ? '' : 's' }}
99
+ </div>
100
+ <div class="usage-summary-metrics">
101
+ <div class="usage-metric-card usage-metric-card-summary">
102
+ <span class="usage-metric-label">Requests</span>
103
+ <span class="usage-metric-value">{{ totalRequests }} reqs</span>
104
+ </div>
105
+ <div class="usage-metric-card usage-metric-card-summary">
106
+ <span class="usage-metric-label">Models</span>
107
+ <span class="usage-metric-value">{{ totalModels }}</span>
108
+ </div>
109
+ <div class="usage-metric-card usage-metric-card-summary">
110
+ <span class="usage-metric-label">API Time</span>
111
+ <span class="usage-metric-value">{{ formatDuration(metadata.usage.totalApiDurationMs) }}</span>
112
+ </div>
113
+ </div>
89
114
  </div>
90
115
 
91
- <!-- Expanded view -->
92
- <div v-if="usageExpanded" class="usage-expanded">
116
+ <div class="usage-expanded">
93
117
  <!-- Model breakdown -->
94
118
  <div v-if="Object.keys(metadata.usage.modelMetrics).length > 0" class="usage-section">
95
- <div class="usage-section-title">Models</div>
96
- <div v-for="(metrics, model) in metadata.usage.modelMetrics" :key="model" class="usage-model">
97
- <div class="usage-model-name">{{ model }}</div>
98
- <div class="usage-model-details">
99
- <div>{{ metrics.requests?.count || 0 }} reqs</div>
100
- <div v-if="metrics.requests?.cost">Cost: {{ formatCost(metrics.requests.cost) }}</div>
101
- <div v-if="metrics.usage">
102
- <span class="usage-token-label">In:</span> {{ formatTokens(metrics.usage.inputTokens || 0) }}
103
- <span class="usage-token-label">Out:</span> {{ formatTokens(metrics.usage.outputTokens || 0) }}
104
- </div>
105
- <div v-if="metrics.usage?.cacheReadTokens">
106
- <span class="usage-token-label">Cache Read:</span> {{ formatTokens(metrics.usage.cacheReadTokens) }}
107
- <span v-if="getCacheHitRatio(model)" class="usage-cache-ratio">({{ getCacheHitRatio(model) }}%)</span>
119
+ <div class="usage-section-header">
120
+ <div class="usage-section-title">Models</div>
121
+ <div class="usage-section-badge">{{ totalModels }}</div>
122
+ </div>
123
+ <div class="usage-model-list">
124
+ <div v-for="(metrics, model) in metadata.usage.modelMetrics" :key="model" class="usage-model">
125
+ <div class="usage-model-header">
126
+ <div class="usage-model-name" :title="model">{{ model }}</div>
127
+ <div class="usage-model-meta">
128
+ <span class="usage-meta-pill">{{ metrics.requests?.count || 0 }} reqs</span>
129
+ <span v-if="metrics.requests?.cost" class="usage-meta-pill usage-meta-pill-premium">{{ formatCost(metrics.requests.cost) }}</span>
130
+ <span v-if="getModelCacheHitRatio(model) !== null" class="usage-meta-pill usage-meta-pill-cache">{{ getModelCacheHitRatio(model) }}% cache</span>
131
+ </div>
108
132
  </div>
109
- <div v-if="metrics.usage?.cacheWriteTokens">
110
- <span class="usage-token-label">Cache Write:</span> {{ formatTokens(metrics.usage.cacheWriteTokens) }}
133
+ <div v-if="metrics.usage" class="usage-metric-grid">
134
+ <div class="usage-metric-card">
135
+ <span class="usage-metric-label">Input</span>
136
+ <span class="usage-metric-value">{{ formatTokens(getDisplayUsageInputTokens(model)) }}</span>
137
+ </div>
138
+ <div class="usage-metric-card">
139
+ <span class="usage-metric-label">Output</span>
140
+ <span class="usage-metric-value">{{ formatTokens(metrics.usage.outputTokens || 0) }}</span>
141
+ </div>
142
+ <div v-if="metrics.usage?.cacheReadTokens" class="usage-metric-card">
143
+ <span class="usage-metric-label">Cache Read</span>
144
+ <span class="usage-metric-value">{{ formatTokens(metrics.usage.cacheReadTokens) }}</span>
145
+ </div>
146
+ <div v-if="metrics.usage?.cacheWriteTokens" class="usage-metric-card">
147
+ <span class="usage-metric-label">Cache Write</span>
148
+ <span class="usage-metric-value">{{ formatTokens(metrics.usage.cacheWriteTokens) }}</span>
149
+ </div>
111
150
  </div>
112
151
  </div>
113
152
  </div>
@@ -115,48 +154,62 @@
115
154
 
116
155
  <!-- Context window breakdown -->
117
156
  <div v-if="metadata.usage.currentTokens || metadata.usage.systemTokens || metadata.usage.conversationTokens || metadata.usage.toolDefinitionsTokens" class="usage-section">
118
- <div class="usage-section-title">Context Window</div>
119
- <div class="usage-context">
120
- <div v-if="metadata.usage.currentTokens">
121
- <span class="usage-token-label">Current:</span> {{ formatTokens(metadata.usage.currentTokens) }}
157
+ <div class="usage-section-header">
158
+ <div class="usage-section-title">Context Window</div>
159
+ </div>
160
+ <div class="usage-metric-grid">
161
+ <div v-if="metadata.usage.currentTokens" class="usage-metric-card">
162
+ <span class="usage-metric-label">Current</span>
163
+ <span class="usage-metric-value">{{ formatTokens(metadata.usage.currentTokens) }}</span>
122
164
  </div>
123
- <div v-if="metadata.usage.systemTokens">
124
- <span class="usage-token-label">System:</span> {{ formatTokens(metadata.usage.systemTokens) }}
165
+ <div v-if="metadata.usage.systemTokens" class="usage-metric-card">
166
+ <span class="usage-metric-label">System</span>
167
+ <span class="usage-metric-value">{{ formatTokens(metadata.usage.systemTokens) }}</span>
125
168
  </div>
126
- <div v-if="metadata.usage.conversationTokens">
127
- <span class="usage-token-label">Conversation:</span> {{ formatTokens(metadata.usage.conversationTokens) }}
169
+ <div v-if="metadata.usage.conversationTokens" class="usage-metric-card">
170
+ <span class="usage-metric-label">Conversation</span>
171
+ <span class="usage-metric-value">{{ formatTokens(metadata.usage.conversationTokens) }}</span>
128
172
  </div>
129
- <div v-if="metadata.usage.toolDefinitionsTokens">
130
- <span class="usage-token-label">Tools:</span> {{ formatTokens(metadata.usage.toolDefinitionsTokens) }}
173
+ <div v-if="metadata.usage.toolDefinitionsTokens" class="usage-metric-card">
174
+ <span class="usage-metric-label">Tools</span>
175
+ <span class="usage-metric-value">{{ formatTokens(metadata.usage.toolDefinitionsTokens) }}</span>
131
176
  </div>
132
177
  </div>
133
178
  </div>
134
179
 
135
180
  <!-- Code changes -->
136
181
  <div v-if="metadata.usage.codeChanges && (metadata.usage.codeChanges.linesAdded > 0 || metadata.usage.codeChanges.linesRemoved > 0)" class="usage-section">
137
- <div class="usage-section-title">Code Changes</div>
138
- <div class="usage-code-changes">
139
- <span class="usage-code-added">+{{ metadata.usage.codeChanges.linesAdded }}</span>
140
- <span class="usage-code-removed">-{{ metadata.usage.codeChanges.linesRemoved }}</span>
141
- <span class="usage-code-files">({{ metadata.usage.codeChanges.filesModified?.length || 0 }} files)</span>
182
+ <div class="usage-section-header">
183
+ <div class="usage-section-title">Code Changes</div>
184
+ </div>
185
+ <div class="usage-metric-grid usage-metric-grid-compact">
186
+ <div class="usage-metric-card">
187
+ <span class="usage-metric-label">Added</span>
188
+ <span class="usage-metric-value usage-metric-value-added">+{{ metadata.usage.codeChanges.linesAdded }}</span>
189
+ </div>
190
+ <div class="usage-metric-card">
191
+ <span class="usage-metric-label">Removed</span>
192
+ <span class="usage-metric-value usage-metric-value-removed">-{{ metadata.usage.codeChanges.linesRemoved }}</span>
193
+ </div>
194
+ <div class="usage-metric-card">
195
+ <span class="usage-metric-label">Files</span>
196
+ <span class="usage-metric-value">{{ metadata.usage.codeChanges.filesModified?.length || 0 }}</span>
197
+ </div>
142
198
  </div>
143
199
  </div>
144
200
  </div>
145
201
  </div>
146
202
  </div>
147
203
 
148
- <div class="sidebar-section">
149
- <div class="sidebar-section-title">Event Filters</div>
150
- <div class="event-filters">
151
- <button
152
- v-for="filter in filters"
153
- :key="filter.type"
154
- :class="['filter-btn', { active: currentFilter === filter.type }]"
155
- :disabled="filter.disabled"
156
- @click="setFilter(filter.type)"
157
- >
158
- {{ filter.label }}
159
- </button>
204
+ <!-- Tool Calling Summary -->
205
+ <div v-if="toolCallingSummary.length" class="sidebar-section">
206
+ <div class="sidebar-section-title">Tool Calls</div>
207
+ <div class="tool-summary-list">
208
+ <div v-for="item in toolCallingSummary" :key="item.name" class="tool-summary-item">
209
+ <div class="tool-summary-bar" :style="{ width: (item.count / toolCallingSummary[0].count * 100) + '%' }"></div>
210
+ <span class="tool-summary-name" :title="item.name">{{ item.name }}</span>
211
+ <span class="tool-summary-count">{{ item.count }}</span>
212
+ </div>
160
213
  </div>
161
214
  </div>
162
215
 
@@ -216,8 +269,8 @@
216
269
  </div>
217
270
 
218
271
  <div class="content">
219
- <div class="scroll-indicator">
220
- <div class="content-toolbar-left">
272
+ <div class="unified-filter-bar">
273
+ <div class="filter-bar-row">
221
274
  <button
222
275
  class="sidebar-toggle"
223
276
  @click="() => { sidebarCollapsed = !sidebarCollapsed; trackClick && trackClick('SidebarToggled', { state: sidebarCollapsed ? 'open' : 'collapsed', sessionId: sessionId }); }"
@@ -226,6 +279,20 @@
226
279
  \u2630
227
280
  </button>
228
281
 
282
+ <div class="filter-bar-search">
283
+ <input
284
+ v-model="searchText"
285
+ type="text"
286
+ placeholder="\u{1F50D} Search events..."
287
+ class="search-input"
288
+ />
289
+ <span v-if="searchResultCount" class="search-result-count">
290
+ {{ searchResultCount }}
291
+ </span>
292
+ </div>
293
+
294
+ <div class="filter-bar-divider"></div>
295
+
229
296
  <!-- Turn dropdown with optgroup -->
230
297
  <select
231
298
  v-if="turns.length > 0"
@@ -243,19 +310,69 @@
243
310
  </option>
244
311
  </optgroup>
245
312
  </select>
313
+
314
+ <div class="filter-bar-divider"></div>
315
+
316
+ <!-- Subagent selector -->
317
+ <div v-if="subagentList.length > 0" class="subagent-selector">
318
+ <select
319
+ :value="selectedSubagent || ''"
320
+ @change="selectSubagent($event.target.value || null)"
321
+ class="subagent-dropdown"
322
+ >
323
+ <option value="">\u{1F916} All Agents</option>
324
+ <option v-for="sa in subagentList" :key="sa.toolCallId" :value="sa.toolCallId">
325
+ \u{1F916} {{ sa.name }}
326
+ </option>
327
+ </select>
328
+ <span v-if="subagentTokenUsage" class="subagent-usage-badge">
329
+ {{ subagentTokenUsage.eventCount }} events \xB7 {{ formatDuration(subagentTokenUsage.durationMs) }}
330
+ </span>
331
+ </div>
332
+
333
+ <div class="filter-bar-divider"></div>
334
+
335
+ <!-- Event type dropdown -->
336
+ <div class="filter-type-wrapper">
337
+ <button
338
+ class="filter-type-toggle"
339
+ :class="{ active: currentFilter !== 'all' }"
340
+ @click.stop="typeFilterOpen = !typeFilterOpen"
341
+ >
342
+ \u26A1 {{ currentFilter === 'all' ? 'All Types' : currentFilter }} \u25BE
343
+ </button>
344
+ <div v-if="typeFilterOpen" class="filter-type-menu">
345
+ <div class="filter-type-menu-header">Event Types</div>
346
+ <div class="filter-type-menu-options">
347
+ <div
348
+ v-for="filter in filters"
349
+ :key="filter.type"
350
+ :class="['filter-type-menu-item', { active: currentFilter === filter.type }]"
351
+ @click="setFilter(filter.type); typeFilterOpen = false"
352
+ >
353
+ <span class="filter-type-menu-label">{{ filter.type === 'all' ? 'All' : filter.type }}</span>
354
+ <span class="filter-type-menu-count">{{ filter.count }}</span>
355
+ </div>
356
+ </div>
357
+ </div>
358
+ </div>
246
359
  </div>
247
- <div class="content-toolbar-center">
248
- </div>
249
- <div class="content-toolbar-right">
250
- <input
251
- v-model="searchText"
252
- type="text"
253
- placeholder="\u{1F50D} Search events..."
254
- class="search-input"
255
- />
256
- <span v-if="searchResultCount" class="search-result-count">
257
- {{ searchResultCount }}
360
+
361
+ <!-- Active filter chips -->
362
+ <div v-if="activeFilterCount > 0" class="active-filters-bar">
363
+ <span v-if="currentFilter !== 'all'" class="filter-chip">
364
+ Type: {{ currentFilter }}
365
+ <button @click="setFilter('all')" class="filter-chip-remove" title="Remove filter">\xD7</button>
366
+ </span>
367
+ <span v-if="selectedSubagent" class="filter-chip">
368
+ Agent: {{ subagentList.find(s => s.toolCallId === selectedSubagent)?.name || selectedSubagent }}
369
+ <button @click="selectSubagent(null)" class="filter-chip-remove" title="Remove filter">\xD7</button>
370
+ </span>
371
+ <span v-if="searchText.trim()" class="filter-chip">
372
+ Search: "{{ searchText.length > 20 ? searchText.substring(0, 20) + '\u2026' : searchText }}"
373
+ <button @click="searchText = ''" class="filter-chip-remove" title="Remove filter">\xD7</button>
258
374
  </span>
375
+ <button class="clear-all-filters-btn" @click="clearAllFilters">Clear all</button>
259
376
  </div>
260
377
  </div>
261
378
 
@@ -344,8 +461,10 @@
344
461
  <span
345
462
  v-if="getSubagentInfo(item)"
346
463
  class="subagent-owner-tag"
347
- :style="{ color: getSubagentColor(item), borderColor: getSubagentColor(item) }"
348
- >{{ getSubagentInfo(item).name }}</span>
464
+ :style="{ '--subagent-color': getSubagentColor(item) || '#58a6ff', '--subagent-hover-bg': ((getSubagentColor(item) || '#58a6ff') + '26') }"
465
+ :title="'Filter to ' + getSubagentInfo(item).name"
466
+ @click.stop="selectSubagent(getSubagentInfo(item).toolCallId)"
467
+ >\u{1F916} {{ getSubagentInfo(item).name }}</span>
349
468
  <span v-if="metadata.source !== 'vscode'" class="event-timestamp">{{ formatTime(item.timestamp) }}</span>
350
469
  </div>
351
470
 
@@ -556,4 +675,4 @@
556
675
  </div>
557
676
 
558
677
  </div>
559
- `});console.log("Mounting Vue app to #app..."),console.log("App config:",Y.config),console.log("Target element:",document.getElementById("app"));try{let m=Y.mount("#app");console.log("Vue app mounted successfully!",m?"Instance created":"No instance"),console.log("VM type:",typeof m,"Has exportSession:",typeof m?.exportSession),console.log("VM keys:",m?Object.keys(m).slice(0,10):"NO_VM"),console.log("#app innerHTML length:",document.getElementById("app").innerHTML.length),console.log("#app first 100 chars:",document.getElementById("app").innerHTML.substring(0,100))}catch(m){console.error("Mount failed:",m),console.error("Error stack:",m.stack)}})();})();
678
+ `});console.log("Mounting Vue app to #app..."),console.log("App config:",P.config),console.log("Target element:",document.getElementById("app"));try{let p=P.mount("#app");console.log("Vue app mounted successfully!",p?"Instance created":"No instance"),console.log("VM type:",typeof p,"Has exportSession:",typeof p?.exportSession),console.log("VM keys:",p?Object.keys(p).slice(0,10):"NO_VM"),console.log("#app innerHTML length:",document.getElementById("app").innerHTML.length),console.log("#app first 100 chars:",document.getElementById("app").innerHTML.substring(0,100))}catch(p){console.error("Mount failed:",p),console.error("Error stack:",p.stack)}})();})();