aicodeman 1.3.5 → 1.4.1

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 (111) hide show
  1. package/README.md +16 -0
  2. package/dist/docker-export.d.ts +107 -0
  3. package/dist/docker-export.d.ts.map +1 -0
  4. package/dist/docker-export.js +335 -0
  5. package/dist/docker-export.js.map +1 -0
  6. package/dist/docker-hosts.d.ts +264 -0
  7. package/dist/docker-hosts.d.ts.map +1 -0
  8. package/dist/docker-hosts.js +744 -0
  9. package/dist/docker-hosts.js.map +1 -0
  10. package/dist/mux-interface.d.ts +7 -1
  11. package/dist/mux-interface.d.ts.map +1 -1
  12. package/dist/session.d.ts +9 -2
  13. package/dist/session.d.ts.map +1 -1
  14. package/dist/session.js +48 -4
  15. package/dist/session.js.map +1 -1
  16. package/dist/tmux-manager.d.ts +58 -1
  17. package/dist/tmux-manager.d.ts.map +1 -1
  18. package/dist/tmux-manager.js +247 -7
  19. package/dist/tmux-manager.js.map +1 -1
  20. package/dist/types/api.d.ts +9 -1
  21. package/dist/types/api.d.ts.map +1 -1
  22. package/dist/types/api.js.map +1 -1
  23. package/dist/types/session.d.ts +102 -0
  24. package/dist/types/session.d.ts.map +1 -1
  25. package/dist/types/session.js.map +1 -1
  26. package/dist/web/network-auth-policy.d.ts +9 -0
  27. package/dist/web/network-auth-policy.d.ts.map +1 -1
  28. package/dist/web/network-auth-policy.js +12 -0
  29. package/dist/web/network-auth-policy.js.map +1 -1
  30. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  31. package/dist/web/public/{app.6890f3d0.js → app.6c4b9893.js} +1 -1
  32. package/dist/web/public/app.6c4b9893.js.br +0 -0
  33. package/dist/web/public/app.6c4b9893.js.gz +0 -0
  34. package/dist/web/public/{constants.5b18ed64.js → constants.48da7f03.js} +7 -0
  35. package/dist/web/public/constants.48da7f03.js.br +0 -0
  36. package/dist/web/public/{constants.5b18ed64.js.gz → constants.48da7f03.js.gz} +0 -0
  37. package/dist/web/public/cron-ui.js.gz +0 -0
  38. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  39. package/dist/web/public/index.html +148 -11
  40. package/dist/web/public/index.html.br +0 -0
  41. package/dist/web/public/index.html.gz +0 -0
  42. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  43. package/dist/web/public/keyboard-accessory.3f91acef.js.gz +0 -0
  44. package/dist/web/public/mobile-handlers.b5a667ef.js.gz +0 -0
  45. package/dist/web/public/mobile.0644e3ac.css.gz +0 -0
  46. package/dist/web/public/notification-manager.ca9dc40d.js.gz +0 -0
  47. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  48. package/dist/web/public/{panels-ui.ca03853f.js → panels-ui.3c9b0465.js} +53 -53
  49. package/dist/web/public/panels-ui.3c9b0465.js.br +0 -0
  50. package/dist/web/public/panels-ui.3c9b0465.js.gz +0 -0
  51. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  52. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  53. package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
  54. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  55. package/dist/web/public/session-ui.4851c61a.js +58 -0
  56. package/dist/web/public/session-ui.4851c61a.js.br +0 -0
  57. package/dist/web/public/session-ui.4851c61a.js.gz +0 -0
  58. package/dist/web/public/settings-ui.29214cf1.js +67 -0
  59. package/dist/web/public/settings-ui.29214cf1.js.br +0 -0
  60. package/dist/web/public/settings-ui.29214cf1.js.gz +0 -0
  61. package/dist/web/public/{styles.3d78fd0d.css → styles.ff43f80f.css} +1 -1
  62. package/dist/web/public/styles.ff43f80f.css.br +0 -0
  63. package/dist/web/public/styles.ff43f80f.css.gz +0 -0
  64. package/dist/web/public/subagent-windows.69b60c35.js.gz +0 -0
  65. package/dist/web/public/sw.js.gz +0 -0
  66. package/dist/web/public/terminal-ui.efda6083.js.gz +0 -0
  67. package/dist/web/public/ultracode-panel.js.gz +0 -0
  68. package/dist/web/public/ultracode-windows.js.gz +0 -0
  69. package/dist/web/public/upload.html.gz +0 -0
  70. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  71. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  72. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  73. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  74. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  75. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  76. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  77. package/dist/web/public/vendor/xterm.css.gz +0 -0
  78. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  79. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  80. package/dist/web/routes/case-routes.d.ts.map +1 -1
  81. package/dist/web/routes/case-routes.js +422 -3
  82. package/dist/web/routes/case-routes.js.map +1 -1
  83. package/dist/web/routes/session-routes.d.ts.map +1 -1
  84. package/dist/web/routes/session-routes.js +85 -5
  85. package/dist/web/routes/session-routes.js.map +1 -1
  86. package/dist/web/schemas.d.ts +72 -1
  87. package/dist/web/schemas.d.ts.map +1 -1
  88. package/dist/web/schemas.js +158 -0
  89. package/dist/web/schemas.js.map +1 -1
  90. package/dist/web/server.d.ts +11 -0
  91. package/dist/web/server.d.ts.map +1 -1
  92. package/dist/web/server.js +81 -1
  93. package/dist/web/server.js.map +1 -1
  94. package/dist/web/sse-events.d.ts +21 -0
  95. package/dist/web/sse-events.d.ts.map +1 -1
  96. package/dist/web/sse-events.js +23 -0
  97. package/dist/web/sse-events.js.map +1 -1
  98. package/package.json +1 -1
  99. package/dist/web/public/app.6890f3d0.js.br +0 -0
  100. package/dist/web/public/app.6890f3d0.js.gz +0 -0
  101. package/dist/web/public/constants.5b18ed64.js.br +0 -0
  102. package/dist/web/public/panels-ui.ca03853f.js.br +0 -0
  103. package/dist/web/public/panels-ui.ca03853f.js.gz +0 -0
  104. package/dist/web/public/session-ui.c9094fe9.js +0 -49
  105. package/dist/web/public/session-ui.c9094fe9.js.br +0 -0
  106. package/dist/web/public/session-ui.c9094fe9.js.gz +0 -0
  107. package/dist/web/public/settings-ui.9538a0c1.js +0 -67
  108. package/dist/web/public/settings-ui.9538a0c1.js.br +0 -0
  109. package/dist/web/public/settings-ui.9538a0c1.js.gz +0 -0
  110. package/dist/web/public/styles.3d78fd0d.css.br +0 -0
  111. package/dist/web/public/styles.3d78fd0d.css.gz +0 -0
