aicodeman 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/config/workflow-config.d.ts +24 -0
  2. package/dist/config/workflow-config.d.ts.map +1 -0
  3. package/dist/config/workflow-config.js +24 -0
  4. package/dist/config/workflow-config.js.map +1 -0
  5. package/dist/subagent-watcher.d.ts +34 -0
  6. package/dist/subagent-watcher.d.ts.map +1 -1
  7. package/dist/subagent-watcher.js +147 -4
  8. package/dist/subagent-watcher.js.map +1 -1
  9. package/dist/types/index.d.ts +1 -0
  10. package/dist/types/index.d.ts.map +1 -1
  11. package/dist/types/index.js +1 -0
  12. package/dist/types/index.js.map +1 -1
  13. package/dist/types/workflow-run.d.ts +130 -0
  14. package/dist/types/workflow-run.d.ts.map +1 -0
  15. package/dist/types/workflow-run.js +20 -0
  16. package/dist/types/workflow-run.js.map +1 -0
  17. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  18. package/dist/web/public/{app.92f49a9d.js → app.eaa14cdd.js} +4 -4
  19. package/dist/web/public/app.eaa14cdd.js.br +0 -0
  20. package/dist/web/public/app.eaa14cdd.js.gz +0 -0
  21. package/dist/web/public/{constants.59faac65.js → constants.1c779517.js} +5 -0
  22. package/dist/web/public/constants.1c779517.js.br +0 -0
  23. package/dist/web/public/constants.1c779517.js.gz +0 -0
  24. package/dist/web/public/image-input.0ea86695.js.gz +0 -0
  25. package/dist/web/public/index.html +39 -7
  26. package/dist/web/public/index.html.br +0 -0
  27. package/dist/web/public/index.html.gz +0 -0
  28. package/dist/web/public/input-cjk.b8686b5e.js.gz +0 -0
  29. package/dist/web/public/keyboard-accessory.bc753cc7.js.gz +0 -0
  30. package/dist/web/public/mobile-handlers.db3dc3c8.js.gz +0 -0
  31. package/dist/web/public/mobile.06b38d3a.css.gz +0 -0
  32. package/dist/web/public/notification-manager.9c984ac2.js.gz +0 -0
  33. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  34. package/dist/web/public/{panels-ui.2f467969.js → panels-ui.f3f08e26.js} +48 -48
  35. package/dist/web/public/panels-ui.f3f08e26.js.br +0 -0
  36. package/dist/web/public/panels-ui.f3f08e26.js.gz +0 -0
  37. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  38. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  39. package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
  40. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  41. package/dist/web/public/session-ui.1463b824.js.gz +0 -0
  42. package/dist/web/public/settings-ui.601c30c1.js +55 -0
  43. package/dist/web/public/settings-ui.601c30c1.js.br +0 -0
  44. package/dist/web/public/settings-ui.601c30c1.js.gz +0 -0
  45. package/dist/web/public/{styles.8e1ea0c6.css → styles.7e612fc4.css} +1 -1
  46. package/dist/web/public/styles.7e612fc4.css.br +0 -0
  47. package/dist/web/public/styles.7e612fc4.css.gz +0 -0
  48. package/dist/web/public/subagent-windows.a366a4ad.js.gz +0 -0
  49. package/dist/web/public/sw.js.gz +0 -0
  50. package/dist/web/public/terminal-ui.a7e046da.js.gz +0 -0
  51. package/dist/web/public/ultracode-panel.js +304 -0
  52. package/dist/web/public/ultracode-panel.js.br +0 -0
  53. package/dist/web/public/ultracode-panel.js.gz +0 -0
  54. package/dist/web/public/upload.html.gz +0 -0
  55. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  56. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  57. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  58. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  59. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  60. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  61. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  62. package/dist/web/public/vendor/xterm.css.gz +0 -0
  63. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  64. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  65. package/dist/web/routes/file-routes.d.ts.map +1 -1
  66. package/dist/web/routes/file-routes.js +80 -24
  67. package/dist/web/routes/file-routes.js.map +1 -1
  68. package/dist/web/routes/system-routes.d.ts.map +1 -1
  69. package/dist/web/routes/system-routes.js +21 -0
  70. package/dist/web/routes/system-routes.js.map +1 -1
  71. package/dist/web/schemas.d.ts +1 -0
  72. package/dist/web/schemas.d.ts.map +1 -1
  73. package/dist/web/schemas.js +2 -0
  74. package/dist/web/schemas.js.map +1 -1
  75. package/dist/web/server.d.ts +12 -0
  76. package/dist/web/server.d.ts.map +1 -1
  77. package/dist/web/server.js +55 -0
  78. package/dist/web/server.js.map +1 -1
  79. package/dist/web/sse-events.d.ts +10 -0
  80. package/dist/web/sse-events.d.ts.map +1 -1
  81. package/dist/web/sse-events.js +12 -0
  82. package/dist/web/sse-events.js.map +1 -1
  83. package/dist/workflow-run-watcher.d.ts +76 -0
  84. package/dist/workflow-run-watcher.d.ts.map +1 -0
  85. package/dist/workflow-run-watcher.js +327 -0
  86. package/dist/workflow-run-watcher.js.map +1 -0
  87. package/package.json +1 -1
  88. package/dist/web/public/app.92f49a9d.js.br +0 -0
  89. package/dist/web/public/app.92f49a9d.js.gz +0 -0
  90. package/dist/web/public/constants.59faac65.js.br +0 -0
  91. package/dist/web/public/constants.59faac65.js.gz +0 -0
  92. package/dist/web/public/panels-ui.2f467969.js.br +0 -0
  93. package/dist/web/public/panels-ui.2f467969.js.gz +0 -0
  94. package/dist/web/public/settings-ui.44b99ce0.js +0 -55
  95. package/dist/web/public/settings-ui.44b99ce0.js.br +0 -0
  96. package/dist/web/public/settings-ui.44b99ce0.js.gz +0 -0
  97. package/dist/web/public/styles.8e1ea0c6.css.br +0 -0
  98. package/dist/web/public/styles.8e1ea0c6.css.gz +0 -0
