aicodeman 0.4.5 → 0.4.7

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 (129) hide show
  1. package/dist/orchestrator-loop.d.ts +124 -0
  2. package/dist/orchestrator-loop.d.ts.map +1 -0
  3. package/dist/orchestrator-loop.js +853 -0
  4. package/dist/orchestrator-loop.js.map +1 -0
  5. package/dist/orchestrator-planner.d.ts +58 -0
  6. package/dist/orchestrator-planner.d.ts.map +1 -0
  7. package/dist/orchestrator-planner.js +342 -0
  8. package/dist/orchestrator-planner.js.map +1 -0
  9. package/dist/orchestrator-verifier.d.ts +52 -0
  10. package/dist/orchestrator-verifier.d.ts.map +1 -0
  11. package/dist/orchestrator-verifier.js +234 -0
  12. package/dist/orchestrator-verifier.js.map +1 -0
  13. package/dist/prompts/index.d.ts +1 -0
  14. package/dist/prompts/index.d.ts.map +1 -1
  15. package/dist/prompts/index.js +1 -0
  16. package/dist/prompts/index.js.map +1 -1
  17. package/dist/prompts/orchestrator.d.ts +65 -0
  18. package/dist/prompts/orchestrator.d.ts.map +1 -0
  19. package/dist/prompts/orchestrator.js +112 -0
  20. package/dist/prompts/orchestrator.js.map +1 -0
  21. package/dist/state-store.d.ts +6 -0
  22. package/dist/state-store.d.ts.map +1 -1
  23. package/dist/state-store.js +21 -0
  24. package/dist/state-store.js.map +1 -1
  25. package/dist/types/app-state.d.ts +2 -0
  26. package/dist/types/app-state.d.ts.map +1 -1
  27. package/dist/types/app-state.js.map +1 -1
  28. package/dist/types/index.d.ts +2 -0
  29. package/dist/types/index.d.ts.map +1 -1
  30. package/dist/types/index.js +2 -0
  31. package/dist/types/index.js.map +1 -1
  32. package/dist/types/orchestrator.d.ts +211 -0
  33. package/dist/types/orchestrator.d.ts.map +1 -0
  34. package/dist/types/orchestrator.js +58 -0
  35. package/dist/types/orchestrator.js.map +1 -0
  36. package/dist/web/ports/index.d.ts +1 -0
  37. package/dist/web/ports/index.d.ts.map +1 -1
  38. package/dist/web/ports/orchestrator-port.d.ts +10 -0
  39. package/dist/web/ports/orchestrator-port.d.ts.map +1 -0
  40. package/dist/web/ports/orchestrator-port.js +6 -0
  41. package/dist/web/ports/orchestrator-port.js.map +1 -0
  42. package/dist/web/public/api-client.3adebdc2.js.gz +0 -0
  43. package/dist/web/public/app.cbf6e9e8.js +26 -0
  44. package/dist/web/public/app.cbf6e9e8.js.br +0 -0
  45. package/dist/web/public/app.cbf6e9e8.js.gz +0 -0
  46. package/dist/web/public/{constants.cd61abbc.js → constants.64161167.js} +14 -0
  47. package/dist/web/public/constants.64161167.js.br +0 -0
  48. package/dist/web/public/constants.64161167.js.gz +0 -0
  49. package/dist/web/public/index.html +23 -9
  50. package/dist/web/public/index.html.br +0 -0
  51. package/dist/web/public/index.html.gz +0 -0
  52. package/dist/web/public/input-cjk.92544c51.js.gz +0 -0
  53. package/dist/web/public/keyboard-accessory.9fb81db6.js.gz +0 -0
  54. package/dist/web/public/{mobile-handlers.65e5638d.js → mobile-handlers.1e2a8ef8.js} +86 -22
  55. package/dist/web/public/mobile-handlers.1e2a8ef8.js.br +0 -0
  56. package/dist/web/public/mobile-handlers.1e2a8ef8.js.gz +0 -0
  57. package/dist/web/public/mobile.fdd28a54.css +1 -0
  58. package/dist/web/public/mobile.fdd28a54.css.br +0 -0
  59. package/dist/web/public/mobile.fdd28a54.css.gz +0 -0
  60. package/dist/web/public/notification-manager.2d5ea8ec.js.gz +0 -0
  61. package/dist/web/public/orchestrator-panel.js +475 -0
  62. package/dist/web/public/orchestrator-panel.js.br +0 -0
  63. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  64. package/dist/web/public/{panels-ui.d7f6be08.js → panels-ui.3dd2e29b.js} +25 -25
  65. package/dist/web/public/panels-ui.3dd2e29b.js.br +0 -0
  66. package/dist/web/public/panels-ui.3dd2e29b.js.gz +0 -0
  67. package/dist/web/public/ralph-panel.7b014f16.js.gz +0 -0
  68. package/dist/web/public/ralph-wizard.f31ab90e.js.gz +0 -0
  69. package/dist/web/public/respawn-ui.372c6ea7.js.gz +0 -0
  70. package/dist/web/public/session-ui.0a07c3b7.js.gz +0 -0
  71. package/dist/web/public/settings-ui.94c57184.js.gz +0 -0
  72. package/dist/web/public/styles.8e110d27.css +1 -0
  73. package/dist/web/public/styles.8e110d27.css.br +0 -0
  74. package/dist/web/public/styles.8e110d27.css.gz +0 -0
  75. package/dist/web/public/subagent-windows.a366a4ad.js.gz +0 -0
  76. package/dist/web/public/sw.js.gz +0 -0
  77. package/dist/web/public/terminal-ui.9b40798a.js +3 -0
  78. package/dist/web/public/terminal-ui.9b40798a.js.br +0 -0
  79. package/dist/web/public/terminal-ui.9b40798a.js.gz +0 -0
  80. package/dist/web/public/upload.html.gz +0 -0
  81. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  82. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  83. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  84. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  85. package/dist/web/public/vendor/xterm.css.gz +0 -0
  86. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  87. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  88. package/dist/web/routes/index.d.ts +1 -0
  89. package/dist/web/routes/index.d.ts.map +1 -1
  90. package/dist/web/routes/index.js +1 -0
  91. package/dist/web/routes/index.js.map +1 -1
  92. package/dist/web/routes/orchestrator-routes.d.ts +21 -0
  93. package/dist/web/routes/orchestrator-routes.d.ts.map +1 -0
  94. package/dist/web/routes/orchestrator-routes.js +230 -0
  95. package/dist/web/routes/orchestrator-routes.js.map +1 -0
  96. package/dist/web/routes/session-routes.d.ts.map +1 -1
  97. package/dist/web/routes/session-routes.js +62 -9
  98. package/dist/web/routes/session-routes.js.map +1 -1
  99. package/dist/web/schemas.d.ts +25 -0
  100. package/dist/web/schemas.d.ts.map +1 -1
  101. package/dist/web/schemas.js +22 -0
  102. package/dist/web/schemas.js.map +1 -1
  103. package/dist/web/server.d.ts +2 -0
  104. package/dist/web/server.d.ts.map +1 -1
  105. package/dist/web/server.js +23 -1
  106. package/dist/web/server.js.map +1 -1
  107. package/dist/web/sse-events.d.ts +37 -1
  108. package/dist/web/sse-events.d.ts.map +1 -1
  109. package/dist/web/sse-events.js +39 -1
  110. package/dist/web/sse-events.js.map +1 -1
  111. package/package.json +1 -1
  112. package/dist/web/public/app.9dab4ee2.js +0 -26
  113. package/dist/web/public/app.9dab4ee2.js.br +0 -0
  114. package/dist/web/public/app.9dab4ee2.js.gz +0 -0
  115. package/dist/web/public/constants.cd61abbc.js.br +0 -0
  116. package/dist/web/public/constants.cd61abbc.js.gz +0 -0
  117. package/dist/web/public/mobile-handlers.65e5638d.js.br +0 -0
  118. package/dist/web/public/mobile-handlers.65e5638d.js.gz +0 -0
  119. package/dist/web/public/mobile.b09497a4.css +0 -1
  120. package/dist/web/public/mobile.b09497a4.css.br +0 -0
  121. package/dist/web/public/mobile.b09497a4.css.gz +0 -0
  122. package/dist/web/public/panels-ui.d7f6be08.js.br +0 -0
  123. package/dist/web/public/panels-ui.d7f6be08.js.gz +0 -0
  124. package/dist/web/public/styles.b8ec2f5a.css +0 -1
  125. package/dist/web/public/styles.b8ec2f5a.css.br +0 -0
  126. package/dist/web/public/styles.b8ec2f5a.css.gz +0 -0
  127. package/dist/web/public/terminal-ui.e4565c7b.js +0 -3
  128. package/dist/web/public/terminal-ui.e4565c7b.js.br +0 -0
  129. package/dist/web/public/terminal-ui.e4565c7b.js.gz +0 -0