@@ -1,12 +1,12 @@
1
- "use strict";const AWAY_DIGEST_LAST_VIEWED_KEY="codeman-away-digest-last-viewed",AWAY_DIGEST_SECTIONS=[["needsAttention","Needs Attention"],["completed","Completed"],["stillRunning","Still Running"],["idle","Idle"],["informational","Informational"]];Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},shouldOpenCommandPaletteFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const s=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(o=>o.id==="command-palette"):null;if(s){if(s.disabled||!this.matchesShortcutEvent(e,s))return!1}else if((e.key||"").toLowerCase()!=="k"&&e.code!=="KeyK"||e.shiftKey)return!1;const n=e.target;if(!n)return!0;const i=(n.tagName||"").toUpperCase(),a=typeof n.className=="string"?n.className:"";return n.classList?.contains?.("xterm-helper-textarea")||a.includes("xterm-helper-textarea")?!0:!(i==="INPUT"||i==="TEXTAREA"||i==="SELECT"||n.isContentEditable||typeof n.closest=="function"&&n.closest('[contenteditable="true"]'))},openCommandPalette(){const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch");!e||!t||(this.commandPaletteActiveIndex=0,t.value="",e.classList.add("active"),this._wireCommandPalette(),this.renderCommandPalette(),t.focus(),t.select?.())},closeCommandPalette(){const e=document.getElementById("commandPaletteModal");e&&e.classList.remove("active")},_wireCommandPalette(){if(this._commandPaletteWired)return;this._commandPaletteWired=!0;const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch"),s=document.getElementById("commandPaletteList");t?.addEventListener("input",()=>{this.commandPaletteActiveIndex=0,this.renderCommandPalette()}),t?.addEventListener("keydown",async n=>{if(n.key==="ArrowDown"){n.preventDefault(),this.moveCommandPaletteSelection(1);return}if(n.key==="ArrowUp"){n.preventDefault(),this.moveCommandPaletteSelection(-1);return}if(n.key==="Enter"){n.preventDefault(),n.stopPropagation(),await this.activateCommandPaletteItem();return}n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),e?.addEventListener("keydown",n=>{n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),s?.addEventListener?.("click",n=>{const i=n.target?.closest?.("[data-command-index]");i&&(this.commandPaletteActiveIndex=Number(i.dataset.commandIndex)||0,this.activateCommandPaletteItem())})},buildCommandPaletteItems(e=""){const t=e.trim().toLowerCase(),s=[...Array.isArray(this.sessionOrder)?this.sessionOrder:[],...Array.from(this.sessions?.keys?.()||[]).filter(a=>!this.sessionOrder?.includes?.(a))],n=new Set,i=[];for(const a of s){if(n.has(a))continue;n.add(a);const r=this.sessions?.get?.(a);if(!r)continue;const o=this.getSessionName?.(r)||r.name||r.title||a.slice(0,8),l=[r.workingDir,r.mode,r.status].filter(Boolean),d=[o,r.workingDir,r.mode,r.status,a].filter(Boolean).join(" ").toLowerCase();t&&!d.includes(t)||i.push({id:`session:${a}`,type:"session",sessionId:a,title:o,subtitle:l.join(" \xB7 ")})}return i.push(this._buildCommandPaletteNewSessionItem(e)),i.push({id:"browse-sessions",type:"browse-sessions",title:"Browse all sessions\u2026",subtitle:"Open Session Manager"}),i},_buildCommandPaletteNewSessionItem(e=""){const t=this.runMode||this._runMode||"claude",s={claude:"Claude",opencode:"OpenCode",codex:"Codex",gemini:"Gemini"},n=this._findCommandPaletteCaseMatch(e)||document.getElementById("quickStartCase")?.value||"testcase";return{id:"new-session",type:"new-session",caseName:n,title:"New session",subtitle:`Run ${s[t]||t} in ${n}`}},_findCommandPaletteCaseMatch(e=""){const t=e.trim().toLowerCase();if(!t||!Array.isArray(this.cases))return null;const s=a=>{const r=String(a?.name||"").trim();if(!r)return 0;const o=[r,a?.path,a?.casePath,a?.workingDir,a?.remote?.path,a?.remote?.hostId].filter(Boolean).join(" ").toLowerCase(),l=r.toLowerCase();return l===t?100:l.startsWith(t)?90:l.includes(t)?80:o.includes(t)?60:0};let n=null,i=0;for(const a of this.cases){const r=s(a);r>i&&(n=a,i=r)}return n?.name||null},renderCommandPalette(){const e=document.getElementById("commandPaletteSearch"),t=document.getElementById("commandPaletteList");if(!t)return;const s=e?.value||"",n=this.buildCommandPaletteItems(s);this.commandPaletteItems=n,this.commandPaletteActiveIndex=Math.max(0,Math.min(this.commandPaletteActiveIndex||0,n.length-1)),t.innerHTML=n.map((i,a)=>{const r=a===this.commandPaletteActiveIndex?" active":"",o=i.type==="new-session"?"+":i.type==="browse-sessions"?"\u2261":"\u203A",l=i.type==="browse-sessions"?" command-palette-item--browse":"";return`
2
- <button class="command-palette-item${r}${l}" type="button" data-command-index="${a}">
1
+ "use strict";const AWAY_DIGEST_LAST_VIEWED_KEY="codeman-away-digest-last-viewed",AWAY_DIGEST_SECTIONS=[["needsAttention","Needs Attention"],["completed","Completed"],["stillRunning","Still Running"],["idle","Idle"],["informational","Informational"]];Object.assign(CodemanApp.prototype,{_addActivityEntry(e,t,s=50){const n=this.subagentActivity.get(e)||[];n.push(t),n.length>s&&n.shift(),this.subagentActivity.set(e,n)},_onTaskCreated(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskCompleted(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskFailed(e){this.renderSessionTabs(),e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onTaskUpdated(e){e.sessionId===this.activeSessionId&&this.renderTaskPanel()},_onMuxCreated(e){this.muxSessions.push(e),this.renderMuxSessions()},_onMuxKilled(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions()},_onMuxDied(e){this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e.sessionId),this.renderMuxSessions(),this.showToast("Mux session died: "+this.getShortId(e.sessionId),"warning")},_onMuxStatsUpdated(e){this.muxSessions=e,document.getElementById("monitorPanel").classList.contains("open")&&this.renderMuxSessions()},_onBashToolStart(e){this.handleBashToolStart(e.sessionId,e.tool)},_onBashToolEnd(e){this.handleBashToolEnd(e.sessionId,e.tool)},_onBashToolsUpdate(e){this.handleBashToolsUpdate(e.sessionId,e.tools)},_onSubagentDiscovered(e){this.subagents.set(e.agentId,e),this.subagentActivity.set(e.agentId,[]),this.subagentToolResults.delete(e.agentId),this.subagentWindows.has(e.agentId)&&this.forceCloseSubagentWindow(e.agentId),this.renderSubagentPanel(),this.findParentSessionForSubagent(e.agentId),requestAnimationFrame(()=>{this.updateConnectionLines()});const t=this.subagentParentMap.get(e.agentId);this._notifySession(t||e.sessionId,"info","subagent-spawn","Subagent Spawned",e.description||"New background agent started")},_onSubagentUpdated(e){const t=this.subagents.get(e.agentId);t?(Object.assign(t,e),this.subagents.set(e.agentId,t)):this.subagents.set(e.agentId,e),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&(this.renderSubagentWindowContent(e.agentId),this.updateSubagentWindowHeader(e.agentId))},_onSubagentToolCall(e){this._addActivityEntry(e.agentId,{type:"tool",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.renderSubagentPanel(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentProgress(e){this._addActivityEntry(e.agentId,{type:"progress",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentMessage(e){this._addActivityEntry(e.agentId,{type:"message",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},_onSubagentToolResult(e){this.subagentToolResults.has(e.agentId)||this.subagentToolResults.set(e.agentId,new Map);const t=this.subagentToolResults.get(e.agentId);if(t.set(e.toolUseId,e),t.size>50){const s=t.keys().next().value;t.delete(s)}this._addActivityEntry(e.agentId,{type:"tool_result",...e}),this.activeSubagentId===e.agentId&&this.renderSubagentDetail(),this.subagentWindows.has(e.agentId)&&this.scheduleSubagentWindowRender(e.agentId)},async _onSubagentCompleted(e){const t=this.subagents.get(e.agentId);if(t&&(t.status="completed",this.subagents.set(e.agentId,t)),this.renderSubagentPanel(),this.updateSubagentWindows(),this.subagentWindows.has(e.agentId)){const n=this.subagentWindows.get(e.agentId);n&&!n.minimized&&(await this.closeSubagentWindow(e.agentId),this.saveSubagentWindowStates())}const s=this.subagentParentMap.get(e.agentId);this._notifySession(s||t?.sessionId||e.sessionId,"info","subagent-complete","Subagent Completed",t?.description||e.description||"Background agent finished"),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&(this.subagentActivity.delete(e.agentId),this.subagentToolResults.delete(e.agentId))},300*1e3),setTimeout(()=>{this.subagents.get(e.agentId)?.status==="completed"&&!this.subagentWindows.has(e.agentId)&&(this.subagents.delete(e.agentId),this.subagentParentMap.delete(e.agentId))},1800*1e3)},_onImageDetected(e){console.log("[Image Detected]",e),this.openImagePopup(e)},shouldOpenCommandPaletteFromShortcut(e){if(!e||!e.ctrlKey&&!e.metaKey&&!e.altKey)return!1;const s=typeof this.getShortcutRegistry=="function"&&typeof this.matchesShortcutEvent=="function"?this.getShortcutRegistry().find(o=>o.id==="command-palette"):null;if(s){if(s.disabled||!this.matchesShortcutEvent(e,s))return!1}else if((e.key||"").toLowerCase()!=="k"&&e.code!=="KeyK"||e.shiftKey)return!1;const n=e.target;if(!n)return!0;const a=(n.tagName||"").toUpperCase(),i=typeof n.className=="string"?n.className:"";return n.classList?.contains?.("xterm-helper-textarea")||i.includes("xterm-helper-textarea")?!0:!(a==="INPUT"||a==="TEXTAREA"||a==="SELECT"||n.isContentEditable||typeof n.closest=="function"&&n.closest('[contenteditable="true"]'))},openCommandPalette(){const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch");!e||!t||(this.commandPaletteActiveIndex=0,t.value="",e.classList.add("active"),this._wireCommandPalette(),this.renderCommandPalette(),t.focus(),t.select?.())},closeCommandPalette(){const e=document.getElementById("commandPaletteModal");e&&e.classList.remove("active")},_wireCommandPalette(){if(this._commandPaletteWired)return;this._commandPaletteWired=!0;const e=document.getElementById("commandPaletteModal"),t=document.getElementById("commandPaletteSearch"),s=document.getElementById("commandPaletteList");t?.addEventListener("input",()=>{this.commandPaletteActiveIndex=0,this.renderCommandPalette()}),t?.addEventListener("keydown",async n=>{if(n.key==="ArrowDown"){n.preventDefault(),this.moveCommandPaletteSelection(1);return}if(n.key==="ArrowUp"){n.preventDefault(),this.moveCommandPaletteSelection(-1);return}if(n.key==="Enter"){n.preventDefault(),n.stopPropagation(),await this.activateCommandPaletteItem();return}n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),e?.addEventListener("keydown",n=>{n.key==="Escape"&&(n.preventDefault(),this.closeCommandPalette())}),s?.addEventListener?.("click",n=>{const a=n.target?.closest?.("[data-command-index]");a&&(this.commandPaletteActiveIndex=Number(a.dataset.commandIndex)||0,this.activateCommandPaletteItem())})},buildCommandPaletteItems(e=""){const t=e.trim().toLowerCase(),s=[...Array.isArray(this.sessionOrder)?this.sessionOrder:[],...Array.from(this.sessions?.keys?.()||[]).filter(i=>!this.sessionOrder?.includes?.(i))],n=new Set,a=[];for(const i of s){if(n.has(i))continue;n.add(i);const r=this.sessions?.get?.(i);if(!r)continue;const o=this.getSessionName?.(r)||r.name||r.title||i.slice(0,8),l=[r.workingDir,r.mode,r.status].filter(Boolean),d=[o,r.workingDir,r.mode,r.status,i].filter(Boolean).join(" ").toLowerCase();t&&!d.includes(t)||a.push({id:`session:${i}`,type:"session",sessionId:i,title:o,subtitle:l.join(" \xB7 ")})}return a.push(this._buildCommandPaletteNewSessionItem(e)),a.push({id:"browse-sessions",type:"browse-sessions",title:"Browse all sessions\u2026",subtitle:"Open Session Manager"}),a},_buildCommandPaletteNewSessionItem(e=""){const t=this.runMode||this._runMode||"claude",s={claude:"Claude",opencode:"OpenCode",codex:"Codex",gemini:"Gemini"},n=this._findCommandPaletteCaseMatch(e)||document.getElementById("quickStartCase")?.value||"testcase";return{id:"new-session",type:"new-session",caseName:n,title:"New session",subtitle:`Run ${s[t]||t} in ${n}`}},_findCommandPaletteCaseMatch(e=""){const t=e.trim().toLowerCase();if(!t||!Array.isArray(this.cases))return null;const s=i=>{const r=String(i?.name||"").trim();if(!r)return 0;const o=[r,i?.path,i?.casePath,i?.workingDir,i?.remote?.path,i?.remote?.hostId].filter(Boolean).join(" ").toLowerCase(),l=r.toLowerCase();return l===t?100:l.startsWith(t)?90:l.includes(t)?80:o.includes(t)?60:0};let n=null,a=0;for(const i of this.cases){const r=s(i);r>a&&(n=i,a=r)}return n?.name||null},renderCommandPalette(){const e=document.getElementById("commandPaletteSearch"),t=document.getElementById("commandPaletteList");if(!t)return;const s=e?.value||"",n=this.buildCommandPaletteItems(s);this.commandPaletteItems=n,this.commandPaletteActiveIndex=Math.max(0,Math.min(this.commandPaletteActiveIndex||0,n.length-1)),t.innerHTML=n.map((a,i)=>{const r=i===this.commandPaletteActiveIndex?" active":"",o=a.type==="new-session"?"+":a.type==="browse-sessions"?"\u2261":"\u203A",l=a.type==="browse-sessions"?" command-palette-item--browse":"";return`
2
+ <button class="command-palette-item${r}${l}" type="button" data-command-index="${i}">
3
3
  <span class="command-palette-icon" aria-hidden="true">${o}</span>
4
4
  <span class="command-palette-text">
5
- <span class="command-palette-title">${escapeHtml(i.title)}</span>
6
- <span class="command-palette-subtitle">${escapeHtml(i.subtitle||"")}</span>
5
+ <span class="command-palette-title">${escapeHtml(a.title)}</span>
6
+ <span class="command-palette-subtitle">${escapeHtml(a.subtitle||"")}</span>
7
7
  </span>
8
8
  </button>
9
- `}).join("")},moveCommandPaletteSelection(e){const t=this.commandPaletteItems||this.buildCommandPaletteItems(document.getElementById("commandPaletteSearch")?.value||"");t.length&&(this.commandPaletteActiveIndex=(this.commandPaletteActiveIndex+e+t.length)%t.length,this.renderCommandPalette())},async activateCommandPaletteItem(e=this.commandPaletteActiveIndex||0){const t=(this.commandPaletteItems||[])[e];if(t){if(this.closeCommandPalette(),t.type==="session"&&t.sessionId){await this.selectSession(t.sessionId);return}if(t.type==="browse-sessions"){this.openSessionManager();return}if(t.type==="new-session"){const s=document.getElementById("quickStartCase");if(s&&t.caseName){if(s.tagName==="SELECT"&&typeof s.appendChild=="function"&&!Array.from(s.options||[]).some(n=>n.value===t.caseName)){const n=document.createElement("option");n.value=t.caseName,n.textContent=t.caseName,s.appendChild(n)}typeof this.selectQuickStartCase=="function"?this.selectQuickStartCase(t.caseName):s.value=t.caseName}await this.run()}}},async openSessionManager(){const e=document.getElementById("sessionManagerModal");if(e&&(e.classList.add("active"),this._sessionManagerEscWired||(this._sessionManagerEscWired=!0,e.addEventListener("keydown",s=>{s.key==="Escape"&&(s.preventDefault(),s.stopPropagation(),this.closeSessionManager())}))),!Array.isArray(this.cases)||this.cases.length===0)try{const s=await fetch("/api/cases"),n=s.ok?await s.json():null;this.cases=n?.data||[]}catch{this.cases=this.cases||[]}const t=document.getElementById("sessionManagerSearch");t&&(this._sessionManagerSearchWired||(this._sessionManagerSearchWired=!0,t.addEventListener("input",()=>{const s=t.value.trim();this._debouncedCall("sessionManagerSearch",()=>this._loadSessionManagerList(s),200)})),t.value="",t.focus()),await this._loadSessionManagerList("")},closeSessionManager(){const e=document.getElementById("sessionManagerModal");e&&e.classList.remove("active")},_setSessionManagerMessage(e,t){e.replaceChildren();const s=document.createElement("p");s.className="empty-message",s.textContent=t,e.appendChild(s)},async _loadSessionManagerList(e=""){this._sessionManagerQuery=e;const t=document.getElementById("sessionManagerList");if(t)try{const s="/api/sessions/unified?limit=200"+(e?"&q="+encodeURIComponent(e):""),n=await fetch(s),i=await n.json().catch(()=>null);if(!n.ok||!i||i.success===!1||!i.data){this._setSessionManagerMessage(t,i?.error||`Failed to load sessions (HTTP ${n.status})`);return}const a=i.data.sessions||[];if(t.replaceChildren(),a.length===0){this._setSessionManagerMessage(t,e?"No sessions match your search":"No sessions found");return}for(const r of a){const o={sessionId:r.sessionId,workingDir:r.workingDir||"",sizeBytes:r.sizeBytes??0,lastModified:new Date(r.lastActivityAt??r.createdAt??Date.now()).toISOString(),firstPrompt:r.firstPrompt||r.name||""},l=!!this.sessions?.has?.(r.sessionId),d=this._buildHistoryItem(o,this.cases,{showViewAll:!1,onActivate:()=>{this.closeSessionManager(),l?this.selectSession(r.sessionId):o.workingDir&&this.resumeHistorySession(r.claudeSessionId||r.sessionId,o.workingDir)}});t.appendChild(d)}}catch(s){console.error("[_loadSessionManagerList]",s),this._setSessionManagerMessage(t,"Failed to load sessions")}},async openAwayDigest(e="since-last-visit"){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this._awayDigestSinceLastVisitGeneratedAt=void 0;const t=document.getElementById("awayDigestModal");t&&t.classList.add("active"),this.updateAwayDigestRangeControls(),await this.loadAwayDigest()},closeAwayDigest(){const e=document.getElementById("awayDigestModal"),t=this._awayDigestSinceLastVisitGeneratedAt;if(Number.isFinite(t))try{localStorage.setItem(AWAY_DIGEST_LAST_VIEWED_KEY,String(t))}catch(s){console.warn("Failed to save away digest last-viewed marker:",s)}e&&e.classList.remove("active")},_onSessionListMaybeChanged(){const e=document.getElementById("sessionManagerModal");e&&e.classList.contains("active")&&this._debouncedCall("sessionManagerRefresh",()=>this._loadSessionManagerList(this._sessionManagerQuery||""),400);const t=document.getElementById("welcomeOverlay");t&&t.classList.contains("visible")&&this._debouncedCall("welcomeHistoryRefresh",()=>this.loadHistorySessions(),600)},setAwayDigestRange(e){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this.updateAwayDigestRangeControls(),this.loadAwayDigest()},updateAwayDigestRangeControls(){const e=this.awayDigestRange||"since-last-visit";document.querySelectorAll("[data-away-range]").forEach(s=>{s.classList.toggle("active",s.dataset.awayRange===e)});const t=document.getElementById("awayDigestCustomRange");t&&t.classList.toggle("active",e==="custom"),e==="custom"&&this.ensureAwayDigestCustomDefaults()},ensureAwayDigestCustomDefaults(){const e=document.getElementById("awayDigestCustomSince"),t=document.getElementById("awayDigestCustomUntil");if(!e||!t)return;const s=new Date;if(t.value||(t.value=this.formatAwayDigestDateTimeLocal(s)),!e.value){const n=new Date(s.getTime()-36e5);e.value=this.formatAwayDigestDateTimeLocal(n)}},formatAwayDigestDateTimeLocal(e){const t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`},async loadAwayDigest(){const e=document.getElementById("awayDigestSummary"),t=document.getElementById("awayDigestFreshness"),s=document.getElementById("awayDigestSections");e&&(e.innerHTML='<div class="away-digest-loading">Loading digest...</div>'),t&&(t.textContent=""),s&&(s.innerHTML="");try{const n=this.awayDigestRange||"since-last-visit",i=new URLSearchParams({range:n});if(n==="since-last-visit"){const o=this.readAwayDigestLastViewed();Number.isFinite(o)&&i.set("lastViewed",String(o))}if(n==="custom"){this.ensureAwayDigestCustomDefaults();const o=this.readAwayDigestDateTimeInput("awayDigestCustomSince"),l=this.readAwayDigestDateTimeInput("awayDigestCustomUntil");if(!Number.isFinite(o))throw new Error("Choose a custom start time");i.set("since",String(o)),Number.isFinite(l)&&i.set("until",String(l))}const a=await fetch(`/api/away-digest?${i.toString()}`),r=await a.json();if(!a.ok||!r.success)throw new Error(r.error||"Failed to load away digest");this._awayDigestLoadedSuccessfully=!0,this._awayDigestGeneratedAt=r.digest.generatedAt,n==="since-last-visit"&&(this._awayDigestSinceLastVisitGeneratedAt=r.digest.generatedAt),this.renderAwayDigest(r.digest)}catch(n){const i=n instanceof Error?n.message:"Failed to load away digest";console.error("Failed to fetch away digest:",n),e&&(e.innerHTML='<div class="away-digest-load-error">Failed to load away digest</div>'),s&&(s.innerHTML=`<div class="empty-message">${escapeHtml(i)}</div>`),this.showToast(i,"error")}},readAwayDigestLastViewed(){try{const e=localStorage.getItem(AWAY_DIGEST_LAST_VIEWED_KEY),t=Number(e);return Number.isFinite(t)?t:void 0}catch{return}},readAwayDigestDateTimeInput(e){const t=document.getElementById(e);if(!t||!t.value)return;const s=Date.parse(t.value);return Number.isFinite(s)?s:void 0},renderAwayDigest(e){const t=document.getElementById("awayDigestSummary"),s=document.getElementById("awayDigestFreshness"),n=document.getElementById("awayDigestSections");if(!t||!s||!n)return;const i=e.totals.inputTokens||0,a=e.totals.outputTokens||0,r=e.totals.estimatedCost||0;t.innerHTML=`
9
+ `}).join("")},moveCommandPaletteSelection(e){const t=this.commandPaletteItems||this.buildCommandPaletteItems(document.getElementById("commandPaletteSearch")?.value||"");t.length&&(this.commandPaletteActiveIndex=(this.commandPaletteActiveIndex+e+t.length)%t.length,this.renderCommandPalette())},async activateCommandPaletteItem(e=this.commandPaletteActiveIndex||0){const t=(this.commandPaletteItems||[])[e];if(t){if(this.closeCommandPalette(),t.type==="session"&&t.sessionId){await this.selectSession(t.sessionId);return}if(t.type==="browse-sessions"){this.openSessionManager();return}if(t.type==="new-session"){const s=document.getElementById("quickStartCase");if(s&&t.caseName){if(s.tagName==="SELECT"&&typeof s.appendChild=="function"&&!Array.from(s.options||[]).some(n=>n.value===t.caseName)){const n=document.createElement("option");n.value=t.caseName,n.textContent=t.caseName,s.appendChild(n)}typeof this.selectQuickStartCase=="function"?this.selectQuickStartCase(t.caseName):s.value=t.caseName}await this.run()}}},async openSessionManager(){const e=document.getElementById("sessionManagerModal");if(e&&(e.classList.add("active"),this._sessionManagerEscWired||(this._sessionManagerEscWired=!0,e.addEventListener("keydown",s=>{s.key==="Escape"&&(s.preventDefault(),s.stopPropagation(),this.closeSessionManager())}))),!Array.isArray(this.cases)||this.cases.length===0)try{const s=await fetch("/api/cases"),n=s.ok?await s.json():null;this.cases=n?.data||[]}catch{this.cases=this.cases||[]}const t=document.getElementById("sessionManagerSearch");t&&(this._sessionManagerSearchWired||(this._sessionManagerSearchWired=!0,t.addEventListener("input",()=>{const s=t.value.trim();this._debouncedCall("sessionManagerSearch",()=>this._loadSessionManagerList(s),200)})),t.value="",t.focus()),await this._loadSessionManagerList("")},closeSessionManager(){const e=document.getElementById("sessionManagerModal");e&&e.classList.remove("active")},_setSessionManagerMessage(e,t){e.replaceChildren();const s=document.createElement("p");s.className="empty-message",s.textContent=t,e.appendChild(s)},async _loadSessionManagerList(e=""){this._sessionManagerQuery=e;const t=document.getElementById("sessionManagerList");if(t)try{const s="/api/sessions/unified?limit=200"+(e?"&q="+encodeURIComponent(e):""),n=await fetch(s),a=await n.json().catch(()=>null);if(!n.ok||!a||a.success===!1||!a.data){this._setSessionManagerMessage(t,a?.error||`Failed to load sessions (HTTP ${n.status})`);return}const i=a.data.sessions||[];if(t.replaceChildren(),i.length===0){this._setSessionManagerMessage(t,e?"No sessions match your search":"No sessions found");return}for(const r of i){const o={sessionId:r.sessionId,workingDir:r.workingDir||"",sizeBytes:r.sizeBytes??0,lastModified:new Date(r.lastActivityAt??r.createdAt??Date.now()).toISOString(),firstPrompt:r.firstPrompt||r.name||""},l=!!this.sessions?.has?.(r.sessionId),d=this._buildHistoryItem(o,this.cases,{showViewAll:!1,onActivate:()=>{this.closeSessionManager(),l?this.selectSession(r.sessionId):o.workingDir&&this.resumeHistorySession(r.claudeSessionId||r.sessionId,o.workingDir)}});t.appendChild(d)}}catch(s){console.error("[_loadSessionManagerList]",s),this._setSessionManagerMessage(t,"Failed to load sessions")}},async openAwayDigest(e="since-last-visit"){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this._awayDigestSinceLastVisitGeneratedAt=void 0;const t=document.getElementById("awayDigestModal");t&&t.classList.add("active"),this.updateAwayDigestRangeControls(),await this.loadAwayDigest()},closeAwayDigest(){const e=document.getElementById("awayDigestModal"),t=this._awayDigestSinceLastVisitGeneratedAt;if(Number.isFinite(t))try{localStorage.setItem(AWAY_DIGEST_LAST_VIEWED_KEY,String(t))}catch(s){console.warn("Failed to save away digest last-viewed marker:",s)}e&&e.classList.remove("active")},_onSessionListMaybeChanged(){const e=document.getElementById("sessionManagerModal");e&&e.classList.contains("active")&&this._debouncedCall("sessionManagerRefresh",()=>this._loadSessionManagerList(this._sessionManagerQuery||""),400);const t=document.getElementById("welcomeOverlay");t&&t.classList.contains("visible")&&this._debouncedCall("welcomeHistoryRefresh",()=>this.loadHistorySessions(),600)},setAwayDigestRange(e){this.awayDigestRange=e,this._awayDigestLoadedSuccessfully=!1,this.updateAwayDigestRangeControls(),this.loadAwayDigest()},updateAwayDigestRangeControls(){const e=this.awayDigestRange||"since-last-visit";document.querySelectorAll("[data-away-range]").forEach(s=>{s.classList.toggle("active",s.dataset.awayRange===e)});const t=document.getElementById("awayDigestCustomRange");t&&t.classList.toggle("active",e==="custom"),e==="custom"&&this.ensureAwayDigestCustomDefaults()},ensureAwayDigestCustomDefaults(){const e=document.getElementById("awayDigestCustomSince"),t=document.getElementById("awayDigestCustomUntil");if(!e||!t)return;const s=new Date;if(t.value||(t.value=this.formatAwayDigestDateTimeLocal(s)),!e.value){const n=new Date(s.getTime()-36e5);e.value=this.formatAwayDigestDateTimeLocal(n)}},formatAwayDigestDateTimeLocal(e){const t=s=>String(s).padStart(2,"0");return`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}T${t(e.getHours())}:${t(e.getMinutes())}`},async loadAwayDigest(){const e=document.getElementById("awayDigestSummary"),t=document.getElementById("awayDigestFreshness"),s=document.getElementById("awayDigestSections");e&&(e.innerHTML='<div class="away-digest-loading">Loading digest...</div>'),t&&(t.textContent=""),s&&(s.innerHTML="");try{const n=this.awayDigestRange||"since-last-visit",a=new URLSearchParams({range:n});if(n==="since-last-visit"){const o=this.readAwayDigestLastViewed();Number.isFinite(o)&&a.set("lastViewed",String(o))}if(n==="custom"){this.ensureAwayDigestCustomDefaults();const o=this.readAwayDigestDateTimeInput("awayDigestCustomSince"),l=this.readAwayDigestDateTimeInput("awayDigestCustomUntil");if(!Number.isFinite(o))throw new Error("Choose a custom start time");a.set("since",String(o)),Number.isFinite(l)&&a.set("until",String(l))}const i=await fetch(`/api/away-digest?${a.toString()}`),r=await i.json();if(!i.ok||!r.success)throw new Error(r.error||"Failed to load away digest");this._awayDigestLoadedSuccessfully=!0,this._awayDigestGeneratedAt=r.digest.generatedAt,n==="since-last-visit"&&(this._awayDigestSinceLastVisitGeneratedAt=r.digest.generatedAt),this.renderAwayDigest(r.digest)}catch(n){const a=n instanceof Error?n.message:"Failed to load away digest";console.error("Failed to fetch away digest:",n),e&&(e.innerHTML='<div class="away-digest-load-error">Failed to load away digest</div>'),s&&(s.innerHTML=`<div class="empty-message">${escapeHtml(a)}</div>`),this.showToast(a,"error")}},readAwayDigestLastViewed(){try{const e=localStorage.getItem(AWAY_DIGEST_LAST_VIEWED_KEY),t=Number(e);return Number.isFinite(t)?t:void 0}catch{return}},readAwayDigestDateTimeInput(e){const t=document.getElementById(e);if(!t||!t.value)return;const s=Date.parse(t.value);return Number.isFinite(s)?s:void 0},renderAwayDigest(e){const t=document.getElementById("awayDigestSummary"),s=document.getElementById("awayDigestFreshness"),n=document.getElementById("awayDigestSections");if(!t||!s||!n)return;const a=e.totals.inputTokens||0,i=e.totals.outputTokens||0,r=e.totals.estimatedCost||0;t.innerHTML=`
10
10
  <div class="away-digest-card">
11
11
  <span class="away-digest-card-label">Needs Attention</span>
12
12
  <span class="away-digest-card-value">${e.totals.needsAttention}</span>
@@ -21,10 +21,10 @@
21
21
  </div>
22
22
  <div class="away-digest-card">
23
23
  <span class="away-digest-card-label">Tokens</span>
24
- <span class="away-digest-card-value">${this.formatTokens(i+a)}</span>
24
+ <span class="away-digest-card-value">${this.formatTokens(a+i)}</span>
25
25
  <span class="away-digest-card-cost">~$${r.toFixed(2)}</span>
26
26
  </div>
27
- `;const o=[];(e.dataFreshness.runSummariesLiveOnly||e.dataFreshness.subagentsLiveOnly)&&o.push("Run summaries and subagent completions use recent live state; lifecycle and token stats are persisted."),e.totals.tokenWindowPrecision==="day"&&o.push("Token totals are aggregated at day precision."),s.textContent=o.join(" "),n.innerHTML=AWAY_DIGEST_SECTIONS.map(([l,d])=>this.renderAwayDigestSection(d,e.sections[l]||[])).join(""),this.attachAwayDigestActions()},renderAwayDigestSection(e,t){const s=t.length,n=s?t.map(i=>this.renderAwayDigestItem(i)).join(""):'<div class="away-digest-empty">No items</div>';return`
27
+ `;const o=[];(e.dataFreshness.runSummariesLiveOnly||e.dataFreshness.subagentsLiveOnly)&&o.push("Run summaries and subagent completions use recent live state; lifecycle and token stats are persisted."),e.totals.tokenWindowPrecision==="day"&&o.push("Token totals are aggregated at day precision."),s.textContent=o.join(" "),n.innerHTML=AWAY_DIGEST_SECTIONS.map(([l,d])=>this.renderAwayDigestSection(d,e.sections[l]||[])).join(""),this.attachAwayDigestActions()},renderAwayDigestSection(e,t){const s=t.length,n=s?t.map(a=>this.renderAwayDigestItem(a)).join(""):'<div class="away-digest-empty">No items</div>';return`
28
28
  <section class="away-digest-section">
29
29
  <div class="away-digest-section-title">
30
30
  <h4>${escapeHtml(e)}</h4>
@@ -32,7 +32,7 @@
32
32
  </div>
33
33
  ${n}
34
34
  </section>
35
- `},renderAwayDigestItem(e){const t=this.formatAwayDigestSource(e.source),s=e.sessionName||e.sessionId||"",n=e.detail?`<div class="away-digest-item-detail">${escapeHtml(e.detail)}</div>`:"",i=e.link?`
35
+ `},renderAwayDigestItem(e){const t=this.formatAwayDigestSource(e.source),s=e.sessionName||e.sessionId||"",n=e.detail?`<div class="away-digest-item-detail">${escapeHtml(e.detail)}</div>`:"",a=e.link?`
36
36
  <button class="away-digest-action"
37
37
  data-away-link-type="${escapeHtml(e.link.type)}"
38
38
  data-away-session-id="${escapeHtml(e.link.sessionId||"")}">
@@ -49,13 +49,13 @@
49
49
  <div class="away-digest-item-title">${escapeHtml(e.title)}</div>
50
50
  ${n}
51
51
  </div>
52
- ${i}
52
+ ${a}
53
53
  </article>
54
- `},attachAwayDigestActions(){const e=document.getElementById("awayDigestSections");e&&e.querySelectorAll("[data-away-link-type]").forEach(t=>{t.addEventListener("click",()=>{this.openAwayDigestItem(t.dataset.awayLinkType,t.dataset.awaySessionId||void 0)})})},async openAwayDigestItem(e,t){if(e==="session"&&t){await this.selectSession(t),this.closeAwayDigest();return}if(e==="run_summary"&&t){await this.openRunSummary(t),this.closeAwayDigest();return}e==="lifecycle"&&(this.openLifecycleLog(),this.closeAwayDigest())},formatAwayDigestTimestamp(e){return Number.isFinite(e)?new Date(e).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}):""},formatAwayDigestSource(e){return{lifecycle:"Lifecycle",run_summary:"Run Summary",status:"Status",token_stats:"Token Stats",subagent:"Subagent"}[e]||e},async openTokenStats(){try{const t=await(await fetch("/api/token-stats")).json();t.success?(this.renderTokenStats(t.data),document.getElementById("tokenStatsModal").classList.add("active")):this.showToast("Failed to load token stats","error")}catch(e){console.error("Failed to fetch token stats:",e),this.showToast("Failed to load token stats","error")}},renderTokenStats(e){const{daily:t,totals:s}=e,n=new Date().toISOString().split("T")[0],i=t.find(g=>g.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},a=new Date;a.setDate(a.getDate()-7);const r=t.filter(g=>new Date(g.date)>=a),o=r.reduce((g,S)=>g+S.inputTokens,0),l=r.reduce((g,S)=>g+S.outputTokens,0),d=this.estimateCost(o,l),c=s.totalInputTokens,m=s.totalOutputTokens,u=this.estimateCost(c,m),h=document.getElementById("statsSummary");h.innerHTML=`
54
+ `},attachAwayDigestActions(){const e=document.getElementById("awayDigestSections");e&&e.querySelectorAll("[data-away-link-type]").forEach(t=>{t.addEventListener("click",()=>{this.openAwayDigestItem(t.dataset.awayLinkType,t.dataset.awaySessionId||void 0)})})},async openAwayDigestItem(e,t){if(e==="session"&&t){await this.selectSession(t),this.closeAwayDigest();return}if(e==="run_summary"&&t){await this.openRunSummary(t),this.closeAwayDigest();return}e==="lifecycle"&&(this.openLifecycleLog(),this.closeAwayDigest())},formatAwayDigestTimestamp(e){return Number.isFinite(e)?new Date(e).toLocaleString([],{month:"short",day:"numeric",hour:"numeric",minute:"2-digit"}):""},formatAwayDigestSource(e){return{lifecycle:"Lifecycle",run_summary:"Run Summary",status:"Status",token_stats:"Token Stats",subagent:"Subagent"}[e]||e},async openTokenStats(){try{const t=await(await fetch("/api/token-stats")).json();t.success?(this.renderTokenStats(t.data),document.getElementById("tokenStatsModal").classList.add("active")):this.showToast("Failed to load token stats","error")}catch(e){console.error("Failed to fetch token stats:",e),this.showToast("Failed to load token stats","error")}},renderTokenStats(e){const{daily:t,totals:s}=e,n=new Date().toISOString().split("T")[0],a=t.find(g=>g.date===n)||{inputTokens:0,outputTokens:0,estimatedCost:0},i=new Date;i.setDate(i.getDate()-7);const r=t.filter(g=>new Date(g.date)>=i),o=r.reduce((g,S)=>g+S.inputTokens,0),l=r.reduce((g,S)=>g+S.outputTokens,0),d=this.estimateCost(o,l),c=s.totalInputTokens,m=s.totalOutputTokens,u=this.estimateCost(c,m),h=document.getElementById("statsSummary");h.innerHTML=`
55
55
  <div class="stat-card">
56
56
  <span class="stat-card-label">Today</span>
57
- <span class="stat-card-value">${this.formatTokens(i.inputTokens+i.outputTokens)}</span>
58
- <span class="stat-card-cost">~$${i.estimatedCost.toFixed(2)}</span>
57
+ <span class="stat-card-value">${this.formatTokens(a.inputTokens+a.outputTokens)}</span>
58
+ <span class="stat-card-cost">~$${a.estimatedCost.toFixed(2)}</span>
59
59
  </div>
60
60
  <div class="stat-card">
61
61
  <span class="stat-card-label">7 Days</span>
@@ -82,7 +82,7 @@
82
82
  <span class="cell cell-cost">$${g.estimatedCost.toFixed(2)}</span>
83
83
  </div>
84
84
  `).join("")}