@@ -1,12 +1,12 @@
1
- "use strict";Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},async openTokenStats(){try{const t=await(await fetch("/api/token-stats")).json();t.success?(this.renderTokenStats(t.data),document.getElementById("tokenStatsModal").classList.add("active")):this.showToast("Failed to load token stats","error")}catch(e){console.error("Failed to fetch token stats:",e),this.showToast("Failed to load token stats","error")}},renderTokenStats(e){const{daily:t,totals:s}=e,n=new Date().toISOString().split("T")[0],a=t.find(g=>g.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},i=new Date;i.setDate(i.getDate()-7);const r=t.filter(g=>new Date(g.date)>=i),o=r.reduce((g,S)=>g+S.inputTokens,0),l=r.reduce((g,S)=>g+S.outputTokens,0),d=this.estimateCost(o,l),c=s.totalInputTokens,h=s.totalOutputTokens,m=this.estimateCost(c,h),u=document.getElementById("statsSummary");u.innerHTML=`
1
+ "use strict";Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},async openTokenStats(){try{const t=await(await fetch("/api/token-stats")).json();t.success?(this.renderTokenStats(t.data),document.getElementById("tokenStatsModal").classList.add("active")):this.showToast("Failed to load token stats","error")}catch(e){console.error("Failed to fetch token stats:",e),this.showToast("Failed to load token stats","error")}},renderTokenStats(e){const{daily:t,totals:s}=e,n=new Date().toISOString().split("T")[0],o=t.find(g=>g.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},i=new Date;i.setDate(i.getDate()-7);const r=t.filter(g=>new Date(g.date)>=i),a=r.reduce((g,S)=>g+S.inputTokens,0),l=r.reduce((g,S)=>g+S.outputTokens,0),d=this.estimateCost(a,l),c=s.totalInputTokens,h=s.totalOutputTokens,m=this.estimateCost(c,h),u=document.getElementById("statsSummary");u.innerHTML=`
2
2
  <div class="stat-card">
3
3
  <span class="stat-card-label">Today</span>
4
- <span class="stat-card-value">${this.formatTokens(a.inputTokens+a.outputTokens)}</span>
5
- <span class="stat-card-cost">~$${a.estimatedCost.toFixed(2)}</span>
4
+ <span class="stat-card-value">${this.formatTokens(o.inputTokens+o.outputTokens)}</span>
5
+ <span class="stat-card-cost">~$${o.estimatedCost.toFixed(2)}</span>
6
6
  </div>
7
7
  <div class="stat-card">
8
8
  <span class="stat-card-label">7 Days</span>
9
- <span class="stat-card-value">${this.formatTokens(o+l)}</span>
9
+ <span class="stat-card-value">${this.formatTokens(a+l)}</span>
10
10
  <span class="stat-card-cost">~$${d.toFixed(2)}</span>
11
11
  </div>
12
12
  <div class="stat-card">
@@ -29,7 +29,7 @@
29
29
  <span class="cell cell-cost">$${g.estimatedCost.toFixed(2)}</span>
30
30
  </div>
31
31
  `).join("")}
32
- `},closeTokenStats(){const e=document.getElementById("tokenStatsModal");e&&e.classList.remove("active")},async toggleMonitorPanel(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorToggleBtn");e.classList.toggle("open"),e.classList.contains("open")?(e.style.display="",await this.loadMuxSessions(),await fetch("/api/mux-sessions/stats/start",{method:"POST"}),this.renderTaskPanel(),t&&(t.innerHTML="&#x25BC;")):(await fetch("/api/mux-sessions/stats/stop",{method:"POST"}),t&&(t.innerHTML="&#x25B2;"))},toggleTaskPanel(){this.toggleMonitorPanel()},toggleMonitorDetach(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupMonitorDrag())},setupMonitorDrag(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorPanelHeader");if(!e||!t)return;let s=!1,n,a,i,r;const o=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const h=getEventCoords(c);n=h.clientX,a=h.clientY;const m=e.getBoundingClientRect();i=m.left,r=m.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const h=getEventCoords(c),m=h.clientX-n,u=h.clientY-a;let p=i+m,v=r+u;const y=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-y.width,p)),v=Math.max(0,Math.min(window.innerHeight-y.height,v)),e.style.left=p+"px",e.style.top=v+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=o,t._touchDragHandler=o,t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})},toggleSubagentsDetach(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupSubagentsDrag())},setupSubagentsDrag(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsPanelHeader");if(!e||!t)return;let s=!1,n,a,i,r;const o=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const h=getEventCoords(c);n=h.clientX,a=h.clientY;const m=e.getBoundingClientRect();i=m.left,r=m.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const h=getEventCoords(c),m=h.clientX-n,u=h.clientY-a;let p=i+m,v=r+u;const y=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-y.width,p)),v=Math.max(0,Math.min(window.innerHeight-y.height,v)),e.style.left=p+"px",e.style.top=v+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=o,t._touchDragHandler=o,t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})},renderTaskPanel(){this._debouncedCall("taskPanel",this._renderTaskPanelImmediate)},_renderTaskPanelImmediate(){const e=this.sessions.get(this.activeSessionId),t=document.getElementById("backgroundTasksBody"),s=document.getElementById("taskPanelStats"),n=document.getElementById("backgroundTasksSection");if(!e||!e.taskTree||e.taskTree.length===0){n&&(n.style.display="none"),t.innerHTML="",s.textContent="0 tasks";return}n&&(n.style.display="");const a=e.taskStats||{running:0,completed:0,failed:0,total:0};s.textContent=`${a.running} running, ${a.completed} done`;const i=(l,d)=>{const c=l.status==="running"?"":l.status==="completed"?"&#x2713;":"&#x2717;",h=l.endTime?`${((l.endTime-l.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-l.startTime)/1e3).toFixed(0)}s...`;let m="";if(l.children&&l.children.length>0){m='<div class="task-children">';for(const u of l.children){const p=d.find(v=>v.id===u);p&&(m+=`<div class="task-node">${i(p,d)}</div>`)}m+="</div>"}return`
32
+ `},closeTokenStats(){const e=document.getElementById("tokenStatsModal");e&&e.classList.remove("active")},async toggleMonitorPanel(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorToggleBtn");e.classList.toggle("open"),e.classList.contains("open")?(e.style.display="",await this.loadMuxSessions(),await fetch("/api/mux-sessions/stats/start",{method:"POST"}),this.renderTaskPanel(),t&&(t.innerHTML="&#x25BC;")):(await fetch("/api/mux-sessions/stats/stop",{method:"POST"}),t&&(t.innerHTML="&#x25B2;"))},toggleTaskPanel(){this.toggleMonitorPanel()},toggleMonitorDetach(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupMonitorDrag())},setupMonitorDrag(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorPanelHeader");if(!e||!t)return;let s=!1,n,o,i,r;const a=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const h=getEventCoords(c);n=h.clientX,o=h.clientY;const m=e.getBoundingClientRect();i=m.left,r=m.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const h=getEventCoords(c),m=h.clientX-n,u=h.clientY-o;let p=i+m,v=r+u;const y=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-y.width,p)),v=Math.max(0,Math.min(window.innerHeight-y.height,v)),e.style.left=p+"px",e.style.top=v+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=a,t._touchDragHandler=a,t.addEventListener("mousedown",a),t.addEventListener("touchstart",a,{passive:!1})},toggleSubagentsDetach(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupSubagentsDrag())},setupSubagentsDrag(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsPanelHeader");if(!e||!t)return;let s=!1,n,o,i,r;const a=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const h=getEventCoords(c);n=h.clientX,o=h.clientY;const m=e.getBoundingClientRect();i=m.left,r=m.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const h=getEventCoords(c),m=h.clientX-n,u=h.clientY-o;let p=i+m,v=r+u;const y=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-y.width,p)),v=Math.max(0,Math.min(window.innerHeight-y.height,v)),e.style.left=p+"px",e.style.top=v+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=a,t._touchDragHandler=a,t.addEventListener("mousedown",a),t.addEventListener("touchstart",a,{passive:!1})},renderTaskPanel(){this._debouncedCall("taskPanel",this._renderTaskPanelImmediate)},_renderTaskPanelImmediate(){const e=this.sessions.get(this.activeSessionId),t=document.getElementById("backgroundTasksBody"),s=document.getElementById("taskPanelStats"),n=document.getElementById("backgroundTasksSection");if(!e||!e.taskTree||e.taskTree.length===0){n&&(n.style.display="none"),t.innerHTML="",s.textContent="0 tasks";return}n&&(n.style.display="");const o=e.taskStats||{running:0,completed:0,failed:0,total:0};s.textContent=`${o.running} running, ${o.completed} done`;const i=(l,d)=>{const c=l.status==="running"?"":l.status==="completed"?"&#x2713;":"&#x2717;",h=l.endTime?`${((l.endTime-l.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-l.startTime)/1e3).toFixed(0)}s...`;let m="";if(l.children&&l.children.length>0){m='<div class="task-children">';for(const u of l.children){const p=d.find(v=>v.id===u);p&&(m+=`<div class="task-node">${i(p,d)}</div>`)}m+="</div>"}return`
33
33
  <div class="task-item">
34
34
  <span class="task-status-icon ${l.status}">${c}</span>
35
35
  <div class="task-info">
@@ -41,8 +41,8 @@
41
41
  </div>
42
42
  </div>
43
43
  ${m}
44
- `},r=this.flattenTaskTree(e.taskTree);let o='<div class="task-tree">';for(const l of e.taskTree)o+=`<div class="task-node">${i(l,r)}</div>`;o+="</div>",t.innerHTML=o},flattenTaskTree(e,t=[]){for(const s of e)t.push(s);return t},toggleSubagentPanel(){this.toggleSubagentsPanel()},updateSubagentBadge(){const e=this.$("subagentCountBadge"),t=Array.from(this.subagents.values()).filter(s=>s.status==="active"||s.status==="idle").length;e&&(e.textContent=t>0?t:"")},renderSubagentPanel(){this._subagentPanelRenderTimeout&&clearTimeout(this._subagentPanelRenderTimeout),this._subagentPanelRenderTimeout=setTimeout(()=>{scheduleBackground(()=>this._renderSubagentPanelImmediate())},150)},_renderSubagentPanelImmediate(){const e=this.$("subagentList");if(!e||(this.updateSubagentBadge(),this.renderMonitorSubagents(),!this.subagentPanelVisible))return;if(this.subagents.size===0){e.innerHTML='<div class="subagent-empty">No background agents detected</div>';return}const t=[],s=Array.from(this.subagents.values()).sort((n,a)=>n.status==="active"&&a.status!=="active"?-1:a.status==="active"&&n.status!=="active"?1:(a.lastActivityAt||0)-(n.lastActivityAt||0));for(const n of s){const a=this.activeSubagentId===n.agentId,i=n.status==="active"?"active":n.status==="idle"?"idle":"completed",r=this.subagentActivity.get(n.agentId)||[],o=r[r.length-1],l=o?.type==="tool"?o.tool:null,d=this.subagentWindows.has(n.agentId),c=n.status==="active"||n.status==="idle",h=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",m=this.getTeammateInfo(n),u=m?m.name:n.description||n.agentId.substring(0,7),p=this.getTeammateBadgeHtml(n),v=m?`<span class="subagent-icon teammate-dot teammate-color-${m.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
45
- <div class="subagent-item ${i} ${a?"selected":""}${m?" is-teammate":""}"
44
+ `},r=this.flattenTaskTree(e.taskTree);let a='<div class="task-tree">';for(const l of e.taskTree)a+=`<div class="task-node">${i(l,r)}</div>`;a+="</div>",t.innerHTML=a},flattenTaskTree(e,t=[]){for(const s of e)t.push(s);return t},toggleSubagentPanel(){this.toggleSubagentsPanel()},updateSubagentBadge(){const e=this.$("subagentCountBadge"),t=Array.from(this.subagents.values()).filter(s=>s.status==="active"||s.status==="idle").length;e&&(e.textContent=t>0?t:"")},renderSubagentPanel(){this._subagentPanelRenderTimeout&&clearTimeout(this._subagentPanelRenderTimeout),this._subagentPanelRenderTimeout=setTimeout(()=>{scheduleBackground(()=>this._renderSubagentPanelImmediate())},150)},_renderSubagentPanelImmediate(){const e=this.$("subagentList");if(!e||(this.updateSubagentBadge(),this.renderMonitorSubagents(),!this.subagentPanelVisible))return;if(this.subagents.size===0){e.innerHTML='<div class="subagent-empty">No background agents detected</div>';return}const t=[],s=Array.from(this.subagents.values()).sort((n,o)=>n.status==="active"&&o.status!=="active"?-1:o.status==="active"&&n.status!=="active"?1:(o.lastActivityAt||0)-(n.lastActivityAt||0));for(const n of s){const o=this.activeSubagentId===n.agentId,i=n.status==="active"?"active":n.status==="idle"?"idle":"completed",r=this.subagentActivity.get(n.agentId)||[],a=r[r.length-1],l=a?.type==="tool"?a.tool:null,d=this.subagentWindows.has(n.agentId),c=n.status==="active"||n.status==="idle",h=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",m=this.getTeammateInfo(n),u=m?m.name:n.description||n.agentId.substring(0,7),p=this.getTeammateBadgeHtml(n),v=m?`<span class="subagent-icon teammate-dot teammate-color-${m.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
45
+ <div class="subagent-item ${i} ${o?"selected":""}${m?" is-teammate":""}"
46
46
  onclick="app.selectSubagent('${escapeHtml(n.agentId)}')"
47
47
  ondblclick="app.openSubagentWindow('${escapeHtml(n.agentId)}')"
48
48
  title="Double-click to open tracking window">
@@ -62,29 +62,29 @@
62
62
  ${l?`<span class="subagent-last-tool">${this.getToolIcon(l)} ${l}</span>`:""}
63
63
  </div>
64
64
  </div>
65
- `)}e.innerHTML=t.join("")},selectSubagent(e){this.activeSubagentId=e,this.renderSubagentPanel(),this.renderSubagentDetail()},renderSubagentDetail(){const e=this.$("subagentDetail");if(!e)return;if(!this.activeSubagentId){e.innerHTML='<div class="subagent-empty">Select an agent to view details</div>';return}const t=this.subagents.get(this.activeSubagentId),s=this.subagentActivity.get(this.activeSubagentId)||[];if(!t){e.innerHTML='<div class="subagent-empty">Agent not found</div>';return}const n=s.slice(-30).map(o=>{const l=new Date(o.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(o.type==="tool"){const d=this.getToolDetailExpanded(o.tool,o.input,o.fullInput,o.toolUseId);return`<div class="subagent-activity tool" data-tool-use-id="${escapeHtml(o.toolUseId||"")}">
65
+ `)}e.innerHTML=t.join("")},selectSubagent(e){this.activeSubagentId=e,this.renderSubagentPanel(),this.renderSubagentDetail()},renderSubagentDetail(){const e=this.$("subagentDetail");if(!e)return;if(!this.activeSubagentId){e.innerHTML='<div class="subagent-empty">Select an agent to view details</div>';return}const t=this.subagents.get(this.activeSubagentId),s=this.subagentActivity.get(this.activeSubagentId)||[];if(!t){e.innerHTML='<div class="subagent-empty">Agent not found</div>';return}const n=s.slice(-30).map(a=>{const l=new Date(a.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(a.type==="tool"){const d=this.getToolDetailExpanded(a.tool,a.input,a.fullInput,a.toolUseId);return`<div class="subagent-activity tool" data-tool-use-id="${escapeHtml(a.toolUseId||"")}">
66
66
  <span class="time">${l}</span>
67
- <span class="icon">${this.getToolIcon(o.tool)}</span>
68
- <span class="name">${escapeHtml(o.tool)}</span>
67
+ <span class="icon">${this.getToolIcon(a.tool)}</span>
68
+ <span class="name">${escapeHtml(a.tool)}</span>
69
69
  <span class="detail">${escapeHtml(d.primary)}</span>
70
- ${d.hasMore?`<button class="tool-expand-btn" onclick="app.toggleToolParams('${escapeHtml(o.toolUseId)}')">\u25B6</button>`:""}
71
- ${d.hasMore?`<div class="tool-params-expanded" id="tool-params-${escapeHtml(o.toolUseId)}" style="display:none;"><pre>${escapeHtml(JSON.stringify(o.fullInput||o.input,null,2))}</pre></div>`:""}
72
- </div>`}else if(o.type==="tool_result"){const d=o.isError?"\u274C":"\u{1F4C4}",c=o.isError?"error":"",h=o.contentLength>500?` (${this.formatBytes(o.contentLength)})`:"",m=o.preview.length>80?o.preview.substring(0,80)+"...":o.preview;return`<div class="subagent-activity tool-result ${c}">
70
+ ${d.hasMore?`<button class="tool-expand-btn" onclick="app.toggleToolParams('${escapeHtml(a.toolUseId)}')">\u25B6</button>`:""}
71
+ ${d.hasMore?`<div class="tool-params-expanded" id="tool-params-${escapeHtml(a.toolUseId)}" style="display:none;"><pre>${escapeHtml(JSON.stringify(a.fullInput||a.input,null,2))}</pre></div>`:""}
72
+ </div>`}else if(a.type==="tool_result"){const d=a.isError?"\u274C":"\u{1F4C4}",c=a.isError?"error":"",h=a.contentLength>500?` (${this.formatBytes(a.contentLength)})`:"",m=a.preview.length>80?a.preview.substring(0,80)+"...":a.preview;return`<div class="subagent-activity tool-result ${c}">
73
73
  <span class="time">${l}</span>
74
74
  <span class="icon">${d}</span>
75
- <span class="name">${escapeHtml(o.tool||"result")}</span>
75
+ <span class="name">${escapeHtml(a.tool||"result")}</span>
76
76
  <span class="detail">${escapeHtml(m)}${h}</span>
77
- </div>`}else if(o.type==="progress"){const d=o.hookEvent||o.hookName,c=d?"\u{1FA9D}":o.progressType==="query_update"?"\u27F3":"\u2713",h=d?" hook":"",m=d?o.hookName||o.hookEvent:o.query||o.progressType;return`<div class="subagent-activity progress${h}">
77
+ </div>`}else if(a.type==="progress"){const d=a.hookEvent||a.hookName,c=d?"\u{1FA9D}":a.progressType==="query_update"?"\u27F3":"\u2713",h=d?" hook":"",m=d?a.hookName||a.hookEvent:a.query||a.progressType;return`<div class="subagent-activity progress${h}">
78
78
  <span class="time">${l}</span>
79
79
  <span class="icon">${c}</span>
80
80
  <span class="detail">${escapeHtml(m)}</span>
81
- </div>`}else if(o.type==="message"){const d=o.text.length>100?o.text.substring(0,100)+"...":o.text;return`<div class="subagent-activity message">
81
+ </div>`}else if(a.type==="message"){const d=a.text.length>100?a.text.substring(0,100)+"...":a.text;return`<div class="subagent-activity message">
82
82
  <span class="time">${l}</span>
83
83
  <span class="icon">\u{1F4AC}</span>
84
84
  <span class="detail">${escapeHtml(d)}</span>
85
- </div>`}return""}).join(""),a=t.description||`Agent ${t.agentId}`,i=t.modelShort?`<span class="subagent-model-badge ${escapeHtml(t.modelShort)}">${escapeHtml(t.modelShort)}</span>`:"",r=t.totalInputTokens||t.totalOutputTokens?`<span>Tokens: ${this.formatTokenCount(t.totalInputTokens||0)}\u2193 ${this.formatTokenCount(t.totalOutputTokens||0)}\u2191</span>`:"";e.innerHTML=`
85
+ </div>`}return""}).join(""),o=t.description||`Agent ${t.agentId}`,i=t.modelShort?`<span class="subagent-model-badge ${escapeHtml(t.modelShort)}">${escapeHtml(t.modelShort)}</span>`:"",r=t.totalInputTokens||t.totalOutputTokens?`<span>Tokens: ${this.formatTokenCount(t.totalInputTokens||0)}\u2193 ${this.formatTokenCount(t.totalOutputTokens||0)}\u2191</span>`:"";e.innerHTML=`
86
86
  <div class="subagent-detail-header">
87
- <span class="subagent-id" title="${escapeHtml(t.description||t.agentId)}">${escapeHtml(a.length>60?a.substring(0,60)+"...":a)}</span>
87
+ <span class="subagent-id" title="${escapeHtml(t.description||t.agentId)}">${escapeHtml(o.length>60?o.substring(0,60)+"...":o)}</span>
88
88
  ${i}
89
89
  <span class="subagent-status ${t.status}">${t.status}</span>
90
90
  <button class="subagent-transcript-btn" onclick="app.viewSubagentTranscript('${escapeHtml(t.agentId)}')">
@@ -100,7 +100,7 @@
100
100
  <div class="subagent-activity-log">
101
101
  ${n||'<div class="subagent-empty">No activity yet</div>'}
102
102
  </div>
103
- `},toggleToolParams(e){const t=document.getElementById(`tool-params-${e}`);if(!t)return;const s=t.previousElementSibling;t.style.display==="none"?(t.style.display="block",s&&(s.textContent="\u25BC")):(t.style.display="none",s&&(s.textContent="\u25B6"))},formatTokenCount(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()},formatBytes(e){return e>=1024*1024?(e/(1024*1024)).toFixed(1)+"MB":e>=1024?(e/1024).toFixed(1)+"KB":e+"B"},getToolIcon(e){return{WebSearch:"\u{1F50D}",WebFetch:"\u{1F310}",Read:"\u{1F4D6}",Write:"\u{1F4DD}",Edit:"\u270F\uFE0F",Bash:"\u{1F4BB}",Glob:"\u{1F4C1}",Grep:"\u{1F50E}",Task:"\u{1F916}"}[e]||"\u{1F527}"},getToolDetail(e,t){if(!t)return"";if(e==="WebSearch"&&t.query)return`"${t.query}"`;if(e==="WebFetch"&&t.url)return t.url;if(e==="Read"&&t.file_path||(e==="Write"||e==="Edit")&&t.file_path)return t.file_path;if(e==="Bash"&&t.command){const s=t.command;return s.length>40?s.substring(0,40)+"...":s}return e==="Glob"&&t.pattern||e==="Grep"&&t.pattern?t.pattern:""},getToolDetailExpanded(e,t,s,n){const a=this.getToolDetail(e,t),i=["query","url","file_path","command","pattern"],l=Object.keys(s||t||{}).filter(d=>!i.includes(d)).length>0||s&&JSON.stringify(s).length>100;return{primary:a,hasMore:l,fullInput:s||t}},async killSubagent(e){try{const s=await(await this._apiDelete(`/api/subagents/${e}`))?.json();if(s?.success){const n=this.subagents.get(e);n&&(n.status="completed",this.subagents.set(e,n)),this.renderSubagentPanel(),this.renderSubagentDetail(),this.updateSubagentWindows(),this.showToast(`Subagent ${e.substring(0,7)} killed`,"success")}else this.showToast(s.error||"Failed to kill subagent","error")}catch(t){console.error("Failed to kill subagent:",t),this.showToast("Failed to kill subagent: "+t.message,"error")}},async viewSubagentTranscript(e){try{const s=await(await fetch(`/api/subagents/${e}/transcript?format=formatted`)).json();if(!s.success){alert("Failed to load transcript");return}const n=s.data.formatted.join(`
103
+ `},toggleToolParams(e){const t=document.getElementById(`tool-params-${e}`);if(!t)return;const s=t.previousElementSibling;t.style.display==="none"?(t.style.display="block",s&&(s.textContent="\u25BC")):(t.style.display="none",s&&(s.textContent="\u25B6"))},formatTokenCount(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()},formatBytes(e){return e>=1024*1024?(e/(1024*1024)).toFixed(1)+"MB":e>=1024?(e/1024).toFixed(1)+"KB":e+"B"},getToolIcon(e){return{WebSearch:"\u{1F50D}",WebFetch:"\u{1F310}",Read:"\u{1F4D6}",Write:"\u{1F4DD}",Edit:"\u270F\uFE0F",Bash:"\u{1F4BB}",Glob:"\u{1F4C1}",Grep:"\u{1F50E}",Task:"\u{1F916}"}[e]||"\u{1F527}"},getToolDetail(e,t){if(!t)return"";if(e==="WebSearch"&&t.query)return`"${t.query}"`;if(e==="WebFetch"&&t.url)return t.url;if(e==="Read"&&t.file_path||(e==="Write"||e==="Edit")&&t.file_path)return t.file_path;if(e==="Bash"&&t.command){const s=t.command;return s.length>40?s.substring(0,40)+"...":s}return e==="Glob"&&t.pattern||e==="Grep"&&t.pattern?t.pattern:""},getToolDetailExpanded(e,t,s,n){const o=this.getToolDetail(e,t),i=["query","url","file_path","command","pattern"],l=Object.keys(s||t||{}).filter(d=>!i.includes(d)).length>0||s&&JSON.stringify(s).length>100;return{primary:o,hasMore:l,fullInput:s||t}},async killSubagent(e){try{const s=await(await this._apiDelete(`/api/subagents/${e}`))?.json();if(s?.success){const n=this.subagents.get(e);n&&(n.status="completed",this.subagents.set(e,n)),this.renderSubagentPanel(),this.renderSubagentDetail(),this.updateSubagentWindows(),this.showToast(`Subagent ${e.substring(0,7)} killed`,"success")}else this.showToast(s.error||"Failed to kill subagent","error")}catch(t){console.error("Failed to kill subagent:",t),this.showToast("Failed to kill subagent: "+t.message,"error")}},async viewSubagentTranscript(e){try{const s=await(await fetch(`/api/subagents/${e}/transcript?format=formatted`)).json();if(!s.success){alert("Failed to load transcript");return}const n=s.data.formatted.join(`
104
104
  `);window.open("","_blank","width=800,height=600").document.write(`
105
105
  <html>
106
106
  <head>
@@ -115,26 +115,26 @@
115
115
  <pre>${escapeHtml(n)}</pre>
116
116
  </body>
117
117
  </html>
118
- `)}catch(t){console.error("Failed to load transcript:",t),alert("Failed to load transcript: "+t.message)}},findParentSessionForSubagent(e){if(this.subagentParentMap.has(e)){const s=this.subagentParentMap.get(e);if(this.sessions.has(s)){const n=this.subagents.get(e);if(n&&!n.parentSessionId){n.parentSessionId=s;const a=this.sessions.get(s);a&&(n.parentSessionName=this.getSessionName(a)),this.subagents.set(e,n),this.updateSubagentWindowParent(e)}return}this.subagentParentMap.delete(e)}const t=this.subagents.get(e);if(t){if(t.sessionId){for(const[s,n]of this.sessions)if(n.claudeSessionId===t.sessionId){this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}}if(this.activeSessionId&&this.sessions.has(this.activeSessionId)){this.setAgentParentSessionId(e,this.activeSessionId),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}if(this.sessions.size>0){const s=this.sessions.keys().next().value;this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines()}}},recheckOrphanSubagents(){let e=!1;for(const[t,s]of this.subagents)if(!this.subagentParentMap.has(t))this.findParentSessionForSubagent(t),this.subagentParentMap.has(t)&&(e=!0);else if(s.sessionId){const n=this.subagentParentMap.get(t),a=this.sessions.get(n);if(a&&a.claudeSessionId!==s.sessionId){for(const[i,r]of this.sessions)if(r.claudeSessionId===s.sessionId){this.subagentParentMap.set(t,i),s.parentSessionId=i,s.parentSessionName=this.getSessionName(r),this.subagents.set(t,s),this.updateSubagentWindowParent(t),e=!0;break}}}e&&(this.saveSubagentParentMap(),this.updateConnectionLines())},updateSubagentParentNames(e){const t=this.sessions.get(e);if(!t)return;const s=this.getSessionName(t);if(this._parentNameCache?.get(e)!==s){this._parentNameCache||(this._parentNameCache=new Map),this._parentNameCache.set(e,s);for(const[a,i]of this.subagentParentMap)if(i===e){const r=this.subagents.get(a);if(r){r.parentSessionName=s,this.subagents.set(a,r);const o=this.subagentWindows.get(a);if(o){const l=o.element.querySelector(".subagent-window-parent .parent-name");l&&(l.textContent=s)}}}}},updateSubagentWindowParent(e){const t=this.subagentWindows.get(e);if(!t)return;const s=this.subagentParentMap.get(e);if(!s)return;const n=this.sessions.get(s),a=n?this.getSessionName(n):"Unknown",i=t.element,r=i.querySelector(".subagent-window-parent");if(r){r.dataset.parentSession=s;const l=r.querySelector(".parent-name");l&&(l.textContent=a,l.onclick=()=>this.selectSession(s));return}const o=i.querySelector(".subagent-window-header");if(o){const l=document.createElement("div");l.className="subagent-window-parent",l.dataset.parentSession=s,l.innerHTML=`
118
+ `)}catch(t){console.error("Failed to load transcript:",t),alert("Failed to load transcript: "+t.message)}},findParentSessionForSubagent(e){if(this.subagentParentMap.has(e)){const s=this.subagentParentMap.get(e);if(this.sessions.has(s)){const n=this.subagents.get(e);if(n&&!n.parentSessionId){n.parentSessionId=s;const o=this.sessions.get(s);o&&(n.parentSessionName=this.getSessionName(o)),this.subagents.set(e,n),this.updateSubagentWindowParent(e)}return}this.subagentParentMap.delete(e)}const t=this.subagents.get(e);if(t){if(t.sessionId){for(const[s,n]of this.sessions)if(n.claudeSessionId===t.sessionId){this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}}if(this.activeSessionId&&this.sessions.has(this.activeSessionId)){this.setAgentParentSessionId(e,this.activeSessionId),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}if(this.sessions.size>0){const s=this.sessions.keys().next().value;this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines()}}},recheckOrphanSubagents(){let e=!1;for(const[t,s]of this.subagents)if(!this.subagentParentMap.has(t))this.findParentSessionForSubagent(t),this.subagentParentMap.has(t)&&(e=!0);else if(s.sessionId){const n=this.subagentParentMap.get(t),o=this.sessions.get(n);if(o&&o.claudeSessionId!==s.sessionId){for(const[i,r]of this.sessions)if(r.claudeSessionId===s.sessionId){this.subagentParentMap.set(t,i),s.parentSessionId=i,s.parentSessionName=this.getSessionName(r),this.subagents.set(t,s),this.updateSubagentWindowParent(t),e=!0;break}}}e&&(this.saveSubagentParentMap(),this.updateConnectionLines())},updateSubagentParentNames(e){const t=this.sessions.get(e);if(!t)return;const s=this.getSessionName(t);if(this._parentNameCache?.get(e)!==s){this._parentNameCache||(this._parentNameCache=new Map),this._parentNameCache.set(e,s);for(const[o,i]of this.subagentParentMap)if(i===e){const r=this.subagents.get(o);if(r){r.parentSessionName=s,this.subagents.set(o,r);const a=this.subagentWindows.get(o);if(a){const l=a.element.querySelector(".subagent-window-parent .parent-name");l&&(l.textContent=s)}}}}},updateSubagentWindowParent(e){const t=this.subagentWindows.get(e);if(!t)return;const s=this.subagentParentMap.get(e);if(!s)return;const n=this.sessions.get(s),o=n?this.getSessionName(n):"Unknown",i=t.element,r=i.querySelector(".subagent-window-parent");if(r){r.dataset.parentSession=s;const l=r.querySelector(".parent-name");l&&(l.textContent=o,l.onclick=()=>this.selectSession(s));return}const a=i.querySelector(".subagent-window-header");if(a){const l=document.createElement("div");l.className="subagent-window-parent",l.dataset.parentSession=s,l.innerHTML=`
119
119
  <span class="parent-label">from</span>
120
- <span class="parent-name" onclick="app.selectSession('${escapeHtml(s)}')">${escapeHtml(a)}</span>
121
- `,o.insertAdjacentElement("afterend",l)}},updateSubagentWindowVisibility(){const t=this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0;for(const[s,n]of this.subagentWindows){const a=this.subagentParentMap.get(s),i=this.subagents.get(s),r=a||i?.parentSessionId;let o;t?o=!!!r||r===this.activeSessionId:o=!0,o?(n.minimized||(n.element.style.display="flex",n._lazyTerminal&&this._restoreTeammateTerminalFromLazy(s)),n.hidden=!1):(this._disposeTeammateTerminalForMinimize(s),n.element.style.display="none",n.hidden=!0)}this.updateConnectionLines(),this.relayoutMobileSubagentWindows()},closeSessionSubagentWindows(e,t=!1){const s=[];for(const[n,a]of this.subagentWindows){const i=this.subagents.get(n),r=this.subagentParentMap.get(n);(i?.parentSessionId===e||r===e)&&s.push(n)}for(const n of s)this.forceCloseSubagentWindow(n),t&&(this.subagents.delete(n),this.subagentActivity.delete(n),this.subagentToolResults.delete(n),this.subagentParentMap.delete(n));this.minimizedSubagents.delete(e),this.renderSessionTabs()},forceCloseSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(t.resizeObserver&&t.resizeObserver.disconnect(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.subagentWindows.delete(e));const s=this.teammateTerminals.get(e);if(s){if(s.resizeObserver&&s.resizeObserver.disconnect(),s.terminal)try{s.terminal.dispose()}catch{}this.teammateTerminals.delete(e)}},minimizeSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(this._disposeTeammateTerminalForMinimize(e),t.element.style.display="none",t.minimized=!0,this.updateConnectionLines())},scheduleSubagentWindowRender(e){this.subagentWindows.get(e)?.minimized||(this._subagentWindowRenderTimeouts||(this._subagentWindowRenderTimeouts=new Map),this._subagentWindowRenderTimeouts.has(e)&&clearTimeout(this._subagentWindowRenderTimeouts.get(e)),this._subagentWindowRenderTimeouts.set(e,setTimeout(()=>{this._subagentWindowRenderTimeouts.delete(e),scheduleBackground(()=>this.renderSubagentWindowContent(e))},100)))},renderSubagentWindowContent(e){if(this.teammateTerminals.has(e)||this.subagentWindows.get(e)?._lazyTerminal)return;const s=document.getElementById(`subagent-window-body-${e}`);if(!s)return;const n=this.subagentActivity.get(e)||[];if(n.length===0){s.innerHTML='<div class="subagent-empty">No activity yet</div>';return}const a=s.dataset.renderedCount?parseInt(s.dataset.renderedCount,10):0,i=100,r=n.slice(-i);if(a===0||a>r.length||s.children.length===0||s.children.length===1&&s.querySelector(".subagent-empty")){const o=r.map(l=>this._renderActivityItem(l)).join("");s.innerHTML=o,s.dataset.renderedCount=String(r.length)}else{const o=r.slice(a);if(o.length>0){const l=o.map(d=>this._renderActivityItem(d)).join("");for(s.insertAdjacentHTML("beforeend",l),s.dataset.renderedCount=String(r.length);s.children.length>i;)s.removeChild(s.firstChild)}}s.scrollTop=s.scrollHeight},_renderActivityItem(e){const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(e.type==="tool")return`<div class="activity-line">
120
+ <span class="parent-name" onclick="app.selectSession('${escapeHtml(s)}')">${escapeHtml(o)}</span>
121
+ `,a.insertAdjacentElement("afterend",l)}},updateSubagentWindowVisibility(){const t=this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0;for(const[s,n]of this.subagentWindows){const o=this.subagentParentMap.get(s),i=this.subagents.get(s),r=o||i?.parentSessionId;let a;t?a=!!!r||r===this.activeSessionId:a=!0,a?(n.minimized||(n.element.style.display="flex",n._lazyTerminal&&this._restoreTeammateTerminalFromLazy(s)),n.hidden=!1):(this._disposeTeammateTerminalForMinimize(s),n.element.style.display="none",n.hidden=!0)}this.updateConnectionLines(),this.relayoutMobileSubagentWindows()},closeSessionSubagentWindows(e,t=!1){const s=[];for(const[n,o]of this.subagentWindows){const i=this.subagents.get(n),r=this.subagentParentMap.get(n);(i?.parentSessionId===e||r===e)&&s.push(n)}for(const n of s)this.forceCloseSubagentWindow(n),t&&(this.subagents.delete(n),this.subagentActivity.delete(n),this.subagentToolResults.delete(n),this.subagentParentMap.delete(n));this.minimizedSubagents.delete(e),this.renderSessionTabs()},forceCloseSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(t.resizeObserver&&t.resizeObserver.disconnect(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.subagentWindows.delete(e));const s=this.teammateTerminals.get(e);if(s){if(s.resizeObserver&&s.resizeObserver.disconnect(),s.terminal)try{s.terminal.dispose()}catch{}this.teammateTerminals.delete(e)}},minimizeSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(this._disposeTeammateTerminalForMinimize(e),t.element.style.display="none",t.minimized=!0,this.updateConnectionLines())},scheduleSubagentWindowRender(e){this.subagentWindows.get(e)?.minimized||(this._subagentWindowRenderTimeouts||(this._subagentWindowRenderTimeouts=new Map),this._subagentWindowRenderTimeouts.has(e)&&clearTimeout(this._subagentWindowRenderTimeouts.get(e)),this._subagentWindowRenderTimeouts.set(e,setTimeout(()=>{this._subagentWindowRenderTimeouts.delete(e),scheduleBackground(()=>this.renderSubagentWindowContent(e))},100)))},renderSubagentWindowContent(e){if(this.teammateTerminals.has(e)||this.subagentWindows.get(e)?._lazyTerminal)return;const s=document.getElementById(`subagent-window-body-${e}`);if(!s)return;const n=this.subagentActivity.get(e)||[];if(n.length===0){s.innerHTML='<div class="subagent-empty">No activity yet</div>';return}const o=s.dataset.renderedCount?parseInt(s.dataset.renderedCount,10):0,i=100,r=n.slice(-i);if(o===0||o>r.length||s.children.length===0||s.children.length===1&&s.querySelector(".subagent-empty")){const a=r.map(l=>this._renderActivityItem(l)).join("");s.innerHTML=a,s.dataset.renderedCount=String(r.length)}else{const a=r.slice(o);if(a.length>0){const l=a.map(d=>this._renderActivityItem(d)).join("");for(s.insertAdjacentHTML("beforeend",l),s.dataset.renderedCount=String(r.length);s.children.length>i;)s.removeChild(s.firstChild)}}s.scrollTop=s.scrollHeight},_renderActivityItem(e){const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(e.type==="tool")return`<div class="activity-line">
122
122
  <span class="time">${t}</span>
123
123
  <span class="tool-icon">${this.getToolIcon(e.tool)}</span>
124
124
  <span class="tool-name">${escapeHtml(e.tool)}</span>
125
125
  <span class="tool-detail">${escapeHtml(this.getToolDetail(e.tool,e.input))}</span>
126
- </div>`;if(e.type==="tool_result"){const s=e.isError?"\u274C":"\u{1F4C4}",n=e.isError?" error":"",a=e.contentLength>500?` (${this.formatBytes(e.contentLength)})`:"",i=e.preview.length>60?e.preview.substring(0,60)+"...":e.preview;return`<div class="activity-line result-line${n}">
126
+ </div>`;if(e.type==="tool_result"){const s=e.isError?"\u274C":"\u{1F4C4}",n=e.isError?" error":"",o=e.contentLength>500?` (${this.formatBytes(e.contentLength)})`:"",i=e.preview.length>60?e.preview.substring(0,60)+"...":e.preview;return`<div class="activity-line result-line${n}">
127
127
  <span class="time">${t}</span>
128
128
  <span class="tool-icon">${s}</span>
129
129
  <span class="tool-name">${escapeHtml(e.tool||"\u2192")}</span>
130
- <span class="tool-detail">${escapeHtml(i)}${a}</span>
131
- </div>`}else if(e.type==="progress"){const s=e.hookEvent||e.hookName,n=s?"\u{1FA9D}":e.progressType==="query_update"?"\u27F3":"\u2713",a=s?e.hookName||e.hookEvent:e.query||e.progressType;return`<div class="activity-line progress-line${s?" hook-line":""}">
130
+ <span class="tool-detail">${escapeHtml(i)}${o}</span>
131
+ </div>`}else if(e.type==="progress"){const s=e.hookEvent||e.hookName,n=s?"\u{1FA9D}":e.progressType==="query_update"?"\u27F3":"\u2713",o=s?e.hookName||e.hookEvent:e.query||e.progressType;return`<div class="activity-line progress-line${s?" hook-line":""}">
132
132
  <span class="time">${t}</span>
133
133
  <span class="tool-icon">${n}</span>
134
- <span class="tool-detail">${escapeHtml(a)}</span>
134
+ <span class="tool-detail">${escapeHtml(o)}</span>
135
135
  </div>`}else if(e.type==="message"){const s=e.text.length>150?e.text.substring(0,150)+"...":e.text;return`<div class="message-line">
136
136
  <span class="time">${t}</span> \u{1F4AC} ${escapeHtml(s)}
137
- </div>`}return""},updateSubagentWindows(){for(const e of this.subagentWindows.keys())this.renderSubagentWindowContent(e),this.updateSubagentWindowHeader(e)},updateSubagentWindowHeader(e){const t=this.subagents.get(e);if(!t)return;const s=document.getElementById(`subagent-window-${e}`);if(!s)return;const n=s.querySelector(".subagent-window-title .id");if(n){const d=this.getTeammateInfo(t),c=d?d.name:t.description||e.substring(0,7),h=c.length>50?c.substring(0,50)+"...":c;n.textContent=h}let a=s.querySelector(".teammate-badge");const i=this.getTeammateInfo(t);if(i&&!a){const d=s.querySelector(".subagent-window-title");if(d){const c=document.createElement("span");c.className=`teammate-badge teammate-color-${i.color}`,c.title=`Team: ${i.teamName}`,c.textContent=`@${i.name}`;const h=d.querySelector(".status");h&&h.insertAdjacentElement("beforebegin",c)}}const r=s.querySelector(".subagent-window-title");r&&(r.title=t.description||e);let o=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!o){o=document.createElement("span"),o.className=`subagent-model-badge ${t.modelShort}`;const d=s.querySelector(".subagent-window-title .status");d&&d.insertAdjacentElement("beforebegin",o)}o.className=`subagent-model-badge ${t.modelShort}`,o.textContent=t.modelShort}const l=s.querySelector(".subagent-window-title .status");l&&(l.className=`status ${t.status}`,l.textContent=t.status)},openAllActiveSubagentWindows(){for(const[e,t]of this.subagents)t.status==="active"&&!this.subagentWindows.has(e)&&this.openSubagentWindow(e)},initTeammateTerminal(e,t,s){const n=s.querySelector(".subagent-window-body");if(!n)return;n.innerHTML="",n.classList.add("teammate-terminal-body"),s.classList.add("has-terminal");const a=t.sessionId,i=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:a,resizeObserver:null,pendingData:i}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const r=new Terminal({theme:{...window.codemanCurrentXtermTheme()},fontFamily:'"Fira Code", "Cascadia Code", "JetBrains Mono", "SF Mono", Monaco, monospace',fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:DEFAULT_SCROLLBACK,allowTransparency:!0,allowProposedApi:!0}),o=new FitAddon.FitAddon;if(r.loadAddon(o),typeof Unicode11Addon<"u")try{const c=new Unicode11Addon.Unicode11Addon;r.loadAddon(c),r.unicode.activeVersion="11"}catch{}try{r.open(n)}catch(c){console.warn("[TeammateTerminal] Failed to open terminal:",c),this.teammateTerminals.delete(e);return}setTimeout(()=>{try{o.fit()}catch{}fetch(`/api/sessions/${a}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(c=>c.json()).then(c=>{if(c.success&&c.data?.buffer)try{r.write(c.data.buffer)}catch{}}).catch(c=>console.error("[TeammateTerminal] Failed to fetch buffer:",c));for(const c of i)try{r.write(c)}catch{}i.length=0},100),r.onData(c=>{fetch(`/api/sessions/${a}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:c})}).catch(h=>console.error("[TeammateTerminal] Failed to send input:",h))});const l=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{o.fit()}catch{}})});l.observe(n);const d=this.teammateTerminals.get(e);d&&(d.terminal=r,d.fitAddon=o,d.resizeObserver=l)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const w=this.subagentWindows.get(t);w.hidden&&(w.element.style.display="flex",w.hidden=!1),w.element.style.zIndex=++this.subagentWindowZIndex,w.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,a=400,i=20,r=window.innerWidth,o=window.innerHeight,l=50,d=120,c=Math.floor((r-l-50)/(n+i))||1,h=Math.floor((o-d-50)/(a+i))||1,m=s%c,u=Math.floor(s/c)%h;let p=l+m*(n+i),v=d+u*(a+i);p=Math.max(10,Math.min(p,r-n-10)),v=Math.max(10,Math.min(v,o-a-10));const y=e.color||"blue",f=document.createElement("div");f.className="subagent-window has-terminal",f.id=`subagent-window-${t}`,f.style.zIndex=++this.subagentWindowZIndex,f.style.left=`${p}px`,f.style.top=`${v}px`,f.style.width=`${n}px`,f.style.height=`${a}px`,f.innerHTML=`
137
+ </div>`}return""},updateSubagentWindows(){for(const e of this.subagentWindows.keys())this.renderSubagentWindowContent(e),this.updateSubagentWindowHeader(e)},updateSubagentWindowHeader(e){const t=this.subagents.get(e);if(!t)return;const s=document.getElementById(`subagent-window-${e}`);if(!s)return;const n=s.querySelector(".subagent-window-title .id");if(n){const d=this.getTeammateInfo(t),c=d?d.name:t.description||e.substring(0,7),h=c.length>50?c.substring(0,50)+"...":c;n.textContent=h}let o=s.querySelector(".teammate-badge");const i=this.getTeammateInfo(t);if(i&&!o){const d=s.querySelector(".subagent-window-title");if(d){const c=document.createElement("span");c.className=`teammate-badge teammate-color-${i.color}`,c.title=`Team: ${i.teamName}`,c.textContent=`@${i.name}`;const h=d.querySelector(".status");h&&h.insertAdjacentElement("beforebegin",c)}}const r=s.querySelector(".subagent-window-title");r&&(r.title=t.description||e);let a=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!a){a=document.createElement("span"),a.className=`subagent-model-badge ${t.modelShort}`;const d=s.querySelector(".subagent-window-title .status");d&&d.insertAdjacentElement("beforebegin",a)}a.className=`subagent-model-badge ${t.modelShort}`,a.textContent=t.modelShort}const l=s.querySelector(".subagent-window-title .status");l&&(l.className=`status ${t.status}`,l.textContent=t.status)},openAllActiveSubagentWindows(){for(const[e,t]of this.subagents)t.status==="active"&&!this.subagentWindows.has(e)&&this.openSubagentWindow(e)},initTeammateTerminal(e,t,s){const n=s.querySelector(".subagent-window-body");if(!n)return;n.innerHTML="",n.classList.add("teammate-terminal-body"),s.classList.add("has-terminal");const o=t.sessionId,i=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:o,resizeObserver:null,pendingData:i}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const r=new Terminal({theme:{...window.codemanCurrentXtermTheme()},fontFamily:'"Fira Code", "Cascadia Code", "JetBrains Mono", "SF Mono", Monaco, monospace',fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:DEFAULT_SCROLLBACK,allowTransparency:!0,allowProposedApi:!0}),a=new FitAddon.FitAddon;if(r.loadAddon(a),typeof Unicode11Addon<"u")try{const c=new Unicode11Addon.Unicode11Addon;r.loadAddon(c),r.unicode.activeVersion="11"}catch{}try{r.open(n)}catch(c){console.warn("[TeammateTerminal] Failed to open terminal:",c),this.teammateTerminals.delete(e);return}setTimeout(()=>{try{a.fit()}catch{}fetch(`/api/sessions/${o}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(c=>c.json()).then(c=>{if(c.success&&c.data?.buffer)try{r.write(c.data.buffer)}catch{}}).catch(c=>console.error("[TeammateTerminal] Failed to fetch buffer:",c));for(const c of i)try{r.write(c)}catch{}i.length=0},100),r.onData(c=>{fetch(`/api/sessions/${o}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:c})}).catch(h=>console.error("[TeammateTerminal] Failed to send input:",h))});const l=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{a.fit()}catch{}})});l.observe(n);const d=this.teammateTerminals.get(e);d&&(d.terminal=r,d.fitAddon=a,d.resizeObserver=l)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const w=this.subagentWindows.get(t);w.hidden&&(w.element.style.display="flex",w.hidden=!1),w.element.style.zIndex=++this.subagentWindowZIndex,w.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,o=400,i=20,r=window.innerWidth,a=window.innerHeight,l=50,d=120,c=Math.floor((r-l-50)/(n+i))||1,h=Math.floor((a-d-50)/(o+i))||1,m=s%c,u=Math.floor(s/c)%h;let p=l+m*(n+i),v=d+u*(o+i);p=Math.max(10,Math.min(p,r-n-10)),v=Math.max(10,Math.min(v,a-o-10));const y=e.color||"blue",f=document.createElement("div");f.className="subagent-window has-terminal",f.id=`subagent-window-${t}`,f.style.zIndex=++this.subagentWindowZIndex,f.style.left=`${p}px`,f.style.top=`${v}px`,f.style.width=`${n}px`,f.style.height=`${o}px`,f.innerHTML=`
138
138
  <div class="subagent-window-header">
139
139
  <div class="subagent-window-title" title="Teammate terminal: ${escapeHtml(e.teammateName)} (pane ${e.paneTarget})">
140
140
  <span class="icon" style="color: var(--team-color-${y}, #339af0)">\u2B24</span>
@@ -147,11 +147,11 @@
147
147
  </div>
148
148
  <div class="subagent-window-body teammate-terminal-body" id="subagent-window-body-${t}">
149
149
  </div>
150
- `,document.body.appendChild(f);const b=this.makeWindowDraggable(f,f.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(f);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:f,minimized:!1,hidden:S,dragListeners:b,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(f.style.display="none"),f.addEventListener("mousedown",()=>{f.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(f),this.subagentWindows.get(t).resizeObserver=$,S){const w=this.subagentWindows.get(t);w&&(w._lazyTerminal=!0,w._lazyPaneTarget=e.paneTarget,w._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,f);requestAnimationFrame(()=>{f.style.transition="transform 0.3s ease, opacity 0.3s ease",f.style.transform="scale(1)",f.style.opacity="1"})},rebuildTeammateMap(){this.teammateMap.clear();for(const[e,t]of this.teams)for(const s of t.members)s.agentType!=="team-lead"&&this.teammateMap.set(s.name,{name:s.name,color:s.color||"blue",teamName:e,agentId:s.agentId})},getTeammateInfo(e){if(!e?.description)return null;const t=e.description.match(/<teammate-message\s+teammate_id="?([^">\s]+)/);if(!t)return null;const n=t[1].split("@")[0];return this.teammateMap.get(n)||{name:n,color:"blue",teamName:"unknown"}},getTeammateBadgeHtml(e){const t=this.getTeammateInfo(e);return t?`<span class="teammate-badge teammate-color-${t.color}" title="Team: ${escapeHtml(t.teamName)}">@${escapeHtml(t.name)}</span>`:""},renderTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");if(!e)return;let t=null,s=null;if(this.activeSessionId){for(const[u,p]of this.teams)if(p.leadSessionId===this.activeSessionId){t=p,s=u;break}}if(!t){e.style.display="none";return}const n=e.style.display==="none";if(e.style.display="flex",n&&!this.teamTasksDragListeners){e.style.left=`${Math.max(10,window.innerWidth-360-20)}px`,e.style.top=`${Math.max(10,window.innerHeight-300-70)}px`;const v=e.querySelector(".team-tasks-header");v&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,v))}const a=this.teamTasks.get(s)||[],i=a.filter(u=>u.status==="completed").length,r=a.length,o=r>0?Math.round(i/r*100):0,l=e.querySelector(".team-tasks-header-text");if(l){const u=t.members.filter(p=>p.agentType!=="team-lead").length;l.textContent=`Team Tasks (${u} teammates)`}const d=e.querySelector(".team-tasks-progress-fill");d&&(d.style.width=`${o}%`);const c=e.querySelector(".team-tasks-progress-text");c&&(c.textContent=`${i}/${r}`);const h=e.querySelector(".team-tasks-list");if(!h)return;if(a.length===0){h.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const m=a.map(u=>{const p=u.status==="completed"?"\u2713":u.status==="in_progress"?"\u25C9":"\u25CB",v=u.status.replace("_","-"),y=u.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(u.owner)}">${escapeHtml(u.owner)}</span>`:"";return`<div class="team-task-item ${v}">
150
+ `,document.body.appendChild(f);const b=this.makeWindowDraggable(f,f.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(f);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:f,minimized:!1,hidden:S,dragListeners:b,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(f.style.display="none"),f.addEventListener("mousedown",()=>{f.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(f),this.subagentWindows.get(t).resizeObserver=$,S){const w=this.subagentWindows.get(t);w&&(w._lazyTerminal=!0,w._lazyPaneTarget=e.paneTarget,w._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,f);requestAnimationFrame(()=>{f.style.transition="transform 0.3s ease, opacity 0.3s ease",f.style.transform="scale(1)",f.style.opacity="1"})},rebuildTeammateMap(){this.teammateMap.clear();for(const[e,t]of this.teams)for(const s of t.members)s.agentType!=="team-lead"&&this.teammateMap.set(s.name,{name:s.name,color:s.color||"blue",teamName:e,agentId:s.agentId})},getTeammateInfo(e){if(!e?.description)return null;const t=e.description.match(/<teammate-message\s+teammate_id="?([^">\s]+)/);if(!t)return null;const n=t[1].split("@")[0];return this.teammateMap.get(n)||{name:n,color:"blue",teamName:"unknown"}},getTeammateBadgeHtml(e){const t=this.getTeammateInfo(e);return t?`<span class="teammate-badge teammate-color-${t.color}" title="Team: ${escapeHtml(t.teamName)}">@${escapeHtml(t.name)}</span>`:""},renderTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");if(!e)return;let t=null,s=null;if(this.activeSessionId){for(const[u,p]of this.teams)if(p.leadSessionId===this.activeSessionId){t=p,s=u;break}}if(!t){e.style.display="none";return}const n=e.style.display==="none";if(e.style.display="flex",n&&!this.teamTasksDragListeners){e.style.left=`${Math.max(10,window.innerWidth-360-20)}px`,e.style.top=`${Math.max(10,window.innerHeight-300-70)}px`;const v=e.querySelector(".team-tasks-header");v&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,v))}const o=this.teamTasks.get(s)||[],i=o.filter(u=>u.status==="completed").length,r=o.length,a=r>0?Math.round(i/r*100):0,l=e.querySelector(".team-tasks-header-text");if(l){const u=t.members.filter(p=>p.agentType!=="team-lead").length;l.textContent=`Team Tasks (${u} teammates)`}const d=e.querySelector(".team-tasks-progress-fill");d&&(d.style.width=`${a}%`);const c=e.querySelector(".team-tasks-progress-text");c&&(c.textContent=`${i}/${r}`);const h=e.querySelector(".team-tasks-list");if(!h)return;if(o.length===0){h.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const m=o.map(u=>{const p=u.status==="completed"?"\u2713":u.status==="in_progress"?"\u25C9":"\u25CB",v=u.status.replace("_","-"),y=u.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(u.owner)}">${escapeHtml(u.owner)}</span>`:"";return`<div class="team-task-item ${v}">
151
151
  <span class="team-task-status">${p}</span>
152
152
  <span class="team-task-subject">${escapeHtml(u.subject)}</span>
153
153
  ${y}
154
- </div>`}).join("");h.innerHTML=m},hideTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");e&&(e.style.display="none"),this.teamTasksDragListeners&&(document.removeEventListener("mousemove",this.teamTasksDragListeners.move),document.removeEventListener("mouseup",this.teamTasksDragListeners.up),this.teamTasksDragListeners.touchMove&&(document.removeEventListener("touchmove",this.teamTasksDragListeners.touchMove),document.removeEventListener("touchend",this.teamTasksDragListeners.up),document.removeEventListener("touchcancel",this.teamTasksDragListeners.up)),this.teamTasksDragListeners.handle&&(this.teamTasksDragListeners.handle.removeEventListener("mousedown",this.teamTasksDragListeners.handleMouseDown),this.teamTasksDragListeners.handle.removeEventListener("touchstart",this.teamTasksDragListeners.handleTouchStart)),this.teamTasksDragListeners=null)},getTeammateColor(e){return this.teammateMap.get(e)?.color||"blue"},normalizeFilePath(e,t){if(!e)return"";let s=e.trim();const n="/home/"+(window.USER||"user");s.startsWith("~/")?s=n+s.slice(1):s==="~"&&(s=n),!s.startsWith("/")&&t&&(s=t+"/"+s);const a=s.split("/"),i=[];for(const r of a)r===""||r==="."||(r===".."?i.length>1&&i.pop():i.push(r));return"/"+i.join("/")},getFilename(e){const t=e.split("/");return t[t.length-1]||""},isShallowRootPath(e){return e.startsWith("/")?e.split("/").filter(s=>s!=="").length===1:!1},isPathInWorkingDir(e,t){if(!t)return!1;const s=this.normalizeFilePath(e,t);return s.startsWith(t+"/")||s===t},pathsAreEquivalent(e,t,s){const n=this.normalizeFilePath(e,s),a=this.normalizeFilePath(t,s);if(n===a)return!0;const i=this.getFilename(n),r=this.getFilename(a);if(i!==r)return!1;const o=this.isShallowRootPath(e),l=this.isShallowRootPath(t),d=this.isPathInWorkingDir(n,s),c=this.isPathInWorkingDir(a,s);return!!(o&&c||l&&d)},pickBetterPath(e,t,s){if(s){const i=this.isPathInWorkingDir(e,s),r=this.isPathInWorkingDir(t,s);if(i&&!r)return e;if(r&&!i)return t}const n=e.startsWith("/"),a=t.startsWith("/");return n&&!a?e:a&&!n?t:e.length!==t.length?e.length>t.length?e:t:!e.includes("~")&&t.includes("~")?e:!t.includes("~")&&e.includes("~")?t:e},deduplicateProjectInsightPaths(e,t){const s=[];for(const i of e)for(const r of i.filePaths)s.push({rawPath:r,toolId:i.id});if(s.length<=1){const i=new Map;for(const r of s)i.set(this.normalizeFilePath(r.rawPath,t),r);return i}s.sort((i,r)=>{const o=this.isPathInWorkingDir(i.rawPath,t),l=this.isPathInWorkingDir(r.rawPath,t);return o&&!l?-1:l&&!o?1:r.rawPath.length-i.rawPath.length});const n=new Map,a=new Set;for(const{rawPath:i,toolId:r}of s){const o=this.normalizeFilePath(i,t);let l=!1;for(const[,d]of n)if(this.pathsAreEquivalent(i,d.rawPath,t)){l=!0;break}!l&&!a.has(o)&&(n.set(o,{rawPath:i,toolId:r}),a.add(o))}return n},handleBashToolStart(e,t){let s=this.projectInsights.get(e)||[];s=s.filter(n=>n.id!==t.id),s.push(t),this.projectInsights.set(e,s),this.renderProjectInsightsPanel()},handleBashToolEnd(e,t){const n=(this.projectInsights.get(e)||[]).find(a=>a.id===t.id);n&&(n.status="completed"),this.renderProjectInsightsPanel(),setTimeout(()=>{const a=this.projectInsights.get(e)||[];this.projectInsights.set(e,a.filter(i=>i.id!==t.id)),this.renderProjectInsightsPanel()},2e3)},handleBashToolsUpdate(e,t){this.projectInsights.set(e,t),this.renderProjectInsightsPanel()},renderProjectInsightsPanel(){const e=this.$("projectInsightsPanel"),t=this.$("projectInsightsList");if(!e||!t)return;if(!(this.loadAppSettingsFromStorage().showProjectInsights??!1)){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}const i=(this.projectInsights.get(this.activeSessionId)||[]).filter(h=>h.status==="running");if(i.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const o=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,l=this.deduplicateProjectInsightPaths(i,o),d=new Set(Array.from(l.values()).map(h=>h.rawPath)),c=[];for(const h of i){const m=h.filePaths.filter(p=>d.has(p));if(m.length===0)continue;const u=h.command.length>50?h.command.substring(0,50)+"...":h.command;c.push(`
154
+ </div>`}).join("");h.innerHTML=m},hideTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");e&&(e.style.display="none"),this.teamTasksDragListeners&&(document.removeEventListener("mousemove",this.teamTasksDragListeners.move),document.removeEventListener("mouseup",this.teamTasksDragListeners.up),this.teamTasksDragListeners.touchMove&&(document.removeEventListener("touchmove",this.teamTasksDragListeners.touchMove),document.removeEventListener("touchend",this.teamTasksDragListeners.up),document.removeEventListener("touchcancel",this.teamTasksDragListeners.up)),this.teamTasksDragListeners.handle&&(this.teamTasksDragListeners.handle.removeEventListener("mousedown",this.teamTasksDragListeners.handleMouseDown),this.teamTasksDragListeners.handle.removeEventListener("touchstart",this.teamTasksDragListeners.handleTouchStart)),this.teamTasksDragListeners=null)},getTeammateColor(e){return this.teammateMap.get(e)?.color||"blue"},normalizeFilePath(e,t){if(!e)return"";let s=e.trim();const n="/home/"+(window.USER||"user");s.startsWith("~/")?s=n+s.slice(1):s==="~"&&(s=n),!s.startsWith("/")&&t&&(s=t+"/"+s);const o=s.split("/"),i=[];for(const r of o)r===""||r==="."||(r===".."?i.length>1&&i.pop():i.push(r));return"/"+i.join("/")},getFilename(e){const t=e.split("/");return t[t.length-1]||""},isShallowRootPath(e){return e.startsWith("/")?e.split("/").filter(s=>s!=="").length===1:!1},isPathInWorkingDir(e,t){if(!t)return!1;const s=this.normalizeFilePath(e,t);return s.startsWith(t+"/")||s===t},pathsAreEquivalent(e,t,s){const n=this.normalizeFilePath(e,s),o=this.normalizeFilePath(t,s);if(n===o)return!0;const i=this.getFilename(n),r=this.getFilename(o);if(i!==r)return!1;const a=this.isShallowRootPath(e),l=this.isShallowRootPath(t),d=this.isPathInWorkingDir(n,s),c=this.isPathInWorkingDir(o,s);return!!(a&&c||l&&d)},pickBetterPath(e,t,s){if(s){const i=this.isPathInWorkingDir(e,s),r=this.isPathInWorkingDir(t,s);if(i&&!r)return e;if(r&&!i)return t}const n=e.startsWith("/"),o=t.startsWith("/");return n&&!o?e:o&&!n?t:e.length!==t.length?e.length>t.length?e:t:!e.includes("~")&&t.includes("~")?e:!t.includes("~")&&e.includes("~")?t:e},deduplicateProjectInsightPaths(e,t){const s=[];for(const i of e)for(const r of i.filePaths)s.push({rawPath:r,toolId:i.id});if(s.length<=1){const i=new Map;for(const r of s)i.set(this.normalizeFilePath(r.rawPath,t),r);return i}s.sort((i,r)=>{const a=this.isPathInWorkingDir(i.rawPath,t),l=this.isPathInWorkingDir(r.rawPath,t);return a&&!l?-1:l&&!a?1:r.rawPath.length-i.rawPath.length});const n=new Map,o=new Set;for(const{rawPath:i,toolId:r}of s){const a=this.normalizeFilePath(i,t);let l=!1;for(const[,d]of n)if(this.pathsAreEquivalent(i,d.rawPath,t)){l=!0;break}!l&&!o.has(a)&&(n.set(a,{rawPath:i,toolId:r}),o.add(a))}return n},handleBashToolStart(e,t){let s=this.projectInsights.get(e)||[];s=s.filter(n=>n.id!==t.id),s.push(t),this.projectInsights.set(e,s),this.renderProjectInsightsPanel()},handleBashToolEnd(e,t){const n=(this.projectInsights.get(e)||[]).find(o=>o.id===t.id);n&&(n.status="completed"),this.renderProjectInsightsPanel(),setTimeout(()=>{const o=this.projectInsights.get(e)||[];this.projectInsights.set(e,o.filter(i=>i.id!==t.id)),this.renderProjectInsightsPanel()},2e3)},handleBashToolsUpdate(e,t){this.projectInsights.set(e,t),this.renderProjectInsightsPanel()},renderProjectInsightsPanel(){const e=this.$("projectInsightsPanel"),t=this.$("projectInsightsList");if(!e||!t)return;if(!(this.loadAppSettingsFromStorage().showProjectInsights??!1)){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}const i=(this.projectInsights.get(this.activeSessionId)||[]).filter(h=>h.status==="running");if(i.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const a=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,l=this.deduplicateProjectInsightPaths(i,a),d=new Set(Array.from(l.values()).map(h=>h.rawPath)),c=[];for(const h of i){const m=h.filePaths.filter(p=>d.has(p));if(m.length===0)continue;const u=h.command.length>50?h.command.substring(0,50)+"...":h.command;c.push(`
155
155
  <div class="project-insight-item" data-tool-id="${h.id}">
156
156
  <div class="project-insight-command">
157
157
  <span class="icon">\u{1F4BB}</span>
@@ -167,7 +167,7 @@
167
167
  `)}c.push(`
168
168
  </div>
169
169
  </div>
170
- `)}t.innerHTML=c.join("")},closeProjectInsightsPanel(){const e=this.$("projectInsightsPanel");e&&(e.classList.remove("visible"),this.projectInsightsPanelVisible=!1)},async loadFileBrowser(e){if(!e)return;const t=this.$("fileBrowserTree"),s=this.$("fileBrowserStatus");if(t){t.innerHTML='<div class="file-browser-loading">Loading files...</div>';try{const n=await fetch(`/api/sessions/${e}/files?depth=5&showHidden=false`);if(!n.ok)throw new Error("Failed to load files");const a=await n.json();if(!a.success)throw new Error(a.error||"Failed to load files");if(this.fileBrowserData=a.data,this.renderFileBrowserTree(),s){const{totalFiles:i,totalDirectories:r,truncated:o}=a.data;s.textContent=`${i} files, ${r} dirs${o?" (truncated)":""}`}}catch(n){console.error("Failed to load file browser:",n),t.innerHTML=`<div class="file-browser-empty">Failed to load files: ${escapeHtml(n.message)}</div>`}}},renderFileBrowserTree(){const e=this.$("fileBrowserTree");if(!e||!this.fileBrowserData)return;const{tree:t}=this.fileBrowserData;if(!t||t.length===0){e.innerHTML='<div class="file-browser-empty">No files found</div>';return}const s=[],n=this.fileBrowserFilter.toLowerCase(),a=(i,r)=>{const o=i.type==="directory",l=this.fileBrowserExpandedDirs.has(i.path),d=!n||i.name.toLowerCase().includes(n);let c=!1;o&&n&&i.children&&(c=this.hasMatchingChild(i,n));const m=!(d||c)&&n?" hidden-by-filter":"",u=o?l?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(i.extension),p=o?`<span class="file-tree-expand${l?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',v=!o&&i.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(i.size)}</span>`:"",y=o?"file-tree-name directory":"file-tree-name",f=o?"":`<a class="file-tree-download" href="/api/sessions/${this.activeSessionId}/file-raw?path=${encodeURIComponent(i.path)}&download=true" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;if(s.push(`
170
+ `)}t.innerHTML=c.join("")},closeProjectInsightsPanel(){const e=this.$("projectInsightsPanel");e&&(e.classList.remove("visible"),this.projectInsightsPanelVisible=!1)},async loadFileBrowser(e){if(!e)return;const t=this.$("fileBrowserTree"),s=this.$("fileBrowserStatus");if(t){t.innerHTML='<div class="file-browser-loading">Loading files...</div>';try{const n=await fetch(`/api/sessions/${e}/files?depth=5&showHidden=false`);if(!n.ok)throw new Error("Failed to load files");const o=await n.json();if(!o.success)throw new Error(o.error||"Failed to load files");if(this.fileBrowserData=o.data,this.renderFileBrowserTree(),s){const{totalFiles:i,totalDirectories:r,truncated:a}=o.data;s.textContent=`${i} files, ${r} dirs${a?" (truncated)":""}`}}catch(n){console.error("Failed to load file browser:",n),t.innerHTML=`<div class="file-browser-empty">Failed to load files: ${escapeHtml(n.message)}</div>`}}},renderFileBrowserTree(){const e=this.$("fileBrowserTree");if(!e||!this.fileBrowserData)return;const{tree:t}=this.fileBrowserData;if(!t||t.length===0){e.innerHTML='<div class="file-browser-empty">No files found</div>';return}const s=[],n=this.fileBrowserFilter.toLowerCase(),o=(i,r)=>{const a=i.type==="directory",l=this.fileBrowserExpandedDirs.has(i.path),d=!n||i.name.toLowerCase().includes(n);let c=!1;a&&n&&i.children&&(c=this.hasMatchingChild(i,n));const m=!(d||c)&&n?" hidden-by-filter":"",u=a?l?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(i.extension),p=a?`<span class="file-tree-expand${l?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',v=!a&&i.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(i.size)}</span>`:"",y=a?"file-tree-name directory":"file-tree-name",f=a?"":`<a class="file-tree-download" href="/api/sessions/${this.activeSessionId}/file-raw?path=${encodeURIComponent(i.path)}&download=true" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;if(s.push(`
171
171
  <div class="file-tree-item${m}" data-path="${escapeHtml(i.path)}" data-type="${i.type}" data-depth="${r}">
172
172
  ${p}
173
173
  <span class="file-tree-icon">${u}</span>
@@ -175,7 +175,7 @@
175
175
  ${v}
176
176
  ${f}
177
177
  </div>
178
- `),o&&l&&i.children)for(const b of i.children)a(b,r+1)};for(const i of t)a(i,0);e.innerHTML=s.join(""),e.querySelectorAll(".file-tree-item").forEach(i=>{i.addEventListener("click",()=>{const r=i.dataset.path;i.dataset.type==="directory"?this.toggleFileBrowserFolder(r):this.openFilePreview(r)})})},hasMatchingChild(e,t){if(!e.children)return!1;for(const s of e.children)if(s.name.toLowerCase().includes(t)||s.type==="directory"&&this.hasMatchingChild(s,t))return!0;return!1},toggleFileBrowserFolder(e){this.fileBrowserExpandedDirs.has(e)?this.fileBrowserExpandedDirs.delete(e):this.fileBrowserExpandedDirs.add(e),this.renderFileBrowserTree()},filterFileBrowser(e){this.fileBrowserFilter=e,e&&this.expandAllDirectories(this.fileBrowserData?.tree||[]),this.renderFileBrowserTree()},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){if(this.activeSessionId){this.fileBrowserExpandedDirs.clear(),this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1;const e=this.$("fileBrowserSearch");e&&(e.value=""),this.loadFileBrowser(this.activeSessionId)}},closeFileBrowserPanel(){const e=this.$("fileBrowserPanel");if(e&&(e.classList.remove("visible"),e.style.left="",e.style.top="",e.style.bottom="",e.style.right=""),this.fileBrowserDragListeners){const s=this.fileBrowserDragListeners;document.removeEventListener("mousemove",s.move),document.removeEventListener("mouseup",s.up),document.removeEventListener("touchmove",s.touchMove),document.removeEventListener("touchend",s.up),document.removeEventListener("touchcancel",s.up),s.handle&&(s.handle.removeEventListener("mousedown",s.handleMouseDown),s.handle.removeEventListener("touchstart",s.handleTouchStart),s._onFirstDrag&&(s.handle.removeEventListener("mousedown",s._onFirstDrag),s.handle.removeEventListener("touchstart",s._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t)},async openFilePreview(e,t=this.activeSessionId,s=null){if(!t||!e)return;const n=this.$("filePreviewOverlay"),a=this.$("filePreviewTitle"),i=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!n||!i)return;n.classList.add("visible"),a.textContent=e,i.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const o=(e.split(".").pop()||"").toLowerCase();if(s){const l=`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`,d=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]);if(r.textContent=o.toUpperCase(),d.has(o))i.innerHTML=`<img src="${escapeHtml(`${l}/raw`)}" alt="${escapeHtml(e)}">`;else if(o==="pdf")i.innerHTML=`<iframe src="${escapeHtml(`${l}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(o==="docx"||o==="pptx")i.innerHTML=`<iframe src="${escapeHtml(`${l}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else try{const c=await fetch(`${l}/raw`);if(!c.ok)throw new Error("Failed to load attachment");const h=await c.text();i.innerHTML=`<pre><code>${escapeHtml(h)}</code></pre>`}catch(c){i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(c.message)}</div>`}return}if(o==="docx"||o==="pptx"){r.textContent=o.toUpperCase();const l=`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`;i.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(o==="pdf"){r.textContent="PDF";const l=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`;i.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}try{const l=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!l.ok)throw new Error("Failed to load file");const d=await l.json();if(!d.success)throw new Error(d.error||"Failed to load file");const c=d.data;if(c.type==="image")i.innerHTML=`<img src="${c.url}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="video")i.innerHTML=`<video src="${c.url}" controls autoplay></video>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="binary")i.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(c.size)})<br>Cannot preview</div>`,r.textContent=c.extension||"binary";else{this.filePreviewContent=c.content,i.innerHTML=`<pre><code>${escapeHtml(c.content)}</code></pre>`;const h=c.truncated?` (showing 500/${c.totalLines} lines)`:"";r.textContent=`${c.totalLines} lines \u2022 ${this.formatFileSize(c.size)}${h}`}}catch(l){console.error("Failed to preview file:",l),i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}},closeFilePreview(){const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this.filePreviewContent=""},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`;window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:a,size:i,attachmentType:r,extension:o,attachmentId:l,rawUrl:d,previewUrl:c,thumbnailUrl:h}=e,m=s||n,u=l||`${t}-${a}-${n}`;if(this.attachmentCards.has(u)){this.attachmentCards.get(u).element.focus?.();return}if(this.attachmentCards.size>=10){const I=this.attachmentCards.keys().next().value;I&&this.closeAttachmentCard(I)}const v=this.ensureAttachmentCardStack(),f=this.sessions.get(t)?.name||t.substring(0,8),b=d||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(m)}`),T=c||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/preview`:null),g=h||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(m)}`),S=l?`${b}?download=true`:`${b}&download=true`,$=(o||r||"file").toUpperCase(),w=document.createElement("article");w.className=`attachment-card attachment-${escapeHtml(r||"file")}`,w.tabIndex=0,w.dataset.attachmentId=u,w.dataset.previewUrl=T||"",w.innerHTML=`
178
+ `),a&&l&&i.children)for(const b of i.children)o(b,r+1)};for(const i of t)o(i,0);e.innerHTML=s.join(""),e.querySelectorAll(".file-tree-item").forEach(i=>{i.addEventListener("click",()=>{const r=i.dataset.path;i.dataset.type==="directory"?this.toggleFileBrowserFolder(r):this.openFilePreview(r)})})},hasMatchingChild(e,t){if(!e.children)return!1;for(const s of e.children)if(s.name.toLowerCase().includes(t)||s.type==="directory"&&this.hasMatchingChild(s,t))return!0;return!1},toggleFileBrowserFolder(e){this.fileBrowserExpandedDirs.has(e)?this.fileBrowserExpandedDirs.delete(e):this.fileBrowserExpandedDirs.add(e),this.renderFileBrowserTree()},filterFileBrowser(e){this.fileBrowserFilter=e,e&&this.expandAllDirectories(this.fileBrowserData?.tree||[]),this.renderFileBrowserTree()},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){if(this.activeSessionId){this.fileBrowserExpandedDirs.clear(),this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1;const e=this.$("fileBrowserSearch");e&&(e.value=""),this.loadFileBrowser(this.activeSessionId)}},closeFileBrowserPanel(){const e=this.$("fileBrowserPanel");if(e&&(e.classList.remove("visible"),e.style.left="",e.style.top="",e.style.bottom="",e.style.right=""),this.fileBrowserDragListeners){const s=this.fileBrowserDragListeners;document.removeEventListener("mousemove",s.move),document.removeEventListener("mouseup",s.up),document.removeEventListener("touchmove",s.touchMove),document.removeEventListener("touchend",s.up),document.removeEventListener("touchcancel",s.up),s.handle&&(s.handle.removeEventListener("mousedown",s.handleMouseDown),s.handle.removeEventListener("touchstart",s.handleTouchStart),s._onFirstDrag&&(s.handle.removeEventListener("mousedown",s._onFirstDrag),s.handle.removeEventListener("touchstart",s._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t)},async openFilePreview(e,t=this.activeSessionId,s=null){if(!t||!e)return;const n=this.$("filePreviewOverlay"),o=this.$("filePreviewTitle"),i=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!n||!i)return;n.classList.add("visible"),o.textContent=e,i.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const a=(e.split(".").pop()||"").toLowerCase();if(s){const l=`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`,d=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]);if(r.textContent=a.toUpperCase(),d.has(a))i.innerHTML=`<img src="${escapeHtml(`${l}/raw`)}" alt="${escapeHtml(e)}">`;else if(a==="pdf")i.innerHTML=`<iframe src="${escapeHtml(`${l}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(a==="docx"||a==="pptx")i.innerHTML=`<iframe src="${escapeHtml(`${l}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else try{const c=await fetch(`${l}/raw`);if(!c.ok)throw new Error("Failed to load attachment");const h=await c.text();i.innerHTML=`<pre><code>${escapeHtml(h)}</code></pre>`}catch(c){i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(c.message)}</div>`}return}if(a==="docx"||a==="pptx"){r.textContent=a.toUpperCase();const l=`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`;i.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(a==="pdf"){r.textContent="PDF";const l=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`;i.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(a==="svg"){r.textContent="SVG";try{const l=await fetch(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);if(!l.ok)throw new Error("Failed to load image");const d=URL.createObjectURL(new Blob([await l.text()],{type:"image/svg+xml"}));i.innerHTML=`<img src="${d}" alt="${escapeHtml(e)}">`;const c=i.querySelector("img");c&&(c.onload=()=>URL.revokeObjectURL(d))}catch(l){i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}return}try{const l=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!l.ok)throw new Error("Failed to load file");const d=await l.json();if(!d.success)throw new Error(d.error||"Failed to load file");const c=d.data;if(c.type==="image")i.innerHTML=`<img src="${c.url}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="video")i.innerHTML=`<video src="${c.url}" controls autoplay></video>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="audio")i.innerHTML=`<audio src="${c.url}" controls autoplay></audio>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="binary"){const h=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}&download=true`;i.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(c.size)})<br>Cannot preview<br><a href="${escapeHtml(h)}" download>Download</a></div>`,r.textContent=c.extension||"binary"}else{this.filePreviewContent=c.content,i.innerHTML=`<pre><code>${escapeHtml(c.content)}</code></pre>`;const h=c.truncated?` (showing 500/${c.totalLines} lines)`:"";r.textContent=`${c.totalLines} lines \u2022 ${this.formatFileSize(c.size)}${h}`}}catch(l){console.error("Failed to preview file:",l),i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}},closeFilePreview(){const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this.filePreviewContent=""},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`;window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:o,size:i,attachmentType:r,extension:a,attachmentId:l,rawUrl:d,previewUrl:c,thumbnailUrl:h}=e,m=s||n,u=l||`${t}-${o}-${n}`;if(this.attachmentCards.has(u)){this.attachmentCards.get(u).element.focus?.();return}if(this.attachmentCards.size>=10){const I=this.attachmentCards.keys().next().value;I&&this.closeAttachmentCard(I)}const v=this.ensureAttachmentCardStack(),f=this.sessions.get(t)?.name||t.substring(0,8),b=d||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(m)}`),T=c||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/preview`:null),g=h||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(m)}`),S=l?`${b}?download=true`:`${b}&download=true`,$=(a||r||"file").toUpperCase(),w=document.createElement("article");w.className=`attachment-card attachment-${escapeHtml(r||"file")}`,w.tabIndex=0,w.dataset.attachmentId=u,w.dataset.previewUrl=T||"",w.innerHTML=`
179
179
  <div class="attachment-thumbnail">
180
180
  ${g?`<img class="attachment-thumbnail-img" src="${escapeHtml(g)}" alt="">`:""}
181
181
  <div class="attachment-thumbnail-fallback ${g?"":"visible"}">${escapeHtml($)}</div>
@@ -193,7 +193,7 @@
193
193
  </div>
194
194
  </div>
195
195
  <button type="button" class="attachment-close-btn" title="Dismiss">&times;</button>
196
- `;const C=w.querySelector(".attachment-thumbnail-img");C&&(C.onerror=()=>{C.remove(),w.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),w.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(m,t,l||null)}),w.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,m,l||null)}),w.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(u)}),v.prepend(w),this.attachmentCards.set(u,{element:w,sessionId:t,filePath:m}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,n]of this.attachmentCards)n.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),n=this.activeSessionId,a=e??(n&&this.attachmentHistoryCounts.get(n)||0);t&&(t.textContent=a>99?"99+":String(a),t.style.display=a>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
196
+ `;const C=w.querySelector(".attachment-thumbnail-img");C&&(C.onerror=()=>{C.remove(),w.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),w.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(m,t,l||null)}),w.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,m,l||null)}),w.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(u)}),v.prepend(w),this.attachmentCards.set(u,{element:w,sessionId:t,filePath:m}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,n]of this.attachmentCards)n.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),n=this.activeSessionId,o=e??(n&&this.attachmentHistoryCounts.get(n)||0);t&&(t.textContent=o>99?"99+":String(o),t.style.display=o>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
197
197
  <div class="attachment-history-header">
198
198
  <div>
199
199
  <div class="attachment-history-title">Attachments</div>
@@ -205,14 +205,14 @@
205
205
  </div>
206
206
  </div>
207
207
  <div class="attachment-history-list" id="attachmentHistoryList"></div>
208
- `,document.body.appendChild(e),e.querySelector("#attachmentHistoryRefreshBtn")?.addEventListener("click",()=>{this.loadAttachmentHistory(this.activeSessionId)}),e.querySelector("#attachmentHistoryCloseBtn")?.addEventListener("click",()=>{this.closeAttachmentHistory()}),e)},async toggleAttachmentHistory(){if(this.attachmentHistoryDrawerOpen){this.closeAttachmentHistory();return}await this.openAttachmentHistory()},async openAttachmentHistory(){const e=this.ensureAttachmentHistoryDrawer();this.attachmentHistoryDrawerOpen=!0,e.classList.add("open"),this.updateAttachmentHistoryBadge(),await this.loadAttachmentHistory(this.activeSessionId)},closeAttachmentHistory(){const e=document.getElementById("attachmentHistoryDrawer");this.attachmentHistoryDrawerOpen=!1,e?.classList.remove("open"),this._debounceTimers?.attachmentHistoryRefresh&&(clearTimeout(this._debounceTimers.attachmentHistoryRefresh),this._debounceTimers.attachmentHistoryRefresh=null),this.updateAttachmentHistoryBadge()},async loadAttachmentHistory(e=this.activeSessionId){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(!e){this.attachmentHistoryItems=[],n.textContent="No session",s.innerHTML='<div class="attachment-history-empty">No active session</div>',this.updateAttachmentHistoryBadge(0);return}s.innerHTML='<div class="attachment-history-empty">Loading...</div>';try{const a=await fetch(`/api/sessions/${e}/attachments`);if(!a.ok)throw new Error("Failed to load attachments");const i=await a.json();if(!i.success)throw new Error(i.error||"Failed to load attachments");const r=i.data?.items||[];this.attachmentHistoryItems=r,this.attachmentHistoryCounts.set(e,r.length),this.updateAttachmentHistoryBadge(r.length),this.renderAttachmentHistory(r)}catch(a){console.error("Failed to load attachment history:",a),n.textContent="Unavailable",s.innerHTML=`<div class="attachment-history-empty">Error: ${escapeHtml(a.message)}</div>`}}},renderAttachmentHistory(e=this.attachmentHistoryItems||[]){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(n.textContent=`${e.length} ${e.length===1?"file":"files"}`,e.length===0){s.innerHTML=`
208
+ `,document.body.appendChild(e),e.querySelector("#attachmentHistoryRefreshBtn")?.addEventListener("click",()=>{this.loadAttachmentHistory(this.activeSessionId)}),e.querySelector("#attachmentHistoryCloseBtn")?.addEventListener("click",()=>{this.closeAttachmentHistory()}),e)},async toggleAttachmentHistory(){if(this.attachmentHistoryDrawerOpen){this.closeAttachmentHistory();return}await this.openAttachmentHistory()},async openAttachmentHistory(){const e=this.ensureAttachmentHistoryDrawer();this.attachmentHistoryDrawerOpen=!0,e.classList.add("open"),this.updateAttachmentHistoryBadge(),await this.loadAttachmentHistory(this.activeSessionId)},closeAttachmentHistory(){const e=document.getElementById("attachmentHistoryDrawer");this.attachmentHistoryDrawerOpen=!1,e?.classList.remove("open"),this._debounceTimers?.attachmentHistoryRefresh&&(clearTimeout(this._debounceTimers.attachmentHistoryRefresh),this._debounceTimers.attachmentHistoryRefresh=null),this.updateAttachmentHistoryBadge()},async loadAttachmentHistory(e=this.activeSessionId){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(!e){this.attachmentHistoryItems=[],n.textContent="No session",s.innerHTML='<div class="attachment-history-empty">No active session</div>',this.updateAttachmentHistoryBadge(0);return}s.innerHTML='<div class="attachment-history-empty">Loading...</div>';try{const o=await fetch(`/api/sessions/${e}/attachments`);if(!o.ok)throw new Error("Failed to load attachments");const i=await o.json();if(!i.success)throw new Error(i.error||"Failed to load attachments");const r=i.data?.items||[];this.attachmentHistoryItems=r,this.attachmentHistoryCounts.set(e,r.length),this.updateAttachmentHistoryBadge(r.length),this.renderAttachmentHistory(r)}catch(o){console.error("Failed to load attachment history:",o),n.textContent="Unavailable",s.innerHTML=`<div class="attachment-history-empty">Error: ${escapeHtml(o.message)}</div>`}}},renderAttachmentHistory(e=this.attachmentHistoryItems||[]){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(n.textContent=`${e.length} ${e.length===1?"file":"files"}`,e.length===0){s.innerHTML=`
209
209
  <div class="attachment-history-empty">
210
210
  <div class="attachment-history-empty-title">No attachments yet</div>
211
211
  <div>Show a file here by running:</div>
212
212
  <code>codeman attach /absolute/path/to/file.pptx</code>
213
213
  <div>Supports .pptx, .docx, .pdf, .png, .md, and .txt.</div>
214
214
  </div>
215
- `;return}s.innerHTML=e.map(a=>this.renderAttachmentHistoryItem(a)).join(""),s.querySelectorAll(".attachment-history-thumb-img").forEach(a=>{a.onerror=()=>{a.remove(),a.closest(".attachment-history-thumb")?.querySelector(".attachment-history-thumb-fallback")?.classList.add("visible")}}),s.querySelectorAll("[data-attachment-action]").forEach(a=>{a.addEventListener("click",()=>{const i=a.getAttribute("data-history-id"),r=a.getAttribute("data-attachment-action");!i||!r||(r==="preview"&&this.previewAttachmentHistoryItem(i),r==="download"&&this.downloadAttachmentHistoryItem(i),r==="open"&&this.openAttachmentHistoryItem(i),r==="reshow"&&this.reshowAttachmentCard(i))})})}},renderAttachmentHistoryItem(e){const t=(e.extension||e.attachmentType||"file").toUpperCase(),s=[e.source==="external"?"published":"workspace",this.formatFileSize(e.size||0),e.missing?"missing":""].filter(Boolean).join(" \u2022 "),n=e.thumbnailUrl&&!e.missing?`<img class="attachment-history-thumb-img" src="${escapeHtml(e.thumbnailUrl)}" alt="">`:"",a=e.missing?'disabled aria-disabled="true"':"";return`
215
+ `;return}s.innerHTML=e.map(o=>this.renderAttachmentHistoryItem(o)).join(""),s.querySelectorAll(".attachment-history-thumb-img").forEach(o=>{o.onerror=()=>{o.remove(),o.closest(".attachment-history-thumb")?.querySelector(".attachment-history-thumb-fallback")?.classList.add("visible")}}),s.querySelectorAll("[data-attachment-action]").forEach(o=>{o.addEventListener("click",()=>{const i=o.getAttribute("data-history-id"),r=o.getAttribute("data-attachment-action");!i||!r||(r==="preview"&&this.previewAttachmentHistoryItem(i),r==="download"&&this.downloadAttachmentHistoryItem(i),r==="open"&&this.openAttachmentHistoryItem(i),r==="reshow"&&this.reshowAttachmentCard(i))})})}},renderAttachmentHistoryItem(e){const t=(e.extension||e.attachmentType||"file").toUpperCase(),s=[e.source==="external"?"published":"workspace",this.formatFileSize(e.size||0),e.missing?"missing":""].filter(Boolean).join(" \u2022 "),n=e.thumbnailUrl&&!e.missing?`<img class="attachment-history-thumb-img" src="${escapeHtml(e.thumbnailUrl)}" alt="">`:"",o=e.missing?'disabled aria-disabled="true"':"";return`
216
216
  <div class="attachment-history-item ${e.missing?"missing":""}" data-history-item="${escapeHtml(e.id)}">
217
217
  <div class="attachment-history-thumb">
218
218
  ${n}
@@ -222,14 +222,14 @@
222
222
  <div class="attachment-history-file-name" title="${escapeHtml(e.fileName)}">${escapeHtml(e.fileName)}</div>
223
223
  <div class="attachment-history-meta">${escapeHtml(s)}</div>
224
224
  <div class="attachment-history-actions">
225
- <button type="button" data-attachment-action="preview" data-history-id="${escapeHtml(e.id)}" ${a}>Preview</button>
226
- <button type="button" data-attachment-action="download" data-history-id="${escapeHtml(e.id)}" ${a}>Download</button>
227
- <button type="button" data-attachment-action="open" data-history-id="${escapeHtml(e.id)}" ${a}>Open</button>
228
- <button type="button" data-attachment-action="reshow" data-history-id="${escapeHtml(e.id)}" ${a}>Card</button>
225
+ <button type="button" data-attachment-action="preview" data-history-id="${escapeHtml(e.id)}" ${o}>Preview</button>
226
+ <button type="button" data-attachment-action="download" data-history-id="${escapeHtml(e.id)}" ${o}>Download</button>
227
+ <button type="button" data-attachment-action="open" data-history-id="${escapeHtml(e.id)}" ${o}>Open</button>
228
+ <button type="button" data-attachment-action="reshow" data-history-id="${escapeHtml(e.id)}" ${o}>Card</button>
229
229
  </div>
230
230
  </div>
231
231
  </div>
232
- `},getAttachmentHistoryItem(e){return(this.attachmentHistoryItems||[]).find(t=>t.id===e)||null},previewAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!t||t.missing)return;const s=t.relativePath||t.fileName;this.openFilePreview(s,t.sessionId,t.attachmentId||null),this.closeAttachmentHistory()},openAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!(!t||t.missing)){if(t.rawUrl||t.url){window.open(t.rawUrl||t.url,"_blank");return}this.openAttachmentInNewTab(t.sessionId,t.relativePath||t.fileName,t.attachmentId||null)}},downloadAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||!t.downloadUrl||window.open(t.downloadUrl,"_blank")},reshowAttachmentCard(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||this.addAttachmentCard({sessionId:t.sessionId,relativePath:t.relativePath,fileName:t.fileName,timestamp:t.timestamp??Date.now(),size:t.size,attachmentType:t.attachmentType,extension:t.extension,attachmentId:t.attachmentId,rawUrl:t.rawUrl,previewUrl:t.previewUrl,thumbnailUrl:t.thumbnailUrl})},copyFilePreviewContent(){this.filePreviewContent&&navigator.clipboard.writeText(this.filePreviewContent).then(()=>{this.showToast("Copied to clipboard","success")}).catch(()=>{this.showToast("Failed to copy","error")})},getFileIcon(e){return e&&{ts:"\u{1F4D8}",tsx:"\u{1F4D8}",js:"\u{1F4D2}",jsx:"\u{1F4D2}",mjs:"\u{1F4D2}",cjs:"\u{1F4D2}",py:"\u{1F40D}",pyx:"\u{1F40D}",pyw:"\u{1F40D}",rs:"\u{1F980}",go:"\u{1F439}",c:"\u2699\uFE0F",cpp:"\u2699\uFE0F",h:"\u2699\uFE0F",hpp:"\u2699\uFE0F",html:"\u{1F310}",htm:"\u{1F310}",css:"\u{1F3A8}",scss:"\u{1F3A8}",sass:"\u{1F3A8}",less:"\u{1F3A8}",json:"\u{1F4CB}",yaml:"\u{1F4CB}",yml:"\u{1F4CB}",xml:"\u{1F4CB}",toml:"\u{1F4CB}",csv:"\u{1F4CB}",md:"\u{1F4DD}",markdown:"\u{1F4DD}",txt:"\u{1F4DD}",rst:"\u{1F4DD}",png:"\u{1F5BC}\uFE0F",jpg:"\u{1F5BC}\uFE0F",jpeg:"\u{1F5BC}\uFE0F",gif:"\u{1F5BC}\uFE0F",svg:"\u{1F5BC}\uFE0F",webp:"\u{1F5BC}\uFE0F",ico:"\u{1F5BC}\uFE0F",bmp:"\u{1F5BC}\uFE0F",mp4:"\u{1F3AC}",webm:"\u{1F3AC}",mov:"\u{1F3AC}",mp3:"\u{1F3B5}",wav:"\u{1F3B5}",ogg:"\u{1F3B5}",sh:"\u{1F4BB}",bash:"\u{1F4BB}",zsh:"\u{1F4BB}",env:"\u{1F510}",gitignore:"\u{1F6AB}",dockerfile:"\u{1F433}",lock:"\u{1F512}"}[e.toLowerCase()]||"\u{1F4C4}"},formatFileSize(e){return e==null?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`},openLogViewerWindow(e,t){if(t=t||this.activeSessionId,!t)return;const s=`${t}-${e.replace(/[^a-zA-Z0-9]/g,"_")}`;if(this.logViewerWindows.has(s)){const c=this.logViewerWindows.get(s);c.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,a=100+n%5*30,i=100+n%5*30,r=e.split("/").pop(),o=document.createElement("div");o.className="log-viewer-window",o.id=`log-viewer-window-${s}`,o.style.left=`${a}px`,o.style.top=`${i}px`,o.style.zIndex=++this.logViewerWindowZIndex,o.innerHTML=`
232
+ `},getAttachmentHistoryItem(e){return(this.attachmentHistoryItems||[]).find(t=>t.id===e)||null},previewAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!t||t.missing)return;const s=t.relativePath||t.fileName;this.openFilePreview(s,t.sessionId,t.attachmentId||null),this.closeAttachmentHistory()},openAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!(!t||t.missing)){if(t.rawUrl||t.url){window.open(t.rawUrl||t.url,"_blank");return}this.openAttachmentInNewTab(t.sessionId,t.relativePath||t.fileName,t.attachmentId||null)}},downloadAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||!t.downloadUrl||window.open(t.downloadUrl,"_blank")},reshowAttachmentCard(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||this.addAttachmentCard({sessionId:t.sessionId,relativePath:t.relativePath,fileName:t.fileName,timestamp:t.timestamp??Date.now(),size:t.size,attachmentType:t.attachmentType,extension:t.extension,attachmentId:t.attachmentId,rawUrl:t.rawUrl,previewUrl:t.previewUrl,thumbnailUrl:t.thumbnailUrl})},copyFilePreviewContent(){this.filePreviewContent&&navigator.clipboard.writeText(this.filePreviewContent).then(()=>{this.showToast("Copied to clipboard","success")}).catch(()=>{this.showToast("Failed to copy","error")})},getFileIcon(e){return e&&{ts:"\u{1F4D8}",tsx:"\u{1F4D8}",js:"\u{1F4D2}",jsx:"\u{1F4D2}",mjs:"\u{1F4D2}",cjs:"\u{1F4D2}",py:"\u{1F40D}",pyx:"\u{1F40D}",pyw:"\u{1F40D}",rs:"\u{1F980}",go:"\u{1F439}",c:"\u2699\uFE0F",cpp:"\u2699\uFE0F",h:"\u2699\uFE0F",hpp:"\u2699\uFE0F",html:"\u{1F310}",htm:"\u{1F310}",css:"\u{1F3A8}",scss:"\u{1F3A8}",sass:"\u{1F3A8}",less:"\u{1F3A8}",json:"\u{1F4CB}",yaml:"\u{1F4CB}",yml:"\u{1F4CB}",xml:"\u{1F4CB}",toml:"\u{1F4CB}",csv:"\u{1F4CB}",md:"\u{1F4DD}",markdown:"\u{1F4DD}",txt:"\u{1F4DD}",rst:"\u{1F4DD}",png:"\u{1F5BC}\uFE0F",jpg:"\u{1F5BC}\uFE0F",jpeg:"\u{1F5BC}\uFE0F",gif:"\u{1F5BC}\uFE0F",svg:"\u{1F5BC}\uFE0F",webp:"\u{1F5BC}\uFE0F",ico:"\u{1F5BC}\uFE0F",bmp:"\u{1F5BC}\uFE0F",mp4:"\u{1F3AC}",webm:"\u{1F3AC}",mov:"\u{1F3AC}",mp3:"\u{1F3B5}",wav:"\u{1F3B5}",ogg:"\u{1F3B5}",sh:"\u{1F4BB}",bash:"\u{1F4BB}",zsh:"\u{1F4BB}",env:"\u{1F510}",gitignore:"\u{1F6AB}",dockerfile:"\u{1F433}",lock:"\u{1F512}"}[e.toLowerCase()]||"\u{1F4C4}"},formatFileSize(e){return e==null?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`},openLogViewerWindow(e,t){if(t=t||this.activeSessionId,!t)return;const s=`${t}-${e.replace(/[^a-zA-Z0-9]/g,"_")}`;if(this.logViewerWindows.has(s)){const c=this.logViewerWindows.get(s);c.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,o=100+n%5*30,i=100+n%5*30,r=e.split("/").pop(),a=document.createElement("div");a.className="log-viewer-window",a.id=`log-viewer-window-${s}`,a.style.left=`${o}px`,a.style.top=`${i}px`,a.style.zIndex=++this.logViewerWindowZIndex,a.innerHTML=`
233
233
  <div class="log-viewer-window-header">
234
234
  <div class="log-viewer-window-title" title="${escapeHtml(e)}">
235
235
  <span class="icon">\u{1F4C4}</span>
@@ -243,27 +243,27 @@
243
243
  <div class="log-viewer-window-body" id="log-viewer-body-${s}">
244
244
  <div class="log-info">Connecting to ${escapeHtml(e)}...</div>
245
245
  </div>
246
- `,document.body.appendChild(o);const l=this.makeWindowDraggable(o,o.querySelector(".log-viewer-window-header")),d=new EventSource(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`);d.onmessage=c=>{const h=JSON.parse(c.data),m=document.getElementById(`log-viewer-body-${s}`);if(m)switch(h.type){case"connected":m.innerHTML="";break;case"data":const u=m.scrollTop+m.clientHeight>=m.scrollHeight-10,p=escapeHtml(h.content);m.innerHTML+=p,u&&(m.scrollTop=m.scrollHeight),m.innerHTML.length>5e5&&(m.innerHTML=m.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":m.innerHTML+=`<div class="log-error">${escapeHtml(h.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},d.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:o,eventSource:d,filePath:e,sessionId:t,dragListeners:l})},updateLogViewerStatus(e,t,s){const n=document.querySelector(`#log-viewer-window-${e} .status`);n&&(n.className=`status ${t}`,n.textContent=s)},closeLogViewerWindow(e){const t=this.logViewerWindows.get(e);t&&(t.eventSource&&t.eventSource.close(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.logViewerWindows.delete(e))},closeSessionLogViewerWindows(e){const t=[];for(const[s,n]of this.logViewerWindows)n.sessionId===e&&t.push(s);for(const s of t)this.closeLogViewerWindow(s)},openImagePopup(e){const{sessionId:t,filePath:s,relativePath:n,fileName:a,timestamp:i,size:r}=e,o=`${t}-${i}`;if(this.imagePopups.has(o)){const g=this.imagePopups.get(o);g.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const g=this.imagePopups.keys().next().value;g&&this.closeImagePopup(g)}const d=this.imagePopups.size,c=(window.innerWidth-600)/2,h=(window.innerHeight-500)/2,m=c+d%5*30,u=h+d%5*30,v=this.sessions.get(t)?.name||t.substring(0,8),y=(r/1024).toFixed(1),f=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||a)}`,b=document.createElement("div");b.className="image-popup-window",b.id=`image-popup-${o}`,b.style.left=`${m}px`,b.style.top=`${u}px`,b.style.zIndex=++this.imagePopupZIndex,b.innerHTML=`
246
+ `,document.body.appendChild(a);const l=this.makeWindowDraggable(a,a.querySelector(".log-viewer-window-header")),d=new EventSource(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`);d.onmessage=c=>{const h=JSON.parse(c.data),m=document.getElementById(`log-viewer-body-${s}`);if(m)switch(h.type){case"connected":m.innerHTML="";break;case"data":const u=m.scrollTop+m.clientHeight>=m.scrollHeight-10,p=escapeHtml(h.content);m.innerHTML+=p,u&&(m.scrollTop=m.scrollHeight),m.innerHTML.length>5e5&&(m.innerHTML=m.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":m.innerHTML+=`<div class="log-error">${escapeHtml(h.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},d.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:a,eventSource:d,filePath:e,sessionId:t,dragListeners:l})},updateLogViewerStatus(e,t,s){const n=document.querySelector(`#log-viewer-window-${e} .status`);n&&(n.className=`status ${t}`,n.textContent=s)},closeLogViewerWindow(e){const t=this.logViewerWindows.get(e);t&&(t.eventSource&&t.eventSource.close(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.logViewerWindows.delete(e))},closeSessionLogViewerWindows(e){const t=[];for(const[s,n]of this.logViewerWindows)n.sessionId===e&&t.push(s);for(const s of t)this.closeLogViewerWindow(s)},openImagePopup(e){const{sessionId:t,filePath:s,relativePath:n,fileName:o,timestamp:i,size:r}=e,a=`${t}-${i}`;if(this.imagePopups.has(a)){const g=this.imagePopups.get(a);g.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const g=this.imagePopups.keys().next().value;g&&this.closeImagePopup(g)}const d=this.imagePopups.size,c=(window.innerWidth-600)/2,h=(window.innerHeight-500)/2,m=c+d%5*30,u=h+d%5*30,v=this.sessions.get(t)?.name||t.substring(0,8),y=(r/1024).toFixed(1),f=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||o)}`,b=document.createElement("div");b.className="image-popup-window",b.id=`image-popup-${a}`,b.style.left=`${m}px`,b.style.top=`${u}px`,b.style.zIndex=++this.imagePopupZIndex,b.innerHTML=`
247
247
  <div class="image-popup-header">
248
248
  <div class="image-popup-title" title="${escapeHtml(s)}">
249
249
  <span class="icon">\u{1F5BC}\uFE0F</span>
250
- <span class="filename">${escapeHtml(a)}</span>
250
+ <span class="filename">${escapeHtml(o)}</span>
251
251
  <span class="session-badge">${escapeHtml(v)}</span>
252
252
  <span class="size-badge">${y} KB</span>
253
253
  </div>
254
254
  <div class="image-popup-actions">
255
255
  <button onclick="app.openImageInNewTab('${escapeHtml(f)}')" title="Open in new tab">\u2197</button>
256
- <button onclick="app.closeImagePopup('${escapeHtml(o)}')" title="Close">\xD7</button>
256
+ <button onclick="app.closeImagePopup('${escapeHtml(a)}')" title="Close">\xD7</button>
257
257
  </div>
258
258
  </div>
259
259
  <div class="image-popup-body">
260
- <img src="${f}" alt="${escapeHtml(a)}"
260
+ <img src="${f}" alt="${escapeHtml(o)}"
261
261
  onerror="this.parentElement.innerHTML='<div class=\\'image-error\\'>Failed to load image</div>'"
262
262
  onclick="app.openImageInNewTab('${escapeHtml(f)}')" />
263
263
  </div>
264
- `,document.body.appendChild(b);const T=this.makeWindowDraggable(b,b.querySelector(".image-popup-header"));b.addEventListener("mousedown",()=>{b.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(o,{element:b,sessionId:t,filePath:s,dragListeners:T})},closeImagePopup(e){const t=this.imagePopups.get(e);t&&(t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.imagePopups.delete(e))},openImageInNewTab(e){window.open(e,"_blank")},closeSessionImagePopups(e){const t=[];for(const[s,n]of this.imagePopups)n.sessionId===e&&t.push(s);for(const s of t)this.closeImagePopup(s)},async loadMuxSessions(){try{const t=await(await fetch("/api/mux-sessions")).json();this.muxSessions=t.data?.sessions||[],this.renderMuxSessions()}catch(e){console.error("Failed to load mux sessions:",e)}},killAllMuxSessions(){const e=this.muxSessions?.length||0;if(e===0){alert("No sessions to kill");return}document.getElementById("killAllCount").textContent=e;const t=document.getElementById("killAllModal");t.classList.add("active"),this.activeFocusTrap=new FocusTrap(t),this.activeFocusTrap.activate()},closeKillAllModal(){document.getElementById("killAllModal").classList.remove("active"),this.activeFocusTrap&&(this.activeFocusTrap.deactivate(),this.activeFocusTrap=null)},async confirmKillAll(e){this.closeKillAllModal();try{if(e){if((await(await fetch("/api/sessions",{method:"DELETE"})).json()).success){this.sessions.clear(),this.muxSessions=[],this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.renderMuxSessions(),this.terminal.clear(),this.terminal.reset(),this.toast("All sessions and tmux killed","success")}}else{this.sessions.clear(),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.terminal.clear(),this.terminal.reset(),this.toast("All tabs removed, tmux still running","info")}}catch(t){console.error("Failed to kill sessions:",t),this.toast("Failed to kill sessions: "+t.message,"error")}},renderMuxSessions(){this._debouncedCall("muxSessions",this._renderMuxSessionsImmediate)},_renderMuxSessionsImmediate(){const e=document.getElementById("muxSessionsBody");if(!this.muxSessions||this.muxSessions.length===0){e.innerHTML='<div class="monitor-empty">No mux sessions</div>';return}let t="";for(const s of this.muxSessions){const n=s.stats||{memoryMB:0,cpuPercent:0,childCount:0},a=this.sessions.get(s.sessionId),i=a?a.status:"unknown",r=a?a.isWorking:!1;let o,l;i==="idle"&&!r?(o="IDLE",l="status-idle"):i==="busy"||r?(o="WORKING",l="status-working"):i==="stopped"?(o="STOPPED",l="status-stopped"):(o=i.toUpperCase(),l="");const d=a&&a.tokens?a.tokens:null,c=a?a.totalCost:0,h=a&&a.cliModel||"",m=h.includes("opus")?"opus":h.includes("sonnet")?"sonnet":h.includes("haiku")?"haiku":"",u=a?a.ralphTodoStats:null;let p="";if(u&&u.total>0){const T=Math.round(u.completed/u.total*100);p=`<span class="process-stat todo-progress">${u.completed}/${u.total} (${T}%)</span>`}let v="";d&&d.total>0&&(v=`<span class="process-stat tokens">${(d.total/1e3).toFixed(1)}k tok</span>`);let y="";c>0&&(y=`<span class="process-stat cost">$${c.toFixed(2)}</span>`);let f="";m&&(f=`<span class="monitor-model-badge ${m}">${m}</span>`);const b=escapeHtml(s.sessionId);t+=`
264
+ `,document.body.appendChild(b);const T=this.makeWindowDraggable(b,b.querySelector(".image-popup-header"));b.addEventListener("mousedown",()=>{b.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(a,{element:b,sessionId:t,filePath:s,dragListeners:T})},closeImagePopup(e){const t=this.imagePopups.get(e);t&&(t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.imagePopups.delete(e))},openImageInNewTab(e){window.open(e,"_blank")},closeSessionImagePopups(e){const t=[];for(const[s,n]of this.imagePopups)n.sessionId===e&&t.push(s);for(const s of t)this.closeImagePopup(s)},async loadMuxSessions(){try{const t=await(await fetch("/api/mux-sessions")).json();this.muxSessions=t.data?.sessions||[],this.renderMuxSessions()}catch(e){console.error("Failed to load mux sessions:",e)}},killAllMuxSessions(){const e=this.muxSessions?.length||0;if(e===0){alert("No sessions to kill");return}document.getElementById("killAllCount").textContent=e;const t=document.getElementById("killAllModal");t.classList.add("active"),this.activeFocusTrap=new FocusTrap(t),this.activeFocusTrap.activate()},closeKillAllModal(){document.getElementById("killAllModal").classList.remove("active"),this.activeFocusTrap&&(this.activeFocusTrap.deactivate(),this.activeFocusTrap=null)},async confirmKillAll(e){this.closeKillAllModal();try{if(e){if((await(await fetch("/api/sessions",{method:"DELETE"})).json()).success){this.sessions.clear(),this.muxSessions=[],this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.renderMuxSessions(),this.terminal.clear(),this.terminal.reset(),this.toast("All sessions and tmux killed","success")}}else{this.sessions.clear(),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.terminal.clear(),this.terminal.reset(),this.toast("All tabs removed, tmux still running","info")}}catch(t){console.error("Failed to kill sessions:",t),this.toast("Failed to kill sessions: "+t.message,"error")}},renderMuxSessions(){this._debouncedCall("muxSessions",this._renderMuxSessionsImmediate)},_renderMuxSessionsImmediate(){const e=document.getElementById("muxSessionsBody");if(!this.muxSessions||this.muxSessions.length===0){e.innerHTML='<div class="monitor-empty">No mux sessions</div>';return}let t="";for(const s of this.muxSessions){const n=s.stats||{memoryMB:0,cpuPercent:0,childCount:0},o=this.sessions.get(s.sessionId),i=o?o.status:"unknown",r=o?o.isWorking:!1;let a,l;i==="idle"&&!r?(a="IDLE",l="status-idle"):i==="busy"||r?(a="WORKING",l="status-working"):i==="stopped"?(a="STOPPED",l="status-stopped"):(a=i.toUpperCase(),l="");const d=o&&o.tokens?o.tokens:null,c=o?o.totalCost:0,h=o&&o.cliModel||"",m=h.includes("opus")?"opus":h.includes("sonnet")?"sonnet":h.includes("haiku")?"haiku":"",u=o?o.ralphTodoStats:null;let p="";if(u&&u.total>0){const T=Math.round(u.completed/u.total*100);p=`<span class="process-stat todo-progress">${u.completed}/${u.total} (${T}%)</span>`}let v="";d&&d.total>0&&(v=`<span class="process-stat tokens">${(d.total/1e3).toFixed(1)}k tok</span>`);let y="";c>0&&(y=`<span class="process-stat cost">$${c.toFixed(2)}</span>`);let f="";m&&(f=`<span class="monitor-model-badge ${m}">${m}</span>`);const b=escapeHtml(s.sessionId);t+=`
265
265
  <div class="process-item process-item-clickable" onclick="app.selectSession('${b}')" title="Switch to session">
266
- <span class="monitor-status-badge ${l}">${o}</span>
266
+ <span class="monitor-status-badge ${l}">${a}</span>
267
267
  <div class="process-info">
268
268
  <div class="process-name">${f} ${escapeHtml(s.name||s.muxName)}</div>
269
269
  <div class="process-meta">
@@ -278,11 +278,11 @@
278
278
  <button class="btn-toolbar btn-sm btn-danger" onclick="event.stopPropagation(); app.killMuxSession('${b}')" title="Kill session">Kill</button>
279
279
  </div>
280
280
  </div>
281
- `}e.innerHTML=t},renderMonitorSubagents(){const e=document.getElementById("monitorSubagentsBody"),t=document.getElementById("monitorSubagentStats");if(!e)return;const s=Array.from(this.subagents.values()),n=s.filter(i=>i.status==="active"||i.status==="idle").length;if(t&&(t.textContent=`${s.length} tracked`+(n>0?`, ${n} active`:"")),s.length===0){e.innerHTML='<div class="monitor-empty">No background agents</div>';return}let a="";for(const i of s){const r=i.status==="active"?"active":i.status==="idle"?"idle":"completed",o=i.modelShort?`<span class="model-badge ${i.modelShort}">${i.modelShort}</span>`:"",l=i.description?escapeHtml(i.description.substring(0,40)):i.agentId;a+=`
281
+ `}e.innerHTML=t},renderMonitorSubagents(){const e=document.getElementById("monitorSubagentsBody"),t=document.getElementById("monitorSubagentStats");if(!e)return;const s=Array.from(this.subagents.values()),n=s.filter(i=>i.status==="active"||i.status==="idle").length;if(t&&(t.textContent=`${s.length} tracked`+(n>0?`, ${n} active`:"")),s.length===0){e.innerHTML='<div class="monitor-empty">No background agents</div>';return}let o="";for(const i of s){const r=i.status==="active"?"active":i.status==="idle"?"idle":"completed",a=i.modelShort?`<span class="model-badge ${i.modelShort}">${i.modelShort}</span>`:"",l=i.description?escapeHtml(i.description.substring(0,40)):i.agentId;o+=`
282
282
  <div class="process-item">
283
283
  <span class="process-mode ${r}">${i.status}</span>
284
284
  <div class="process-info">
285
- <div class="process-name">${o} ${l}</div>
285
+ <div class="process-name">${a} ${l}</div>
286
286
  <div class="process-meta">
287
287
  <span>ID: ${i.agentId}</span>
288
288
  <span>${i.toolCallCount||0} tools</span>
@@ -292,4 +292,4 @@
292
292
  ${i.status!=="completed"?`<button class="btn-toolbar btn-sm btn-danger" onclick="app.killSubagent('${escapeHtml(i.agentId)}')" title="Kill agent">Kill</button>`:""}
293
293
  </div>
294
294
  </div>
295
- `}e.innerHTML=a},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=3e3,action:a}=s,i=document.createElement("div");i.className=`toast toast-${t}`;const r=document.createElement("span");if(r.textContent=e,i.appendChild(r),a){const o=document.createElement("button");o.textContent=a.label,o.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",o.onclick=l=>{l.stopPropagation(),a.onClick(),i.remove()},i.appendChild(o)}this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer.appendChild(i),requestAnimationFrame(()=>i.classList.add("show")),setTimeout(()=>{i.classList.remove("show"),setTimeout(()=>i.remove(),200)},n)},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none"))try{const s=await(await fetch("/api/system/stats")).json();this.updateSystemStatsDisplay(s.data)}catch{}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),n=this.$("statMem"),a=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),n&&a){const i=(e.memory.usedMB/1024).toFixed(1);n.textContent=`${i}G`,a.style.width=`${Math.min(100,e.memory.percent)}%`,a.classList.remove("medium","high"),n.classList.remove("high"),e.memory.percent>80?(a.classList.add("high"),n.classList.add("high")):e.memory.percent>50&&a.classList.add("medium")}},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:space-between;align-items:center";const a=document.createElement("span");a.style.cssText="color:#cdd6f4;font-weight:600",a.textContent="Clipboard (browser blocked auto-copy)";const i=document.createElement("button");i.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",i.textContent="\xD7",n.appendChild(a),n.appendChild(i);const r=document.createElement("textarea");r.readOnly=!0,r.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",r.value=e;const o=document.createElement("button");o.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",o.textContent="Copy to Clipboard",s.appendChild(n),s.appendChild(r),s.appendChild(o),t.appendChild(s),document.body.appendChild(t),o.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{r.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const l=()=>t.remove();i.onclick=l,t.onclick=d=>{d.target===t&&l()}}});
295
+ `}e.innerHTML=o},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=3e3,action:o}=s,i=document.createElement("div");i.className=`toast toast-${t}`;const r=document.createElement("span");if(r.textContent=e,i.appendChild(r),o){const a=document.createElement("button");a.textContent=o.label,a.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",a.onclick=l=>{l.stopPropagation(),o.onClick(),i.remove()},i.appendChild(a)}this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer.appendChild(i),requestAnimationFrame(()=>i.classList.add("show")),setTimeout(()=>{i.classList.remove("show"),setTimeout(()=>i.remove(),200)},n)},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none"))try{const s=await(await fetch("/api/system/stats")).json();this.updateSystemStatsDisplay(s.data)}catch{}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),n=this.$("statMem"),o=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),n&&o){const i=(e.memory.usedMB/1024).toFixed(1);n.textContent=`${i}G`,o.style.width=`${Math.min(100,e.memory.percent)}%`,o.classList.remove("medium","high"),n.classList.remove("high"),e.memory.percent>80?(o.classList.add("high"),n.classList.add("high")):e.memory.percent>50&&o.classList.add("medium")}},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:space-between;align-items:center";const o=document.createElement("span");o.style.cssText="color:#cdd6f4;font-weight:600",o.textContent="Clipboard (browser blocked auto-copy)";const i=document.createElement("button");i.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",i.textContent="\xD7",n.appendChild(o),n.appendChild(i);const r=document.createElement("textarea");r.readOnly=!0,r.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",r.value=e;const a=document.createElement("button");a.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",a.textContent="Copy to Clipboard",s.appendChild(n),s.appendChild(r),s.appendChild(a),t.appendChild(s),document.body.appendChild(t),a.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{r.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const l=()=>t.remove();i.onclick=l,t.onclick=d=>{d.target===t&&l()}}});