@@ -1,4 +1,4 @@
1
- "use strict";Object.assign(CodemanApp.prototype,{_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){if(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),e.status==="active"){const n=this.subagents.get(e.agentId);n?.sessionId&&Array.from(this.sessions.values()).some(o=>o.claudeSessionId===n.sessionId)&&this.openSubagentWindow(e.agentId)}requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId),s=t?this.sessions.get(t):null;this.notificationManager?.notify({urgency:"info",category:"subagent-spawn",sessionId:t||e.sessionId,sessionName:s?.name||t||e.sessionId,title:"Subagent Spawned",message: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){const t=this.subagentActivity.get(e.agentId)||[];t.push({type:"tool",...e}),t.length>50&&t.shift(),this.subagentActivity.set(e.agentId,t),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){const t=this.subagentActivity.get(e.agentId)||[];t.push({type:"progress",...e}),t.length>50&&t.shift(),this.subagentActivity.set(e.agentId,t),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){const t=this.subagentActivity.get(e.agentId)||[];t.push({type:"message",...e}),t.length>50&&t.shift(),this.subagentActivity.set(e.agentId,t),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 n=t.keys().next().value;t.delete(n)}const s=this.subagentActivity.get(e.agentId)||[];s.push({type:"tool_result",...e}),s.length>50&&s.shift(),this.subagentActivity.set(e.agentId,s),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 a=this.subagentWindows.get(e.agentId);a&&!a.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId),n=s?this.sessions.get(s):null;this.notificationManager?.notify({urgency:"info",category:"subagent-complete",sessionId:s||t?.sessionId||e.sessionId,sessionName:n?.name||s||e.sessionId,title:"Subagent Completed",message: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),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(v=>v.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},o=new Date;o.setDate(o.getDate()-7);const r=t.filter(v=>new Date(v.date)>=o),i=r.reduce((v,S)=>v+S.inputTokens,0),l=r.reduce((v,S)=>v+S.outputTokens,0),c=this.estimateCost(i,l),d=s.totalInputTokens,u=s.totalOutputTokens,h=this.estimateCost(d,u),m=document.getElementById("statsSummary");m.innerHTML=`
1
+ "use strict";Object.assign(CodemanApp.prototype,{_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),s=t?this.sessions.get(t):null;this.notificationManager?.notify({urgency:"info",category:"subagent-spawn",sessionId:t||e.sessionId,sessionName:s?.name||t||e.sessionId,title:"Subagent Spawned",message: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){const t=this.subagentActivity.get(e.agentId)||[];t.push({type:"tool",...e}),t.length>50&&t.shift(),this.subagentActivity.set(e.agentId,t),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){const t=this.subagentActivity.get(e.agentId)||[];t.push({type:"progress",...e}),t.length>50&&t.shift(),this.subagentActivity.set(e.agentId,t),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){const t=this.subagentActivity.get(e.agentId)||[];t.push({type:"message",...e}),t.length>50&&t.shift(),this.subagentActivity.set(e.agentId,t),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 n=t.keys().next().value;t.delete(n)}const s=this.subagentActivity.get(e.agentId)||[];s.push({type:"tool_result",...e}),s.length>50&&s.shift(),this.subagentActivity.set(e.agentId,s),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 a=this.subagentWindows.get(e.agentId);a&&!a.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId),n=s?this.sessions.get(s):null;this.notificationManager?.notify({urgency:"info",category:"subagent-complete",sessionId:s||t?.sessionId||e.sessionId,sessionName:n?.name||s||e.sessionId,title:"Subagent Completed",message: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),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(v=>v.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},o=new Date;o.setDate(o.getDate()-7);const r=t.filter(v=>new Date(v.date)>=o),i=r.reduce((v,S)=>v+S.inputTokens,0),l=r.reduce((v,S)=>v+S.outputTokens,0),c=this.estimateCost(i,l),d=s.totalInputTokens,u=s.totalOutputTokens,h=this.estimateCost(d,u),m=document.getElementById("statsSummary");m.innerHTML=`
2
2
  <div class="stat-card">
3
3
  <span class="stat-card-label">Today</span>
4
4
  <span class="stat-card-value">${this.formatTokens(a.inputTokens+a.outputTokens)}</span>
@@ -14,14 +14,14 @@
14
14
  <span class="stat-card-value">${this.formatTokens(d+u)}</span>
15
15
  <span class="stat-card-cost">~$${h.toFixed(2)}</span>
16
16
  </div>
17
- `;const g=document.getElementById("statsChart"),f=document.getElementById("statsChartDays"),w=[];for(let v=6;v>=0;v--){const S=new Date;S.setDate(S.getDate()-v);const T=S.toISOString().split("T")[0],y=t.find(D=>D.date===T);w.push({date:T,dayName:S.toLocaleDateString("en-US",{weekday:"short"}),tokens:y?y.inputTokens+y.outputTokens:0,cost:y?y.estimatedCost:0})}const p=Math.max(...w.map(v=>v.tokens),1);g.innerHTML=w.map(v=>{const S=Math.max(v.tokens/p*100,3),T=`${v.dayName}: ${this.formatTokens(v.tokens)} (~$${v.cost.toFixed(2)})`;return`<div class="bar" style="height: ${S}%" data-tooltip="${T}"></div>`}).join(""),f.innerHTML=w.map(v=>`<span>${v.dayName}</span>`).join("");const b=document.getElementById("statsTable"),$=t.slice(0,14);$.length===0?b.innerHTML='<div class="stats-no-data">No usage data recorded yet</div>':b.innerHTML=`
17
+ `;const p=document.getElementById("statsChart"),f=document.getElementById("statsChartDays"),w=[];for(let v=6;v>=0;v--){const S=new Date;S.setDate(S.getDate()-v);const $=S.toISOString().split("T")[0],y=t.find(D=>D.date===$);w.push({date:$,dayName:S.toLocaleDateString("en-US",{weekday:"short"}),tokens:y?y.inputTokens+y.outputTokens:0,cost:y?y.estimatedCost:0})}const g=Math.max(...w.map(v=>v.tokens),1);p.innerHTML=w.map(v=>{const S=Math.max(v.tokens/g*100,3),$=`${v.dayName}: ${this.formatTokens(v.tokens)} (~$${v.cost.toFixed(2)})`;return`<div class="bar" style="height: ${S}%" data-tooltip="${$}"></div>`}).join(""),f.innerHTML=w.map(v=>`<span>${v.dayName}</span>`).join("");const b=document.getElementById("statsTable"),T=t.slice(0,14);T.length===0?b.innerHTML='<div class="stats-no-data">No usage data recorded yet</div>':b.innerHTML=`
18
18
  <div class="stats-table-header">
19
19
  <span>Date</span>
20
20
  <span>Input</span>
21
21
  <span>Output</span>
22
22
  <span>Cost</span>
23
23
  </div>
24
- ${$.map(v=>`
24
+ ${T.map(v=>`
25
25
  <div class="stats-table-row">
26
26
  <span class="cell cell-date">${new Date(v.date+"T00:00:00").toLocaleDateString("en-US",{month:"short",day:"numeric"})}</span>
27
27
  <span class="cell">${this.formatTokens(v.inputTokens)}</span>
@@ -29,7 +29,7 @@
29
29
  <span class="cell cell-cost">$${v.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")?(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,o,r;const i=d=>{if(d.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const u=getEventCoords(d);n=u.clientX,a=u.clientY;const h=e.getBoundingClientRect();o=h.left,r=h.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",c),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",c),d.preventDefault()},l=d=>{if(!s)return;const u=getEventCoords(d),h=u.clientX-n,m=u.clientY-a;let g=o+h,f=r+m;const w=e.getBoundingClientRect();g=Math.max(0,Math.min(window.innerWidth-w.width,g)),f=Math.max(0,Math.min(window.innerHeight-w.height,f)),e.style.left=g+"px",e.style.top=f+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=i,t._touchDragHandler=i,t.addEventListener("mousedown",i),t.addEventListener("touchstart",i,{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,o,r;const i=d=>{if(d.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const u=getEventCoords(d);n=u.clientX,a=u.clientY;const h=e.getBoundingClientRect();o=h.left,r=h.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",c),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",c),d.preventDefault()},l=d=>{if(!s)return;const u=getEventCoords(d),h=u.clientX-n,m=u.clientY-a;let g=o+h,f=r+m;const w=e.getBoundingClientRect();g=Math.max(0,Math.min(window.innerWidth-w.width,g)),f=Math.max(0,Math.min(window.innerHeight-w.height,f)),e.style.left=g+"px",e.style.top=f+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=i,t._touchDragHandler=i,t.addEventListener("mousedown",i),t.addEventListener("touchstart",i,{passive:!1})},renderTaskPanel(){this.renderTaskPanelTimeout&&clearTimeout(this.renderTaskPanelTimeout),this.renderTaskPanelTimeout=setTimeout(()=>{this._renderTaskPanelImmediate()},100)},_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 o=(l,c)=>{const d=l.status==="running"?"":l.status==="completed"?"&#x2713;":"&#x2717;",u=l.endTime?`${((l.endTime-l.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-l.startTime)/1e3).toFixed(0)}s...`;let h="";if(l.children&&l.children.length>0){h='<div class="task-children">';for(const m of l.children){const g=c.find(f=>f.id===m);g&&(h+=`<div class="task-node">${o(g,c)}</div>`)}h+="</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")?(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,o,r;const i=d=>{if(d.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const u=getEventCoords(d);n=u.clientX,a=u.clientY;const h=e.getBoundingClientRect();o=h.left,r=h.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",c),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",c),d.preventDefault()},l=d=>{if(!s)return;const u=getEventCoords(d),h=u.clientX-n,m=u.clientY-a;let p=o+h,f=r+m;const w=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-w.width,p)),f=Math.max(0,Math.min(window.innerHeight-w.height,f)),e.style.left=p+"px",e.style.top=f+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=i,t._touchDragHandler=i,t.addEventListener("mousedown",i),t.addEventListener("touchstart",i,{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,o,r;const i=d=>{if(d.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const u=getEventCoords(d);n=u.clientX,a=u.clientY;const h=e.getBoundingClientRect();o=h.left,r=h.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",c),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",c),d.preventDefault()},l=d=>{if(!s)return;const u=getEventCoords(d),h=u.clientX-n,m=u.clientY-a;let p=o+h,f=r+m;const w=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-w.width,p)),f=Math.max(0,Math.min(window.innerHeight-w.height,f)),e.style.left=p+"px",e.style.top=f+"px"},c=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",c),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",c)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=i,t._touchDragHandler=i,t.addEventListener("mousedown",i),t.addEventListener("touchstart",i,{passive:!1})},renderTaskPanel(){this.renderTaskPanelTimeout&&clearTimeout(this.renderTaskPanelTimeout),this.renderTaskPanelTimeout=setTimeout(()=>{this._renderTaskPanelImmediate()},100)},_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 o=(l,c)=>{const d=l.status==="running"?"":l.status==="completed"?"&#x2713;":"&#x2717;",u=l.endTime?`${((l.endTime-l.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-l.startTime)/1e3).toFixed(0)}s...`;let h="";if(l.children&&l.children.length>0){h='<div class="task-children">';for(const m of l.children){const p=c.find(f=>f.id===m);p&&(h+=`<div class="task-node">${o(p,c)}</div>`)}h+="</div>"}return`
33
33
  <div class="task-item">
34
34
  <span class="task-status-icon ${l.status}">${d}</span>
35
35
  <div class="task-info">
@@ -41,7 +41,7 @@
41
41
  </div>
42
42
  </div>
43
43
  ${h}
44
- `},r=this.flattenTaskTree(e.taskTree);let i='<div class="task-tree">';for(const l of e.taskTree)i+=`<div class="task-node">${o(l,r)}</div>`;i+="</div>",t.innerHTML=i},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,o=n.status==="active"?"active":n.status==="idle"?"idle":"completed",r=this.subagentActivity.get(n.agentId)||[],i=r[r.length-1],l=i?.type==="tool"?i.tool:null,c=this.subagentWindows.has(n.agentId),d=n.status==="active"||n.status==="idle",u=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",h=this.getTeammateInfo(n),m=h?h.name:n.description||n.agentId.substring(0,7),g=this.getTeammateBadgeHtml(n),f=h?`<span class="subagent-icon teammate-dot teammate-color-${h.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
44
+ `},r=this.flattenTaskTree(e.taskTree);let i='<div class="task-tree">';for(const l of e.taskTree)i+=`<div class="task-node">${o(l,r)}</div>`;i+="</div>",t.innerHTML=i},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,o=n.status==="active"?"active":n.status==="idle"?"idle":"completed",r=this.subagentActivity.get(n.agentId)||[],i=r[r.length-1],l=i?.type==="tool"?i.tool:null,c=this.subagentWindows.has(n.agentId),d=n.status==="active"||n.status==="idle",u=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",h=this.getTeammateInfo(n),m=h?h.name:n.description||n.agentId.substring(0,7),p=this.getTeammateBadgeHtml(n),f=h?`<span class="subagent-icon teammate-dot teammate-color-${h.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
45
45
  <div class="subagent-item ${o} ${a?"selected":""}${h?" is-teammate":""}"
46
46
  onclick="app.selectSubagent('${escapeHtml(n.agentId)}')"
47
47
  ondblclick="app.openSubagentWindow('${escapeHtml(n.agentId)}')"
@@ -49,7 +49,7 @@
49
49
  <div class="subagent-header">
50
50
  ${f}
51
51
  <span class="subagent-id" title="${escapeHtml(n.description||n.agentId)}">${escapeHtml(m.length>40?m.substring(0,40)+"...":m)}</span>
52
- ${g}
52
+ ${p}
53
53
  ${u}
54
54
  <span class="subagent-status ${o}">${n.status}</span>
55
55
  ${d?`<button class="subagent-kill-btn" onclick="event.stopPropagation(); app.killSubagent('${escapeHtml(n.agentId)}')" title="Kill agent">&#x2715;</button>`:""}
@@ -134,7 +134,7 @@
134
134
  <span class="tool-detail">${escapeHtml(a)}</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 c=this.getTeammateInfo(t),d=c?c.name:t.description||e.substring(0,7),u=d.length>50?d.substring(0,50)+"...":d;n.textContent=u}let a=s.querySelector(".teammate-badge");const o=this.getTeammateInfo(t);if(o&&!a){const c=s.querySelector(".subagent-window-title");if(c){const d=document.createElement("span");d.className=`teammate-badge teammate-color-${o.color}`,d.title=`Team: ${o.teamName}`,d.textContent=`@${o.name}`;const u=c.querySelector(".status");u&&u.insertAdjacentElement("beforebegin",d)}}const r=s.querySelector(".subagent-window-title");r&&(r.title=t.description||e);let i=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!i){i=document.createElement("span"),i.className=`subagent-model-badge ${t.modelShort}`;const c=s.querySelector(".subagent-window-title .status");c&&c.insertAdjacentElement("beforebegin",i)}i.className=`subagent-model-badge ${t.modelShort}`,i.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,o=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:a,resizeObserver:null,pendingData:o}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const r=new Terminal({theme:{background:"#0d0d0d",foreground:"#e0e0e0",cursor:"#e0e0e0",cursorAccent:"#0d0d0d",selection:"rgba(255, 255, 255, 0.3)",black:"#0d0d0d",red:"#ff6b6b",green:"#51cf66",yellow:"#ffd43b",blue:"#339af0",magenta:"#cc5de8",cyan:"#22b8cf",white:"#e0e0e0",brightBlack:"#495057",brightRed:"#ff8787",brightGreen:"#69db7c",brightYellow:"#ffe066",brightBlue:"#5c7cfa",brightMagenta:"#da77f2",brightCyan:"#66d9e8",brightWhite:"#ffffff"},fontFamily:'"Fira Code", "Cascadia Code", "JetBrains Mono", "SF Mono", Monaco, monospace',fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:5e3,allowTransparency:!0,allowProposedApi:!0}),i=new FitAddon.FitAddon;if(r.loadAddon(i),typeof Unicode11Addon<"u")try{const d=new Unicode11Addon.Unicode11Addon;r.loadAddon(d),r.unicode.activeVersion="11"}catch{}try{r.open(n)}catch(d){console.warn("[TeammateTerminal] Failed to open terminal:",d),this.teammateTerminals.delete(e);return}setTimeout(()=>{try{i.fit()}catch{}fetch(`/api/sessions/${a}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(d=>d.json()).then(d=>{if(d.success&&d.data?.buffer)try{r.write(d.data.buffer)}catch{}}).catch(d=>console.error("[TeammateTerminal] Failed to fetch buffer:",d));for(const d of o)try{r.write(d)}catch{}o.length=0},100),r.onData(d=>{fetch(`/api/sessions/${a}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:d})}).catch(u=>console.error("[TeammateTerminal] Failed to send input:",u))});const l=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{i.fit()}catch{}})});l.observe(n);const c=this.teammateTerminals.get(e);c&&(c.terminal=r,c.fitAddon=i,c.resizeObserver=l)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const y=this.subagentWindows.get(t);y.hidden&&(y.element.style.display="flex",y.hidden=!1),y.element.style.zIndex=++this.subagentWindowZIndex,y.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,a=400,o=20,r=window.innerWidth,i=window.innerHeight,l=50,c=120,d=Math.floor((r-l-50)/(n+o))||1,u=Math.floor((i-c-50)/(a+o))||1,h=s%d,m=Math.floor(s/d)%u;let g=l+h*(n+o),f=c+m*(a+o);g=Math.max(10,Math.min(g,r-n-10)),f=Math.max(10,Math.min(f,i-a-10));const w=e.color||"blue",p=document.createElement("div");p.className="subagent-window has-terminal",p.id=`subagent-window-${t}`,p.style.zIndex=++this.subagentWindowZIndex,p.style.left=`${g}px`,p.style.top=`${f}px`,p.style.width=`${n}px`,p.style.height=`${a}px`,p.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 c=this.getTeammateInfo(t),d=c?c.name:t.description||e.substring(0,7),u=d.length>50?d.substring(0,50)+"...":d;n.textContent=u}let a=s.querySelector(".teammate-badge");const o=this.getTeammateInfo(t);if(o&&!a){const c=s.querySelector(".subagent-window-title");if(c){const d=document.createElement("span");d.className=`teammate-badge teammate-color-${o.color}`,d.title=`Team: ${o.teamName}`,d.textContent=`@${o.name}`;const u=c.querySelector(".status");u&&u.insertAdjacentElement("beforebegin",d)}}const r=s.querySelector(".subagent-window-title");r&&(r.title=t.description||e);let i=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!i){i=document.createElement("span"),i.className=`subagent-model-badge ${t.modelShort}`;const c=s.querySelector(".subagent-window-title .status");c&&c.insertAdjacentElement("beforebegin",i)}i.className=`subagent-model-badge ${t.modelShort}`,i.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,o=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:a,resizeObserver:null,pendingData:o}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const r=new Terminal({theme:{background:"#0d0d0d",foreground:"#e0e0e0",cursor:"#e0e0e0",cursorAccent:"#0d0d0d",selection:"rgba(255, 255, 255, 0.3)",black:"#0d0d0d",red:"#ff6b6b",green:"#51cf66",yellow:"#ffd43b",blue:"#339af0",magenta:"#cc5de8",cyan:"#22b8cf",white:"#e0e0e0",brightBlack:"#495057",brightRed:"#ff8787",brightGreen:"#69db7c",brightYellow:"#ffe066",brightBlue:"#5c7cfa",brightMagenta:"#da77f2",brightCyan:"#66d9e8",brightWhite:"#ffffff"},fontFamily:'"Fira Code", "Cascadia Code", "JetBrains Mono", "SF Mono", Monaco, monospace',fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:5e3,allowTransparency:!0,allowProposedApi:!0}),i=new FitAddon.FitAddon;if(r.loadAddon(i),typeof Unicode11Addon<"u")try{const d=new Unicode11Addon.Unicode11Addon;r.loadAddon(d),r.unicode.activeVersion="11"}catch{}try{r.open(n)}catch(d){console.warn("[TeammateTerminal] Failed to open terminal:",d),this.teammateTerminals.delete(e);return}setTimeout(()=>{try{i.fit()}catch{}fetch(`/api/sessions/${a}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(d=>d.json()).then(d=>{if(d.success&&d.data?.buffer)try{r.write(d.data.buffer)}catch{}}).catch(d=>console.error("[TeammateTerminal] Failed to fetch buffer:",d));for(const d of o)try{r.write(d)}catch{}o.length=0},100),r.onData(d=>{fetch(`/api/sessions/${a}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:d})}).catch(u=>console.error("[TeammateTerminal] Failed to send input:",u))});const l=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{i.fit()}catch{}})});l.observe(n);const c=this.teammateTerminals.get(e);c&&(c.terminal=r,c.fitAddon=i,c.resizeObserver=l)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const y=this.subagentWindows.get(t);y.hidden&&(y.element.style.display="flex",y.hidden=!1),y.element.style.zIndex=++this.subagentWindowZIndex,y.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,a=400,o=20,r=window.innerWidth,i=window.innerHeight,l=50,c=120,d=Math.floor((r-l-50)/(n+o))||1,u=Math.floor((i-c-50)/(a+o))||1,h=s%d,m=Math.floor(s/d)%u;let p=l+h*(n+o),f=c+m*(a+o);p=Math.max(10,Math.min(p,r-n-10)),f=Math.max(10,Math.min(f,i-a-10));const w=e.color||"blue",g=document.createElement("div");g.className="subagent-window has-terminal",g.id=`subagent-window-${t}`,g.style.zIndex=++this.subagentWindowZIndex,g.style.left=`${p}px`,g.style.top=`${f}px`,g.style.width=`${n}px`,g.style.height=`${a}px`,g.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-${w}, #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(p);const b=this.makeWindowDraggable(p,p.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(p);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:p,minimized:!1,hidden:S,dragListeners:b,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(p.style.display="none"),p.addEventListener("mousedown",()=>{p.style.zIndex=++this.subagentWindowZIndex});const T=new ResizeObserver(()=>{this.updateConnectionLines()});if(T.observe(p),this.subagentWindows.get(t).resizeObserver=T,S){const y=this.subagentWindows.get(t);y&&(y._lazyTerminal=!0,y._lazyPaneTarget=e.paneTarget,y._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,p);requestAnimationFrame(()=>{p.style.transition="transform 0.3s ease, opacity 0.3s ease",p.style.transform="scale(1)",p.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[m,g]of this.teams)if(g.leadSessionId===this.activeSessionId){t=g,s=m;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 f=e.querySelector(".team-tasks-header");f&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,f))}const a=this.teamTasks.get(s)||[],o=a.filter(m=>m.status==="completed").length,r=a.length,i=r>0?Math.round(o/r*100):0,l=e.querySelector(".team-tasks-header-text");if(l){const m=t.members.filter(g=>g.agentType!=="team-lead").length;l.textContent=`Team Tasks (${m} teammates)`}const c=e.querySelector(".team-tasks-progress-fill");c&&(c.style.width=`${i}%`);const d=e.querySelector(".team-tasks-progress-text");d&&(d.textContent=`${o}/${r}`);const u=e.querySelector(".team-tasks-list");if(!u)return;if(a.length===0){u.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const h=a.map(m=>{const g=m.status==="completed"?"\u2713":m.status==="in_progress"?"\u25C9":"\u25CB",f=m.status.replace("_","-"),w=m.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(m.owner)}">${escapeHtml(m.owner)}</span>`:"";return`<div class="team-task-item ${f}">