85
- `},closeTokenStats(){const e=document.getElementById("tokenStatsModal");e&&e.classList.remove("active")},async toggleMonitorPanel(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorToggleBtn");e.classList.toggle("open"),e.classList.contains("open")?(e.style.display="",await this.loadMuxSessions(),await fetch("/api/mux-sessions/stats/start",{method:"POST"}),this.renderTaskPanel(),t&&(t.innerHTML="&#x25BC;")):(await fetch("/api/mux-sessions/stats/stop",{method:"POST"}),t&&(t.innerHTML="&#x25B2;"))},toggleTaskPanel(){this.toggleMonitorPanel()},toggleMonitorDetach(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupMonitorDrag())},setupMonitorDrag(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorPanelHeader");if(!e||!t)return;let s=!1,n,i,a,r;const o=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const m=getEventCoords(c);n=m.clientX,i=m.clientY;const u=e.getBoundingClientRect();a=u.left,r=u.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const m=getEventCoords(c),u=m.clientX-n,h=m.clientY-i;let p=a+u,y=r+h;const b=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-b.width,p)),y=Math.max(0,Math.min(window.innerHeight-b.height,y)),e.style.left=p+"px",e.style.top=y+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=o,t._touchDragHandler=o,t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})},toggleSubagentsDetach(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupSubagentsDrag())},setupSubagentsDrag(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsPanelHeader");if(!e||!t)return;let s=!1,n,i,a,r;const o=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const m=getEventCoords(c);n=m.clientX,i=m.clientY;const u=e.getBoundingClientRect();a=u.left,r=u.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const m=getEventCoords(c),u=m.clientX-n,h=m.clientY-i;let p=a+u,y=r+h;const b=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-b.width,p)),y=Math.max(0,Math.min(window.innerHeight-b.height,y)),e.style.left=p+"px",e.style.top=y+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=o,t._touchDragHandler=o,t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})},renderTaskPanel(){this._debouncedCall("taskPanel",this._renderTaskPanelImmediate)},_renderTaskPanelImmediate(){const e=this.sessions.get(this.activeSessionId),t=document.getElementById("backgroundTasksBody"),s=document.getElementById("taskPanelStats"),n=document.getElementById("backgroundTasksSection");if(!e||!e.taskTree||e.taskTree.length===0){n&&(n.style.display="none"),t.innerHTML="",s.textContent="0 tasks";return}n&&(n.style.display="");const i=e.taskStats||{running:0,completed:0,failed:0,total:0};s.textContent=`${i.running} running, ${i.completed} done`;const a=(l,d)=>{const c=l.status==="running"?"":l.status==="completed"?"&#x2713;":"&#x2717;",m=l.endTime?`${((l.endTime-l.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-l.startTime)/1e3).toFixed(0)}s...`;let u="";if(l.children&&l.children.length>0){u='<div class="task-children">';for(const h of l.children){const p=d.find(y=>y.id===h);p&&(u+=`<div class="task-node">${a(p,d)}</div>`)}u+="</div>"}return`
85
+ `},closeTokenStats(){const e=document.getElementById("tokenStatsModal");e&&e.classList.remove("active")},async toggleMonitorPanel(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorToggleBtn");e.classList.toggle("open"),e.classList.contains("open")?(e.style.display="",await this.loadMuxSessions(),await fetch("/api/mux-sessions/stats/start",{method:"POST"}),this.renderTaskPanel(),t&&(t.innerHTML="&#x25BC;")):(await fetch("/api/mux-sessions/stats/stop",{method:"POST"}),t&&(t.innerHTML="&#x25B2;"))},toggleTaskPanel(){this.toggleMonitorPanel()},toggleMonitorDetach(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupMonitorDrag())},setupMonitorDrag(){const e=document.getElementById("monitorPanel"),t=document.getElementById("monitorPanelHeader");if(!e||!t)return;let s=!1,n,a,i,r;const o=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const m=getEventCoords(c);n=m.clientX,a=m.clientY;const u=e.getBoundingClientRect();i=u.left,r=u.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const m=getEventCoords(c),u=m.clientX-n,h=m.clientY-a;let p=i+u,y=r+h;const b=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-b.width,p)),y=Math.max(0,Math.min(window.innerHeight-b.height,y)),e.style.left=p+"px",e.style.top=y+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=o,t._touchDragHandler=o,t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})},toggleSubagentsDetach(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsDetachBtn");e.classList.contains("detached")?(e.classList.remove("detached"),e.style.top="",e.style.left="",e.style.width="",e.style.height="",t&&(t.innerHTML="&#x29C9;",t.title="Detach panel")):(e.classList.add("detached"),e.classList.add("open"),t&&(t.innerHTML="&#x229E;",t.title="Attach panel"),this.setupSubagentsDrag())},setupSubagentsDrag(){const e=document.getElementById("subagentsPanel"),t=document.getElementById("subagentsPanelHeader");if(!e||!t)return;let s=!1,n,a,i,r;const o=c=>{if(c.target.closest("button")||!e.classList.contains("detached"))return;s=!0;const m=getEventCoords(c);n=m.clientX,a=m.clientY;const u=e.getBoundingClientRect();i=u.left,r=u.top,document.addEventListener("mousemove",l),document.addEventListener("mouseup",d),document.addEventListener("touchmove",l,{passive:!1}),document.addEventListener("touchend",d),c.preventDefault()},l=c=>{if(!s)return;const m=getEventCoords(c),u=m.clientX-n,h=m.clientY-a;let p=i+u,y=r+h;const b=e.getBoundingClientRect();p=Math.max(0,Math.min(window.innerWidth-b.width,p)),y=Math.max(0,Math.min(window.innerHeight-b.height,y)),e.style.left=p+"px",e.style.top=y+"px"},d=()=>{s=!1,document.removeEventListener("mousemove",l),document.removeEventListener("mouseup",d),document.removeEventListener("touchmove",l),document.removeEventListener("touchend",d)};t.removeEventListener("mousedown",t._dragHandler),t.removeEventListener("touchstart",t._touchDragHandler),t._dragHandler=o,t._touchDragHandler=o,t.addEventListener("mousedown",o),t.addEventListener("touchstart",o,{passive:!1})},renderTaskPanel(){this._debouncedCall("taskPanel",this._renderTaskPanelImmediate)},_renderTaskPanelImmediate(){const e=this.sessions.get(this.activeSessionId),t=document.getElementById("backgroundTasksBody"),s=document.getElementById("taskPanelStats"),n=document.getElementById("backgroundTasksSection");if(!e||!e.taskTree||e.taskTree.length===0){n&&(n.style.display="none"),t.innerHTML="",s.textContent="0 tasks";return}n&&(n.style.display="");const a=e.taskStats||{running:0,completed:0,failed:0,total:0};s.textContent=`${a.running} running, ${a.completed} done`;const i=(l,d)=>{const c=l.status==="running"?"":l.status==="completed"?"&#x2713;":"&#x2717;",m=l.endTime?`${((l.endTime-l.startTime)/1e3).toFixed(1)}s`:`${((Date.now()-l.startTime)/1e3).toFixed(0)}s...`;let u="";if(l.children&&l.children.length>0){u='<div class="task-children">';for(const h of l.children){const p=d.find(y=>y.id===h);p&&(u+=`<div class="task-node">${i(p,d)}</div>`)}u+="</div>"}return`
86
86
  <div class="task-item">
87
87
  <span class="task-status-icon ${l.status}">${c}</span>
88
88
  <div class="task-info">
@@ -94,8 +94,8 @@
94
94
  </div>
95
95
  </div>
96
96
  ${u}
97
- `},r=this.flattenTaskTree(e.taskTree);let o='<div class="task-tree">';for(const l of e.taskTree)o+=`<div class="task-node">${a(l,r)}</div>`;o+="</div>",t.innerHTML=o},flattenTaskTree(e,t=[]){for(const s of e)t.push(s);return t},toggleSubagentPanel(){this.toggleSubagentsPanel()},updateSubagentBadge(){const e=this.$("subagentCountBadge"),t=Array.from(this.subagents.values()).filter(s=>s.status==="active"||s.status==="idle").length;e&&(e.textContent=t>0?t:"")},renderSubagentPanel(){this._subagentPanelRenderTimeout&&clearTimeout(this._subagentPanelRenderTimeout),this._subagentPanelRenderTimeout=setTimeout(()=>{scheduleBackground(()=>this._renderSubagentPanelImmediate())},150)},_renderSubagentPanelImmediate(){const e=this.$("subagentList");if(!e||(this.updateSubagentBadge(),this.renderMonitorSubagents(),!this.subagentPanelVisible))return;if(this.subagents.size===0){e.innerHTML='<div class="subagent-empty">No background agents detected</div>';return}const t=[],s=Array.from(this.subagents.values()).sort((n,i)=>n.status==="active"&&i.status!=="active"?-1:i.status==="active"&&n.status!=="active"?1:(i.lastActivityAt||0)-(n.lastActivityAt||0));for(const n of s){const i=this.activeSubagentId===n.agentId,a=n.status==="active"?"active":n.status==="idle"?"idle":"completed",r=this.subagentActivity.get(n.agentId)||[],o=r[r.length-1],l=o?.type==="tool"?o.tool:null,d=this.subagentWindows.has(n.agentId),c=n.status==="active"||n.status==="idle",m=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",u=this.getTeammateInfo(n),h=u?u.name:n.description||n.agentId.substring(0,7),p=this.getTeammateBadgeHtml(n),y=u?`<span class="subagent-icon teammate-dot teammate-color-${u.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
98
- <div class="subagent-item ${a} ${i?"selected":""}${u?" is-teammate":""}"
97
+ `},r=this.flattenTaskTree(e.taskTree);let o='<div class="task-tree">';for(const l of e.taskTree)o+=`<div class="task-node">${i(l,r)}</div>`;o+="</div>",t.innerHTML=o},flattenTaskTree(e,t=[]){for(const s of e)t.push(s);return t},toggleSubagentPanel(){this.toggleSubagentsPanel()},updateSubagentBadge(){const e=this.$("subagentCountBadge"),t=Array.from(this.subagents.values()).filter(s=>s.status==="active"||s.status==="idle").length;e&&(e.textContent=t>0?t:"")},renderSubagentPanel(){this._subagentPanelRenderTimeout&&clearTimeout(this._subagentPanelRenderTimeout),this._subagentPanelRenderTimeout=setTimeout(()=>{scheduleBackground(()=>this._renderSubagentPanelImmediate())},150)},_renderSubagentPanelImmediate(){const e=this.$("subagentList");if(!e||(this.updateSubagentBadge(),this.renderMonitorSubagents(),!this.subagentPanelVisible))return;if(this.subagents.size===0){e.innerHTML='<div class="subagent-empty">No background agents detected</div>';return}const t=[],s=Array.from(this.subagents.values()).sort((n,a)=>n.status==="active"&&a.status!=="active"?-1:a.status==="active"&&n.status!=="active"?1:(a.lastActivityAt||0)-(n.lastActivityAt||0));for(const n of s){const a=this.activeSubagentId===n.agentId,i=n.status==="active"?"active":n.status==="idle"?"idle":"completed",r=this.subagentActivity.get(n.agentId)||[],o=r[r.length-1],l=o?.type==="tool"?o.tool:null,d=this.subagentWindows.has(n.agentId),c=n.status==="active"||n.status==="idle",m=n.modelShort?`<span class="subagent-model-badge ${escapeHtml(n.modelShort)}">${escapeHtml(n.modelShort)}</span>`:"",u=this.getTeammateInfo(n),h=u?u.name:n.description||n.agentId.substring(0,7),p=this.getTeammateBadgeHtml(n),y=u?`<span class="subagent-icon teammate-dot teammate-color-${u.color}">\u25CF</span>`:'<span class="subagent-icon">\u{1F916}</span>';t.push(`
98
+ <div class="subagent-item ${i} ${a?"selected":""}${u?" is-teammate":""}"
99
99
  onclick="app.selectSubagent(${escapeHtml(JSON.stringify(n.agentId))})"
100
100
  ondblclick="app.openSubagentWindow(${escapeHtml(JSON.stringify(n.agentId))})"
101
101
  title="Double-click to open tracking window">
@@ -104,7 +104,7 @@
104
104
  <span class="subagent-id" title="${escapeHtml(n.description||n.agentId)}">${escapeHtml(h.length>40?h.substring(0,40)+"...":h)}</span>
105
105
  ${p}
106
106
  ${m}
107
- <span class="subagent-status ${a}">${n.status}</span>
107
+ <span class="subagent-status ${i}">${n.status}</span>
108
108
  ${c?`<button class="subagent-kill-btn" onclick="event.stopPropagation(); app.killSubagent(${escapeHtml(JSON.stringify(n.agentId))})" title="Kill agent">&#x2715;</button>`:""}
109
109
  <button class="subagent-window-btn" onclick="event.stopPropagation(); app.${d?"closeSubagentWindow":"openSubagentWindow"}(${escapeHtml(JSON.stringify(n.agentId))})" title="${d?"Close window":"Open in window"}">
110
110
  ${d?"\u2715":"\u29C9"}
@@ -135,10 +135,10 @@
135
135
  <span class="time">${l}</span>
136
136
  <span class="icon">\u{1F4AC}</span>
137
137
  <span class="detail">${escapeHtml(d)}</span>
138
- </div>`}return""}).join(""),i=t.description||`Agent ${t.agentId}`,a=t.modelShort?`<span class="subagent-model-badge ${escapeHtml(t.modelShort)}">${escapeHtml(t.modelShort)}</span>`:"",r=t.totalInputTokens||t.totalOutputTokens?`<span>Tokens: ${this.formatTokenCount(t.totalInputTokens||0)}\u2193 ${this.formatTokenCount(t.totalOutputTokens||0)}\u2191</span>`:"";e.innerHTML=`
138
+ </div>`}return""}).join(""),a=t.description||`Agent ${t.agentId}`,i=t.modelShort?`<span class="subagent-model-badge ${escapeHtml(t.modelShort)}">${escapeHtml(t.modelShort)}</span>`:"",r=t.totalInputTokens||t.totalOutputTokens?`<span>Tokens: ${this.formatTokenCount(t.totalInputTokens||0)}\u2193 ${this.formatTokenCount(t.totalOutputTokens||0)}\u2191</span>`:"";e.innerHTML=`
139
139
  <div class="subagent-detail-header">
140
- <span class="subagent-id" title="${escapeHtml(t.description||t.agentId)}">${escapeHtml(i.length>60?i.substring(0,60)+"...":i)}</span>
141
- ${a}
140
+ <span class="subagent-id" title="${escapeHtml(t.description||t.agentId)}">${escapeHtml(a.length>60?a.substring(0,60)+"...":a)}</span>
141
+ ${i}
142
142
  <span class="subagent-status ${t.status}">${t.status}</span>
143
143
  <button class="subagent-transcript-btn" onclick="app.viewSubagentTranscript(${escapeHtml(JSON.stringify(t.agentId))})">
144
144
  View Full Transcript
@@ -153,7 +153,7 @@
153
153
  <div class="subagent-activity-log">
154
154
  ${n||'<div class="subagent-empty">No activity yet</div>'}
155
155
  </div>
156
- `},toggleToolParams(e){const t=document.getElementById(`tool-params-${e}`);if(!t)return;const s=t.previousElementSibling;t.style.display==="none"?(t.style.display="block",s&&(s.textContent="\u25BC")):(t.style.display="none",s&&(s.textContent="\u25B6"))},formatTokenCount(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()},formatBytes(e){return e>=1024*1024?(e/(1024*1024)).toFixed(1)+"MB":e>=1024?(e/1024).toFixed(1)+"KB":e+"B"},getToolIcon(e){return{WebSearch:"\u{1F50D}",WebFetch:"\u{1F310}",Read:"\u{1F4D6}",Write:"\u{1F4DD}",Edit:"\u270F\uFE0F",Bash:"\u{1F4BB}",Glob:"\u{1F4C1}",Grep:"\u{1F50E}",Task:"\u{1F916}"}[e]||"\u{1F527}"},getToolDetail(e,t){if(!t)return"";if(e==="WebSearch"&&t.query)return`"${t.query}"`;if(e==="WebFetch"&&t.url)return t.url;if(e==="Read"&&t.file_path||(e==="Write"||e==="Edit")&&t.file_path)return t.file_path;if(e==="Bash"&&t.command){const s=t.command;return s.length>40?s.substring(0,40)+"...":s}return e==="Glob"&&t.pattern||e==="Grep"&&t.pattern?t.pattern:""},getToolDetailExpanded(e,t,s,n){const i=this.getToolDetail(e,t),a=["query","url","file_path","command","pattern"],l=Object.keys(s||t||{}).filter(d=>!a.includes(d)).length>0||s&&JSON.stringify(s).length>100;return{primary:i,hasMore:l,fullInput:s||t}},async killSubagent(e){try{const s=await(await this._apiDelete(`/api/subagents/${e}`))?.json();if(s?.success){const n=this.subagents.get(e);n&&(n.status="completed",this.subagents.set(e,n)),this.renderSubagentPanel(),this.renderSubagentDetail(),this.updateSubagentWindows(),this.showToast(`Subagent ${e.substring(0,7)} killed`,"success")}else this.showToast(s.error||"Failed to kill subagent","error")}catch(t){console.error("Failed to kill subagent:",t),this.showToast("Failed to kill subagent: "+t.message,"error")}},async viewSubagentTranscript(e){try{const s=await(await fetch(`/api/subagents/${e}/transcript?format=formatted`)).json();if(!s.success){alert("Failed to load transcript");return}const n=s.data.formatted.join(`
156
+ `},toggleToolParams(e){const t=document.getElementById(`tool-params-${e}`);if(!t)return;const s=t.previousElementSibling;t.style.display==="none"?(t.style.display="block",s&&(s.textContent="\u25BC")):(t.style.display="none",s&&(s.textContent="\u25B6"))},formatTokenCount(e){return e>=1e6?(e/1e6).toFixed(1)+"M":e>=1e3?(e/1e3).toFixed(1)+"k":e.toString()},formatBytes(e){return e>=1024*1024?(e/(1024*1024)).toFixed(1)+"MB":e>=1024?(e/1024).toFixed(1)+"KB":e+"B"},getToolIcon(e){return{WebSearch:"\u{1F50D}",WebFetch:"\u{1F310}",Read:"\u{1F4D6}",Write:"\u{1F4DD}",Edit:"\u270F\uFE0F",Bash:"\u{1F4BB}",Glob:"\u{1F4C1}",Grep:"\u{1F50E}",Task:"\u{1F916}"}[e]||"\u{1F527}"},getToolDetail(e,t){if(!t)return"";if(e==="WebSearch"&&t.query)return`"${t.query}"`;if(e==="WebFetch"&&t.url)return t.url;if(e==="Read"&&t.file_path||(e==="Write"||e==="Edit")&&t.file_path)return t.file_path;if(e==="Bash"&&t.command){const s=t.command;return s.length>40?s.substring(0,40)+"...":s}return e==="Glob"&&t.pattern||e==="Grep"&&t.pattern?t.pattern:""},getToolDetailExpanded(e,t,s,n){const a=this.getToolDetail(e,t),i=["query","url","file_path","command","pattern"],l=Object.keys(s||t||{}).filter(d=>!i.includes(d)).length>0||s&&JSON.stringify(s).length>100;return{primary:a,hasMore:l,fullInput:s||t}},async killSubagent(e){try{const s=await(await this._apiDelete(`/api/subagents/${e}`))?.json();if(s?.success){const n=this.subagents.get(e);n&&(n.status="completed",this.subagents.set(e,n)),this.renderSubagentPanel(),this.renderSubagentDetail(),this.updateSubagentWindows(),this.showToast(`Subagent ${e.substring(0,7)} killed`,"success")}else this.showToast(s.error||"Failed to kill subagent","error")}catch(t){console.error("Failed to kill subagent:",t),this.showToast("Failed to kill subagent: "+t.message,"error")}},async viewSubagentTranscript(e){try{const s=await(await fetch(`/api/subagents/${e}/transcript?format=formatted`)).json();if(!s.success){alert("Failed to load transcript");return}const n=s.data.formatted.join(`
157
157
  `);window.open("","_blank","width=800,height=600").document.write(`
158
158
  <html>
159
159
  <head>
@@ -168,26 +168,26 @@
168
168
  <pre>${escapeHtml(n)}</pre>
169
169
  </body>
170
170
  </html>
171
- `)}catch(t){console.error("Failed to load transcript:",t),alert("Failed to load transcript: "+t.message)}},findParentSessionForSubagent(e){if(this.subagentParentMap.has(e)){const s=this.subagentParentMap.get(e);if(this.sessions.has(s)){const n=this.subagents.get(e);if(n&&!n.parentSessionId){n.parentSessionId=s;const i=this.sessions.get(s);i&&(n.parentSessionName=this.getSessionName(i)),this.subagents.set(e,n),this.updateSubagentWindowParent(e)}return}this.subagentParentMap.delete(e)}const t=this.subagents.get(e);if(t){if(t.sessionId){for(const[s,n]of this.sessions)if(n.claudeSessionId===t.sessionId){this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}}if(this.activeSessionId&&this.sessions.has(this.activeSessionId)){this.setAgentParentSessionId(e,this.activeSessionId),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}if(this.sessions.size>0){const s=this.sessions.keys().next().value;this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines()}}},recheckOrphanSubagents(){let e=!1;for(const[t,s]of this.subagents)if(!this.subagentParentMap.has(t))this.findParentSessionForSubagent(t),this.subagentParentMap.has(t)&&(e=!0);else if(s.sessionId){const n=this.subagentParentMap.get(t),i=this.sessions.get(n);if(i&&i.claudeSessionId!==s.sessionId){for(const[a,r]of this.sessions)if(r.claudeSessionId===s.sessionId){this.subagentParentMap.set(t,a),s.parentSessionId=a,s.parentSessionName=this.getSessionName(r),this.subagents.set(t,s),this.updateSubagentWindowParent(t),e=!0;break}}}e&&(this.saveSubagentParentMap(),this.updateConnectionLines())},updateSubagentParentNames(e){const t=this.sessions.get(e);if(!t)return;const s=this.getSessionName(t);if(this._parentNameCache?.get(e)!==s){this._parentNameCache||(this._parentNameCache=new Map),this._parentNameCache.set(e,s);for(const[i,a]of this.subagentParentMap)if(a===e){const r=this.subagents.get(i);if(r){r.parentSessionName=s,this.subagents.set(i,r);const o=this.subagentWindows.get(i);if(o){const l=o.element.querySelector(".subagent-window-parent .parent-name");l&&(l.textContent=s)}}}}},updateSubagentWindowParent(e){const t=this.subagentWindows.get(e);if(!t)return;const s=this.subagentParentMap.get(e);if(!s)return;const n=this.sessions.get(s),i=n?this.getSessionName(n):"Unknown",a=t.element,r=a.querySelector(".subagent-window-parent");if(r){r.dataset.parentSession=s;const l=r.querySelector(".parent-name");l&&(l.textContent=i,l.onclick=()=>this.selectSession(s));return}const o=a.querySelector(".subagent-window-header");if(o){const l=document.createElement("div");l.className="subagent-window-parent",l.dataset.parentSession=s,l.innerHTML=`
171
+ `)}catch(t){console.error("Failed to load transcript:",t),alert("Failed to load transcript: "+t.message)}},findParentSessionForSubagent(e){if(this.subagentParentMap.has(e)){const s=this.subagentParentMap.get(e);if(this.sessions.has(s)){const n=this.subagents.get(e);if(n&&!n.parentSessionId){n.parentSessionId=s;const a=this.sessions.get(s);a&&(n.parentSessionName=this.getSessionName(a)),this.subagents.set(e,n),this.updateSubagentWindowParent(e)}return}this.subagentParentMap.delete(e)}const t=this.subagents.get(e);if(t){if(t.sessionId){for(const[s,n]of this.sessions)if(n.claudeSessionId===t.sessionId){this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}}if(this.activeSessionId&&this.sessions.has(this.activeSessionId)){this.setAgentParentSessionId(e,this.activeSessionId),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines();return}if(this.sessions.size>0){const s=this.sessions.keys().next().value;this.setAgentParentSessionId(e,s),this.updateSubagentWindowParent(e),this.updateSubagentWindowVisibility(),this.updateConnectionLines()}}},recheckOrphanSubagents(){let e=!1;for(const[t,s]of this.subagents)if(!this.subagentParentMap.has(t))this.findParentSessionForSubagent(t),this.subagentParentMap.has(t)&&(e=!0);else if(s.sessionId){const n=this.subagentParentMap.get(t),a=this.sessions.get(n);if(a&&a.claudeSessionId!==s.sessionId){for(const[i,r]of this.sessions)if(r.claudeSessionId===s.sessionId){this.subagentParentMap.set(t,i),s.parentSessionId=i,s.parentSessionName=this.getSessionName(r),this.subagents.set(t,s),this.updateSubagentWindowParent(t),e=!0;break}}}e&&(this.saveSubagentParentMap(),this.updateConnectionLines())},updateSubagentParentNames(e){const t=this.sessions.get(e);if(!t)return;const s=this.getSessionName(t);if(this._parentNameCache?.get(e)!==s){this._parentNameCache||(this._parentNameCache=new Map),this._parentNameCache.set(e,s);for(const[a,i]of this.subagentParentMap)if(i===e){const r=this.subagents.get(a);if(r){r.parentSessionName=s,this.subagents.set(a,r);const o=this.subagentWindows.get(a);if(o){const l=o.element.querySelector(".subagent-window-parent .parent-name");l&&(l.textContent=s)}}}}},updateSubagentWindowParent(e){const t=this.subagentWindows.get(e);if(!t)return;const s=this.subagentParentMap.get(e);if(!s)return;const n=this.sessions.get(s),a=n?this.getSessionName(n):"Unknown",i=t.element,r=i.querySelector(".subagent-window-parent");if(r){r.dataset.parentSession=s;const l=r.querySelector(".parent-name");l&&(l.textContent=a,l.onclick=()=>this.selectSession(s));return}const o=i.querySelector(".subagent-window-header");if(o){const l=document.createElement("div");l.className="subagent-window-parent",l.dataset.parentSession=s,l.innerHTML=`
172
172
  <span class="parent-label">from</span>
173
- <span class="parent-name" onclick="app.selectSession(${escapeHtml(JSON.stringify(s))})">${escapeHtml(i)}</span>
174
- `,o.insertAdjacentElement("afterend",l)}},updateSubagentWindowVisibility(){const t=this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0;for(const[s,n]of this.subagentWindows){const i=this.subagentParentMap.get(s),a=this.subagents.get(s),r=i||a?.parentSessionId;let o;t?o=!!!r||r===this.activeSessionId:o=!0,o?(n.minimized||(n.element.style.display="flex",n._lazyTerminal&&this._restoreTeammateTerminalFromLazy(s)),n.hidden=!1):(this._disposeTeammateTerminalForMinimize(s),n.element.style.display="none",n.hidden=!0)}this.updateConnectionLines(),this.relayoutMobileSubagentWindows()},closeSessionSubagentWindows(e,t=!1){const s=[];for(const[n,i]of this.subagentWindows){const a=this.subagents.get(n),r=this.subagentParentMap.get(n);(a?.parentSessionId===e||r===e)&&s.push(n)}for(const n of s)this.forceCloseSubagentWindow(n),t&&(this.subagents.delete(n),this.subagentActivity.delete(n),this.subagentToolResults.delete(n),this.subagentParentMap.delete(n));this.minimizedSubagents.delete(e),this.renderSessionTabs()},forceCloseSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(t.resizeObserver&&t.resizeObserver.disconnect(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.subagentWindows.delete(e));const s=this.teammateTerminals.get(e);if(s){if(s.resizeObserver&&s.resizeObserver.disconnect(),s.terminal)try{s.terminal.dispose()}catch{}this.teammateTerminals.delete(e)}},minimizeSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(this._disposeTeammateTerminalForMinimize(e),t.element.style.display="none",t.minimized=!0,this.updateConnectionLines())},scheduleSubagentWindowRender(e){this.subagentWindows.get(e)?.minimized||(this._subagentWindowRenderTimeouts||(this._subagentWindowRenderTimeouts=new Map),this._subagentWindowRenderTimeouts.has(e)&&clearTimeout(this._subagentWindowRenderTimeouts.get(e)),this._subagentWindowRenderTimeouts.set(e,setTimeout(()=>{this._subagentWindowRenderTimeouts.delete(e),scheduleBackground(()=>this.renderSubagentWindowContent(e))},100)))},renderSubagentWindowContent(e){if(this.teammateTerminals.has(e)||this.subagentWindows.get(e)?._lazyTerminal)return;const s=document.getElementById(`subagent-window-body-${e}`);if(!s)return;const n=this.subagentActivity.get(e)||[];if(n.length===0){s.innerHTML='<div class="subagent-empty">No activity yet</div>';return}const i=s.dataset.renderedCount?parseInt(s.dataset.renderedCount,10):0,a=100,r=n.slice(-a);if(i===0||i>r.length||s.children.length===0||s.children.length===1&&s.querySelector(".subagent-empty")){const o=r.map(l=>this._renderActivityItem(l)).join("");s.innerHTML=o,s.dataset.renderedCount=String(r.length)}else{const o=r.slice(i);if(o.length>0){const l=o.map(d=>this._renderActivityItem(d)).join("");for(s.insertAdjacentHTML("beforeend",l),s.dataset.renderedCount=String(r.length);s.children.length>a;)s.removeChild(s.firstChild)}}s.scrollTop=s.scrollHeight},_renderActivityItem(e){const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(e.type==="tool")return`<div class="activity-line">
173
+ <span class="parent-name" onclick="app.selectSession(${escapeHtml(JSON.stringify(s))})">${escapeHtml(a)}</span>
174
+ `,o.insertAdjacentElement("afterend",l)}},updateSubagentWindowVisibility(){const t=this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0;for(const[s,n]of this.subagentWindows){const a=this.subagentParentMap.get(s),i=this.subagents.get(s),r=a||i?.parentSessionId;let o;t?o=!!!r||r===this.activeSessionId:o=!0,o?(n.minimized||(n.element.style.display="flex",n._lazyTerminal&&this._restoreTeammateTerminalFromLazy(s)),n.hidden=!1):(this._disposeTeammateTerminalForMinimize(s),n.element.style.display="none",n.hidden=!0)}this.updateConnectionLines(),this.relayoutMobileSubagentWindows()},closeSessionSubagentWindows(e,t=!1){const s=[];for(const[n,a]of this.subagentWindows){const i=this.subagents.get(n),r=this.subagentParentMap.get(n);(i?.parentSessionId===e||r===e)&&s.push(n)}for(const n of s)this.forceCloseSubagentWindow(n),t&&(this.subagents.delete(n),this.subagentActivity.delete(n),this.subagentToolResults.delete(n),this.subagentParentMap.delete(n));this.minimizedSubagents.delete(e),this.renderSessionTabs()},forceCloseSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(t.resizeObserver&&t.resizeObserver.disconnect(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.subagentWindows.delete(e));const s=this.teammateTerminals.get(e);if(s){if(s.resizeObserver&&s.resizeObserver.disconnect(),s.terminal)try{s.terminal.dispose()}catch{}this.teammateTerminals.delete(e)}},minimizeSubagentWindow(e){const t=this.subagentWindows.get(e);t&&(this._disposeTeammateTerminalForMinimize(e),t.element.style.display="none",t.minimized=!0,this.updateConnectionLines())},scheduleSubagentWindowRender(e){this.subagentWindows.get(e)?.minimized||(this._subagentWindowRenderTimeouts||(this._subagentWindowRenderTimeouts=new Map),this._subagentWindowRenderTimeouts.has(e)&&clearTimeout(this._subagentWindowRenderTimeouts.get(e)),this._subagentWindowRenderTimeouts.set(e,setTimeout(()=>{this._subagentWindowRenderTimeouts.delete(e),scheduleBackground(()=>this.renderSubagentWindowContent(e))},100)))},renderSubagentWindowContent(e){if(this.teammateTerminals.has(e)||this.subagentWindows.get(e)?._lazyTerminal)return;const s=document.getElementById(`subagent-window-body-${e}`);if(!s)return;const n=this.subagentActivity.get(e)||[];if(n.length===0){s.innerHTML='<div class="subagent-empty">No activity yet</div>';return}const a=s.dataset.renderedCount?parseInt(s.dataset.renderedCount,10):0,i=100,r=n.slice(-i);if(a===0||a>r.length||s.children.length===0||s.children.length===1&&s.querySelector(".subagent-empty")){const o=r.map(l=>this._renderActivityItem(l)).join("");s.innerHTML=o,s.dataset.renderedCount=String(r.length)}else{const o=r.slice(a);if(o.length>0){const l=o.map(d=>this._renderActivityItem(d)).join("");for(s.insertAdjacentHTML("beforeend",l),s.dataset.renderedCount=String(r.length);s.children.length>i;)s.removeChild(s.firstChild)}}s.scrollTop=s.scrollHeight},_renderActivityItem(e){const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1});if(e.type==="tool")return`<div class="activity-line">
175
175
  <span class="time">${t}</span>
176
176
  <span class="tool-icon">${this.getToolIcon(e.tool)}</span>
177
177
  <span class="tool-name">${escapeHtml(e.tool)}</span>
178
178
  <span class="tool-detail">${escapeHtml(this.getToolDetail(e.tool,e.input))}</span>
179
- </div>`;if(e.type==="tool_result"){const s=e.isError?"\u274C":"\u{1F4C4}",n=e.isError?" error":"",i=e.contentLength>500?` (${this.formatBytes(e.contentLength)})`:"",a=e.preview.length>60?e.preview.substring(0,60)+"...":e.preview;return`<div class="activity-line result-line${n}">
179
+ </div>`;if(e.type==="tool_result"){const s=e.isError?"\u274C":"\u{1F4C4}",n=e.isError?" error":"",a=e.contentLength>500?` (${this.formatBytes(e.contentLength)})`:"",i=e.preview.length>60?e.preview.substring(0,60)+"...":e.preview;return`<div class="activity-line result-line${n}">
180
180
  <span class="time">${t}</span>
181
181
  <span class="tool-icon">${s}</span>
182
182
  <span class="tool-name">${escapeHtml(e.tool||"\u2192")}</span>
183
- <span class="tool-detail">${escapeHtml(a)}${i}</span>
184
- </div>`}else if(e.type==="progress"){const s=e.hookEvent||e.hookName,n=s?"\u{1FA9D}":e.progressType==="query_update"?"\u27F3":"\u2713",i=s?e.hookName||e.hookEvent:e.query||e.progressType;return`<div class="activity-line progress-line${s?" hook-line":""}">
183
+ <span class="tool-detail">${escapeHtml(i)}${a}</span>
184
+ </div>`}else if(e.type==="progress"){const s=e.hookEvent||e.hookName,n=s?"\u{1FA9D}":e.progressType==="query_update"?"\u27F3":"\u2713",a=s?e.hookName||e.hookEvent:e.query||e.progressType;return`<div class="activity-line progress-line${s?" hook-line":""}">
185
185
  <span class="time">${t}</span>
186
186
  <span class="tool-icon">${n}</span>
187
- <span class="tool-detail">${escapeHtml(i)}</span>
187
+ <span class="tool-detail">${escapeHtml(a)}</span>
188
188
  </div>`}else if(e.type==="message"){const s=e.text.length>150?e.text.substring(0,150)+"...":e.text;return`<div class="message-line">
189
189
  <span class="time">${t}</span> \u{1F4AC} ${escapeHtml(s)}