151
- <span class="team-task-status">${g}</span>
150
+ `,document.body.appendChild(g);const b=this.makeWindowDraggable(g,g.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(g);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:g,minimized:!1,hidden:S,dragListeners:b,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(g.style.display="none"),g.addEventListener("mousedown",()=>{g.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(g),this.subagentWindows.get(t).resizeObserver=$,S){const y=this.subagentWindows.get(t);y&&(y._lazyTerminal=!0,y._lazyPaneTarget=e.paneTarget,y._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,g);requestAnimationFrame(()=>{g.style.transition="transform 0.3s ease, opacity 0.3s ease",g.style.transform="scale(1)",g.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[m,p]of this.teams)if(p.leadSessionId===this.activeSessionId){t=p,s=m;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 f=e.querySelector(".team-tasks-header");f&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,f))}const a=this.teamTasks.get(s)||[],o=a.filter(m=>m.status==="completed").length,r=a.length,i=r>0?Math.round(o/r*100):0,l=e.querySelector(".team-tasks-header-text");if(l){const m=t.members.filter(p=>p.agentType!=="team-lead").length;l.textContent=`Team Tasks (${m} teammates)`}const c=e.querySelector(".team-tasks-progress-fill");c&&(c.style.width=`${i}%`);const d=e.querySelector(".team-tasks-progress-text");d&&(d.textContent=`${o}/${r}`);const u=e.querySelector(".team-tasks-list");if(!u)return;if(a.length===0){u.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const h=a.map(m=>{const p=m.status==="completed"?"\u2713":m.status==="in_progress"?"\u25C9":"\u25CB",f=m.status.replace("_","-"),w=m.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(m.owner)}">${escapeHtml(m.owner)}</span>`:"";return`<div class="team-task-item ${f}">
151
+ <span class="team-task-status">${p}</span>
152
152
  <span class="team-task-subject">${escapeHtml(m.subject)}</span>
153
153
  ${w}
154
- </div>`}).join("");u.innerHTML=h},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("/"),o=[];for(const r of a)r===""||r==="."||(r===".."?o.length>1&&o.pop():o.push(r));return"/"+o.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 o=this.getFilename(n),r=this.getFilename(a);if(o!==r)return!1;const i=this.isShallowRootPath(e),l=this.isShallowRootPath(t),c=this.isPathInWorkingDir(n,s),d=this.isPathInWorkingDir(a,s);return!!(i&&d||l&&c)},pickBetterPath(e,t,s){if(s){const o=this.isPathInWorkingDir(e,s),r=this.isPathInWorkingDir(t,s);if(o&&!r)return e;if(r&&!o)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 o of e)for(const r of o.filePaths)s.push({rawPath:r,toolId:o.id});if(s.length<=1){const o=new Map;for(const r of s)o.set(this.normalizeFilePath(r.rawPath,t),r);return o}s.sort((o,r)=>{const i=this.isPathInWorkingDir(o.rawPath,t),l=this.isPathInWorkingDir(r.rawPath,t);return i&&!l?-1:l&&!i?1:r.rawPath.length-o.rawPath.length});const n=new Map,a=new Set;for(const{rawPath:o,toolId:r}of s){const i=this.normalizeFilePath(o,t);let l=!1;for(const[,c]of n)if(this.pathsAreEquivalent(o,c.rawPath,t)){l=!0;break}!l&&!a.has(i)&&(n.set(i,{rawPath:o,toolId:r}),a.add(i))}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(o=>o.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 o=(this.projectInsights.get(this.activeSessionId)||[]).filter(u=>u.status==="running");if(o.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const i=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,l=this.deduplicateProjectInsightPaths(o,i),c=new Set(Array.from(l.values()).map(u=>u.rawPath)),d=[];for(const u of o){const h=u.filePaths.filter(g=>c.has(g));if(h.length===0)continue;const m=u.command.length>50?u.command.substring(0,50)+"...":u.command;d.push(`
154
+ </div>`}).join("");u.innerHTML=h},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("/"),o=[];for(const r of a)r===""||r==="."||(r===".."?o.length>1&&o.pop():o.push(r));return"/"+o.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 o=this.getFilename(n),r=this.getFilename(a);if(o!==r)return!1;const i=this.isShallowRootPath(e),l=this.isShallowRootPath(t),c=this.isPathInWorkingDir(n,s),d=this.isPathInWorkingDir(a,s);return!!(i&&d||l&&c)},pickBetterPath(e,t,s){if(s){const o=this.isPathInWorkingDir(e,s),r=this.isPathInWorkingDir(t,s);if(o&&!r)return e;if(r&&!o)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 o of e)for(const r of o.filePaths)s.push({rawPath:r,toolId:o.id});if(s.length<=1){const o=new Map;for(const r of s)o.set(this.normalizeFilePath(r.rawPath,t),r);return o}s.sort((o,r)=>{const i=this.isPathInWorkingDir(o.rawPath,t),l=this.isPathInWorkingDir(r.rawPath,t);return i&&!l?-1:l&&!i?1:r.rawPath.length-o.rawPath.length});const n=new Map,a=new Set;for(const{rawPath:o,toolId:r}of s){const i=this.normalizeFilePath(o,t);let l=!1;for(const[,c]of n)if(this.pathsAreEquivalent(o,c.rawPath,t)){l=!0;break}!l&&!a.has(i)&&(n.set(i,{rawPath:o,toolId:r}),a.add(i))}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(o=>o.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 o=(this.projectInsights.get(this.activeSessionId)||[]).filter(u=>u.status==="running");if(o.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const i=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,l=this.deduplicateProjectInsightPaths(o,i),c=new Set(Array.from(l.values()).map(u=>u.rawPath)),d=[];for(const u of o){const h=u.filePaths.filter(p=>c.has(p));if(h.length===0)continue;const m=u.command.length>50?u.command.substring(0,50)+"...":u.command;d.push(`
155
155
  <div class="project-insight-item" data-tool-id="${u.id}">
156
156
  <div class="project-insight-command">
157
157
  <span class="icon">\u{1F4BB}</span>
@@ -160,21 +160,21 @@
160
160
  ${u.timeout?`<span class="project-insight-timeout">${escapeHtml(u.timeout)}</span>`:""}
161
161
  </div>
162
162
  <div class="project-insight-paths">
163
- `);for(const g of h){const f=g.split("/").pop();d.push(`
163
+ `);for(const p of h){const f=p.split("/").pop();d.push(`
164
164
  <span class="project-insight-filepath"
165
- onclick="app.openLogViewerWindow('${escapeHtml(g)}', '${escapeHtml(u.sessionId)}')"
166
- title="${escapeHtml(g)}">${escapeHtml(f)}</span>
165
+ onclick="app.openLogViewerWindow('${escapeHtml(p)}', '${escapeHtml(u.sessionId)}')"
166
+ title="${escapeHtml(p)}">${escapeHtml(f)}</span>
167
167
  `)}d.push(`
168
168
  </div>
169
169
  </div>
170
- `)}t.innerHTML=d.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:o,totalDirectories:r,truncated:i}=a.data;s.textContent=`${o} files, ${r} dirs${i?" (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=(o,r)=>{const i=o.type==="directory",l=this.fileBrowserExpandedDirs.has(o.path),c=!n||o.name.toLowerCase().includes(n);let d=!1;i&&n&&o.children&&(d=this.hasMatchingChild(o,n));const h=!(c||d)&&n?" hidden-by-filter":"",m=i?l?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(o.extension),g=i?`<span class="file-tree-expand${l?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',f=!i&&o.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(o.size)}</span>`:"",w=i?"file-tree-name directory":"file-tree-name";if(s.push(`
170
+ `)}t.innerHTML=d.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:o,totalDirectories:r,truncated:i}=a.data;s.textContent=`${o} files, ${r} dirs${i?" (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=(o,r)=>{const i=o.type==="directory",l=this.fileBrowserExpandedDirs.has(o.path),c=!n||o.name.toLowerCase().includes(n);let d=!1;i&&n&&o.children&&(d=this.hasMatchingChild(o,n));const h=!(c||d)&&n?" hidden-by-filter":"",m=i?l?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(o.extension),p=i?`<span class="file-tree-expand${l?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',f=!i&&o.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(o.size)}</span>`:"",w=i?"file-tree-name directory":"file-tree-name";if(s.push(`
171
171
  <div class="file-tree-item${h}" data-path="${escapeHtml(o.path)}" data-type="${o.type}" data-depth="${r}">
172
- ${g}
172
+ ${p}
173
173
  <span class="file-tree-icon">${m}</span>
174
174
  <span class="${w}">${escapeHtml(o.name)}</span>
175
175
  ${f}
176
176
  </div>
177
- `),i&&l&&o.children)for(const p of o.children)a(p,r+1)};for(const o of t)a(o,0);e.innerHTML=s.join(""),e.querySelectorAll(".file-tree-item").forEach(o=>{o.addEventListener("click",()=>{const r=o.dataset.path;o.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){if(!this.activeSessionId||!e)return;const t=this.$("filePreviewOverlay"),s=this.$("filePreviewTitle"),n=this.$("filePreviewBody"),a=this.$("filePreviewFooter");if(!(!t||!n)){t.classList.add("visible"),s.textContent=e,n.innerHTML='<div class="binary-message">Loading...</div>',a.textContent="";try{const o=await fetch(`/api/sessions/${this.activeSessionId}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!o.ok)throw new Error("Failed to load file");const r=await o.json();if(!r.success)throw new Error(r.error||"Failed to load file");const i=r.data;if(i.type==="image")n.innerHTML=`<img src="${i.url}" alt="${escapeHtml(e)}">`,a.textContent=`${this.formatFileSize(i.size)} \u2022 ${i.extension}`;else if(i.type==="video")n.innerHTML=`<video src="${i.url}" controls autoplay></video>`,a.textContent=`${this.formatFileSize(i.size)} \u2022 ${i.extension}`;else if(i.type==="binary")n.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(i.size)})<br>Cannot preview</div>`,a.textContent=i.extension||"binary";else{this.filePreviewContent=i.content,n.innerHTML=`<pre><code>${escapeHtml(i.content)}</code></pre>`;const l=i.truncated?` (showing 500/${i.totalLines} lines)`:"";a.textContent=`${i.totalLines} lines \u2022 ${this.formatFileSize(i.size)}${l}`}}catch(o){console.error("Failed to preview file:",o),n.innerHTML=`<div class="binary-message">Error: ${escapeHtml(o.message)}</div>`}}},closeFilePreview(){const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this.filePreviewContent=""},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 d=this.logViewerWindows.get(s);d.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,a=100+n%5*30,o=100+n%5*30,r=e.split("/").pop(),i=document.createElement("div");i.className="log-viewer-window",i.id=`log-viewer-window-${s}`,i.style.left=`${a}px`,i.style.top=`${o}px`,i.style.zIndex=++this.logViewerWindowZIndex,i.innerHTML=`
177
+ `),i&&l&&o.children)for(const g of o.children)a(g,r+1)};for(const o of t)a(o,0);e.innerHTML=s.join(""),e.querySelectorAll(".file-tree-item").forEach(o=>{o.addEventListener("click",()=>{const r=o.dataset.path;o.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){if(!this.activeSessionId||!e)return;const t=this.$("filePreviewOverlay"),s=this.$("filePreviewTitle"),n=this.$("filePreviewBody"),a=this.$("filePreviewFooter");if(!(!t||!n)){t.classList.add("visible"),s.textContent=e,n.innerHTML='<div class="binary-message">Loading...</div>',a.textContent="";try{const o=await fetch(`/api/sessions/${this.activeSessionId}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!o.ok)throw new Error("Failed to load file");const r=await o.json();if(!r.success)throw new Error(r.error||"Failed to load file");const i=r.data;if(i.type==="image")n.innerHTML=`<img src="${i.url}" alt="${escapeHtml(e)}">`,a.textContent=`${this.formatFileSize(i.size)} \u2022 ${i.extension}`;else if(i.type==="video")n.innerHTML=`<video src="${i.url}" controls autoplay></video>`,a.textContent=`${this.formatFileSize(i.size)} \u2022 ${i.extension}`;else if(i.type==="binary")n.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(i.size)})<br>Cannot preview</div>`,a.textContent=i.extension||"binary";else{this.filePreviewContent=i.content,n.innerHTML=`<pre><code>${escapeHtml(i.content)}</code></pre>`;const l=i.truncated?` (showing 500/${i.totalLines} lines)`:"";a.textContent=`${i.totalLines} lines \u2022 ${this.formatFileSize(i.size)}${l}`}}catch(o){console.error("Failed to preview file:",o),n.innerHTML=`<div class="binary-message">Error: ${escapeHtml(o.message)}</div>`}}},closeFilePreview(){const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this.filePreviewContent=""},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 d=this.logViewerWindows.get(s);d.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,a=100+n%5*30,o=100+n%5*30,r=e.split("/").pop(),i=document.createElement("div");i.className="log-viewer-window",i.id=`log-viewer-window-${s}`,i.style.left=`${a}px`,i.style.top=`${o}px`,i.style.zIndex=++this.logViewerWindowZIndex,i.innerHTML=`
178
178
  <div class="log-viewer-window-header">