190
- </div>`}return""},updateSubagentWindows(){for(const e of this.subagentWindows.keys())this.renderSubagentWindowContent(e),this.updateSubagentWindowHeader(e)},updateSubagentWindowHeader(e){const t=this.subagents.get(e);if(!t)return;const s=document.getElementById(`subagent-window-${e}`);if(!s)return;const n=s.querySelector(".subagent-window-title .id");if(n){const d=this.getTeammateInfo(t),c=d?d.name:t.description||e.substring(0,7),m=c.length>50?c.substring(0,50)+"...":c;n.textContent=m}let i=s.querySelector(".teammate-badge");const a=this.getTeammateInfo(t);if(a&&!i){const d=s.querySelector(".subagent-window-title");if(d){const c=document.createElement("span");c.className=`teammate-badge teammate-color-${a.color}`,c.title=`Team: ${a.teamName}`,c.textContent=`@${a.name}`;const m=d.querySelector(".status");m&&m.insertAdjacentElement("beforebegin",c)}}const r=s.querySelector(".subagent-window-title");r&&(r.title=t.description||e);let o=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!o){o=document.createElement("span"),o.className=`subagent-model-badge ${t.modelShort}`;const d=s.querySelector(".subagent-window-title .status");d&&d.insertAdjacentElement("beforebegin",o)}o.className=`subagent-model-badge ${t.modelShort}`,o.textContent=t.modelShort}const l=s.querySelector(".subagent-window-title .status");l&&(l.className=`status ${t.status}`,l.textContent=t.status)},openAllActiveSubagentWindows(){for(const[e,t]of this.subagents)t.status==="active"&&!this.subagentWindows.has(e)&&this.openSubagentWindow(e)},initTeammateTerminal(e,t,s){const n=s.querySelector(".subagent-window-body");if(!n)return;n.innerHTML="",n.classList.add("teammate-terminal-body"),s.classList.add("has-terminal");const i=t.sessionId,a=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:i,resizeObserver:null,pendingData:a}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const r=new Terminal({theme:{...window.codemanCurrentXtermTheme()},fontFamily:'"Fira Code", "Cascadia Code", "JetBrains Mono", "SF Mono", Monaco, monospace',fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:DEFAULT_SCROLLBACK,allowTransparency:!0,allowProposedApi:!0}),o=new FitAddon.FitAddon;if(r.loadAddon(o),typeof Unicode11Addon<"u")try{const c=new Unicode11Addon.Unicode11Addon;r.loadAddon(c),r.unicode.activeVersion="11"}catch{}try{r.open(n)}catch(c){console.warn("[TeammateTerminal] Failed to open terminal:",c),this.teammateTerminals.delete(e);return}setTimeout(()=>{try{o.fit()}catch{}fetch(`/api/sessions/${i}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(c=>c.json()).then(c=>{if(c.success&&c.data?.buffer)try{r.write(c.data.buffer)}catch{}}).catch(c=>console.error("[TeammateTerminal] Failed to fetch buffer:",c));for(const c of a)try{r.write(c)}catch{}a.length=0},100),r.onData(c=>{fetch(`/api/sessions/${i}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:c})}).catch(m=>console.error("[TeammateTerminal] Failed to send input:",m))});const l=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{o.fit()}catch{}})});l.observe(n);const d=this.teammateTerminals.get(e);d&&(d.terminal=r,d.fitAddon=o,d.resizeObserver=l)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const w=this.subagentWindows.get(t);w.hidden&&(w.element.style.display="flex",w.hidden=!1),w.element.style.zIndex=++this.subagentWindowZIndex,w.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,i=400,a=20,r=window.innerWidth,o=window.innerHeight,l=50,d=120,c=Math.floor((r-l-50)/(n+a))||1,m=Math.floor((o-d-50)/(i+a))||1,u=s%c,h=Math.floor(s/c)%m;let p=l+u*(n+a),y=d+h*(i+a);p=Math.max(10,Math.min(p,r-n-10)),y=Math.max(10,Math.min(y,o-i-10));const b=e.color||"blue",f=document.createElement("div");f.className="subagent-window has-terminal",f.id=`subagent-window-${t}`,f.style.zIndex=++this.subagentWindowZIndex,f.style.left=`${p}px`,f.style.top=`${y}px`,f.style.width=`${n}px`,f.style.height=`${i}px`,f.innerHTML=`
190
+ </div>`}return""},updateSubagentWindows(){for(const e of this.subagentWindows.keys())this.renderSubagentWindowContent(e),this.updateSubagentWindowHeader(e)},updateSubagentWindowHeader(e){const t=this.subagents.get(e);if(!t)return;const s=document.getElementById(`subagent-window-${e}`);if(!s)return;const n=s.querySelector(".subagent-window-title .id");if(n){const d=this.getTeammateInfo(t),c=d?d.name:t.description||e.substring(0,7),m=c.length>50?c.substring(0,50)+"...":c;n.textContent=m}let a=s.querySelector(".teammate-badge");const i=this.getTeammateInfo(t);if(i&&!a){const d=s.querySelector(".subagent-window-title");if(d){const c=document.createElement("span");c.className=`teammate-badge teammate-color-${i.color}`,c.title=`Team: ${i.teamName}`,c.textContent=`@${i.name}`;const m=d.querySelector(".status");m&&m.insertAdjacentElement("beforebegin",c)}}const r=s.querySelector(".subagent-window-title");r&&(r.title=t.description||e);let o=s.querySelector(".subagent-window-title .subagent-model-badge");if(t.modelShort){if(!o){o=document.createElement("span"),o.className=`subagent-model-badge ${t.modelShort}`;const d=s.querySelector(".subagent-window-title .status");d&&d.insertAdjacentElement("beforebegin",o)}o.className=`subagent-model-badge ${t.modelShort}`,o.textContent=t.modelShort}const l=s.querySelector(".subagent-window-title .status");l&&(l.className=`status ${t.status}`,l.textContent=t.status)},openAllActiveSubagentWindows(){for(const[e,t]of this.subagents)t.status==="active"&&!this.subagentWindows.has(e)&&this.openSubagentWindow(e)},initTeammateTerminal(e,t,s){const n=s.querySelector(".subagent-window-body");if(!n)return;n.innerHTML="",n.classList.add("teammate-terminal-body"),s.classList.add("has-terminal");const a=t.sessionId,i=[];this.teammateTerminals.set(e,{terminal:null,fitAddon:null,paneTarget:t.paneTarget,sessionId:a,resizeObserver:null,pendingData:i}),requestAnimationFrame(()=>{if(!document.contains(n)){this.teammateTerminals.delete(e);return}const r=new Terminal({theme:{...window.codemanCurrentXtermTheme()},fontFamily:'"Fira Code", "Cascadia Code", "JetBrains Mono", "SF Mono", Monaco, monospace',fontSize:12,lineHeight:1.2,cursorBlink:!0,cursorStyle:"block",scrollback:DEFAULT_SCROLLBACK,allowTransparency:!0,allowProposedApi:!0}),o=new FitAddon.FitAddon;if(r.loadAddon(o),typeof Unicode11Addon<"u")try{const c=new Unicode11Addon.Unicode11Addon;r.loadAddon(c),r.unicode.activeVersion="11"}catch{}try{r.open(n)}catch(c){console.warn("[TeammateTerminal] Failed to open terminal:",c),this.teammateTerminals.delete(e);return}setTimeout(()=>{try{o.fit()}catch{}fetch(`/api/sessions/${a}/teammate-pane-buffer/${encodeURIComponent(t.paneTarget)}`).then(c=>c.json()).then(c=>{if(c.success&&c.data?.buffer)try{r.write(c.data.buffer)}catch{}}).catch(c=>console.error("[TeammateTerminal] Failed to fetch buffer:",c));for(const c of i)try{r.write(c)}catch{}i.length=0},100),r.onData(c=>{fetch(`/api/sessions/${a}/teammate-pane-input`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({paneTarget:t.paneTarget,input:c})}).catch(m=>console.error("[TeammateTerminal] Failed to send input:",m))});const l=new ResizeObserver(()=>{requestAnimationFrame(()=>{try{o.fit()}catch{}})});l.observe(n);const d=this.teammateTerminals.get(e);d&&(d.terminal=r,d.fitAddon=o,d.resizeObserver=l)})},openTeammateTerminalWindow(e){if(!this.sessions.has(e.sessionId))return;const t=`pane-${e.paneTarget}`;if(this.subagentWindows.has(t)){const w=this.subagentWindows.get(t);w.hidden&&(w.element.style.display="flex",w.hidden=!1),w.element.style.zIndex=++this.subagentWindowZIndex,w.minimized&&this.restoreSubagentWindow(t);return}const s=this.subagentWindows.size,n=550,a=400,i=20,r=window.innerWidth,o=window.innerHeight,l=50,d=120,c=Math.floor((r-l-50)/(n+i))||1,m=Math.floor((o-d-50)/(a+i))||1,u=s%c,h=Math.floor(s/c)%m;let p=l+u*(n+i),y=d+h*(a+i);p=Math.max(10,Math.min(p,r-n-10)),y=Math.max(10,Math.min(y,o-a-10));const b=e.color||"blue",f=document.createElement("div");f.className="subagent-window has-terminal",f.id=`subagent-window-${t}`,f.style.zIndex=++this.subagentWindowZIndex,f.style.left=`${p}px`,f.style.top=`${y}px`,f.style.width=`${n}px`,f.style.height=`${a}px`,f.innerHTML=`
191
191
  <div class="subagent-window-header">
192
192
  <div class="subagent-window-title" title="Teammate terminal: ${escapeHtml(e.teammateName)} (pane ${e.paneTarget})">
193
193
  <span class="icon" style="color: var(--team-color-${b}, #339af0)">\u2B24</span>
@@ -200,11 +200,11 @@
200
200
  </div>
201
201
  <div class="subagent-window-body teammate-terminal-body" id="subagent-window-body-${t}">
202
202
  </div>
203
- `,document.body.appendChild(f);const v=this.makeWindowDraggable(f,f.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(f);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:f,minimized:!1,hidden:S,dragListeners:v,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(f.style.display="none"),f.addEventListener("mousedown",()=>{f.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(f),this.subagentWindows.get(t).resizeObserver=$,S){const w=this.subagentWindows.get(t);w&&(w._lazyTerminal=!0,w._lazyPaneTarget=e.paneTarget,w._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,f);requestAnimationFrame(()=>{f.style.transition="transform 0.3s ease, opacity 0.3s ease",f.style.transform="scale(1)",f.style.opacity="1"})},rebuildTeammateMap(){this.teammateMap.clear();for(const[e,t]of this.teams)for(const s of t.members)s.agentType!=="team-lead"&&this.teammateMap.set(s.name,{name:s.name,color:s.color||"blue",teamName:e,agentId:s.agentId})},getTeammateInfo(e){if(!e?.description)return null;const t=e.description.match(/<teammate-message\s+teammate_id="?([^">\s]+)/);if(!t)return null;const n=t[1].split("@")[0];return this.teammateMap.get(n)||{name:n,color:"blue",teamName:"unknown"}},getTeammateBadgeHtml(e){const t=this.getTeammateInfo(e);return t?`<span class="teammate-badge teammate-color-${t.color}" title="Team: ${escapeHtml(t.teamName)}">@${escapeHtml(t.name)}</span>`:""},renderTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");if(!e)return;let t=null,s=null;if(this.activeSessionId){for(const[h,p]of this.teams)if(p.leadSessionId===this.activeSessionId){t=p,s=h;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 y=e.querySelector(".team-tasks-header");y&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,y))}const i=this.teamTasks.get(s)||[],a=i.filter(h=>h.status==="completed").length,r=i.length,o=r>0?Math.round(a/r*100):0,l=e.querySelector(".team-tasks-header-text");if(l){const h=t.members.filter(p=>p.agentType!=="team-lead").length;l.textContent=`Team Tasks (${h} teammates)`}const d=e.querySelector(".team-tasks-progress-fill");d&&(d.style.width=`${o}%`);const c=e.querySelector(".team-tasks-progress-text");c&&(c.textContent=`${a}/${r}`);const m=e.querySelector(".team-tasks-list");if(!m)return;if(i.length===0){m.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const u=i.map(h=>{const p=h.status==="completed"?"\u2713":h.status==="in_progress"?"\u25C9":"\u25CB",y=h.status.replace("_","-"),b=h.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(h.owner)}">${escapeHtml(h.owner)}</span>`:"";return`<div class="team-task-item ${y}">
203
+ `,document.body.appendChild(f);const v=this.makeWindowDraggable(f,f.querySelector(".subagent-window-header"));typeof this.makeWindowResizable=="function"&&this.makeWindowResizable(f);const S=(this.loadAppSettingsFromStorage().subagentActiveTabOnly??!0)&&e.sessionId!==this.activeSessionId;this.subagentWindows.set(t,{element:f,minimized:!1,hidden:S,dragListeners:v,description:`Teammate: ${e.teammateName}`}),this.subagentParentMap.set(t,e.sessionId),S&&(f.style.display="none"),f.addEventListener("mousedown",()=>{f.style.zIndex=++this.subagentWindowZIndex});const $=new ResizeObserver(()=>{this.updateConnectionLines()});if($.observe(f),this.subagentWindows.get(t).resizeObserver=$,S){const w=this.subagentWindows.get(t);w&&(w._lazyTerminal=!0,w._lazyPaneTarget=e.paneTarget,w._lazySessionId=e.sessionId)}else this.initTeammateTerminal(t,e,f);requestAnimationFrame(()=>{f.style.transition="transform 0.3s ease, opacity 0.3s ease",f.style.transform="scale(1)",f.style.opacity="1"})},rebuildTeammateMap(){this.teammateMap.clear();for(const[e,t]of this.teams)for(const s of t.members)s.agentType!=="team-lead"&&this.teammateMap.set(s.name,{name:s.name,color:s.color||"blue",teamName:e,agentId:s.agentId})},getTeammateInfo(e){if(!e?.description)return null;const t=e.description.match(/<teammate-message\s+teammate_id="?([^">\s]+)/);if(!t)return null;const n=t[1].split("@")[0];return this.teammateMap.get(n)||{name:n,color:"blue",teamName:"unknown"}},getTeammateBadgeHtml(e){const t=this.getTeammateInfo(e);return t?`<span class="teammate-badge teammate-color-${t.color}" title="Team: ${escapeHtml(t.teamName)}">@${escapeHtml(t.name)}</span>`:""},renderTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");if(!e)return;let t=null,s=null;if(this.activeSessionId){for(const[h,p]of this.teams)if(p.leadSessionId===this.activeSessionId){t=p,s=h;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 y=e.querySelector(".team-tasks-header");y&&(this.teamTasksDragListeners=this.makeWindowDraggable(e,y))}const a=this.teamTasks.get(s)||[],i=a.filter(h=>h.status==="completed").length,r=a.length,o=r>0?Math.round(i/r*100):0,l=e.querySelector(".team-tasks-header-text");if(l){const h=t.members.filter(p=>p.agentType!=="team-lead").length;l.textContent=`Team Tasks (${h} teammates)`}const d=e.querySelector(".team-tasks-progress-fill");d&&(d.style.width=`${o}%`);const c=e.querySelector(".team-tasks-progress-text");c&&(c.textContent=`${i}/${r}`);const m=e.querySelector(".team-tasks-list");if(!m)return;if(a.length===0){m.innerHTML='<div class="team-task-empty">No tasks yet</div>';return}const u=a.map(h=>{const p=h.status==="completed"?"\u2713":h.status==="in_progress"?"\u25C9":"\u25CB",y=h.status.replace("_","-"),b=h.owner?`<span class="team-task-owner teammate-color-${this.getTeammateColor(h.owner)}">${escapeHtml(h.owner)}</span>`:"";return`<div class="team-task-item ${y}">
204
204
  <span class="team-task-status">${p}</span>
205
205
  <span class="team-task-subject">${escapeHtml(h.subject)}</span>
206
206
  ${b}
207
- </div>`}).join("");m.innerHTML=u},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 i=s.split("/"),a=[];for(const r of i)r===""||r==="."||(r===".."?a.length>1&&a.pop():a.push(r));return"/"+a.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),i=this.normalizeFilePath(t,s);if(n===i)return!0;const a=this.getFilename(n),r=this.getFilename(i);if(a!==r)return!1;const o=this.isShallowRootPath(e),l=this.isShallowRootPath(t),d=this.isPathInWorkingDir(n,s),c=this.isPathInWorkingDir(i,s);return!!(o&&c||l&&d)},pickBetterPath(e,t,s){if(s){const a=this.isPathInWorkingDir(e,s),r=this.isPathInWorkingDir(t,s);if(a&&!r)return e;if(r&&!a)return t}const n=e.startsWith("/"),i=t.startsWith("/");return n&&!i?e:i&&!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 a of e)for(const r of a.filePaths)s.push({rawPath:r,toolId:a.id});if(s.length<=1){const a=new Map;for(const r of s)a.set(this.normalizeFilePath(r.rawPath,t),r);return a}s.sort((a,r)=>{const o=this.isPathInWorkingDir(a.rawPath,t),l=this.isPathInWorkingDir(r.rawPath,t);return o&&!l?-1:l&&!o?1:r.rawPath.length-a.rawPath.length});const n=new Map,i=new Set;for(const{rawPath:a,toolId:r}of s){const o=this.normalizeFilePath(a,t);let l=!1;for(const[,d]of n)if(this.pathsAreEquivalent(a,d.rawPath,t)){l=!0;break}!l&&!i.has(o)&&(n.set(o,{rawPath:a,toolId:r}),i.add(o))}return n},handleBashToolStart(e,t){let s=this.projectInsights.get(e)||[];s=s.filter(n=>n.id!==t.id),s.push(t),this.projectInsights.set(e,s),this.renderProjectInsightsPanel()},handleBashToolEnd(e,t){const n=(this.projectInsights.get(e)||[]).find(i=>i.id===t.id);n&&(n.status="completed"),this.renderProjectInsightsPanel(),setTimeout(()=>{const i=this.projectInsights.get(e)||[];this.projectInsights.set(e,i.filter(a=>a.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 a=(this.projectInsights.get(this.activeSessionId)||[]).filter(m=>m.status==="running");if(a.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const o=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,l=this.deduplicateProjectInsightPaths(a,o),d=new Set(Array.from(l.values()).map(m=>m.rawPath)),c=[];for(const m of a){const u=m.filePaths.filter(p=>d.has(p));if(u.length===0)continue;const h=m.command.length>50?m.command.substring(0,50)+"...":m.command;c.push(`
207
+ </div>`}).join("");m.innerHTML=u},hideTeamTasksPanel(){const e=document.getElementById("teamTasksPanel");e&&(e.style.display="none"),this.teamTasksDragListeners&&(document.removeEventListener("mousemove",this.teamTasksDragListeners.move),document.removeEventListener("mouseup",this.teamTasksDragListeners.up),this.teamTasksDragListeners.touchMove&&(document.removeEventListener("touchmove",this.teamTasksDragListeners.touchMove),document.removeEventListener("touchend",this.teamTasksDragListeners.up),document.removeEventListener("touchcancel",this.teamTasksDragListeners.up)),this.teamTasksDragListeners.handle&&(this.teamTasksDragListeners.handle.removeEventListener("mousedown",this.teamTasksDragListeners.handleMouseDown),this.teamTasksDragListeners.handle.removeEventListener("touchstart",this.teamTasksDragListeners.handleTouchStart)),this.teamTasksDragListeners=null)},getTeammateColor(e){return this.teammateMap.get(e)?.color||"blue"},normalizeFilePath(e,t){if(!e)return"";let s=e.trim();const n="/home/"+(window.USER||"user");s.startsWith("~/")?s=n+s.slice(1):s==="~"&&(s=n),!s.startsWith("/")&&t&&(s=t+"/"+s);const a=s.split("/"),i=[];for(const r of a)r===""||r==="."||(r===".."?i.length>1&&i.pop():i.push(r));return"/"+i.join("/")},getFilename(e){const t=e.split("/");return t[t.length-1]||""},isShallowRootPath(e){return e.startsWith("/")?e.split("/").filter(s=>s!=="").length===1:!1},isPathInWorkingDir(e,t){if(!t)return!1;const s=this.normalizeFilePath(e,t);return s.startsWith(t+"/")||s===t},pathsAreEquivalent(e,t,s){const n=this.normalizeFilePath(e,s),a=this.normalizeFilePath(t,s);if(n===a)return!0;const i=this.getFilename(n),r=this.getFilename(a);if(i!==r)return!1;const o=this.isShallowRootPath(e),l=this.isShallowRootPath(t),d=this.isPathInWorkingDir(n,s),c=this.isPathInWorkingDir(a,s);return!!(o&&c||l&&d)},pickBetterPath(e,t,s){if(s){const i=this.isPathInWorkingDir(e,s),r=this.isPathInWorkingDir(t,s);if(i&&!r)return e;if(r&&!i)return t}const n=e.startsWith("/"),a=t.startsWith("/");return n&&!a?e:a&&!n?t:e.length!==t.length?e.length>t.length?e:t:!e.includes("~")&&t.includes("~")?e:!t.includes("~")&&e.includes("~")?t:e},deduplicateProjectInsightPaths(e,t){const s=[];for(const i of e)for(const r of i.filePaths)s.push({rawPath:r,toolId:i.id});if(s.length<=1){const i=new Map;for(const r of s)i.set(this.normalizeFilePath(r.rawPath,t),r);return i}s.sort((i,r)=>{const o=this.isPathInWorkingDir(i.rawPath,t),l=this.isPathInWorkingDir(r.rawPath,t);return o&&!l?-1:l&&!o?1:r.rawPath.length-i.rawPath.length});const n=new Map,a=new Set;for(const{rawPath:i,toolId:r}of s){const o=this.normalizeFilePath(i,t);let l=!1;for(const[,d]of n)if(this.pathsAreEquivalent(i,d.rawPath,t)){l=!0;break}!l&&!a.has(o)&&(n.set(o,{rawPath:i,toolId:r}),a.add(o))}return n},handleBashToolStart(e,t){let s=this.projectInsights.get(e)||[];s=s.filter(n=>n.id!==t.id),s.push(t),this.projectInsights.set(e,s),this.renderProjectInsightsPanel()},handleBashToolEnd(e,t){const n=(this.projectInsights.get(e)||[]).find(a=>a.id===t.id);n&&(n.status="completed"),this.renderProjectInsightsPanel(),setTimeout(()=>{const a=this.projectInsights.get(e)||[];this.projectInsights.set(e,a.filter(i=>i.id!==t.id)),this.renderProjectInsightsPanel()},2e3)},handleBashToolsUpdate(e,t){this.projectInsights.set(e,t),this.renderProjectInsightsPanel()},renderProjectInsightsPanel(){const e=this.$("projectInsightsPanel"),t=this.$("projectInsightsList");if(!e||!t)return;if(!(this.loadAppSettingsFromStorage().showProjectInsights??!1)){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}const i=(this.projectInsights.get(this.activeSessionId)||[]).filter(m=>m.status==="running");if(i.length===0){e.classList.remove("visible"),this.projectInsightsPanelVisible=!1;return}e.classList.add("visible"),this.projectInsightsPanelVisible=!0;const o=this.sessions.get(this.activeSessionId)?.workingDir||this.currentSessionWorkingDir,l=this.deduplicateProjectInsightPaths(i,o),d=new Set(Array.from(l.values()).map(m=>m.rawPath)),c=[];for(const m of i){const u=m.filePaths.filter(p=>d.has(p));if(u.length===0)continue;const h=m.command.length>50?m.command.substring(0,50)+"...":m.command;c.push(`
208
208
  <div class="project-insight-item" data-tool-id="${m.id}">
209
209
  <div class="project-insight-command">
210
210
  <span class="icon">\u{1F4BB}</span>
@@ -220,15 +220,15 @@
220
220
  `)}c.push(`
221
221
  </div>
222
222
  </div>
223
- `)}t.innerHTML=c.join("")},closeProjectInsightsPanel(){const e=this.$("projectInsightsPanel");e&&(e.classList.remove("visible"),this.projectInsightsPanelVisible=!1)},async loadFileBrowser(e){if(!e)return;const t=this.$("fileBrowserTree"),s=this.$("fileBrowserStatus");if(t){t.innerHTML='<div class="file-browser-loading">Loading files...</div>';try{const n=await fetch(`/api/sessions/${e}/files?depth=5&showHidden=false`);if(!n.ok)throw new Error("Failed to load files");const i=await n.json();if(!i.success)throw new Error(i.error||"Failed to load files");if(this.fileBrowserData=i.data,this.renderFileBrowserTree(),s){const{totalFiles:a,totalDirectories:r,truncated:o}=i.data;s.textContent=`${a} files, ${r} dirs${o?" (truncated)":""}`}}catch(n){console.error("Failed to load file browser:",n),t.innerHTML=`<div class="file-browser-empty">Failed to load files: ${escapeHtml(n.message)}</div>`}}},renderFileBrowserTree(){const e=this.$("fileBrowserTree");if(!e||!this.fileBrowserData)return;const{tree:t}=this.fileBrowserData;if(!t||t.length===0){e.innerHTML='<div class="file-browser-empty">No files found</div>';return}const s=[],n=this.fileBrowserFilter.toLowerCase(),i=(a,r)=>{const o=a.type==="directory",l=this.fileBrowserExpandedDirs.has(a.path),d=!n||a.name.toLowerCase().includes(n);let c=!1;o&&n&&a.children&&(c=this.hasMatchingChild(a,n));const u=!(d||c)&&n?" hidden-by-filter":"",h=o?l?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(a.extension),p=o?`<span class="file-tree-expand${l?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',y=!o&&a.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(a.size)}</span>`:"",b=o?"file-tree-name directory":"file-tree-name",f=o?"":`<a class="file-tree-download" href="/api/sessions/${this.activeSessionId}/file-raw?path=${encodeURIComponent(a.path)}&download=true" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;if(s.push(`
224
- <div class="file-tree-item${u}" data-path="${escapeHtml(a.path)}" data-type="${a.type}" data-depth="${r}">
223
+ `)}t.innerHTML=c.join("")},closeProjectInsightsPanel(){const e=this.$("projectInsightsPanel");e&&(e.classList.remove("visible"),this.projectInsightsPanelVisible=!1)},async loadFileBrowser(e){if(!e)return;const t=this.$("fileBrowserTree"),s=this.$("fileBrowserStatus");if(t){t.innerHTML='<div class="file-browser-loading">Loading files...</div>';try{const n=await fetch(`/api/sessions/${e}/files?depth=5&showHidden=false`);if(!n.ok)throw new Error("Failed to load files");const a=await n.json();if(!a.success)throw new Error(a.error||"Failed to load files");if(this.fileBrowserData=a.data,this.renderFileBrowserTree(),s){const{totalFiles:i,totalDirectories:r,truncated:o}=a.data;s.textContent=`${i} files, ${r} dirs${o?" (truncated)":""}`}}catch(n){console.error("Failed to load file browser:",n),t.innerHTML=`<div class="file-browser-empty">Failed to load files: ${escapeHtml(n.message)}</div>`}}},renderFileBrowserTree(){const e=this.$("fileBrowserTree");if(!e||!this.fileBrowserData)return;const{tree:t}=this.fileBrowserData;if(!t||t.length===0){e.innerHTML='<div class="file-browser-empty">No files found</div>';return}const s=[],n=this.fileBrowserFilter.toLowerCase(),a=(i,r)=>{const o=i.type==="directory",l=this.fileBrowserExpandedDirs.has(i.path),d=!n||i.name.toLowerCase().includes(n);let c=!1;o&&n&&i.children&&(c=this.hasMatchingChild(i,n));const u=!(d||c)&&n?" hidden-by-filter":"",h=o?l?"\u{1F4C2}":"\u{1F4C1}":this.getFileIcon(i.extension),p=o?`<span class="file-tree-expand${l?" expanded":""}">\u25B6</span>`:'<span class="file-tree-expand"></span>',y=!o&&i.size!==void 0?`<span class="file-tree-size">${this.formatFileSize(i.size)}</span>`:"",b=o?"file-tree-name directory":"file-tree-name",f=o?"":`<a class="file-tree-download" href="/api/sessions/${this.activeSessionId}/file-raw?path=${encodeURIComponent(i.path)}&download=true" title="Download" onclick="event.stopPropagation()">&#x2B07;</a>`;if(s.push(`
224
+ <div class="file-tree-item${u}" data-path="${escapeHtml(i.path)}" data-type="${i.type}" data-depth="${r}">
225
225
  ${p}
226
226
  <span class="file-tree-icon">${h}</span>
227
- <span class="${b}">${escapeHtml(a.name)}</span>
227
+ <span class="${b}">${escapeHtml(i.name)}</span>
228
228
  ${y}
229
229
  ${f}
230
230
  </div>
231
- `),o&&l&&a.children)for(const v of a.children)i(v,r+1)};for(const a of t)i(a,0);e.innerHTML=s.join(""),e.querySelectorAll(".file-tree-item").forEach(a=>{a.addEventListener("click",()=>{const r=a.dataset.path;a.dataset.type==="directory"?this.toggleFileBrowserFolder(r):this.openFilePreview(r)})})},hasMatchingChild(e,t){if(!e.children)return!1;for(const s of e.children)if(s.name.toLowerCase().includes(t)||s.type==="directory"&&this.hasMatchingChild(s,t))return!0;return!1},toggleFileBrowserFolder(e){this.fileBrowserExpandedDirs.has(e)?this.fileBrowserExpandedDirs.delete(e):this.fileBrowserExpandedDirs.add(e),this.renderFileBrowserTree()},filterFileBrowser(e){this.fileBrowserFilter=e,e&&this.expandAllDirectories(this.fileBrowserData?.tree||[]),this.renderFileBrowserTree()},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){if(this.activeSessionId){this.fileBrowserExpandedDirs.clear(),this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1;const e=this.$("fileBrowserSearch");e&&(e.value=""),this.loadFileBrowser(this.activeSessionId)}},closeFileBrowserPanel(){const e=this.$("fileBrowserPanel");if(e&&(e.classList.remove("visible"),e.style.left="",e.style.top="",e.style.bottom="",e.style.right=""),this.fileBrowserDragListeners){const s=this.fileBrowserDragListeners;document.removeEventListener("mousemove",s.move),document.removeEventListener("mouseup",s.up),document.removeEventListener("touchmove",s.touchMove),document.removeEventListener("touchend",s.up),document.removeEventListener("touchcancel",s.up),s.handle&&(s.handle.removeEventListener("mousedown",s.handleMouseDown),s.handle.removeEventListener("touchstart",s.handleTouchStart),s._onFirstDrag&&(s.handle.removeEventListener("mousedown",s._onFirstDrag),s.handle.removeEventListener("touchstart",s._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t)},async openFilePreview(e,t=this.activeSessionId,s=null){if(!t||!e)return;const n=this.$("filePreviewOverlay"),i=this.$("filePreviewTitle"),a=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!n||!a)return;n.classList.add("visible"),i.textContent=e,a.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const o=(e.split(".").pop()||"").toLowerCase();if(s){const l=`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`,d=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]);if(r.textContent=o.toUpperCase(),d.has(o))a.innerHTML=`<img src="${escapeHtml(`${l}/raw`)}" alt="${escapeHtml(e)}">`;else if(o==="pdf")a.innerHTML=`<iframe src="${escapeHtml(`${l}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(o==="docx"||o==="pptx")a.innerHTML=`<iframe src="${escapeHtml(`${l}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else try{const c=await fetch(`${l}/raw`);if(!c.ok)throw new Error("Failed to load attachment");const m=await c.text();a.innerHTML=`<pre><code>${escapeHtml(m)}</code></pre>`}catch(c){a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(c.message)}</div>`}return}if(o==="docx"||o==="pptx"){r.textContent=o.toUpperCase();const l=`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`;a.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(o==="pdf"){r.textContent="PDF";const l=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`;a.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(o==="svg"){r.textContent="SVG";try{const l=await fetch(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);if(!l.ok)throw new Error("Failed to load image");const d=URL.createObjectURL(new Blob([await l.text()],{type:"image/svg+xml"}));a.innerHTML=`<img src="${d}" alt="${escapeHtml(e)}">`;const c=a.querySelector("img");c&&(c.onload=()=>URL.revokeObjectURL(d))}catch(l){a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}return}try{const l=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!l.ok)throw new Error("Failed to load file");const d=await l.json();if(!d.success)throw new Error(d.error||"Failed to load file");const c=d.data;if(c.type==="image")a.innerHTML=`<img src="${c.url}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="video")a.innerHTML=`<video src="${c.url}" controls autoplay></video>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="audio")a.innerHTML=`<audio src="${c.url}" controls autoplay></audio>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="binary"){const m=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}&download=true`;a.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(c.size)})<br>Cannot preview<br><a href="${escapeHtml(m)}" download>Download</a></div>`,r.textContent=c.extension||"binary"}else{this.filePreviewContent=c.content,a.innerHTML=`<pre><code>${escapeHtml(c.content)}</code></pre>`;const m=c.truncated?` (showing 500/${c.totalLines} lines)`:"";r.textContent=`${c.totalLines} lines \u2022 ${this.formatFileSize(c.size)}${m}`}}catch(l){console.error("Failed to preview file:",l),a.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}},closeFilePreview(){const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this.filePreviewContent=""},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`;window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:i,size:a,attachmentType:r,extension:o,attachmentId:l,rawUrl:d,previewUrl:c,thumbnailUrl:m}=e,u=s||n,h=l||`${t}-${i}-${n}`;if(this.attachmentCards.has(h)){this.attachmentCards.get(h).element.focus?.();return}if(this.attachmentCards.size>=10){const C=this.attachmentCards.keys().next().value;C&&this.closeAttachmentCard(C)}const y=this.ensureAttachmentCardStack(),f=this.sessions.get(t)?.name||t.substring(0,8),v=d||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(u)}`),T=c||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/preview`:null),g=m||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(u)}`),S=l?`${v}?download=true`:`${v}&download=true`,$=(o||r||"file").toUpperCase(),w=document.createElement("article");w.className=`attachment-card attachment-${escapeHtml(r||"file")}`,w.tabIndex=0,w.dataset.attachmentId=h,w.dataset.previewUrl=T||"",w.innerHTML=`
231
+ `),o&&l&&i.children)for(const v of i.children)a(v,r+1)};for(const i of t)a(i,0);e.innerHTML=s.join(""),e.querySelectorAll(".file-tree-item").forEach(i=>{i.addEventListener("click",()=>{const r=i.dataset.path;i.dataset.type==="directory"?this.toggleFileBrowserFolder(r):this.openFilePreview(r)})})},hasMatchingChild(e,t){if(!e.children)return!1;for(const s of e.children)if(s.name.toLowerCase().includes(t)||s.type==="directory"&&this.hasMatchingChild(s,t))return!0;return!1},toggleFileBrowserFolder(e){this.fileBrowserExpandedDirs.has(e)?this.fileBrowserExpandedDirs.delete(e):this.fileBrowserExpandedDirs.add(e),this.renderFileBrowserTree()},filterFileBrowser(e){this.fileBrowserFilter=e,e&&this.expandAllDirectories(this.fileBrowserData?.tree||[]),this.renderFileBrowserTree()},expandAllDirectories(e){for(const t of e)t.type==="directory"&&(this.fileBrowserExpandedDirs.add(t.path),t.children&&this.expandAllDirectories(t.children))},collapseAllDirectories(){this.fileBrowserExpandedDirs.clear()},toggleFileBrowserExpand(){this.fileBrowserAllExpanded=!this.fileBrowserAllExpanded;const e=this.$("fileBrowserExpandBtn");this.fileBrowserAllExpanded?(this.expandAllDirectories(this.fileBrowserData?.tree||[]),e&&(e.innerHTML="\u229F")):(this.collapseAllDirectories(),e&&(e.innerHTML="\u229E")),this.renderFileBrowserTree()},refreshFileBrowser(){if(this.activeSessionId){this.fileBrowserExpandedDirs.clear(),this.fileBrowserFilter="",this.fileBrowserAllExpanded=!1;const e=this.$("fileBrowserSearch");e&&(e.value=""),this.loadFileBrowser(this.activeSessionId)}},toggleFileBrowserButton(){const t=this.$("fileBrowserPanel")?.classList.contains("visible"),s=document.querySelector(".btn-file-viewer");if(t){this.closeFileBrowserPanel(),s&&s.setAttribute("aria-expanded","false");return}if(!this.activeSessionId){this.showToast("Open a session to browse its files","info");return}const n=this.loadAppSettingsFromStorage();n.showFileBrowser=!0,this.saveAppSettingsToStorage(n);const a=document.getElementById("appSettingsShowFileBrowser");a&&(a.checked=!0),this.applyMonitorVisibility(),s&&s.setAttribute("aria-expanded","true")},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 a=this.fileBrowserDragListeners;document.removeEventListener("mousemove",a.move),document.removeEventListener("mouseup",a.up),document.removeEventListener("touchmove",a.touchMove),document.removeEventListener("touchend",a.up),document.removeEventListener("touchcancel",a.up),a.handle&&(a.handle.removeEventListener("mousedown",a.handleMouseDown),a.handle.removeEventListener("touchstart",a.handleTouchStart),a._onFirstDrag&&(a.handle.removeEventListener("mousedown",a._onFirstDrag),a.handle.removeEventListener("touchstart",a._onFirstDrag))),this.fileBrowserDragListeners=null}const t=this.loadAppSettingsFromStorage();t.showFileBrowser=!1,this.saveAppSettingsToStorage(t);const s=document.getElementById("appSettingsShowFileBrowser");s&&(s.checked=!1);const n=document.querySelector(".btn-file-viewer");n&&n.setAttribute("aria-expanded","false")},async openFilePreview(e,t=this.activeSessionId,s=null){if(!t||!e)return;const n=this.$("filePreviewOverlay"),a=this.$("filePreviewTitle"),i=this.$("filePreviewBody"),r=this.$("filePreviewFooter");if(!n||!i)return;n.classList.add("visible"),a.textContent=e,i.innerHTML='<div class="binary-message">Loading...</div>',r.textContent="";const o=(e.split(".").pop()||"").toLowerCase();if(s){const l=`/api/sessions/${t}/attachments/${encodeURIComponent(s)}`,d=new Set(["png","jpg","jpeg","gif","webp","bmp","svg"]);if(r.textContent=o.toUpperCase(),d.has(o))i.innerHTML=`<img src="${escapeHtml(`${l}/raw`)}" alt="${escapeHtml(e)}">`;else if(o==="pdf")i.innerHTML=`<iframe src="${escapeHtml(`${l}/raw`)}" title="${escapeHtml(e)}"></iframe>`;else if(o==="docx"||o==="pptx")i.innerHTML=`<iframe src="${escapeHtml(`${l}/preview`)}" title="${escapeHtml(e)}"></iframe>`;else try{const c=await fetch(`${l}/raw`);if(!c.ok)throw new Error("Failed to load attachment");const m=await c.text();i.innerHTML=`<pre><code>${escapeHtml(m)}</code></pre>`}catch(c){i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(c.message)}</div>`}return}if(o==="docx"||o==="pptx"){r.textContent=o.toUpperCase();const l=`/api/sessions/${t}/file-preview?path=${encodeURIComponent(e)}`;i.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(o==="pdf"){r.textContent="PDF";const l=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`;i.innerHTML=`<iframe src="${escapeHtml(l)}" title="${escapeHtml(e)}"></iframe>`;return}if(o==="svg"){r.textContent="SVG";try{const l=await fetch(`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}`);if(!l.ok)throw new Error("Failed to load image");const d=URL.createObjectURL(new Blob([await l.text()],{type:"image/svg+xml"}));i.innerHTML=`<img src="${d}" alt="${escapeHtml(e)}">`;const c=i.querySelector("img");c&&(c.onload=()=>URL.revokeObjectURL(d))}catch(l){i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}return}try{const l=await fetch(`/api/sessions/${t}/file-content?path=${encodeURIComponent(e)}&lines=500`);if(!l.ok)throw new Error("Failed to load file");const d=await l.json();if(!d.success)throw new Error(d.error||"Failed to load file");const c=d.data;if(c.type==="image")i.innerHTML=`<img src="${c.url}" alt="${escapeHtml(e)}">`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="video")i.innerHTML=`<video src="${c.url}" controls autoplay></video>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="audio")i.innerHTML=`<audio src="${c.url}" controls autoplay></audio>`,r.textContent=`${this.formatFileSize(c.size)} \u2022 ${c.extension}`;else if(c.type==="binary"){const m=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(e)}&download=true`;i.innerHTML=`<div class="binary-message">Binary file (${this.formatFileSize(c.size)})<br>Cannot preview<br><a href="${escapeHtml(m)}" download>Download</a></div>`,r.textContent=c.extension||"binary"}else{this.filePreviewContent=c.content,i.innerHTML=`<pre><code>${escapeHtml(c.content)}</code></pre>`;const m=c.truncated?` (showing 500/${c.totalLines} lines)`:"";r.textContent=`${c.totalLines} lines \u2022 ${this.formatFileSize(c.size)}${m}`}}catch(l){console.error("Failed to preview file:",l),i.innerHTML=`<div class="binary-message">Error: ${escapeHtml(l.message)}</div>`}},closeFilePreview(){const e=this.$("filePreviewOverlay");e&&e.classList.remove("visible"),this.filePreviewContent=""},_onAttachmentDetected(e){if(console.log("[Attachment Detected]",e),this.addAttachmentCard(e),e.sessionId){const t=this.attachmentHistoryCounts.get(e.sessionId)??this.sessions.get(e.sessionId)?.attachmentHistory?.length??0;this.attachmentHistoryCounts.set(e.sessionId,Math.min(t+1,100)),e.sessionId===this.activeSessionId&&(this.updateAttachmentHistoryBadge(),this.attachmentHistoryDrawerOpen&&this._debouncedCall("attachmentHistoryRefresh",()=>{this.attachmentHistoryDrawerOpen&&this.activeSessionId===e.sessionId&&this.loadAttachmentHistory(e.sessionId)},250))}},ensureAttachmentCardStack(){let e=this.attachmentCardStack||document.getElementById("attachmentCardStack");return e||(e=document.createElement("div"),e.id="attachmentCardStack",e.className="attachment-card-stack",document.body.appendChild(e)),this.attachmentCardStack=e,e},openAttachmentInNewTab(e,t,s=null){const n=s?`/api/sessions/${e}/attachments/${encodeURIComponent(s)}/raw`:`/api/sessions/${e}/file-raw?path=${encodeURIComponent(t)}`;window.open(n,"_blank")},addAttachmentCard(e){const{sessionId:t,relativePath:s,fileName:n,timestamp:a,size:i,attachmentType:r,extension:o,attachmentId:l,rawUrl:d,previewUrl:c,thumbnailUrl:m}=e,u=s||n,h=l||`${t}-${a}-${n}`;if(this.attachmentCards.has(h)){this.attachmentCards.get(h).element.focus?.();return}if(this.attachmentCards.size>=10){const C=this.attachmentCards.keys().next().value;C&&this.closeAttachmentCard(C)}const y=this.ensureAttachmentCardStack(),f=this.sessions.get(t)?.name||t.substring(0,8),v=d||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/raw`:`/api/sessions/${t}/file-raw?path=${encodeURIComponent(u)}`),T=c||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/preview`:null),g=m||(l?`/api/sessions/${t}/attachments/${encodeURIComponent(l)}/thumbnail`:`/api/sessions/${t}/file-thumbnail?path=${encodeURIComponent(u)}`),S=l?`${v}?download=true`:`${v}&download=true`,$=(o||r||"file").toUpperCase(),w=document.createElement("article");w.className=`attachment-card attachment-${escapeHtml(r||"file")}`,w.tabIndex=0,w.dataset.attachmentId=h,w.dataset.previewUrl=T||"",w.innerHTML=`
232
232
  <div class="attachment-thumbnail">
233
233
  ${g?`<img class="attachment-thumbnail-img" src="${escapeHtml(g)}" alt="">`:""}
234
234
  <div class="attachment-thumbnail-fallback ${g?"":"visible"}">${escapeHtml($)}</div>
@@ -237,7 +237,7 @@
237
237
  <div class="attachment-file-name" title="${escapeHtml(u)}">${escapeHtml(n)}</div>
238
238
  <div class="attachment-file-meta">
239
239
  <span>${escapeHtml(f)}</span>
240
- <span>${this.formatFileSize(a||0)}</span>
240
+ <span>${this.formatFileSize(i||0)}</span>
241
241
  </div>
242
242
  <div class="attachment-actions">
243
243
  <button type="button" class="attachment-preview-btn">Preview</button>
@@ -246,7 +246,7 @@
246
246
  </div>
247
247
  </div>
248
248
  <button type="button" class="attachment-close-btn" title="Dismiss">&times;</button>