179
179
  <div class="log-viewer-window-title" title="${escapeHtml(e)}">
180
180
  <span class="icon">\u{1F4C4}</span>
@@ -188,7 +188,7 @@
188
188
  <div class="log-viewer-window-body" id="log-viewer-body-${s}">
189
189
  <div class="log-info">Connecting to ${escapeHtml(e)}...</div>
190
190
  </div>
191
- `,document.body.appendChild(i);const l=this.makeWindowDraggable(i,i.querySelector(".log-viewer-window-header")),c=new EventSource(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`);c.onmessage=d=>{const u=JSON.parse(d.data),h=document.getElementById(`log-viewer-body-${s}`);if(h)switch(u.type){case"connected":h.innerHTML="";break;case"data":const m=h.scrollTop+h.clientHeight>=h.scrollHeight-10,g=escapeHtml(u.content);h.innerHTML+=g,m&&(h.scrollTop=h.scrollHeight),h.innerHTML.length>5e5&&(h.innerHTML=h.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":h.innerHTML+=`<div class="log-error">${escapeHtml(u.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},c.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:i,eventSource:c,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:o,size:r}=e,i=`${t}-${o}`;if(this.imagePopups.has(i)){const v=this.imagePopups.get(i);v.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const v=this.imagePopups.keys().next().value;v&&this.closeImagePopup(v)}const c=this.imagePopups.size,d=(window.innerWidth-600)/2,u=(window.innerHeight-500)/2,h=d+c%5*30,m=u+c%5*30,f=this.sessions.get(t)?.name||t.substring(0,8),w=(r/1024).toFixed(1),p=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||a)}`,b=document.createElement("div");b.className="image-popup-window",b.id=`image-popup-${i}`,b.style.left=`${h}px`,b.style.top=`${m}px`,b.style.zIndex=++this.imagePopupZIndex,b.innerHTML=`
191
+ `,document.body.appendChild(i);const l=this.makeWindowDraggable(i,i.querySelector(".log-viewer-window-header")),c=new EventSource(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`);c.onmessage=d=>{const u=JSON.parse(d.data),h=document.getElementById(`log-viewer-body-${s}`);if(h)switch(u.type){case"connected":h.innerHTML="";break;case"data":const m=h.scrollTop+h.clientHeight>=h.scrollHeight-10,p=escapeHtml(u.content);h.innerHTML+=p,m&&(h.scrollTop=h.scrollHeight),h.innerHTML.length>5e5&&(h.innerHTML=h.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":h.innerHTML+=`<div class="log-error">${escapeHtml(u.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},c.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:i,eventSource:c,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:o,size:r}=e,i=`${t}-${o}`;if(this.imagePopups.has(i)){const v=this.imagePopups.get(i);v.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const v=this.imagePopups.keys().next().value;v&&this.closeImagePopup(v)}const c=this.imagePopups.size,d=(window.innerWidth-600)/2,u=(window.innerHeight-500)/2,h=d+c%5*30,m=u+c%5*30,f=this.sessions.get(t)?.name||t.substring(0,8),w=(r/1024).toFixed(1),g=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||a)}`,b=document.createElement("div");b.className="image-popup-window",b.id=`image-popup-${i}`,b.style.left=`${h}px`,b.style.top=`${m}px`,b.style.zIndex=++this.imagePopupZIndex,b.innerHTML=`
192
192
  <div class="image-popup-header">
193
193
  <div class="image-popup-title" title="${escapeHtml(s)}">
194
194
  <span class="icon">\u{1F5BC}\uFE0F</span>
@@ -197,30 +197,30 @@
197
197
  <span class="size-badge">${w} KB</span>
198
198
  </div>
199
199
  <div class="image-popup-actions">
200
- <button onclick="app.openImageInNewTab('${escapeHtml(p)}')" title="Open in new tab">\u2197</button>
200
+ <button onclick="app.openImageInNewTab('${escapeHtml(g)}')" title="Open in new tab">\u2197</button>
201
201
  <button onclick="app.closeImagePopup('${escapeHtml(i)}')" title="Close">\xD7</button>
202
202
  </div>
203
203
  </div>
204
204
  <div class="image-popup-body">
205
- <img src="${p}" alt="${escapeHtml(a)}"
205
+ <img src="${g}" alt="${escapeHtml(a)}"
206
206
  onerror="this.parentElement.innerHTML='<div class=\\'image-error\\'>Failed to load image</div>'"
207
- onclick="app.openImageInNewTab('${escapeHtml(p)}')" />
207
+ onclick="app.openImageInNewTab('${escapeHtml(g)}')" />
208
208
  </div>
209
- `,document.body.appendChild(b);const $=this.makeWindowDraggable(b,b.querySelector(".image-popup-header"));b.addEventListener("mousedown",()=>{b.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(i,{element:b,sessionId:t,filePath:s,dragListeners:$})},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.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.renderMuxSessionsTimeout&&clearTimeout(this.renderMuxSessionsTimeout),this.renderMuxSessionsTimeout=setTimeout(()=>{this._renderMuxSessionsImmediate()},100)},_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),o=a?a.status:"unknown",r=a?a.isWorking:!1;let i,l;o==="idle"&&!r?(i="IDLE",l="status-idle"):o==="busy"||r?(i="WORKING",l="status-working"):o==="stopped"?(i="STOPPED",l="status-stopped"):(i=o.toUpperCase(),l="");const c=a&&a.tokens?a.tokens:null,d=a?a.totalCost:0,u=a&&a.cliModel||"",h=u.includes("opus")?"opus":u.includes("sonnet")?"sonnet":u.includes("haiku")?"haiku":"",m=a?a.ralphTodoStats:null;let g="";if(m&&m.total>0){const b=Math.round(m.completed/m.total*100);g=`<span class="process-stat todo-progress">${m.completed}/${m.total} (${b}%)</span>`}let f="";c&&c.total>0&&(f=`<span class="process-stat tokens">${(c.total/1e3).toFixed(1)}k tok</span>`);let w="";d>0&&(w=`<span class="process-stat cost">$${d.toFixed(2)}</span>`);let p="";h&&(p=`<span class="monitor-model-badge ${h}">${h}</span>`),t+=`
210
- <div class="process-item">
209
+ `,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(i,{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.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.renderMuxSessionsTimeout&&clearTimeout(this.renderMuxSessionsTimeout),this.renderMuxSessionsTimeout=setTimeout(()=>{this._renderMuxSessionsImmediate()},100)},_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),o=a?a.status:"unknown",r=a?a.isWorking:!1;let i,l;o==="idle"&&!r?(i="IDLE",l="status-idle"):o==="busy"||r?(i="WORKING",l="status-working"):o==="stopped"?(i="STOPPED",l="status-stopped"):(i=o.toUpperCase(),l="");const c=a&&a.tokens?a.tokens:null,d=a?a.totalCost:0,u=a&&a.cliModel||"",h=u.includes("opus")?"opus":u.includes("sonnet")?"sonnet":u.includes("haiku")?"haiku":"",m=a?a.ralphTodoStats:null;let p="";if(m&&m.total>0){const T=Math.round(m.completed/m.total*100);p=`<span class="process-stat todo-progress">${m.completed}/${m.total} (${T}%)</span>`}let f="";c&&c.total>0&&(f=`<span class="process-stat tokens">${(c.total/1e3).toFixed(1)}k tok</span>`);let w="";d>0&&(w=`<span class="process-stat cost">$${d.toFixed(2)}</span>`);let g="";h&&(g=`<span class="monitor-model-badge ${h}">${h}</span>`);const b=escapeHtml(s.sessionId);t+=`
210
+ <div class="process-item process-item-clickable" onclick="app.selectSession('${b}')" title="Switch to session">
211
211
  <span class="monitor-status-badge ${l}">${i}</span>
212
212
  <div class="process-info">
213
- <div class="process-name">${p} ${escapeHtml(s.name||s.muxName)}</div>
213
+ <div class="process-name">${g} ${escapeHtml(s.name||s.muxName)}</div>
214
214
  <div class="process-meta">
215
215
  ${f}
216
216
  ${w}
217
- ${g}
217
+ ${p}
218
218
  <span class="process-stat memory">${n.memoryMB}MB</span>
219
219
  <span class="process-stat cpu">${n.cpuPercent}%</span>
220
220
  </div>
221
221
  </div>
222
222
  <div class="process-actions">
223
- <button class="btn-toolbar btn-sm btn-danger" onclick="app.killMuxSession('${escapeHtml(s.sessionId)}')" title="Kill session">Kill</button>
223
+ <button class="btn-toolbar btn-sm btn-danger" onclick="event.stopPropagation(); app.killMuxSession('${b}')" title="Kill session">Kill</button>
224
224
  </div>
225
225
  </div>
226
226
  `}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(o=>o.status==="active"||o.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 o of s){const r=o.status==="active"?"active":o.status==="idle"?"idle":"completed",i=o.modelShort?`<span class="model-badge ${o.modelShort}">${o.modelShort}</span>`:"",l=o.description?escapeHtml(o.description.substring(0,40)):o.agentId;a+=`