249
- `;const D=w.querySelector(".attachment-thumbnail-img");D&&(D.onerror=()=>{D.remove(),w.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),w.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(u,t,l||null)}),w.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,u,l||null)}),w.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(h)}),y.prepend(w),this.attachmentCards.set(h,{element:w,sessionId:t,filePath:u}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,n]of this.attachmentCards)n.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),n=this.activeSessionId,i=e??(n&&this.attachmentHistoryCounts.get(n)||0);t&&(t.textContent=i>99?"99+":String(i),t.style.display=i>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
249
+ `;const D=w.querySelector(".attachment-thumbnail-img");D&&(D.onerror=()=>{D.remove(),w.querySelector(".attachment-thumbnail-fallback")?.classList.add("visible")}),w.querySelector(".attachment-preview-btn")?.addEventListener("click",()=>{this.openFilePreview(u,t,l||null)}),w.querySelector(".attachment-open-btn")?.addEventListener("click",()=>{this.openAttachmentInNewTab(t,u,l||null)}),w.querySelector(".attachment-close-btn")?.addEventListener("click",()=>{this.closeAttachmentCard(h)}),y.prepend(w),this.attachmentCards.set(h,{element:w,sessionId:t,filePath:u}),this._refreshAttachmentClearAll()},_refreshAttachmentClearAll(){const e=this.attachmentCardStack;if(!e)return;let t=e.querySelector(".attachment-clear-all");if(this.attachmentCards.size<2){t&&(t.hidden=!0);return}t||(t=document.createElement("button"),t.type="button",t.className="attachment-clear-all",t.textContent="Clear all",t.title="Dismiss all attachment cards",t.addEventListener("click",()=>this.closeAllAttachmentCards()),e.prepend(t)),t.hidden=!1},closeAttachmentCard(e){const t=this.attachmentCards.get(e);t&&(t.element.remove(),this.attachmentCards.delete(e),this.attachmentCardStack&&this.attachmentCards.size===0?(this.attachmentCardStack.remove(),this.attachmentCardStack=null):this._refreshAttachmentClearAll())},closeAllAttachmentCards(){for(const e of[...this.attachmentCards.keys()])this.closeAttachmentCard(e)},closeSessionAttachmentCards(e){const t=[];for(const[s,n]of this.attachmentCards)n.sessionId===e&&t.push(s);for(const s of t)this.closeAttachmentCard(s)},updateAttachmentHistoryBadge(e=null){const t=document.getElementById("attachmentHistoryBadge"),s=document.getElementById("attachmentsHistoryBtn"),n=this.activeSessionId,a=e??(n&&this.attachmentHistoryCounts.get(n)||0);t&&(t.textContent=a>99?"99+":String(a),t.style.display=a>0?"":"none"),s&&(s.classList.toggle("active",this.attachmentHistoryDrawerOpen),s.setAttribute("aria-expanded",this.attachmentHistoryDrawerOpen?"true":"false"))},ensureAttachmentHistoryDrawer(){let e=document.getElementById("attachmentHistoryDrawer");return e||(e=document.createElement("aside"),e.id="attachmentHistoryDrawer",e.className="attachment-history-drawer",e.setAttribute("aria-label","Attachment history"),e.innerHTML=`
250
250
  <div class="attachment-history-header">
251
251
  <div>
252
252
  <div class="attachment-history-title">Attachments</div>
@@ -258,14 +258,14 @@
258
258
  </div>
259
259
  </div>
260
260
  <div class="attachment-history-list" id="attachmentHistoryList"></div>
261
- `,document.body.appendChild(e),e.querySelector("#attachmentHistoryRefreshBtn")?.addEventListener("click",()=>{this.loadAttachmentHistory(this.activeSessionId)}),e.querySelector("#attachmentHistoryCloseBtn")?.addEventListener("click",()=>{this.closeAttachmentHistory()}),e)},async toggleAttachmentHistory(){if(this.attachmentHistoryDrawerOpen){this.closeAttachmentHistory();return}await this.openAttachmentHistory()},async openAttachmentHistory(){const e=this.ensureAttachmentHistoryDrawer();this.attachmentHistoryDrawerOpen=!0,e.classList.add("open"),this.updateAttachmentHistoryBadge(),await this.loadAttachmentHistory(this.activeSessionId)},closeAttachmentHistory(){const e=document.getElementById("attachmentHistoryDrawer");this.attachmentHistoryDrawerOpen=!1,e?.classList.remove("open"),this._debounceTimers?.attachmentHistoryRefresh&&(clearTimeout(this._debounceTimers.attachmentHistoryRefresh),this._debounceTimers.attachmentHistoryRefresh=null),this.updateAttachmentHistoryBadge()},async loadAttachmentHistory(e=this.activeSessionId){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(!e){this.attachmentHistoryItems=[],n.textContent="No session",s.innerHTML='<div class="attachment-history-empty">No active session</div>',this.updateAttachmentHistoryBadge(0);return}s.innerHTML='<div class="attachment-history-empty">Loading...</div>';try{const i=await fetch(`/api/sessions/${e}/attachments`);if(!i.ok)throw new Error("Failed to load attachments");const a=await i.json();if(!a.success)throw new Error(a.error||"Failed to load attachments");const r=a.data?.items||[];this.attachmentHistoryItems=r,this.attachmentHistoryCounts.set(e,r.length),this.updateAttachmentHistoryBadge(r.length),this.renderAttachmentHistory(r)}catch(i){console.error("Failed to load attachment history:",i),n.textContent="Unavailable",s.innerHTML=`<div class="attachment-history-empty">Error: ${escapeHtml(i.message)}</div>`}}},renderAttachmentHistory(e=this.attachmentHistoryItems||[]){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(n.textContent=`${e.length} ${e.length===1?"file":"files"}`,e.length===0){s.innerHTML=`
261
+ `,document.body.appendChild(e),e.querySelector("#attachmentHistoryRefreshBtn")?.addEventListener("click",()=>{this.loadAttachmentHistory(this.activeSessionId)}),e.querySelector("#attachmentHistoryCloseBtn")?.addEventListener("click",()=>{this.closeAttachmentHistory()}),e)},async toggleAttachmentHistory(){if(this.attachmentHistoryDrawerOpen){this.closeAttachmentHistory();return}await this.openAttachmentHistory()},async openAttachmentHistory(){const e=this.ensureAttachmentHistoryDrawer();this.attachmentHistoryDrawerOpen=!0,e.classList.add("open"),this.updateAttachmentHistoryBadge(),await this.loadAttachmentHistory(this.activeSessionId)},closeAttachmentHistory(){const e=document.getElementById("attachmentHistoryDrawer");this.attachmentHistoryDrawerOpen=!1,e?.classList.remove("open"),this._debounceTimers?.attachmentHistoryRefresh&&(clearTimeout(this._debounceTimers.attachmentHistoryRefresh),this._debounceTimers.attachmentHistoryRefresh=null),this.updateAttachmentHistoryBadge()},async loadAttachmentHistory(e=this.activeSessionId){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(!e){this.attachmentHistoryItems=[],n.textContent="No session",s.innerHTML='<div class="attachment-history-empty">No active session</div>',this.updateAttachmentHistoryBadge(0);return}s.innerHTML='<div class="attachment-history-empty">Loading...</div>';try{const a=await fetch(`/api/sessions/${e}/attachments`);if(!a.ok)throw new Error("Failed to load attachments");const i=await a.json();if(!i.success)throw new Error(i.error||"Failed to load attachments");const r=i.data?.items||[];this.attachmentHistoryItems=r,this.attachmentHistoryCounts.set(e,r.length),this.updateAttachmentHistoryBadge(r.length),this.renderAttachmentHistory(r)}catch(a){console.error("Failed to load attachment history:",a),n.textContent="Unavailable",s.innerHTML=`<div class="attachment-history-empty">Error: ${escapeHtml(a.message)}</div>`}}},renderAttachmentHistory(e=this.attachmentHistoryItems||[]){const t=this.ensureAttachmentHistoryDrawer(),s=t.querySelector("#attachmentHistoryList"),n=t.querySelector("#attachmentHistorySubtitle");if(!(!s||!n)){if(n.textContent=`${e.length} ${e.length===1?"file":"files"}`,e.length===0){s.innerHTML=`
262
262
  <div class="attachment-history-empty">
263
263
  <div class="attachment-history-empty-title">No attachments yet</div>
264
264
  <div>Show a file here by running:</div>
265
265
  <code>codeman attach /absolute/path/to/file.pptx</code>
266
266
  <div>Supports .pptx, .docx, .pdf, .png, .md, and .txt.</div>
267
267
  </div>
268
- `;return}s.innerHTML=e.map(i=>this.renderAttachmentHistoryItem(i)).join(""),s.querySelectorAll(".attachment-history-thumb-img").forEach(i=>{i.onerror=()=>{i.remove(),i.closest(".attachment-history-thumb")?.querySelector(".attachment-history-thumb-fallback")?.classList.add("visible")}}),s.querySelectorAll("[data-attachment-action]").forEach(i=>{i.addEventListener("click",()=>{const a=i.getAttribute("data-history-id"),r=i.getAttribute("data-attachment-action");!a||!r||(r==="preview"&&this.previewAttachmentHistoryItem(a),r==="download"&&this.downloadAttachmentHistoryItem(a),r==="open"&&this.openAttachmentHistoryItem(a),r==="reshow"&&this.reshowAttachmentCard(a))})})}},renderAttachmentHistoryItem(e){const t=(e.extension||e.attachmentType||"file").toUpperCase(),s=[e.source==="external"?"published":"workspace",this.formatFileSize(e.size||0),e.missing?"missing":""].filter(Boolean).join(" \u2022 "),n=e.thumbnailUrl&&!e.missing?`<img class="attachment-history-thumb-img" src="${escapeHtml(e.thumbnailUrl)}" alt="">`:"",i=e.missing?'disabled aria-disabled="true"':"";return`
268
+ `;return}s.innerHTML=e.map(a=>this.renderAttachmentHistoryItem(a)).join(""),s.querySelectorAll(".attachment-history-thumb-img").forEach(a=>{a.onerror=()=>{a.remove(),a.closest(".attachment-history-thumb")?.querySelector(".attachment-history-thumb-fallback")?.classList.add("visible")}}),s.querySelectorAll("[data-attachment-action]").forEach(a=>{a.addEventListener("click",()=>{const i=a.getAttribute("data-history-id"),r=a.getAttribute("data-attachment-action");!i||!r||(r==="preview"&&this.previewAttachmentHistoryItem(i),r==="download"&&this.downloadAttachmentHistoryItem(i),r==="open"&&this.openAttachmentHistoryItem(i),r==="reshow"&&this.reshowAttachmentCard(i))})})}},renderAttachmentHistoryItem(e){const t=(e.extension||e.attachmentType||"file").toUpperCase(),s=[e.source==="external"?"published":"workspace",this.formatFileSize(e.size||0),e.missing?"missing":""].filter(Boolean).join(" \u2022 "),n=e.thumbnailUrl&&!e.missing?`<img class="attachment-history-thumb-img" src="${escapeHtml(e.thumbnailUrl)}" alt="">`:"",a=e.missing?'disabled aria-disabled="true"':"";return`
269
269
  <div class="attachment-history-item ${e.missing?"missing":""}" data-history-item="${escapeHtml(e.id)}">
270
270
  <div class="attachment-history-thumb">
271
271
  ${n}
@@ -275,14 +275,14 @@
275
275
  <div class="attachment-history-file-name" title="${escapeHtml(e.fileName)}">${escapeHtml(e.fileName)}</div>
276
276
  <div class="attachment-history-meta">${escapeHtml(s)}</div>
277
277
  <div class="attachment-history-actions">
278
- <button type="button" data-attachment-action="preview" data-history-id="${escapeHtml(e.id)}" ${i}>Preview</button>
279
- <button type="button" data-attachment-action="download" data-history-id="${escapeHtml(e.id)}" ${i}>Download</button>
280
- <button type="button" data-attachment-action="open" data-history-id="${escapeHtml(e.id)}" ${i}>Open</button>
281
- <button type="button" data-attachment-action="reshow" data-history-id="${escapeHtml(e.id)}" ${i}>Card</button>
278
+ <button type="button" data-attachment-action="preview" data-history-id="${escapeHtml(e.id)}" ${a}>Preview</button>
279
+ <button type="button" data-attachment-action="download" data-history-id="${escapeHtml(e.id)}" ${a}>Download</button>
280
+ <button type="button" data-attachment-action="open" data-history-id="${escapeHtml(e.id)}" ${a}>Open</button>
281
+ <button type="button" data-attachment-action="reshow" data-history-id="${escapeHtml(e.id)}" ${a}>Card</button>
282
282
  </div>
283
283
  </div>
284
284
  </div>
285
- `},getAttachmentHistoryItem(e){return(this.attachmentHistoryItems||[]).find(t=>t.id===e)||null},previewAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!t||t.missing)return;const s=t.relativePath||t.fileName;this.openFilePreview(s,t.sessionId,t.attachmentId||null),this.closeAttachmentHistory()},openAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!(!t||t.missing)){if(t.rawUrl||t.url){window.open(t.rawUrl||t.url,"_blank");return}this.openAttachmentInNewTab(t.sessionId,t.relativePath||t.fileName,t.attachmentId||null)}},downloadAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||!t.downloadUrl||window.open(t.downloadUrl,"_blank")},reshowAttachmentCard(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||this.addAttachmentCard({sessionId:t.sessionId,relativePath:t.relativePath,fileName:t.fileName,timestamp:t.timestamp??Date.now(),size:t.size,attachmentType:t.attachmentType,extension:t.extension,attachmentId:t.attachmentId,rawUrl:t.rawUrl,previewUrl:t.previewUrl,thumbnailUrl:t.thumbnailUrl})},copyFilePreviewContent(){this.filePreviewContent&&navigator.clipboard.writeText(this.filePreviewContent).then(()=>{this.showToast("Copied to clipboard","success")}).catch(()=>{this.showToast("Failed to copy","error")})},getFileIcon(e){return e&&{ts:"\u{1F4D8}",tsx:"\u{1F4D8}",js:"\u{1F4D2}",jsx:"\u{1F4D2}",mjs:"\u{1F4D2}",cjs:"\u{1F4D2}",py:"\u{1F40D}",pyx:"\u{1F40D}",pyw:"\u{1F40D}",rs:"\u{1F980}",go:"\u{1F439}",c:"\u2699\uFE0F",cpp:"\u2699\uFE0F",h:"\u2699\uFE0F",hpp:"\u2699\uFE0F",html:"\u{1F310}",htm:"\u{1F310}",css:"\u{1F3A8}",scss:"\u{1F3A8}",sass:"\u{1F3A8}",less:"\u{1F3A8}",json:"\u{1F4CB}",yaml:"\u{1F4CB}",yml:"\u{1F4CB}",xml:"\u{1F4CB}",toml:"\u{1F4CB}",csv:"\u{1F4CB}",md:"\u{1F4DD}",markdown:"\u{1F4DD}",txt:"\u{1F4DD}",rst:"\u{1F4DD}",png:"\u{1F5BC}\uFE0F",jpg:"\u{1F5BC}\uFE0F",jpeg:"\u{1F5BC}\uFE0F",gif:"\u{1F5BC}\uFE0F",svg:"\u{1F5BC}\uFE0F",webp:"\u{1F5BC}\uFE0F",ico:"\u{1F5BC}\uFE0F",bmp:"\u{1F5BC}\uFE0F",mp4:"\u{1F3AC}",webm:"\u{1F3AC}",mov:"\u{1F3AC}",mp3:"\u{1F3B5}",wav:"\u{1F3B5}",ogg:"\u{1F3B5}",sh:"\u{1F4BB}",bash:"\u{1F4BB}",zsh:"\u{1F4BB}",env:"\u{1F510}",gitignore:"\u{1F6AB}",dockerfile:"\u{1F433}",lock:"\u{1F512}"}[e.toLowerCase()]||"\u{1F4C4}"},formatFileSize(e){return e==null?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`},openLogViewerWindow(e,t){if(t=t||this.activeSessionId,!t)return;const s=`${t}-${e.replace(/[^a-zA-Z0-9]/g,"_")}`;if(this.logViewerWindows.has(s)){const c=this.logViewerWindows.get(s);c.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,i=100+n%5*30,a=100+n%5*30,r=e.split("/").pop(),o=document.createElement("div");o.className="log-viewer-window",o.id=`log-viewer-window-${s}`,o.style.left=`${i}px`,o.style.top=`${a}px`,o.style.zIndex=++this.logViewerWindowZIndex,o.innerHTML=`
285
+ `},getAttachmentHistoryItem(e){return(this.attachmentHistoryItems||[]).find(t=>t.id===e)||null},previewAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!t||t.missing)return;const s=t.relativePath||t.fileName;this.openFilePreview(s,t.sessionId,t.attachmentId||null),this.closeAttachmentHistory()},openAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);if(!(!t||t.missing)){if(t.rawUrl||t.url){window.open(t.rawUrl||t.url,"_blank");return}this.openAttachmentInNewTab(t.sessionId,t.relativePath||t.fileName,t.attachmentId||null)}},downloadAttachmentHistoryItem(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||!t.downloadUrl||window.open(t.downloadUrl,"_blank")},reshowAttachmentCard(e){const t=this.getAttachmentHistoryItem(e);!t||t.missing||this.addAttachmentCard({sessionId:t.sessionId,relativePath:t.relativePath,fileName:t.fileName,timestamp:t.timestamp??Date.now(),size:t.size,attachmentType:t.attachmentType,extension:t.extension,attachmentId:t.attachmentId,rawUrl:t.rawUrl,previewUrl:t.previewUrl,thumbnailUrl:t.thumbnailUrl})},copyFilePreviewContent(){this.filePreviewContent&&navigator.clipboard.writeText(this.filePreviewContent).then(()=>{this.showToast("Copied to clipboard","success")}).catch(()=>{this.showToast("Failed to copy","error")})},getFileIcon(e){return e&&{ts:"\u{1F4D8}",tsx:"\u{1F4D8}",js:"\u{1F4D2}",jsx:"\u{1F4D2}",mjs:"\u{1F4D2}",cjs:"\u{1F4D2}",py:"\u{1F40D}",pyx:"\u{1F40D}",pyw:"\u{1F40D}",rs:"\u{1F980}",go:"\u{1F439}",c:"\u2699\uFE0F",cpp:"\u2699\uFE0F",h:"\u2699\uFE0F",hpp:"\u2699\uFE0F",html:"\u{1F310}",htm:"\u{1F310}",css:"\u{1F3A8}",scss:"\u{1F3A8}",sass:"\u{1F3A8}",less:"\u{1F3A8}",json:"\u{1F4CB}",yaml:"\u{1F4CB}",yml:"\u{1F4CB}",xml:"\u{1F4CB}",toml:"\u{1F4CB}",csv:"\u{1F4CB}",md:"\u{1F4DD}",markdown:"\u{1F4DD}",txt:"\u{1F4DD}",rst:"\u{1F4DD}",png:"\u{1F5BC}\uFE0F",jpg:"\u{1F5BC}\uFE0F",jpeg:"\u{1F5BC}\uFE0F",gif:"\u{1F5BC}\uFE0F",svg:"\u{1F5BC}\uFE0F",webp:"\u{1F5BC}\uFE0F",ico:"\u{1F5BC}\uFE0F",bmp:"\u{1F5BC}\uFE0F",mp4:"\u{1F3AC}",webm:"\u{1F3AC}",mov:"\u{1F3AC}",mp3:"\u{1F3B5}",wav:"\u{1F3B5}",ogg:"\u{1F3B5}",sh:"\u{1F4BB}",bash:"\u{1F4BB}",zsh:"\u{1F4BB}",env:"\u{1F510}",gitignore:"\u{1F6AB}",dockerfile:"\u{1F433}",lock:"\u{1F512}"}[e.toLowerCase()]||"\u{1F4C4}"},formatFileSize(e){return e==null?"":e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:e<1024*1024*1024?`${(e/(1024*1024)).toFixed(1)} MB`:`${(e/(1024*1024*1024)).toFixed(1)} GB`},openLogViewerWindow(e,t){if(t=t||this.activeSessionId,!t)return;const s=`${t}-${e.replace(/[^a-zA-Z0-9]/g,"_")}`;if(this.logViewerWindows.has(s)){const c=this.logViewerWindows.get(s);c.element.style.zIndex=++this.logViewerWindowZIndex;return}const n=this.logViewerWindows.size,a=100+n%5*30,i=100+n%5*30,r=e.split("/").pop(),o=document.createElement("div");o.className="log-viewer-window",o.id=`log-viewer-window-${s}`,o.style.left=`${a}px`,o.style.top=`${i}px`,o.style.zIndex=++this.logViewerWindowZIndex,o.innerHTML=`
286
286
  <div class="log-viewer-window-header">
287
287
  <div class="log-viewer-window-title" title="${escapeHtml(e)}">
288
288
  <span class="icon">\u{1F4C4}</span>
@@ -296,11 +296,11 @@
296
296
  <div class="log-viewer-window-body" id="log-viewer-body-${s}">
297
297
  <div class="log-info">Connecting to ${escapeHtml(e)}...</div>
298
298
  </div>
299
- `,document.body.appendChild(o);const l=this.makeWindowDraggable(o,o.querySelector(".log-viewer-window-header")),d=new EventSource(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`);d.onmessage=c=>{const m=JSON.parse(c.data),u=document.getElementById(`log-viewer-body-${s}`);if(u)switch(m.type){case"connected":u.innerHTML="";break;case"data":const h=u.scrollTop+u.clientHeight>=u.scrollHeight-10,p=escapeHtml(m.content);u.innerHTML+=p,h&&(u.scrollTop=u.scrollHeight),u.innerHTML.length>5e5&&(u.innerHTML=u.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":u.innerHTML+=`<div class="log-error">${escapeHtml(m.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},d.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:o,eventSource:d,filePath:e,sessionId:t,dragListeners:l})},updateLogViewerStatus(e,t,s){const n=document.querySelector(`#log-viewer-window-${e} .status`);n&&(n.className=`status ${t}`,n.textContent=s)},closeLogViewerWindow(e){const t=this.logViewerWindows.get(e);t&&(t.eventSource&&t.eventSource.close(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.logViewerWindows.delete(e))},closeSessionLogViewerWindows(e){const t=[];for(const[s,n]of this.logViewerWindows)n.sessionId===e&&t.push(s);for(const s of t)this.closeLogViewerWindow(s)},openImagePopup(e){const{sessionId:t,filePath:s,relativePath:n,fileName:i,timestamp:a,size:r}=e,o=`${t}-${a}`;if(this.imagePopups.has(o)){const g=this.imagePopups.get(o);g.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const g=this.imagePopups.keys().next().value;g&&this.closeImagePopup(g)}const d=this.imagePopups.size,c=(window.innerWidth-600)/2,m=(window.innerHeight-500)/2,u=c+d%5*30,h=m+d%5*30,y=this.sessions.get(t)?.name||t.substring(0,8),b=(r/1024).toFixed(1),f=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||i)}`,v=document.createElement("div");v.className="image-popup-window",v.id=`image-popup-${o}`,v.style.left=`${u}px`,v.style.top=`${h}px`,v.style.zIndex=++this.imagePopupZIndex,v.innerHTML=`
299
+ `,document.body.appendChild(o);const l=this.makeWindowDraggable(o,o.querySelector(".log-viewer-window-header")),d=new EventSource(`/api/sessions/${t}/tail-file?path=${encodeURIComponent(e)}&lines=50`);d.onmessage=c=>{const m=JSON.parse(c.data),u=document.getElementById(`log-viewer-body-${s}`);if(u)switch(m.type){case"connected":u.innerHTML="";break;case"data":const h=u.scrollTop+u.clientHeight>=u.scrollHeight-10,p=escapeHtml(m.content);u.innerHTML+=p,h&&(u.scrollTop=u.scrollHeight),u.innerHTML.length>5e5&&(u.innerHTML=u.innerHTML.slice(-4e5));break;case"end":this.updateLogViewerStatus(s,"disconnected","ended");break;case"error":u.innerHTML+=`<div class="log-error">${escapeHtml(m.error)}</div>`,this.updateLogViewerStatus(s,"error","error");break}},d.onerror=()=>{this.updateLogViewerStatus(s,"disconnected","connection error")},this.logViewerWindows.set(s,{element:o,eventSource:d,filePath:e,sessionId:t,dragListeners:l})},updateLogViewerStatus(e,t,s){const n=document.querySelector(`#log-viewer-window-${e} .status`);n&&(n.className=`status ${t}`,n.textContent=s)},closeLogViewerWindow(e){const t=this.logViewerWindows.get(e);t&&(t.eventSource&&t.eventSource.close(),t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.logViewerWindows.delete(e))},closeSessionLogViewerWindows(e){const t=[];for(const[s,n]of this.logViewerWindows)n.sessionId===e&&t.push(s);for(const s of t)this.closeLogViewerWindow(s)},openImagePopup(e){const{sessionId:t,filePath:s,relativePath:n,fileName:a,timestamp:i,size:r}=e,o=`${t}-${i}`;if(this.imagePopups.has(o)){const g=this.imagePopups.get(o);g.element.style.zIndex=++this.imagePopupZIndex;return}if(this.imagePopups.size>=20){const g=this.imagePopups.keys().next().value;g&&this.closeImagePopup(g)}const d=this.imagePopups.size,c=(window.innerWidth-600)/2,m=(window.innerHeight-500)/2,u=c+d%5*30,h=m+d%5*30,y=this.sessions.get(t)?.name||t.substring(0,8),b=(r/1024).toFixed(1),f=`/api/sessions/${t}/file-raw?path=${encodeURIComponent(n||a)}`,v=document.createElement("div");v.className="image-popup-window",v.id=`image-popup-${o}`,v.style.left=`${u}px`,v.style.top=`${h}px`,v.style.zIndex=++this.imagePopupZIndex,v.innerHTML=`
300
300
  <div class="image-popup-header">
301
301
  <div class="image-popup-title" title="${escapeHtml(s)}">
302
302
  <span class="icon">\u{1F5BC}\uFE0F</span>
303
- <span class="filename">${escapeHtml(i)}</span>
303
+ <span class="filename">${escapeHtml(a)}</span>
304
304
  <span class="session-badge">${escapeHtml(y)}</span>
305
305
  <span class="size-badge">${b} KB</span>
306
306
  </div>
@@ -310,11 +310,11 @@
310
310
  </div>
311
311
  </div>
312
312
  <div class="image-popup-body">
313
- <img src="${f}" alt="${escapeHtml(i)}"
313
+ <img src="${f}" alt="${escapeHtml(a)}"
314
314
  onerror="this.parentElement.innerHTML='<div class=\\'image-error\\'>Failed to load image</div>'"
315
315
  onclick="app.openImageInNewTab(${escapeHtml(JSON.stringify(f))})" />
316
316
  </div>
317
- `,document.body.appendChild(v);const T=this.makeWindowDraggable(v,v.querySelector(".image-popup-header"));v.addEventListener("mousedown",()=>{v.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(o,{element:v,sessionId:t,filePath:s,dragListeners:T})},closeImagePopup(e){const t=this.imagePopups.get(e);t&&(t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.imagePopups.delete(e))},openImageInNewTab(e){window.open(e,"_blank")},closeSessionImagePopups(e){const t=[];for(const[s,n]of this.imagePopups)n.sessionId===e&&t.push(s);for(const s of t)this.closeImagePopup(s)},async loadMuxSessions(){try{const t=await(await fetch("/api/mux-sessions")).json();this.muxSessions=t.data?.sessions||[],this.renderMuxSessions()}catch(e){console.error("Failed to load mux sessions:",e)}},killAllMuxSessions(){const e=this.muxSessions?.length||0;if(e===0){alert("No sessions to kill");return}document.getElementById("killAllCount").textContent=e;const t=document.getElementById("killAllModal");t.classList.add("active"),this.activeFocusTrap=new FocusTrap(t),this.activeFocusTrap.activate()},closeKillAllModal(){document.getElementById("killAllModal").classList.remove("active"),this.activeFocusTrap&&(this.activeFocusTrap.deactivate(),this.activeFocusTrap=null)},async confirmKillAll(e){this.closeKillAllModal();try{if(e){if((await(await fetch("/api/sessions",{method:"DELETE"})).json()).success){this.sessions.clear(),this.muxSessions=[],this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.renderMuxSessions(),this.terminal.clear(),this.terminal.reset(),this.toast("All sessions and tmux killed","success")}}else{this.sessions.clear(),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.terminal.clear(),this.terminal.reset(),this.toast("All tabs removed, tmux still running","info")}}catch(t){console.error("Failed to kill sessions:",t),this.toast("Failed to kill sessions: "+t.message,"error")}},renderMuxSessions(){this._debouncedCall("muxSessions",this._renderMuxSessionsImmediate)},_renderMuxSessionsImmediate(){const e=document.getElementById("muxSessionsBody");if(!this.muxSessions||this.muxSessions.length===0){e.innerHTML='<div class="monitor-empty">No mux sessions</div>';return}let t="";for(const s of this.muxSessions){const n=s.stats||{memoryMB:0,cpuPercent:0,childCount:0},i=this.sessions.get(s.sessionId),a=i?i.status:"unknown",r=i?i.isWorking:!1;let o,l;a==="idle"&&!r?(o="IDLE",l="status-idle"):a==="busy"||r?(o="WORKING",l="status-working"):a==="stopped"?(o="STOPPED",l="status-stopped"):(o=a.toUpperCase(),l="");const d=i&&i.tokens?i.tokens:null,c=i?i.totalCost:0,m=i&&i.cliModel||"",u=m.includes("opus")?"opus":m.includes("sonnet")?"sonnet":m.includes("haiku")?"haiku":"",h=i?i.ralphTodoStats:null;let p="";if(h&&h.total>0){const T=Math.round(h.completed/h.total*100);p=`<span class="process-stat todo-progress">${h.completed}/${h.total} (${T}%)</span>`}let y="";d&&d.total>0&&(y=`<span class="process-stat tokens">${(d.total/1e3).toFixed(1)}k tok</span>`);let b="";c>0&&(b=`<span class="process-stat cost">$${c.toFixed(2)}</span>`);let f="";u&&(f=`<span class="monitor-model-badge ${u}">${u}</span>`);const v=escapeHtml(JSON.stringify(s.sessionId));t+=`
317
+ `,document.body.appendChild(v);const T=this.makeWindowDraggable(v,v.querySelector(".image-popup-header"));v.addEventListener("mousedown",()=>{v.style.zIndex=++this.imagePopupZIndex}),this.imagePopups.set(o,{element:v,sessionId:t,filePath:s,dragListeners:T})},closeImagePopup(e){const t=this.imagePopups.get(e);t&&(t.dragListeners&&(document.removeEventListener("mousemove",t.dragListeners.move),document.removeEventListener("mouseup",t.dragListeners.up),t.dragListeners.touchMove&&(document.removeEventListener("touchmove",t.dragListeners.touchMove),document.removeEventListener("touchend",t.dragListeners.up),document.removeEventListener("touchcancel",t.dragListeners.up)),t.dragListeners.handle&&(t.dragListeners.handle.removeEventListener("mousedown",t.dragListeners.handleMouseDown),t.dragListeners.handle.removeEventListener("touchstart",t.dragListeners.handleTouchStart))),t.element.remove(),this.imagePopups.delete(e))},openImageInNewTab(e){window.open(e,"_blank")},closeSessionImagePopups(e){const t=[];for(const[s,n]of this.imagePopups)n.sessionId===e&&t.push(s);for(const s of t)this.closeImagePopup(s)},async loadMuxSessions(){try{const t=await(await fetch("/api/mux-sessions")).json();this.muxSessions=t.data?.sessions||[],this.renderMuxSessions()}catch(e){console.error("Failed to load mux sessions:",e)}},killAllMuxSessions(){const e=this.muxSessions?.length||0;if(e===0){alert("No sessions to kill");return}document.getElementById("killAllCount").textContent=e;const t=document.getElementById("killAllModal");t.classList.add("active"),this.activeFocusTrap=new FocusTrap(t),this.activeFocusTrap.activate()},closeKillAllModal(){document.getElementById("killAllModal").classList.remove("active"),this.activeFocusTrap&&(this.activeFocusTrap.deactivate(),this.activeFocusTrap=null)},async confirmKillAll(e){this.closeKillAllModal();try{if(e){if((await(await fetch("/api/sessions",{method:"DELETE"})).json()).success){this.sessions.clear(),this.muxSessions=[],this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.renderMuxSessions(),this.terminal.clear(),this.terminal.reset(),this.toast("All sessions and tmux killed","success")}}else{this.sessions.clear(),this.activeSessionId=null;try{localStorage.removeItem("codeman-active-session")}catch{}this.renderSessionTabs(),this.terminal.clear(),this.terminal.reset(),this.toast("All tabs removed, tmux still running","info")}}catch(t){console.error("Failed to kill sessions:",t),this.toast("Failed to kill sessions: "+t.message,"error")}},renderMuxSessions(){this._debouncedCall("muxSessions",this._renderMuxSessionsImmediate)},_renderMuxSessionsImmediate(){const e=document.getElementById("muxSessionsBody");if(!this.muxSessions||this.muxSessions.length===0){e.innerHTML='<div class="monitor-empty">No mux sessions</div>';return}let t="";for(const s of this.muxSessions){const n=s.stats||{memoryMB:0,cpuPercent:0,childCount:0},a=this.sessions.get(s.sessionId),i=a?a.status:"unknown",r=a?a.isWorking:!1;let o,l;i==="idle"&&!r?(o="IDLE",l="status-idle"):i==="busy"||r?(o="WORKING",l="status-working"):i==="stopped"?(o="STOPPED",l="status-stopped"):(o=i.toUpperCase(),l="");const d=a&&a.tokens?a.tokens:null,c=a?a.totalCost:0,m=a&&a.cliModel||"",u=m.includes("opus")?"opus":m.includes("sonnet")?"sonnet":m.includes("haiku")?"haiku":"",h=a?a.ralphTodoStats:null;let p="";if(h&&h.total>0){const T=Math.round(h.completed/h.total*100);p=`<span class="process-stat todo-progress">${h.completed}/${h.total} (${T}%)</span>`}let y="";d&&d.total>0&&(y=`<span class="process-stat tokens">${(d.total/1e3).toFixed(1)}k tok</span>`);let b="";c>0&&(b=`<span class="process-stat cost">$${c.toFixed(2)}</span>`);let f="";u&&(f=`<span class="monitor-model-badge ${u}">${u}</span>`);const v=escapeHtml(JSON.stringify(s.sessionId));t+=`
318
318
  <div class="process-item process-item-clickable" onclick="app.selectSession(${v})" title="Switch to session">
319
319
  <span class="monitor-status-badge ${l}">${o}</span>
320
320
  <div class="process-info">
@@ -331,18 +331,18 @@
331
331
  <button class="btn-toolbar btn-sm btn-danger" onclick="event.stopPropagation(); app.killMuxSession(${v})" title="Kill session">Kill</button>
332
332
  </div>
333
333
  </div>
334
- `}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(a=>a.status==="active"||a.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 i="";for(const a of s){const r=a.status==="active"?"active":a.status==="idle"?"idle":"completed",o=a.modelShort?`<span class="model-badge ${a.modelShort}">${a.modelShort}</span>`:"",l=a.description?escapeHtml(a.description.substring(0,40)):a.agentId;i+=`
334
+ `}e.innerHTML=t},renderMonitorSubagents(){const e=document.getElementById("monitorSubagentsBody"),t=document.getElementById("monitorSubagentStats");if(!e)return;const s=Array.from(this.subagents.values()),n=s.filter(i=>i.status==="active"||i.status==="idle").length;if(t&&(t.textContent=`${s.length} tracked`+(n>0?`, ${n} active`:"")),s.length===0){e.innerHTML='<div class="monitor-empty">No background agents</div>';return}let a="";for(const i of s){const r=i.status==="active"?"active":i.status==="idle"?"idle":"completed",o=i.modelShort?`<span class="model-badge ${i.modelShort}">${i.modelShort}</span>`:"",l=i.description?escapeHtml(i.description.substring(0,40)):i.agentId;a+=`
335
335
  <div class="process-item">
336
- <span class="process-mode ${r}">${a.status}</span>
336
+ <span class="process-mode ${r}">${i.status}</span>
337
337
  <div class="process-info">
338
338
  <div class="process-name">${o} ${l}</div>
339
339
  <div class="process-meta">
340
- <span>ID: ${a.agentId}</span>
341
- <span>${a.toolCallCount||0} tools</span>
340
+ <span>ID: ${i.agentId}</span>
341
+ <span>${i.toolCallCount||0} tools</span>
342
342
  </div>
343
343
  </div>
344
344
  <div class="process-actions">
345
- ${a.status!=="completed"?`<button class="btn-toolbar btn-sm btn-danger" onclick="app.killSubagent(${escapeHtml(JSON.stringify(a.agentId))})" title="Kill agent">Kill</button>`:""}
345
+ ${i.status!=="completed"?`<button class="btn-toolbar btn-sm btn-danger" onclick="app.killSubagent(${escapeHtml(JSON.stringify(i.agentId))})" title="Kill agent">Kill</button>`:""}
346
346
  </div>
347
347
  </div>
348
- `}e.innerHTML=i},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=3e3,action:i}=s,a=document.createElement("div");a.className=`toast toast-${t}`;const r=document.createElement("span");if(r.textContent=e,a.appendChild(r),i){const o=document.createElement("button");o.textContent=i.label,o.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",o.onclick=l=>{l.stopPropagation(),i.onClick(),a.remove()},a.appendChild(o)}this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer.appendChild(a),requestAnimationFrame(()=>a.classList.add("show")),setTimeout(()=>{a.classList.remove("show"),setTimeout(()=>a.remove(),200)},n)},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none"))try{const s=await(await fetch("/api/system/stats")).json();this.updateSystemStatsDisplay(s.data)}catch{}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),n=this.$("statMem"),i=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),n&&i){const a=(e.memory.usedMB/1024).toFixed(1);n.textContent=`${a}G`,i.style.width=`${Math.min(100,e.memory.percent)}%`,i.classList.remove("medium","high"),n.classList.remove("high"),e.memory.percent>80?(i.classList.add("high"),n.classList.add("high")):e.memory.percent>50&&i.classList.add("medium")}},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:space-between;align-items:center";const i=document.createElement("span");i.style.cssText="color:#cdd6f4;font-weight:600",i.textContent="Clipboard (browser blocked auto-copy)";const a=document.createElement("button");a.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",a.textContent="\xD7",n.appendChild(i),n.appendChild(a);const r=document.createElement("textarea");r.readOnly=!0,r.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",r.value=e;const o=document.createElement("button");o.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",o.textContent="Copy to Clipboard",s.appendChild(n),s.appendChild(r),s.appendChild(o),t.appendChild(s),document.body.appendChild(t),o.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{r.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const l=()=>t.remove();a.onclick=l,t.onclick=d=>{d.target===t&&l()}}});
348
+ `}e.innerHTML=a},async killMuxSession(e){if(confirm("Kill this mux session?")){try{await this.closeSession(e,!0)}catch{try{await fetch(`/api/mux-sessions/${e}`,{method:"DELETE"})}catch{}this.showToast("Tmux session killed","success")}this.muxSessions=this.muxSessions.filter(t=>t.sessionId!==e),this.renderMuxSessions()}},async reconcileMuxSessions(){try{const t=await(await fetch("/api/mux-sessions/reconcile",{method:"POST"})).json();t.data?.dead&&t.data.dead.length>0?(this.showToast(`Found ${t.data.dead.length} dead mux session(s)`,"warning"),await this.loadMuxSessions()):this.showToast("All mux sessions are alive","success")}catch{this.showToast("Failed to reconcile mux sessions","error")}},toggleNotifications(){this.notificationManager?.toggleDrawer()},async launchMultiMonitor(){try{const e=await fetch("/api/system/span-displays",{method:"POST"}),t=await e.json().catch(()=>({}));e.ok&&t.success?this.showToast("Opening Codeman across all displays\u2026","success"):this.showToast(t.error||"Could not open spanning window","error")}catch(e){this.showToast("Could not open spanning window: "+(e?.message||e),"error")}},toast(e,t="info"){return this.showToast(e,t)},showToast(e,t="info",s={}){const{duration:n=3e3,action:a}=s,i=document.createElement("div");i.className=`toast toast-${t}`;const r=document.createElement("span");if(r.textContent=e,i.appendChild(r),a){const o=document.createElement("button");o.textContent=a.label,o.style.cssText="margin-left:12px;padding:2px 10px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.3);border-radius:3px;color:inherit;cursor:pointer;font-size:12px",o.onclick=l=>{l.stopPropagation(),a.onClick(),i.remove()},i.appendChild(o)}this._toastContainer||(this._toastContainer=document.querySelector(".toast-container"),this._toastContainer||(this._toastContainer=document.createElement("div"),this._toastContainer.className="toast-container",document.body.appendChild(this._toastContainer))),this._toastContainer.appendChild(i),requestAnimationFrame(()=>i.classList.add("show")),setTimeout(()=>{i.classList.remove("show"),setTimeout(()=>i.remove(),200)},n)},startSystemStatsPolling(){this.stopSystemStatsPolling(),this.fetchSystemStats(),this.systemStatsInterval=setInterval(()=>{this.fetchSystemStats()},2e3)},stopSystemStatsPolling(){this.systemStatsInterval&&(clearInterval(this.systemStatsInterval),this.systemStatsInterval=null)},async fetchSystemStats(){const e=document.getElementById("headerSystemStats");if(!(!e||e.style.display==="none"))try{const s=await(await fetch("/api/system/stats")).json();this.updateSystemStatsDisplay(s.data)}catch{}},updateSystemStatsDisplay(e){const t=this.$("statCpu"),s=this.$("statCpuBar"),n=this.$("statMem"),a=this.$("statMemBar");if(t&&s&&(t.textContent=`${e.cpu}%`,s.style.width=`${Math.min(100,e.cpu)}%`,s.classList.remove("medium","high"),t.classList.remove("high"),e.cpu>80?(s.classList.add("high"),t.classList.add("high")):e.cpu>50&&s.classList.add("medium")),n&&a){const i=(e.memory.usedMB/1024).toFixed(1);n.textContent=`${i}G`,a.style.width=`${Math.min(100,e.memory.percent)}%`,a.classList.remove("medium","high"),n.classList.remove("high"),e.memory.percent>80?(a.classList.add("high"),n.classList.add("high")):e.memory.percent>50&&a.classList.add("medium")}},async _onClipboardWrite(e){const t=e?.text;if(typeof t=="string")try{await navigator.clipboard.writeText(t),this.showToast(`Copied to clipboard (${t.length} chars)`,"success")}catch{this._showClipboardFallback(t)}},_showClipboardFallback(e){const t=document.createElement("div");t.style.cssText="position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:10000;display:flex;align-items:center;justify-content:center";const s=document.createElement("div");s.style.cssText="background:#1e1e2e;border:1px solid #444;border-radius:8px;padding:16px;max-width:600px;width:90%;max-height:60vh;display:flex;flex-direction:column;gap:12px";const n=document.createElement("div");n.style.cssText="display:flex;justify-content:space-between;align-items:center";const a=document.createElement("span");a.style.cssText="color:#cdd6f4;font-weight:600",a.textContent="Clipboard (browser blocked auto-copy)";const i=document.createElement("button");i.style.cssText="background:none;border:none;color:#cdd6f4;font-size:18px;cursor:pointer",i.textContent="\xD7",n.appendChild(a),n.appendChild(i);const r=document.createElement("textarea");r.readOnly=!0,r.style.cssText="background:#181825;color:#cdd6f4;border:1px solid #555;border-radius:4px;padding:8px;font-family:monospace;font-size:13px;resize:none;height:200px;width:100%",r.value=e;const o=document.createElement("button");o.style.cssText="background:#89b4fa;color:#1e1e2e;border:none;border-radius:4px;padding:8px 16px;cursor:pointer;font-weight:600",o.textContent="Copy to Clipboard",s.appendChild(n),s.appendChild(r),s.appendChild(o),t.appendChild(s),document.body.appendChild(t),o.onclick=async()=>{try{await navigator.clipboard.writeText(e),this.showToast("Copied to clipboard","success"),t.remove()}catch{r.select(),document.execCommand("copy"),this.showToast("Copied (fallback)","success"),t.remove()}};const l=()=>t.remove();i.onclick=l,t.onclick=d=>{d.target===t&&l()}}});