claude-mpm 4.2.44__py3-none-any.whl → 4.2.51__py3-none-any.whl

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 (148) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +43 -1
  3. claude_mpm/agents/INSTRUCTIONS.md +75 -1
  4. claude_mpm/agents/WORKFLOW.md +46 -1
  5. claude_mpm/agents/frontmatter_validator.py +20 -12
  6. claude_mpm/agents/templates/nextjs_engineer.json +277 -0
  7. claude_mpm/agents/templates/python_engineer.json +289 -0
  8. claude_mpm/agents/templates/react_engineer.json +11 -3
  9. claude_mpm/agents/templates/security.json +50 -9
  10. claude_mpm/cli/commands/agents.py +2 -2
  11. claude_mpm/cli/commands/uninstall.py +1 -2
  12. claude_mpm/cli/interactive/agent_wizard.py +3 -3
  13. claude_mpm/cli/parsers/agent_manager_parser.py +3 -3
  14. claude_mpm/cli/parsers/agents_parser.py +1 -1
  15. claude_mpm/constants.py +1 -1
  16. claude_mpm/core/error_handler.py +2 -4
  17. claude_mpm/core/file_utils.py +4 -12
  18. claude_mpm/core/log_manager.py +8 -5
  19. claude_mpm/core/logger.py +1 -1
  20. claude_mpm/core/logging_utils.py +6 -6
  21. claude_mpm/core/unified_agent_registry.py +18 -4
  22. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +188 -0
  23. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +156 -0
  24. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +38 -0
  25. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +92 -0
  26. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +248 -0
  27. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +61 -0
  28. claude_mpm/dashboard/static/archive/test_activity_connection.html +179 -0
  29. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +68 -0
  30. claude_mpm/dashboard/static/archive/test_dashboard.html +409 -0
  31. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +519 -0
  32. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +181 -0
  33. claude_mpm/dashboard/static/archive/test_file_data.html +315 -0
  34. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +243 -0
  35. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +234 -0
  36. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +117 -0
  37. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +115 -0
  38. claude_mpm/dashboard/static/archive/test_file_viewer.html +224 -0
  39. claude_mpm/dashboard/static/archive/test_final_activity.html +220 -0
  40. claude_mpm/dashboard/static/archive/test_tab_fix.html +139 -0
  41. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +1 -0
  42. claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
  43. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +777 -0
  44. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  45. claude_mpm/dashboard/static/built/components/build-tracker.js +333 -0
  46. claude_mpm/dashboard/static/built/components/code-simple.js +857 -0
  47. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +353 -0
  48. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +235 -0
  49. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +409 -0
  50. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +435 -0
  51. claude_mpm/dashboard/static/built/components/code-viewer.js +2 -1076
  52. claude_mpm/dashboard/static/built/components/connection-debug.js +654 -0
  53. claude_mpm/dashboard/static/built/components/diff-viewer.js +891 -0
  54. claude_mpm/dashboard/static/built/components/event-processor.js +1 -1
  55. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  56. claude_mpm/dashboard/static/built/components/export-manager.js +1 -1
  57. claude_mpm/dashboard/static/built/components/file-change-tracker.js +443 -0
  58. claude_mpm/dashboard/static/built/components/file-change-viewer.js +690 -0
  59. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  60. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  61. claude_mpm/dashboard/static/built/components/nav-bar.js +145 -0
  62. claude_mpm/dashboard/static/built/components/page-structure.js +429 -0
  63. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  64. claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -465
  65. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  66. claude_mpm/dashboard/static/built/connection-manager.js +536 -0
  67. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  68. claude_mpm/dashboard/static/built/extension-error-handler.js +164 -0
  69. claude_mpm/dashboard/static/built/react/events.js +30 -0
  70. claude_mpm/dashboard/static/built/shared/dom-helpers.js +396 -0
  71. claude_mpm/dashboard/static/built/shared/event-bus.js +330 -0
  72. claude_mpm/dashboard/static/built/shared/event-filter-service.js +540 -0
  73. claude_mpm/dashboard/static/built/shared/logger.js +385 -0
  74. claude_mpm/dashboard/static/built/shared/page-structure.js +251 -0
  75. claude_mpm/dashboard/static/built/shared/tooltip-service.js +253 -0
  76. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  77. claude_mpm/dashboard/static/built/tab-isolation-fix.js +185 -0
  78. claude_mpm/dashboard/static/css/dashboard.css +28 -5
  79. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +1 -0
  80. claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
  81. claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
  82. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  83. claude_mpm/dashboard/static/dist/components/event-processor.js +1 -1
  84. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  85. claude_mpm/dashboard/static/dist/components/export-manager.js +1 -1
  86. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
  87. claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
  88. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  89. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  90. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  91. claude_mpm/dashboard/static/dist/react/events.js +30 -0
  92. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  93. claude_mpm/dashboard/static/events.html +607 -0
  94. claude_mpm/dashboard/static/index.html +713 -0
  95. claude_mpm/dashboard/static/js/components/activity-tree.js +3 -17
  96. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +4 -1
  97. claude_mpm/dashboard/static/js/components/agent-inference.js +3 -0
  98. claude_mpm/dashboard/static/js/components/build-tracker.js +8 -0
  99. claude_mpm/dashboard/static/js/components/code-viewer.js +306 -66
  100. claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
  101. claude_mpm/dashboard/static/js/components/event-viewer.js +39 -2
  102. claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
  103. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +30 -10
  104. claude_mpm/dashboard/static/js/components/socket-manager.js +4 -0
  105. claude_mpm/dashboard/static/js/components/ui-state-manager.js +285 -85
  106. claude_mpm/dashboard/static/js/components/working-directory.js +3 -0
  107. claude_mpm/dashboard/static/js/dashboard.js +61 -33
  108. claude_mpm/dashboard/static/js/socket-client.js +12 -8
  109. claude_mpm/dashboard/static/js/stores/dashboard-store.js +562 -0
  110. claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
  111. claude_mpm/dashboard/static/legacy/activity.html +736 -0
  112. claude_mpm/dashboard/static/legacy/agents.html +786 -0
  113. claude_mpm/dashboard/static/legacy/files.html +747 -0
  114. claude_mpm/dashboard/static/legacy/tools.html +831 -0
  115. claude_mpm/dashboard/static/monitors-index.html +218 -0
  116. claude_mpm/dashboard/static/monitors.html +431 -0
  117. claude_mpm/dashboard/static/production/events.html +659 -0
  118. claude_mpm/dashboard/static/production/main.html +715 -0
  119. claude_mpm/dashboard/static/production/monitors.html +483 -0
  120. claude_mpm/dashboard/static/socket.io.min.js +7 -0
  121. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
  122. claude_mpm/dashboard/static/test-archive/dashboard.html +635 -0
  123. claude_mpm/dashboard/static/test-archive/debug-events.html +147 -0
  124. claude_mpm/dashboard/static/test-archive/test-navigation.html +256 -0
  125. claude_mpm/dashboard/static/test-archive/test-react-exports.html +180 -0
  126. claude_mpm/dashboard/templates/index.html +79 -9
  127. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +1 -1
  128. claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -0
  129. claude_mpm/services/agents/deployment/agent_template_builder.py +25 -8
  130. claude_mpm/services/agents/deployment/agent_validator.py +3 -0
  131. claude_mpm/services/agents/deployment/validation/template_validator.py +13 -4
  132. claude_mpm/services/agents/local_template_manager.py +2 -6
  133. claude_mpm/services/monitor/daemon.py +1 -2
  134. claude_mpm/services/monitor/daemon_manager.py +2 -5
  135. claude_mpm/services/monitor/event_emitter.py +2 -2
  136. claude_mpm/services/monitor/handlers/code_analysis.py +4 -6
  137. claude_mpm/services/monitor/handlers/hooks.py +2 -4
  138. claude_mpm/services/monitor/server.py +27 -4
  139. claude_mpm/tools/code_tree_analyzer.py +2 -2
  140. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/METADATA +1 -1
  141. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/RECORD +146 -81
  142. claude_mpm/dashboard/static/test-browser-monitor.html +0 -470
  143. claude_mpm/dashboard/static/test-simple.html +0 -97
  144. /claude_mpm/dashboard/static/{test_debug.html → test-archive/test_debug.html} +0 -0
  145. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/WHEEL +0 -0
  146. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/entry_points.txt +0 -0
  147. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/licenses/LICENSE +0 -0
  148. {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/top_level.txt +0 -0
@@ -1,2 +1,2 @@
1
- import{S as e,U as t}from"./socket-client.js";import{E as n,a as i}from"./components/event-viewer.js";import{M as s}from"./components/module-viewer.js";import{S as o}from"./components/session-manager.js";import{A as r}from"./components/agent-inference.js";import{E as a}from"./components/export-manager.js";import{W as l}from"./components/working-directory.js";import{F as c}from"./components/file-tool-tracker.js";import"./components/unified-data-viewer.js";class d{constructor(e,t){this.agentInference=e,this.eventViewer=t,this.state={hierarchyTree:null,nodeMap:new Map,expandedNodes:new Set,selectedNode:null},this.expandAll=!0,this.setupEventListeners(),console.log("Agent hierarchy component initialized")}setupEventListeners(){document.addEventListener("click",e=>{const t=e.target.closest("[data-toggle-node]");if(t&&window.dashboard&&window.dashboard.agentHierarchy){const e=t.dataset.toggleNode;window.dashboard.agentHierarchy.toggleNode(e)}})}buildHierarchy(){this.agentInference.processAgentInference();const e=this.agentInference.getPMDelegations(),t=this.eventViewer.events,n=this.agentInference.getEventAgentMap(),i={id:"pm_main",type:"pm",name:"PM (Main Session)",children:[],events:[],eventCount:0,status:"active",startTime:null,endTime:null,expanded:!0},s=new Map;this.state.nodeMap.clear(),this.state.nodeMap.set(i.id,i);const o=new Set;for(const[h,u]of e){const e={id:h,type:"subagent",name:u.agentName,delegationContext:this.extractDelegationContext(u.pmCall),children:[],events:u.agentEvents,eventCount:u.agentEvents.length,status:u.endIndex?"completed":"active",startTime:u.timestamp,endTime:u.endIndex?t[u.endIndex]?.timestamp:null,startIndex:u.startIndex,endIndex:u.endIndex,expanded:this.expandAll||this.state.expandedNodes.has(h)};if(i.children.push(e),this.state.nodeMap.set(h,e),o.add(u.agentName),i.eventCount++,(!i.startTime||new Date(u.timestamp)<new Date(i.startTime))&&(i.startTime=u.timestamp),u.endIndex&&t[u.endIndex]){const e=t[u.endIndex].timestamp;(!i.endTime||new Date(e)>new Date(i.endTime))&&(i.endTime=e)}}const r=this.agentInference.getOrphanGroups();let a=1;for(const[h,u]of r){const i={id:`pm_implied_${h}`,type:"pm",name:`PM (Implied #${a})`,children:[],events:[],eventCount:0,status:"inferred",startTime:null,endTime:null,expanded:!0,isImplied:!0,tooltip:"Inferred PM - Subagents started without explicit PM delegation"};s.set(h,i),this.state.nodeMap.set(i.id,i),a++;const o=new Map;for(const s of u){const i=[];t.forEach((t,o)=>{const r=n.get(o);if(r&&r.agentName===s.agentName){let n=!0;for(const[t,i]of e)if(i.agentEvents.some(e=>e.eventIndex===o)){n=!1;break}n&&i.push({eventIndex:o,event:t,inference:r})}}),i.length>0&&(o.has(s.agentName)||o.set(s.agentName,[]),o.get(s.agentName).push(...i))}for(const[e,t]of o){if(0===t.length)continue;const n=t[0].event,s=t[t.length-1].event,o={id:`implied_agent_${h}_${e}`,type:"subagent",name:e,delegationContext:"Orphan agent - no explicit PM delegation found",children:[],events:t,eventCount:t.length,status:"inferred",startTime:n.timestamp,endTime:s.timestamp,startIndex:t[0].eventIndex,endIndex:t[t.length-1].eventIndex,expanded:this.expandAll,isImplied:!0,tooltip:"This agent was spawned without an explicit PM Task delegation"};i.children.push(o),this.state.nodeMap.set(o.id,o),i.eventCount+=t.length,(!i.startTime||new Date(n.timestamp)<new Date(i.startTime))&&(i.startTime=n.timestamp),(!i.endTime||new Date(s.timestamp)>new Date(i.endTime))&&(i.endTime=s.timestamp)}}const l=[];if(t.forEach((t,i)=>{const o=n.get(i);if(o&&"subagent"===o.type){let n=!0;for(const[t,s]of e)if(s.agentEvents.some(e=>e.eventIndex===i)){n=!1;break}if(n)for(const[e,t]of s){for(const e of t.children)if(e.events.some(e=>e.eventIndex===i)){n=!1;break}if(!n)break}n&&l.push({eventIndex:i,event:t,inference:o})}}),l.length>0){const e={id:"pm_implied_generic",type:"pm",name:"PM (Implied - Uncategorized)",children:[],events:[],eventCount:0,status:"inferred",startTime:null,endTime:null,expanded:!0,isImplied:!0,tooltip:"Orphan agents without clear grouping"},t=new Map;for(const n of l){const e=n.inference.agentName;t.has(e)||t.set(e,[]),t.get(e).push(n)}for(const[n,i]of t){const t=i[0].event,s=i[i.length-1].event,o={id:`implied_generic_${n}`,type:"subagent",name:n,delegationContext:"Uncategorized orphan agent",children:[],events:i,eventCount:i.length,status:"inferred",startTime:t.timestamp,endTime:s.timestamp,startIndex:i[0].eventIndex,endIndex:i[i.length-1].eventIndex,expanded:this.expandAll,isImplied:!0};e.children.push(o),this.state.nodeMap.set(o.id,o),e.eventCount+=i.length,(!e.startTime||new Date(t.timestamp)<new Date(e.startTime))&&(e.startTime=t.timestamp),(!e.endTime||new Date(s.timestamp)>new Date(e.endTime))&&(e.endTime=s.timestamp)}e.children.length>0&&(s.set("generic",e),this.state.nodeMap.set(e.id,e))}let c=0;if(t.forEach((e,t)=>{const s=n.get(t);s&&"main_agent"===s.type&&(c++,i.events.push({eventIndex:t,event:e,inference:s}))}),i.eventCount+=c,i.children.length>0){const e=i.children.some(e=>"active"===e.status);i.status=e?"active":"completed"}const d={roots:[]};(i.eventCount>0||i.children.length>0)&&d.roots.push(i);for(const[h,u]of s)u.children.length>0&&d.roots.push(u);return this.state.hierarchyTree=d,console.log("Hierarchy built:",{mainPM:{children:i.children.length,events:i.eventCount,ownEvents:c},impliedPMGroups:s.size,totalImpliedAgents:Array.from(s.values()).reduce((e,t)=>e+t.children.length,0)}),d}extractDelegationContext(e){if(!e)return"Unknown delegation";const t=e.tool_parameters||e.data?.tool_parameters||{},n=t.task||t.request||t.description;if(n){const e=100;return n.length>e?n.substring(0,e)+"...":n}const i=e.tool_input||e.data?.tool_input;if(i&&"string"==typeof i){const e=100;return i.length>e?i.substring(0,e)+"...":i}return"Task delegation"}render(e={}){const t=this.state.hierarchyTree||this.buildHierarchy();if(!t.roots||0===t.roots.length)return'<div class="agent-hierarchy-empty">No agent activity detected</div>';return`<div class="agent-hierarchy">${this.applyFilters(t,e).roots.map(e=>this.renderNode(e,0)).join("")}</div>`}renderNode(e,t){const n=e.expanded||this.state.expandedNodes.has(e.id),i=e.children&&e.children.length>0,s=this.state.selectedNode===e.id,o=this.getNodeIcon(e),r=i?n?"▼":"▶":"&nbsp;&nbsp;",a=this.getStatusClass(e.status),l=e.isImplied?"agent-node-implied":"",c=e.tooltip?`title="${this.escapeHtml(e.tooltip)}"`:"";let d=`\n <div class="agent-node agent-node-level-${t} ${s?"agent-node-selected":""} ${l}" \n data-node-id="${e.id}" ${c}>\n <div class="agent-node-header ${a}" \n data-toggle-node="${e.id}" style="cursor: pointer">\n <span class="agent-node-expand">${r}</span>\n <span class="agent-node-icon">${o}</span>\n <span class="agent-node-name">${this.escapeHtml(e.name)}</span>\n <span class="agent-node-stats">\n <span class="agent-event-count">${e.eventCount} events</span>\n ${e.status?`<span class="agent-status">${e.status}</span>`:""}\n </span>\n </div>\n `;if(n&&(e.delegationContext||e.startTime)){if(d+='<div class="agent-node-details">',e.delegationContext&&"Unknown delegation"!==e.delegationContext&&(d+=`\n <div class="agent-delegation-context">\n <strong>Task:</strong> ${this.escapeHtml(e.delegationContext)}\n </div>\n `),e.startTime){const t=this.calculateDuration(e.startTime,e.endTime);d+=`\n <div class="agent-timing">\n <span class="agent-time-start">${this.formatTime(e.startTime)}</span>\n ${t?`<span class="agent-duration">(${t})</span>`:""}\n </div>\n `}d+="</div>"}return n&&i&&(d+='<div class="agent-node-children">',d+=e.children.map(e=>this.renderNode(e,t+1)).join(""),d+="</div>"),d+="</div>",d}getNodeIcon(e){if("pm"===e.type)return e.isImplied?"🔍":"👔";return{"Engineer Agent":"🔧","Research Agent":"🔍","QA Agent":"✅","Documentation Agent":"📝","Security Agent":"🔒","Ops Agent":"⚙️","Version Control Agent":"📦","Data Engineer Agent":"💾","Test Integration Agent":"🧪"}[e.name]||"🤖"}getStatusClass(e){switch(e){case"active":return"agent-status-active";case"completed":return"agent-status-completed";case"pending":return"agent-status-pending";case"inferred":return"agent-status-inferred";default:return"agent-status-unknown"}}toggleNode(e){const t=this.state.nodeMap.get(e);t&&(this.state.expandedNodes.has(e)?(this.state.expandedNodes.delete(e),t.expanded=!1):(this.state.expandedNodes.add(e),t.expanded=!0),window.dashboard&&window.dashboard.renderCurrentTab())}selectNode(e){this.state.selectedNode=e;const t=this.state.nodeMap.get(e);if(t){const e=new CustomEvent("agentNodeSelected",{detail:{node:t}});document.dispatchEvent(e)}}applyFilters(e,t){if(!t||0===Object.keys(t).length)return e;const n={roots:[]};for(const i of e.roots){const e=this.filterNode(i,t);e&&n.roots.push(e)}return n}filterNode(e,t){let n=!0;if(t.searchText){const i=t.searchText.toLowerCase();n=n&&(e.name.toLowerCase().includes(i)||e.delegationContext&&e.delegationContext.toLowerCase().includes(i))}t.agentType&&(n=n&&e.name.includes(t.agentType)),t.status&&(n=n&&e.status===t.status);let i=[];if(e.children)for(const s of e.children){const e=this.filterNode(s,t);e&&i.push(e)}return n||i.length>0?{...e,children:i}:null}formatTime(e){if(!e)return"";return new Date(e).toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}calculateDuration(e,t){if(!e||!t)return"";const n=new Date(e).getTime(),i=new Date(t).getTime()-n;if(i<1e3)return`${i}ms`;if(i<6e4)return`${(i/1e3).toFixed(1)}s`;return`${Math.floor(i/6e4)}m ${Math.floor(i%6e4/1e3)}s`}escapeHtml(e){if(!e)return"";const t=document.createElement("div");return t.textContent=e,t.innerHTML}updateWithNewEvents(e){this.buildHierarchy()}clear(){this.state.hierarchyTree=null,this.state.nodeMap.clear(),this.state.expandedNodes.clear(),this.state.selectedNode=null}expandAllNodes(){for(const[e,t]of this.state.nodeMap)this.state.expandedNodes.add(e),t.expanded=!0;this.expandAll=!0}collapseAllNodes(){this.state.expandedNodes.clear();for(const[e,t]of this.state.nodeMap)t.expanded=!1;this.expandAll=!1}}class h{constructor(){this.element=null,this.buildInfo={monitor:{version:"1.0.0",build:1,formatted_build:"0001",full_version:"v1.0.0-0001"},mpm:{version:"unknown",build:"unknown",full_version:"v0.0.0"}},this.socketClient=null,this.init()}async init(){await this.loadDashboardVersion(),this.createElements(),this.setupEventListeners()}async loadDashboardVersion(){try{const e=await fetch("/version.json");if(e.ok){const t=await e.json();this.buildInfo.monitor={version:t.version||"1.0.0",build:t.build||1,formatted_build:t.formatted_build||"0001",full_version:t.full_version||"v1.0.0-0001"}}}catch(e){}}createElements(){this.element=document.createElement("div"),this.element.className="version-display",this.element.id="version-display";const e=document.createElement("span");e.className="version-item mpm-version",e.id="mpm-version",e.innerHTML='\n <span class="version-label">MPM</span>\n <span class="version-value">v0.0.0</span>\n ';const t=document.createElement("span");t.className="version-separator",t.textContent="|";const n=document.createElement("span");n.className="version-item monitor-version",n.id="monitor-version",n.innerHTML='\n <span class="version-label">Monitor</span>\n <span class="version-value">v1.0.0-0001</span>\n ',this.element.appendChild(e),this.element.appendChild(t),this.element.appendChild(n),this.element.title="Click for detailed version information"}setSocketClient(e){this.socketClient=e,this.socketClient&&this.socketClient.socket&&(this.socketClient.socket.on("welcome",e=>{const t=e.build_info||e.data&&e.data.build_info;t&&this.updateBuildInfo(t)}),this.socketClient.socket.on("status",e=>{const t=e.build_info||e.data&&e.data.build_info;t&&this.updateBuildInfo(t)}),this.socketClient.socket.on("build_info",e=>{this.updateBuildInfo(e)}))}updateBuildInfo(e){this.buildInfo=e,this.updateDisplay()}updateDisplay(){const e=this.element.querySelector(".mpm-version .version-value");if(e&&this.buildInfo.mpm){const t=this.buildInfo.mpm.full_version||`v${this.buildInfo.mpm.version}`;e.textContent=t,this.buildInfo.mpm.build&&"unknown"!==this.buildInfo.mpm.build&&(e.parentElement.title=`MPM Build: ${this.buildInfo.mpm.build}`)}const t=this.element.querySelector(".monitor-version .version-value");if(t&&this.buildInfo.monitor){const e=this.buildInfo.monitor.full_version||`v${this.buildInfo.monitor.version}-${this.buildInfo.monitor.formatted_build}`;if(t.textContent=e,this.buildInfo.monitor.last_updated){const e=new Date(this.buildInfo.monitor.last_updated).toLocaleString();t.parentElement.title=`Monitor Build: ${this.buildInfo.monitor.formatted_build}\nLast Updated: ${e}`}}}setupEventListeners(){this.element.addEventListener("click",()=>{this.showDetailedInfo()})}showDetailedInfo(){const e=[];if(this.buildInfo.mpm&&(e.push("=== MPM Framework ==="),e.push(`Version: ${this.buildInfo.mpm.version}`),this.buildInfo.mpm.build&&"unknown"!==this.buildInfo.mpm.build&&e.push(`Build: ${this.buildInfo.mpm.build}`),e.push(`Full: ${this.buildInfo.mpm.full_version}`)),e.push(""),this.buildInfo.monitor&&(e.push("=== Monitor UI ==="),e.push(`Version: ${this.buildInfo.monitor.version}`),e.push(`Build: ${this.buildInfo.monitor.formatted_build} (${this.buildInfo.monitor.build})`),e.push(`Full: ${this.buildInfo.monitor.full_version}`),this.buildInfo.monitor.last_updated)){const t=new Date(this.buildInfo.monitor.last_updated).toLocaleString();e.push(`Updated: ${t}`)}const t=document.createElement("div");t.className="version-modal",t.innerHTML=`\n <div class="version-modal-content">\n <h3>Version Information</h3>\n <pre>${e.join("\n")}</pre>\n <button onclick="this.parentElement.parentElement.remove()">Close</button>\n </div>\n `,document.body.appendChild(t),setTimeout(()=>{t.remove()},1e4)}mount(e){const t="string"==typeof e?document.querySelector(e):e;this.element&&t&&this.element.parentNode!==t&&t.appendChild(this.element)}getElement(){return this.element}destroy(){this.element&&this.element.parentNode&&this.element.parentNode.removeChild(this.element),this.socketClient&&this.socketClient.socket&&(this.socketClient.socket.off("welcome"),this.socketClient.socket.off("status"),this.socketClient.socket.off("build_info")),this.element=null,this.socketClient=null}}class u{constructor(){this.eventViewer=null,this.moduleViewer=null,this.sessionManager=null,this.activityTreeRetryCount=0,this.maxRetryAttempts=10,this.socketManager=null,this.agentInference=null,this.agentHierarchy=null,this.uiStateManager=null,this.eventProcessor=null,this.exportManager=null,this.workingDirectoryManager=null,this.fileToolTracker=null,this.buildTracker=null,this.init()}init(){console.log("Initializing refactored Claude MPM Dashboard...");try{this.fetchServerConfig(),this.initializeSocketManager(),this.initializeCoreComponents(),this.initializeBuildTracker(),this.initializeAgentInference(),this.initializeAgentHierarchy(),this.initializeUIStateManager(),this.initializeWorkingDirectoryManager(),this.initializeFileToolTracker(),this.initializeEventProcessor(),this.initializeExportManager(),this.setupModuleInteractions(),this.initializeFromURL(),console.log("Claude MPM Dashboard initialized successfully")}catch(e){throw console.error("Error during dashboard initialization:",e),e}}fetchServerConfig(){fetch("/api/config").then(e=>e.json()).then(e=>{window.dashboardConfig=e;const t=document.getElementById("working-dir-path");t&&e.workingDirectory&&(t.textContent=e.workingDirectory);const n=document.getElementById("footer-git-branch");n&&e.gitBranch&&(n.textContent=e.gitBranch),console.log("Dashboard configuration loaded:",e)}).catch(e=>{console.warn("Failed to fetch server config:",e),window.dashboardConfig={workingDirectory:".",gitBranch:"Unknown"}})}validateInitialization(){const e=[{name:"socketManager",component:this.socketManager},{name:"eventViewer",component:this.eventViewer},{name:"agentHierarchy",component:this.agentHierarchy}].filter(e=>!e.component);e.length>0?console.warn("Missing critical components:",e.map(e=>e.name)):console.log("All critical components initialized")}postInit(){try{this.agentHierarchy&&(window.dashboard.agentHierarchy=this.agentHierarchy,console.log("Agent hierarchy global reference set")),this.validateInitialization()}catch(e){console.error("Error in dashboard postInit:",e)}}initializeSocketManager(){this.socketManager=new e,this.socketManager.setupConnectionControls(),this.socketClient=this.socketManager.getSocketClient(),window.socketClient=this.socketClient}initializeCoreComponents(){this.eventViewer=new n("events-list",this.socketClient),this.moduleViewer=new s,this.sessionManager=new o(this.socketClient),window.eventViewer=this.eventViewer,window.moduleViewer=this.moduleViewer,window.sessionManager=this.sessionManager}initializeBuildTracker(){this.buildTracker=new h,this.buildTracker.setSocketClient(this.socketClient);const e=()=>{const t=document.querySelector(".header-title");t?(this.buildTracker.mount(t),console.log("BuildTracker mounted successfully")):(console.warn("Header-title element not found for build tracker, will retry"),setTimeout(e,100))};e(),window.buildTracker=this.buildTracker}initializeAgentInference(){this.agentInference=new r(this.eventViewer),this.agentInference.initialize()}initializeAgentHierarchy(){try{this.agentHierarchy=new d(this.agentInference,this.eventViewer),console.log("Agent hierarchy component created")}catch(e){console.error("Failed to initialize agent hierarchy:",e),this.agentHierarchy={render:()=>'<div class="error">Agent hierarchy unavailable</div>',expandAllNodes:()=>{},collapseAllNodes:()=>{},updateWithNewEvents:()=>{}}}}initializeUIStateManager(){this.uiStateManager=new t,this.setupTabFilters()}initializeWorkingDirectoryManager(){this.workingDirectoryManager=new l(this.socketManager)}initializeFileToolTracker(){this.fileToolTracker=new c(this.agentInference,this.workingDirectoryManager)}initializeEventProcessor(){this.eventProcessor=new i(this.eventViewer,this.agentInference)}initializeExportManager(){this.exportManager=new a(this.eventViewer)}setupModuleInteractions(){this.socketManager.onEventUpdate(e=>{this.fileToolTracker.updateFileOperations(e),this.fileToolTracker.updateToolCalls(e),this.agentInference.processAgentInference(),this.agentHierarchy.updateWithNewEvents(e),"events"===this.uiStateManager.getCurrentTab()&&this.exportManager.scrollListToBottom("events-list"),this.renderCurrentTab()}),this.socketManager.onConnectionStatusChange((e,t)=>{"connected"===t&&this.workingDirectoryManager.updateGitBranch(this.workingDirectoryManager.getCurrentWorkingDir())}),document.addEventListener("tabChanged",e=>{this.renderCurrentTab(),this.uiStateManager.updateTabNavigationItems()}),document.addEventListener("eventsClearing",()=>{this.fileToolTracker.clear(),this.agentInference.initialize()}),document.addEventListener("showCardDetails",e=>{this.showCardDetails(e.detail.tabName,e.detail.index)}),document.addEventListener("sessionFilterChanged",e=>{console.log("Session filter changed, re-rendering current tab:",this.uiStateManager.getCurrentTab()),this.renderCurrentTab()})}setupTabFilters(){const e=document.getElementById("agents-search-input"),t=document.getElementById("agents-type-filter");e&&e.addEventListener("input",()=>{"agents"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()}),t&&t.addEventListener("change",()=>{"agents"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()});const n=document.getElementById("tools-search-input"),i=document.getElementById("tools-type-filter");n&&n.addEventListener("input",()=>{"tools"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()}),i&&i.addEventListener("change",()=>{"tools"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()});const s=document.getElementById("files-search-input"),o=document.getElementById("files-type-filter");s&&s.addEventListener("input",()=>{"files"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()}),o&&o.addEventListener("change",()=>{"files"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()})}initializeFromURL(){const e=new URLSearchParams(window.location.search);this.socketManager.initializeFromURL(e)}renderCurrentTab(){const e=this.uiStateManager.getCurrentTab();switch(e){case"events":break;case"activity":if(window.ActivityTree&&"function"==typeof window.ActivityTree)this.activityTreeRetryCount=0,window.activityTreeInstance||(console.log("Creating new ActivityTree instance..."),window.activityTreeInstance=new window.ActivityTree),window.activityTreeInstance&&(window.activityTreeInstance.initialized||(console.log("Initializing ActivityTree..."),window.activityTreeInstance.initialize()),"function"==typeof window.activityTreeInstance.renderWhenVisible&&(console.log("Dashboard triggering activity tree render..."),window.activityTreeInstance.renderWhenVisible()),"function"==typeof window.activityTreeInstance.forceShow&&(console.log("Dashboard forcing activity tree to show..."),window.activityTreeInstance.forceShow()));else if(window.activityTree&&"function"==typeof window.activityTree){const e=window.activityTree();e&&("function"==typeof e.renderWhenVisible&&(console.log("Dashboard triggering activity tree render (legacy)..."),e.renderWhenVisible()),"function"==typeof e.forceShow&&(console.log("Dashboard forcing activity tree to show (legacy)..."),e.forceShow()))}else if(this.activityTreeRetryCount<this.maxRetryAttempts)this.activityTreeRetryCount++,console.warn(`Activity tree component not available, retrying in 100ms... (attempt ${this.activityTreeRetryCount}/${this.maxRetryAttempts})`),setTimeout(()=>{"activity"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()},100);else{console.error("Maximum retry attempts reached for ActivityTree initialization. Giving up.");const e=document.getElementById("activity-tree-container")||document.getElementById("activity-tree");e&&(e.innerHTML='<div class="error-message">⚠️ Activity Tree failed to load. Please refresh the page.</div>')}break;case"agents":this.renderAgents();break;case"tools":this.renderTools();break;case"files":this.renderFiles()}this.uiStateManager.getSelectedCard().tab===e&&this.uiStateManager.updateCardSelectionUI(),this.uiStateManager.updateUnifiedSelectionUI()}renderAgents(){const e=document.getElementById("agents-list");if(!e)return;const t=document.getElementById("agents-search-input")?.value||"",n=document.getElementById("agents-type-filter")?.value||"",i=this.renderAgentsFlat(t,n);e.innerHTML=i,this.removeHierarchyControls();const s=this.agentInference.getUniqueAgentInstances();this.updateAgentsFilterDropdowns(s)}removeHierarchyControls(){const e=document.getElementById("hierarchy-controls");e&&e.remove()}renderAgentsFlat(e,t){const n=this.eventViewer.events;if(!n||0===n.length)return'<div class="no-events">No agent events found...</div>';this.agentInference.processAgentInference();const i=this.agentInference.getEventAgentMap(),s=[];if(n.forEach((n,o)=>{const r=i.get(o);if(r&&("subagent"===r.type||"main_agent"===r.type)){let i=!0;if(e){const t=e.toLowerCase();i=i&&(r.agentName.toLowerCase().includes(t)||n.tool_name&&n.tool_name.toLowerCase().includes(t)||n.data&&JSON.stringify(n.data).toLowerCase().includes(t))}t&&(i=i&&r.agentName.includes(t)),i&&s.push({event:n,inference:r,index:o,timestamp:new Date(n.timestamp)})}}),0===s.length)return'<div class="no-events">No agent events match the current filters...</div>';return`<div class="agent-events-flat">${s.map((e,t)=>{const{event:n,inference:i,index:s,timestamp:o}=e;let r="Activity",a="📋",l="";if("SubagentStart"===n.event_type)r="Started",a="🟢",l="Agent session began";else if("SubagentStop"===n.event_type)r="Stopped",a="🔴",l="Agent session ended";else if(n.tool_name&&(r=`Tool: ${n.tool_name}`,a=this.getToolIcon(n.tool_name),n.data&&n.data.tool_parameters)){const e=n.data.tool_parameters;e.file_path?l=e.file_path:e.command?l=e.command.substring(0,50)+(e.command.length>50?"...":""):e.pattern?l=`pattern="${e.pattern}"`:e.query&&(l=`query="${e.query}"`)}let c="completed";return"SubagentStart"===n.event_type?c="active":n.data&&n.data.error&&(c="error"),`\n <div class="agent-event-item" data-index="${t}" onclick="window.dashboard.showCardDetails('agents', ${s})">\n <div class="agent-event-header">\n <div class="agent-event-time">${this.formatTimestamp(o)}</div>\n <div class="agent-event-agent">\n ${this.getAgentIcon(i.agentName)} ${i.agentName}\n </div>\n <div class="agent-event-action">\n ${a} ${r}\n </div>\n <div class="agent-event-status status-${c}">\n ${this.getStatusIcon(c)}\n </div>\n </div>\n ${l?`<div class="agent-event-details">${this.escapeHtml(l)}</div>`:""}\n </div>\n `}).join("")}</div>`}getAgentIcon(e){return{PM:"🎯","Engineer Agent":"🔧","Research Agent":"🔍","QA Agent":"✅","Documentation Agent":"📝","Security Agent":"🔒","Ops Agent":"⚙️","Version Control Agent":"📦","Data Engineer Agent":"💾","Test Integration Agent":"🧪"}[e]||"🤖"}getToolIcon(e){return{Read:"📖",Write:"✏️",Edit:"📝",Bash:"💻",Grep:"🔍",Glob:"📂",LS:"📁",Task:"📋"}[e]||"🔧"}getStatusIcon(e){return{active:"🟢",completed:"✅",error:"❌",pending:"🟡"}[e]||"❓"}formatTimestamp(e){return e.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}escapeHtml(e){if(!e)return"";const t=document.createElement("div");return t.textContent=e,t.innerHTML}renderTools(){const e=document.getElementById("tools-list");if(!e)return;const t=this.fileToolTracker.getToolCalls(),n=Array.from(t.entries()),i=this.eventProcessor.getUniqueToolInstances(n),s=this.eventProcessor.generateToolHTML(i);e.innerHTML=s,this.exportManager.scrollListToBottom("tools-list"),this.updateToolsFilterDropdowns(i)}renderFiles(){const e=document.getElementById("files-list");if(!e)return;const t=this.fileToolTracker.getFileOperations(),n=Array.from(t.entries()),i=this.eventProcessor.getUniqueFileInstances(n),s=this.eventProcessor.generateFileHTML(i);e.innerHTML=s,this.exportManager.scrollListToBottom("files-list"),this.updateFilesFilterDropdowns(n)}updateAgentsFilterDropdowns(e){const t=new Set;e.forEach(e=>{e.agentName&&"Unknown"!==e.agentName&&t.add(e.agentName)});const n=Array.from(t).filter(e=>e&&""!==e.trim());this.populateFilterDropdown("agents-type-filter",n,"All Agent Types"),n.length>0?console.log("Agent types found for filter:",n):console.log("No agent types found for filter. Instances:",e.length)}updateToolsFilterDropdowns(e){const t=[...new Set(e.map(([e,t])=>t.tool_name))].filter(e=>e);this.populateFilterDropdown("tools-type-filter",t,"All Tools")}updateFilesFilterDropdowns(e){const t=[...new Set(e.flatMap(([e,t])=>t.operations.map(e=>e.operation)))].filter(e=>e);this.populateFilterDropdown("files-type-filter",t,"All Operations")}populateFilterDropdown(e,t,n="All"){const i=document.getElementById(e);if(!i)return;const s=i.value,o=t.sort((e,t)=>e.localeCompare(t));i.innerHTML=`<option value="">${n}</option>`,o.forEach(e=>{const t=document.createElement("option");t.value=e,t.textContent=e,i.appendChild(t)}),s&&o.includes(s)&&(i.value=s)}showCardDetails(e,t){switch(e){case"events":this.eventViewer&&this.eventViewer.showEventDetails(t);break;case"agents":this.showAgentDetailsByIndex(t);break;case"tools":this.showToolDetailsByIndex(t);break;case"files":this.showFileDetailsByIndex(t)}}showAgentDetailsByIndex(e){const t=this.eventProcessor.getFilteredEventsForTab("agents");if(!t||!Array.isArray(t)||e<0||e>=t.length)return void console.warn("Dashboard: Invalid agent index or events array");const n=this.eventProcessor.applyAgentsFilters([t[e]]);if(n.length>0&&this.moduleViewer&&"function"==typeof this.moduleViewer.showAgentEvent){const t=n[0];this.moduleViewer.showAgentEvent(t,e)}}showAgentInstanceDetails(e){const t=this.agentInference.getPMDelegations().get(e);if(!t){const t=this.agentInference.getUniqueAgentInstances().find(t=>t.id===e);return t?void this.showImpliedAgentDetails(t):void console.error("Agent instance not found:",e)}this.moduleViewer&&"function"==typeof this.moduleViewer.showAgentInstance?this.moduleViewer.showAgentInstance(t):console.log("Agent Instance Details:",{id:e,agentName:t.agentName,type:"PM Delegation",eventCount:t.agentEvents.length,startTime:t.timestamp,pmCall:t.pmCall})}showImpliedAgentDetails(e){this.moduleViewer&&"function"==typeof this.moduleViewer.showImpliedAgent?this.moduleViewer.showImpliedAgent(e):console.log("Implied Agent Details:",{id:e.id,agentName:e.agentName,type:"Implied PM Delegation",eventCount:e.eventCount,startTime:e.timestamp,note:"No explicit PM call found - inferred from agent activity"})}showToolDetailsByIndex(e){const t=this.fileToolTracker.getToolCalls(),n=Array.from(t.entries()),i=this.eventProcessor.applyToolCallFilters(n);if(e>=0&&e<i.length){const[t]=i[e];this.showToolCallDetails(t)}}showFileDetailsByIndex(e){const t=this.fileToolTracker.getFileOperations();let n=Array.from(t.entries());if(n=this.eventProcessor.applyFilesFilters(n),e>=0&&e<n.length){const[t]=n[e];this.showFileDetails(t)}}showToolCallDetails(e){const t=this.fileToolTracker.getToolCall(e);t&&this.moduleViewer&&this.moduleViewer.showToolCall(t,e)}showFileDetails(e){const t=this.fileToolTracker.getFileOperationsForFile(e);t&&this.moduleViewer&&this.moduleViewer.showFileOperations(t,e)}switchTab(e){this.uiStateManager.switchTab(e)}selectCard(e,t,n,i){this.uiStateManager.selectCard(e,t,n,i)}clearEvents(){this.exportManager.clearEvents()}exportEvents(){this.exportManager.exportEvents()}clearSelection(){this.uiStateManager.clearSelection(),this.eventViewer&&this.eventViewer.clearSelection(),this.moduleViewer&&this.moduleViewer.clear()}get currentWorkingDir(){return this.workingDirectoryManager.getCurrentWorkingDir()}set currentWorkingDir(e){this.workingDirectoryManager.setWorkingDirectory(e)}get currentTab(){return this.uiStateManager.getCurrentTab()}get selectedCard(){return this.uiStateManager.getSelectedCard()}get fileOperations(){return this.fileToolTracker.getFileOperations()}get toolCalls(){return this.fileToolTracker.getToolCalls()}get tabNavigation(){return this.uiStateManager?this.uiStateManager.tabNavigation:null}}async function p(e,t,n){const i=e.querySelector(".file-viewer-file-path"),s=e.querySelector(".file-viewer-file-size");i&&(i.textContent=t),s&&(s.textContent="");const o=e.querySelector(".file-viewer-loading"),r=e.querySelector(".file-viewer-error"),a=e.querySelector(".file-viewer-content-area");o&&(o.style.display="flex"),r&&(r.style.display="none"),a&&(a.style.display="none");try{const i=window.socket||window.dashboard?.socketClient?.socket||window.socketClient?.socket;if(console.log("[FileViewer] Socket search results:",{"window.socket":!!window.socket,"window.socket.connected":window.socket?.connected,"dashboard.socketClient.socket":!!window.dashboard?.socketClient?.socket,"dashboard.socketClient.socket.connected":window.dashboard?.socketClient?.socket?.connected,"window.socketClient.socket":!!window.socketClient?.socket,"window.socketClient.socket.connected":window.socketClient?.socket?.connected}),!i)throw new Error("No socket connection available. Please ensure the dashboard is connected.");i.connected||console.warn("[FileViewer] Socket found but not connected, attempting to use anyway..."),console.log("[FileViewer] Socket found, setting up listener for file_content_response");const s=new Promise((e,n)=>{const s=o=>{console.log("[FileViewer] Received file_content_response:",o),o.file_path===t&&(i.off("file_content_response",s),o.success?(console.log("[FileViewer] File content loaded successfully"),e(o)):(console.error("[FileViewer] File read failed:",o.error),n(new Error(o.error||"Failed to read file"))))};i.on("file_content_response",s),console.log("[FileViewer] Listener registered for file_content_response"),setTimeout(()=>{i.off("file_content_response",s),console.error("[FileViewer] Request timeout after 10 seconds"),n(new Error("Request timeout - server did not respond"))},1e4)}),o={file_path:t,working_dir:n};console.log("[FileViewer] Emitting read_file event with data:",o),i.emit("read_file",o);const r=await s,a=e.querySelector(".file-viewer-loading");a&&(a.style.display="none"),function(e,t){const n=e.querySelector(".file-viewer-content-area"),i=e.querySelector(".file-extension"),s=e.querySelector(".file-encoding"),o=e.querySelector(".file-viewer-file-size"),r=e.querySelector(".file-content-code");i&&(i.textContent=`Type: ${t.extension||"unknown"}`);s&&(s.textContent=`Encoding: ${t.encoding||"unknown"}`);o&&(o.textContent=`Size: ${function(e){if(!e)return"0 B";const t=1024,n=["B","KB","MB","GB"],i=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,i)).toFixed(2))+" "+n[i]}(t.file_size)}`);if(r&&t.content){r.innerHTML=function(e,t){const n=e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");switch(t){case".js":case".jsx":case".ts":case".tsx":return function(e){return g(e.replace(/\b(function|const|let|var|if|else|for|while|return|import|export|class|extends)\b/g,'<span class="keyword">$1</span>').replace(/(\/\*[\s\S]*?\*\/|\/\/.*)/g,'<span class="comment">$1</span>').replace(/('[^']*'|"[^"]*"|`[^`]*`)/g,'<span class="string">$1</span>').replace(/\b(\d+)\b/g,'<span class="number">$1</span>'))}(n);case".py":return function(e){return g(e.replace(/\b(def|class|if|elif|else|for|while|return|import|from|as|try|except|finally|with)\b/g,'<span class="keyword">$1</span>').replace(/(#.*)/g,'<span class="comment">$1</span>').replace(/('[^']*'|"[^"]*"|"""[\s\S]*?""")/g,'<span class="string">$1</span>').replace(/\b(\d+)\b/g,'<span class="number">$1</span>'))}(n);case".json":return function(e){return g(e.replace(/("[\w\s]*")\s*:/g,'<span class="property">$1</span>:').replace(/:\s*(".*?")/g,': <span class="string">$1</span>').replace(/:\s*(\d+)/g,': <span class="number">$1</span>').replace(/:\s*(true|false|null)/g,': <span class="keyword">$1</span>'))}(n);case".css":return function(e){return g(e.replace(/([.#]?[\w-]+)\s*\{/g,'<span class="selector">$1</span> {').replace(/([\w-]+)\s*:/g,'<span class="property">$1</span>:').replace(/:\s*([^;]+);/g,': <span class="value">$1</span>;').replace(/(\/\*[\s\S]*?\*\/)/g,'<span class="comment">$1</span>'))}(n);case".html":case".htm":return function(e){return g(e.replace(/(&lt;\/?[\w-]+)/g,'<span class="tag">$1</span>').replace(/([\w-]+)=(['"][^'"]*['"])/g,'<span class="attribute">$1</span>=<span class="string">$2</span>').replace(/(&lt;!--[\s\S]*?--&gt;)/g,'<span class="comment">$1</span>'))}(n);case".md":case".markdown":return function(e){return g(e.replace(/^(#{1,6})\s+(.*)$/gm,'<span class="header">$1</span> <span class="header-text">$2</span>').replace(/\*\*(.*?)\*\*/g,'<span class="bold">**$1**</span>').replace(/\*(.*?)\*/g,'<span class="italic">*$1*</span>').replace(/`([^`]+)`/g,'<span class="code">`$1`</span>').replace(/^\s*[-*+]\s+(.*)$/gm,'<span class="list-marker">•</span> $1'))}(n);default:return g(n)}}(t.content,t.extension);const n=e.querySelector(".file-viewer-scroll-wrapper");n&&setTimeout(()=>{const t=e.querySelector(".modal-content"),i=e.querySelector(".file-viewer-header"),s=e.querySelector(".file-viewer-toolbar"),o=(t?.offsetHeight||0)-(i?.offsetHeight||0)-(s?.offsetHeight||0)-40;n.style.maxHeight=`${o}px`,n.style.overflowY="auto"},50)}else console.warn("⚠️ Missing codeElement or file content");n&&(n.style.display="block")}(e,r)}catch(l){console.error("❌ Failed to fetch file content:",l);const i=e.querySelector(".file-viewer-loading");i&&(i.style.display="none");let s=l.message||"Unknown error occurred",o=[];l.message.includes("No socket connection")?(s="Failed to connect to the monitoring server",o=["Check if the monitoring server is running","Verify the socket connection in the dashboard","Try refreshing the page and reconnecting"]):l.message.includes("timeout")?(s="Request timed out",o=["The file may be too large to load quickly","Check your network connection","Try again in a few moments"]):l.message.includes("File does not exist")?(s="File not found",o=["The file may have been moved or deleted","Check the file path spelling","Refresh the file list to see current files"]):l.message.includes("Access denied")&&(s="Access denied",o=["The file is outside the allowed directories","File access is restricted for security reasons"]),function(e,t){const n=e.querySelector(".file-viewer-error"),i=e.querySelector(".error-message"),s=e.querySelector(".error-suggestions");let o=t.error||"Unknown error occurred";i&&(i.innerHTML=`\n <div class="error-main">${o}</div>\n ${t.file_path?`<div class="error-file">File: ${t.file_path}</div>`:""}\n ${t.working_dir?`<div class="error-dir">Working directory: ${t.working_dir}</div>`:""}\n `);s&&(t.suggestions&&t.suggestions.length>0?s.innerHTML=`\n <h4>Suggestions:</h4>\n <ul>\n ${t.suggestions.map(e=>`<li>${e}</li>`).join("")}\n </ul>\n `:s.innerHTML="");console.log("📋 Displaying file viewer error:",{originalError:t.error,processedMessage:o,suggestions:t.suggestions}),n&&(n.style.display="block")}(e,{error:s,file_path:t,working_dir:n,suggestions:o})}}function g(e){return e.split("\n").map((e,t)=>`<span class="line-number">${String(t+1).padStart(3," ")}</span> ${e||" "}`).join("\n")}function m(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}window.clearEvents=function(){window.dashboard&&window.dashboard.clearEvents()},window.exportEvents=function(){window.dashboard&&window.dashboard.exportEvents()},window.clearSelection=function(){window.dashboard&&window.dashboard.clearSelection()},window.switchTab=function(e){window.dashboard&&window.dashboard.switchTab(e)},window.copyFileContent=function(){const e=document.getElementById("file-viewer-modal");if(!e)return;const t=e.querySelector(".file-content-code");if(!t)return;const n=t.textContent;if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(n).then(()=>{const t=e.querySelector(".file-content-copy");if(t){const e=t.textContent;t.textContent="✅ Copied!",setTimeout(()=>{t.textContent=e},2e3)}}).catch(e=>{console.error("Failed to copy text:",e)});else{const t=document.createElement("textarea");t.value=n,document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t);const i=e.querySelector(".file-content-copy");if(i){const e=i.textContent;i.textContent="✅ Copied!",setTimeout(()=>{i.textContent=e},2e3)}}},window.showFileViewerModal=async function(e){console.log("[FileViewer] Opening file:",e);let t="";window.dashboard&&window.dashboard.currentWorkingDir&&(t=window.dashboard.currentWorkingDir,console.log("[FileViewer] Using working directory:",t));let n=document.getElementById("file-viewer-modal");n||(console.log("[FileViewer] Creating new modal"),n=function(){const e=document.createElement("div");return e.id="file-viewer-modal",e.className="modal file-viewer-modal",e.innerHTML='\n <div class="modal-content file-viewer-content">\n <div class="file-viewer-header">\n <h2 class="file-viewer-title">\n <span class="file-viewer-icon">📄</span>\n <span class="file-viewer-title-text">File Viewer</span>\n </h2>\n <div class="file-viewer-meta">\n <span class="file-viewer-file-path"></span>\n <span class="file-viewer-file-size"></span>\n </div>\n <button class="file-viewer-close" onclick="hideFileViewerModal()">\n <span>&times;</span>\n </button>\n </div>\n <div class="file-viewer-body">\n <div class="file-viewer-loading">\n <div class="loading-spinner"></div>\n <span>Loading file content...</span>\n </div>\n <div class="file-viewer-error" style="display: none;">\n <div class="error-icon">⚠️</div>\n <div class="error-message"></div>\n <div class="error-suggestions"></div>\n </div>\n <div class="file-viewer-content-area" style="display: none;">\n <div class="file-viewer-toolbar">\n <div class="file-viewer-info">\n <span class="file-extension"></span>\n <span class="file-encoding"></span>\n </div>\n <div class="file-viewer-actions">\n <button class="file-content-copy" onclick="copyFileContent()">\n 📋 Copy\n </button>\n </div>\n </div>\n <div class="file-viewer-scroll-wrapper">\n <pre class="file-content-display"><code class="file-content-code"></code></pre>\n </div>\n </div>\n </div>\n </div>\n ',e.addEventListener("click",t=>{t.target===e&&hideFileViewerModal()}),document.addEventListener("keydown",t=>{"Escape"===t.key&&"flex"===e.style.display&&hideFileViewerModal()}),e}(),document.body.appendChild(n),await new Promise(e=>setTimeout(e,10))),n.style.display="flex",document.body.style.overflow="hidden",p(n,e,t).catch(e=>{console.error("Error updating file viewer modal:",e),function(e,t){const n=e.querySelector(".file-viewer-error"),i=e.querySelector(".error-message"),s=e.querySelector(".error-suggestions"),o=e.querySelector(".file-viewer-loading"),r=e.querySelector(".file-viewer-content-area");o&&(o.style.display="none");r&&(r.style.display="none");n&&(n.style.display="flex");let a=t.error||"Unknown error occurred";a.includes("not found")?a="📁 File not found or not accessible":a.includes("permission")?a="🔒 Permission denied accessing this file":a.includes("too large")?a="📏 File is too large to display":a.includes("socket connection")?a="🔌 Not connected to the server. Please check your connection.":a.includes("timeout")?a="⏱️ Request timed out. The server may be busy or unresponsive.":a.includes("📁")||a.includes("🔒")||a.includes("📏")||(a=`⚠️ ${a}`);i&&(i.textContent=a);s&&(t.suggestions&&t.suggestions.length>0?s.innerHTML=`\n <h4>Suggestions:</h4>\n <ul>\n ${t.suggestions.map(e=>`<li>${e}</li>`).join("")}\n </ul>\n `:s.innerHTML="\n <h4>Try:</h4>\n <ul>\n <li>Check if the file exists and is readable</li>\n <li>Verify file permissions</li>\n <li>Ensure the monitoring server has access to this file</li>\n </ul>\n ");console.log("📋 Displaying file content error:",{originalError:t.error,processedMessage:a,suggestions:t.suggestions}),n&&(n.style.display="block")}(n,{error:e.message})})},window.hideFileViewerModal=function(){const e=document.getElementById("file-viewer-modal");e&&(e.style.display="none",document.body.style.overflow="")},window.copyFileContent=function(){const e=document.getElementById("file-viewer-modal");if(!e)return;const t=e.querySelector(".file-content-code");if(!t)return;const n=t.textContent;if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(n).then(()=>{const t=e.querySelector(".file-content-copy");if(t){const e=t.textContent;t.textContent="✅ Copied!",setTimeout(()=>{t.textContent=e},2e3)}}).catch(e=>{console.error("Failed to copy text:",e)});else{const t=document.createElement("textarea");t.value=n,document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t);const i=e.querySelector(".file-content-copy");if(i){const e=i.textContent;i.textContent="✅ Copied!",setTimeout(()=>{i.textContent=e},2e3)}}},window.showSearchViewerModal=function(e,t){let n=document.getElementById("search-viewer-modal");n||(n=function(){const e=document.createElement("div");return e.id="search-viewer-modal",e.className="modal search-viewer-modal",e.innerHTML='\n <div class="modal-content search-viewer-content">\n <div class="search-viewer-header">\n <h2 class="search-viewer-title">\n <span class="search-viewer-icon">🔍</span>\n <span class="search-viewer-title-text">Search Results</span>\n </h2>\n <button class="search-viewer-close" onclick="hideSearchViewerModal()">\n <span>&times;</span>\n </button>\n </div>\n <div class="search-viewer-body">\n <div class="search-params-section">\n <h3>Search Parameters</h3>\n <pre class="search-params-display"></pre>\n </div>\n <div class="search-results-section">\n <h3>Search Results</h3>\n <div class="search-results-display"></div>\n </div>\n </div>\n </div>\n ',e.addEventListener("click",t=>{t.target===e&&hideSearchViewerModal()}),document.addEventListener("keydown",t=>{"Escape"===t.key&&"flex"===e.style.display&&hideSearchViewerModal()}),e}(),document.body.appendChild(n)),function(e,t,n){const i=e.querySelector(".search-params-display"),s=e.querySelector(".search-results-display");i&&t&&(i.textContent=JSON.stringify(t,null,2));if(s&&n){let e="";"string"==typeof n?e=`<pre class="search-results-text">${m(n)}</pre>`:Array.isArray(n)?(e='<ul class="search-results-list">',n.forEach(t=>{e+="object"==typeof t?`<li><pre>${JSON.stringify(t,null,2)}</pre></li>`:`<li>${m(String(t))}</li>`}),e+="</ul>"):e="object"==typeof n?`<pre class="search-results-json">${JSON.stringify(n,null,2)}</pre>`:`<div class="search-results-text">${m(String(n))}</div>`,s.innerHTML=e}}(n,e,t),n.style.display="flex",document.body.style.overflow="hidden"},window.hideSearchViewerModal=function(){const e=document.getElementById("search-viewer-modal");e&&(e.style.display="none",document.body.style.overflow="")},window.showAgentInstanceDetails=function(e){window.dashboard&&"function"==typeof window.dashboard.showAgentInstanceDetails?window.dashboard.showAgentInstanceDetails(e):console.error("Dashboard not available or method not found")},document.addEventListener("DOMContentLoaded",function(){try{window.dashboard=new u,window.dashboard&&"function"==typeof window.dashboard.postInit&&window.dashboard.postInit(),console.log("Dashboard loaded and initialized successfully"),document.dispatchEvent(new CustomEvent("dashboardReady",{detail:{dashboard:window.dashboard}}))}catch(e){console.error("Failed to initialize dashboard:",e),document.body.innerHTML=`\n <div style="padding: 20px; font-family: sans-serif;">\n <h1>Dashboard Initialization Error</h1>\n <p>The dashboard failed to load properly. Please refresh the page or check the console for details.</p>\n <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px;">${e.message}</pre>\n </div>\n `}});
1
+ class e{constructor(){this.eventViewer=null,this.moduleViewer=null,this.sessionManager=null,this.activityTreeRetryCount=0,this.maxRetryAttempts=10,this.socketManager=null,this.agentInference=null,this.agentHierarchy=null,this.uiStateManager=null,this.eventProcessor=null,this.exportManager=null,this.workingDirectoryManager=null,this.fileToolTracker=null,this.buildTracker=null,this.init()}init(){console.log("Initializing refactored Claude MPM Dashboard...");try{this.fetchServerConfig(),this.initializeSocketManager(),this.initializeCoreComponents(),this.initializeBuildTracker(),this.initializeAgentInference(),this.initializeAgentHierarchy(),this.initializeUIStateManager(),this.initializeWorkingDirectoryManager(),this.initializeFileToolTracker(),this.initializeEventProcessor(),this.initializeExportManager(),this.setupModuleInteractions(),this.initializeFromURL(),console.log("Claude MPM Dashboard initialized successfully")}catch(e){throw console.error("Error during dashboard initialization:",e),e}}fetchServerConfig(){fetch("/api/config").then(e=>e.json()).then(e=>{window.dashboardConfig=e;const t=document.getElementById("working-dir-path");t&&e.workingDirectory&&(t.textContent=e.workingDirectory);const n=document.getElementById("footer-git-branch");n&&e.gitBranch&&(n.textContent=e.gitBranch),console.log("Dashboard configuration loaded:",e)}).catch(e=>{console.warn("Failed to fetch server config:",e),window.dashboardConfig={workingDirectory:".",gitBranch:"Unknown"}})}validateInitialization(){const e=[{name:"socketManager",component:this.socketManager},{name:"eventViewer",component:this.eventViewer},{name:"agentHierarchy",component:this.agentHierarchy}].filter(e=>!e.component);e.length>0&&console.warn("Missing critical components:",e.map(e=>e.name))}postInit(){try{this.agentHierarchy&&(window.dashboard.agentHierarchy=this.agentHierarchy),this.validateInitialization()}catch(e){console.error("Error in dashboard postInit:",e)}}initializeSocketManager(){this.socketManager=new SocketManager,this.socketManager.setupConnectionControls(),this.socketClient=this.socketManager.getSocketClient(),window.socketClient=this.socketClient}initializeCoreComponents(){this.eventViewer=new EventViewer("events-list",this.socketClient),setTimeout(()=>{this.eventViewer&&this.eventViewer.updateMetrics&&(this.eventViewer.updateMetrics(),console.log("Initial metrics update triggered"))},100),setTimeout(()=>{this.eventViewer&&this.eventViewer.updateMetrics&&(this.eventViewer.updateMetrics(),console.log("Initial metrics update triggered"))},100),this.moduleViewer=new ModuleViewer,this.sessionManager=new SessionManager(this.socketClient),window.eventViewer=this.eventViewer,window.moduleViewer=this.moduleViewer,window.sessionManager=this.sessionManager}initializeBuildTracker(){this.buildTracker=new BuildTracker,this.buildTracker.setSocketClient(this.socketClient);const e=()=>{const t=document.querySelector(".header-title");t?(this.buildTracker.mount(t),console.log("BuildTracker mounted successfully")):(console.warn("Header-title element not found for build tracker, will retry"),setTimeout(e,100))};e(),window.buildTracker=this.buildTracker}initializeAgentInference(){this.agentInference=new AgentInference(this.eventViewer),this.agentInference.initialize()}initializeAgentHierarchy(){try{this.agentHierarchy=new AgentHierarchy(this.agentInference,this.eventViewer)}catch(e){console.error("Failed to initialize agent hierarchy:",e),this.agentHierarchy={render:()=>'<div class="error">Agent hierarchy unavailable</div>',expandAllNodes:()=>{},collapseAllNodes:()=>{},updateWithNewEvents:()=>{}}}}initializeUIStateManager(){this.uiStateManager=new UIStateManager,this.setupTabFilters()}initializeWorkingDirectoryManager(){this.workingDirectoryManager=new WorkingDirectoryManager(this.socketManager)}initializeFileToolTracker(){this.fileToolTracker=new FileToolTracker(this.agentInference,this.workingDirectoryManager)}initializeEventProcessor(){this.eventProcessor=new EventProcessor(this.eventViewer,this.agentInference)}initializeExportManager(){this.exportManager=new ExportManager(this.eventViewer)}setupModuleInteractions(){this.socketManager.onEventUpdate(e=>{this.eventViewer&&this.eventViewer.updateMetrics&&this.eventViewer.updateMetrics(),this.eventViewer&&this.eventViewer.updateMetrics&&this.eventViewer.updateMetrics(),console.log("[Dashboard] Processing event update with",e.length,"events"),e.length>0&&console.log("[Dashboard] Sample event structure:",{first_event:e[0],has_tool_events:e.some(e=>e.tool_name||e.data&&e.data.tool_name),hook_events:e.filter(e=>"hook"===e.type).length,tool_subtypes:e.filter(e=>"pre_tool"===e.subtype||"post_tool"===e.subtype).length}),this.fileToolTracker.updateFileOperations(e),this.fileToolTracker.updateToolCalls(e);const t=this.fileToolTracker.getFileOperations(),n=this.fileToolTracker.getToolCalls();console.log("[Dashboard] After update - File operations:",t.size,"Tool calls:",n.size),this.agentInference.processAgentInference(),window.CodeViewer&&"function"==typeof window.CodeViewer.refreshFromFileToolTracker&&setTimeout(()=>{window.CodeViewer.refreshFromFileToolTracker()},50),this.agentHierarchy.updateWithNewEvents(e),"events"===this.uiStateManager.getCurrentTab()&&this.exportManager.scrollListToBottom("events-list"),this.renderCurrentTab()}),this.socketManager.onConnectionStatusChange((e,t)=>{"connected"===t&&this.workingDirectoryManager.updateGitBranch(this.workingDirectoryManager.getCurrentWorkingDir())}),document.addEventListener("tabChanged",e=>{this.renderCurrentTab(),this.uiStateManager.updateTabNavigationItems()}),document.addEventListener("eventsClearing",()=>{this.fileToolTracker.clear(),this.agentInference.initialize()}),document.addEventListener("showCardDetails",e=>{this.showCardDetails(e.detail.tabName,e.detail.index)}),document.addEventListener("sessionFilterChanged",e=>{this.renderCurrentTab()})}setupTabFilters(){const e=document.getElementById("agents-search-input"),t=document.getElementById("agents-type-filter");e&&e.addEventListener("input",()=>{"agents"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()}),t&&t.addEventListener("change",()=>{"agents"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()});const n=document.getElementById("tools-search-input"),i=document.getElementById("tools-type-filter");n&&n.addEventListener("input",()=>{"tools"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()}),i&&i.addEventListener("change",()=>{"tools"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()});const o=document.getElementById("files-search-input"),r=document.getElementById("files-type-filter");o&&o.addEventListener("input",()=>{"files"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()}),r&&r.addEventListener("change",()=>{"files"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()})}initializeFromURL(){const e=new URLSearchParams(window.location.search);this.socketManager.initializeFromURL(e)}renderCurrentTab(){const e=this.uiStateManager.getCurrentTab();switch(e){case"events":break;case"claude-tree":window.CodeViewer&&"function"==typeof window.CodeViewer.show&&window.CodeViewer.show();break;case"activity":if(window.ActivityTree&&"function"==typeof window.ActivityTree)this.activityTreeRetryCount=0,window.activityTreeInstance||(window.activityTreeInstance=new window.ActivityTree),window.activityTreeInstance&&(window.activityTreeInstance.initialized||window.activityTreeInstance.initialize(),"function"==typeof window.activityTreeInstance.renderWhenVisible&&window.activityTreeInstance.renderWhenVisible(),"function"==typeof window.activityTreeInstance.forceShow&&window.activityTreeInstance.forceShow());else if(window.activityTree&&"function"==typeof window.activityTree){const e=window.activityTree();e&&("function"==typeof e.renderWhenVisible&&e.renderWhenVisible(),"function"==typeof e.forceShow&&e.forceShow())}else if(this.activityTreeRetryCount<this.maxRetryAttempts)this.activityTreeRetryCount++,console.warn(`Activity tree component not available, retrying in 100ms... (attempt ${this.activityTreeRetryCount}/${this.maxRetryAttempts})`),setTimeout(()=>{"activity"===this.uiStateManager.getCurrentTab()&&this.renderCurrentTab()},100);else{console.error("Maximum retry attempts reached for ActivityTree initialization. Giving up.");const e=document.getElementById("activity-tree-container")||document.getElementById("activity-tree");e&&(e.innerHTML='<div class="error-message">⚠️ Activity Tree failed to load. Please refresh the page.</div>')}break;case"agents":this.renderAgents();break;case"tools":this.renderTools();break;case"files":this.renderFiles()}this.uiStateManager.getSelectedCard().tab===e&&this.uiStateManager.updateCardSelectionUI(),this.uiStateManager.updateUnifiedSelectionUI()}renderAgents(){const e=document.getElementById("agents-list");if(!e)return;const t=document.getElementById("agents-search-input")?.value||"",n=document.getElementById("agents-type-filter")?.value||"",i=this.renderAgentsFlat(t,n);e.innerHTML=i,this.removeHierarchyControls();const o=this.agentInference.getUniqueAgentInstances();this.updateAgentsFilterDropdowns(o)}removeHierarchyControls(){const e=document.getElementById("hierarchy-controls");e&&e.remove()}renderAgentsFlat(e,t){const n=this.eventViewer.events;if(!n||0===n.length)return'<div class="no-events">No agent events found...</div>';this.agentInference.processAgentInference();const i=this.agentInference.getEventAgentMap(),o=[];if(n.forEach((n,r)=>{const s=i.get(r);if(s&&("subagent"===s.type||"main_agent"===s.type)){let i=!0;if(e){const t=e.toLowerCase();i=i&&(s.agentName.toLowerCase().includes(t)||n.tool_name&&n.tool_name.toLowerCase().includes(t)||n.data&&JSON.stringify(n.data).toLowerCase().includes(t))}t&&(i=i&&s.agentName.includes(t)),i&&o.push({event:n,inference:s,index:r,timestamp:new Date(n.timestamp)})}}),0===o.length)return'<div class="no-events">No agent events match the current filters...</div>';return`<div class="agent-events-flat">${o.map((e,t)=>{const{event:n,inference:i,index:o,timestamp:r}=e;let s="Activity",a="📋",l="";if("SubagentStart"===n.event_type)s="Started",a="🟢",l="Agent session began";else if("SubagentStop"===n.event_type)s="Stopped",a="🔴",l="Agent session ended";else if(n.tool_name&&(s=`Tool: ${n.tool_name}`,a=this.getToolIcon(n.tool_name),n.data&&n.data.tool_parameters)){const e=n.data.tool_parameters;e.file_path?l=e.file_path:e.command?l=e.command.substring(0,50)+(e.command.length>50?"...":""):e.pattern?l=`pattern="${e.pattern}"`:e.query&&(l=`query="${e.query}"`)}let c="completed";return"SubagentStart"===n.event_type?c="active":n.data&&n.data.error&&(c="error"),`\n <div class="agent-event-item" data-index="${t}" onclick="window.dashboard.showCardDetails('agents', ${o})">\n <div class="agent-event-header">\n <div class="agent-event-time">${this.formatTimestamp(r)}</div>\n <div class="agent-event-agent">\n ${this.getAgentIcon(i.agentName)} ${i.agentName}\n </div>\n <div class="agent-event-action">\n ${a} ${s}\n </div>\n <div class="agent-event-status status-${c}">\n ${this.getStatusIcon(c)}\n </div>\n </div>\n ${l?`<div class="agent-event-details">${this.escapeHtml(l)}</div>`:""}\n </div>\n `}).join("")}</div>`}getAgentIcon(e){return{PM:"🎯","Engineer Agent":"🔧","Research Agent":"🔍","QA Agent":"✅","Documentation Agent":"📝","Security Agent":"🔒","Ops Agent":"⚙️","Version Control Agent":"📦","Data Engineer Agent":"💾","Test Integration Agent":"🧪"}[e]||"🤖"}getToolIcon(e){return{Read:"📖",Write:"✏️",Edit:"📝",Bash:"💻",Grep:"🔍",Glob:"📂",LS:"📁",Task:"📋"}[e]||"🔧"}getStatusIcon(e){return{active:"🟢",completed:"✅",error:"❌",pending:"🟡"}[e]||"❓"}formatTimestamp(e){return e.toLocaleTimeString("en-US",{hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1})}escapeHtml(e){if(!e)return"";const t=document.createElement("div");return t.textContent=e,t.innerHTML}renderTools(){const e=document.getElementById("tools-list");if(!e)return;const t=this.fileToolTracker.getToolCalls(),n=Array.from(t.entries()),i=this.eventProcessor.getUniqueToolInstances(n),o=this.eventProcessor.generateToolHTML(i);e.innerHTML=o,this.exportManager.scrollListToBottom("tools-list"),this.updateToolsFilterDropdowns(i)}renderFiles(){const e=document.getElementById("files-list");if(!e)return;const t=this.fileToolTracker.getFileOperations(),n=Array.from(t.entries());console.log("[renderFiles] File operations map size:",t.size),console.log("[renderFiles] Files array:",n);const i=this.eventProcessor.getUniqueFileInstances(n),o=this.eventProcessor.generateFileHTML(i);0===n.length?e.innerHTML='<div class="empty-state">No file operations tracked yet. File operations will appear here when tools like Read, Write, Edit, or Grep are used.</div>':e.innerHTML=o,this.exportManager.scrollListToBottom("files-list"),this.updateFilesFilterDropdowns(n)}updateAgentsFilterDropdowns(e){const t=new Set;e.forEach(e=>{e.agentName&&"Unknown"!==e.agentName&&t.add(e.agentName)});const n=Array.from(t).filter(e=>e&&""!==e.trim());this.populateFilterDropdown("agents-type-filter",n,"All Agent Types")}updateToolsFilterDropdowns(e){const t=[...new Set(e.map(([e,t])=>t.tool_name))].filter(e=>e);this.populateFilterDropdown("tools-type-filter",t,"All Tools")}updateFilesFilterDropdowns(e){const t=[...new Set(e.flatMap(([e,t])=>t.operations.map(e=>e.operation)))].filter(e=>e);this.populateFilterDropdown("files-type-filter",t,"All Operations")}populateFilterDropdown(e,t,n="All"){const i=document.getElementById(e);if(!i)return;const o=i.value,r=t.sort((e,t)=>e.localeCompare(t));i.innerHTML=`<option value="">${n}</option>`,r.forEach(e=>{const t=document.createElement("option");t.value=e,t.textContent=e,i.appendChild(t)}),o&&r.includes(o)&&(i.value=o)}showCardDetails(e,t){switch(e){case"events":this.eventViewer&&this.eventViewer.showEventDetails(t);break;case"agents":this.showAgentDetailsByIndex(t);break;case"tools":this.showToolDetailsByIndex(t);break;case"files":this.showFileDetailsByIndex(t)}}showAgentDetailsByIndex(e){const t=this.eventProcessor.getFilteredEventsForTab("agents");if(!t||!Array.isArray(t)||e<0||e>=t.length)return void console.warn("Dashboard: Invalid agent index or events array");const n=this.eventProcessor.applyAgentsFilters([t[e]]);if(n.length>0&&this.moduleViewer&&"function"==typeof this.moduleViewer.showAgentEvent){const t=n[0];this.moduleViewer.showAgentEvent(t,e)}}showAgentInstanceDetails(e){const t=this.agentInference.getPMDelegations().get(e);if(!t){const t=this.agentInference.getUniqueAgentInstances().find(t=>t.id===e);return t?void this.showImpliedAgentDetails(t):void console.error("Agent instance not found:",e)}this.moduleViewer&&"function"==typeof this.moduleViewer.showAgentInstance?this.moduleViewer.showAgentInstance(t):console.log("Agent Instance Details:",{id:e,agentName:t.agentName,type:"PM Delegation",eventCount:t.agentEvents.length,startTime:t.timestamp,pmCall:t.pmCall})}showImpliedAgentDetails(e){this.moduleViewer&&"function"==typeof this.moduleViewer.showImpliedAgent?this.moduleViewer.showImpliedAgent(e):console.log("Implied Agent Details:",{id:e.id,agentName:e.agentName,type:"Implied PM Delegation",eventCount:e.eventCount,startTime:e.timestamp,note:"No explicit PM call found - inferred from agent activity"})}showToolDetailsByIndex(e){const t=this.fileToolTracker.getToolCalls(),n=Array.from(t.entries()),i=this.eventProcessor.applyToolCallFilters(n);if(e>=0&&e<i.length){const[t]=i[e];this.showToolCallDetails(t)}}showFileDetailsByIndex(e){const t=this.fileToolTracker.getFileOperations();let n=Array.from(t.entries());if(n=this.eventProcessor.applyFilesFilters(n),e>=0&&e<n.length){const[t]=n[e];this.showFileDetails(t)}}showToolCallDetails(e){const t=this.fileToolTracker.getToolCall(e);t&&this.moduleViewer&&this.moduleViewer.showToolCall(t,e)}showFileDetails(e){const t=this.fileToolTracker.getFileOperationsForFile(e);t&&this.moduleViewer&&this.moduleViewer.showFileOperations(t,e)}switchTab(e){this.uiStateManager.switchTab(e)}selectCard(e,t,n,i){this.uiStateManager.selectCard(e,t,n,i)}clearEvents(){this.exportManager.clearEvents()}exportEvents(){this.exportManager.exportEvents()}clearSelection(){this.uiStateManager.clearSelection(),this.eventViewer&&this.eventViewer.clearSelection(),this.moduleViewer&&this.moduleViewer.clear()}get currentWorkingDir(){return this.workingDirectoryManager.getCurrentWorkingDir()}set currentWorkingDir(e){this.workingDirectoryManager.setWorkingDirectory(e)}get currentTab(){return this.uiStateManager.getCurrentTab()}get selectedCard(){return this.uiStateManager.getSelectedCard()}get fileOperations(){return this.fileToolTracker.getFileOperations()}get toolCalls(){return this.fileToolTracker.getToolCalls()}get tabNavigation(){return this.uiStateManager?this.uiStateManager.tabNavigation:null}}async function t(e,t,i){const o=e.querySelector(".file-viewer-file-path"),r=e.querySelector(".file-viewer-file-size");o&&(o.textContent=t),r&&(r.textContent="");const s=e.querySelector(".file-viewer-loading"),a=e.querySelector(".file-viewer-error"),l=e.querySelector(".file-viewer-content-area");s&&(s.style.display="flex"),a&&(a.style.display="none"),l&&(l.style.display="none");try{const o=window.socket||window.dashboard?.socketClient?.socket||window.socketClient?.socket;if(console.log("[FileViewer] Socket search results:",{"window.socket":!!window.socket,"window.socket.connected":window.socket?.connected,"dashboard.socketClient.socket":!!window.dashboard?.socketClient?.socket,"dashboard.socketClient.socket.connected":window.dashboard?.socketClient?.socket?.connected,"window.socketClient.socket":!!window.socketClient?.socket,"window.socketClient.socket.connected":window.socketClient?.socket?.connected}),!o)throw new Error("No socket connection available. Please ensure the dashboard is connected.");o.connected||console.warn("[FileViewer] Socket found but not connected, attempting to use anyway..."),console.log("[FileViewer] Socket found, setting up listener for file_content_response");const r=new Promise((e,n)=>{const i=r=>{console.log("[FileViewer] Received file_content_response:",r),r.file_path===t&&(o.off("file_content_response",i),r.success?(console.log("[FileViewer] File content loaded successfully"),e(r)):(console.error("[FileViewer] File read failed:",r.error),n(new Error(r.error||"Failed to read file"))))};o.on("file_content_response",i),console.log("[FileViewer] Listener registered for file_content_response"),setTimeout(()=>{o.off("file_content_response",i),console.error("[FileViewer] Request timeout after 10 seconds"),n(new Error("Request timeout - server did not respond"))},1e4)}),s={file_path:t,working_dir:i};console.log("[FileViewer] Emitting read_file event with data:",s),o.emit("read_file",s);const a=await r,l=e.querySelector(".file-viewer-loading");l&&(l.style.display="none"),function(e,t){const i=e.querySelector(".file-viewer-content-area"),o=e.querySelector(".file-extension"),r=e.querySelector(".file-encoding"),s=e.querySelector(".file-viewer-file-size"),a=e.querySelector(".file-content-code");o&&(o.textContent=`Type: ${t.extension||"unknown"}`);r&&(r.textContent=`Encoding: ${t.encoding||"unknown"}`);s&&(s.textContent=`Size: ${function(e){if(!e)return"0 B";const t=1024,n=["B","KB","MB","GB"],i=Math.floor(Math.log(e)/Math.log(t));return parseFloat((e/Math.pow(t,i)).toFixed(2))+" "+n[i]}(t.file_size)}`);if(a&&t.content){a.innerHTML=function(e,t){const i=e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");switch(t){case".js":case".jsx":case".ts":case".tsx":return function(e){return n(e.replace(/\b(function|const|let|var|if|else|for|while|return|import|export|class|extends)\b/g,'<span class="keyword">$1</span>').replace(/(\/\*[\s\S]*?\*\/|\/\/.*)/g,'<span class="comment">$1</span>').replace(/('[^']*'|"[^"]*"|`[^`]*`)/g,'<span class="string">$1</span>').replace(/\b(\d+)\b/g,'<span class="number">$1</span>'))}(i);case".py":return function(e){return n(e.replace(/\b(def|class|if|elif|else|for|while|return|import|from|as|try|except|finally|with)\b/g,'<span class="keyword">$1</span>').replace(/(#.*)/g,'<span class="comment">$1</span>').replace(/('[^']*'|"[^"]*"|"""[\s\S]*?""")/g,'<span class="string">$1</span>').replace(/\b(\d+)\b/g,'<span class="number">$1</span>'))}(i);case".json":return function(e){return n(e.replace(/("[\w\s]*")\s*:/g,'<span class="property">$1</span>:').replace(/:\s*(".*?")/g,': <span class="string">$1</span>').replace(/:\s*(\d+)/g,': <span class="number">$1</span>').replace(/:\s*(true|false|null)/g,': <span class="keyword">$1</span>'))}(i);case".css":return function(e){return n(e.replace(/([.#]?[\w-]+)\s*\{/g,'<span class="selector">$1</span> {').replace(/([\w-]+)\s*:/g,'<span class="property">$1</span>:').replace(/:\s*([^;]+);/g,': <span class="value">$1</span>;').replace(/(\/\*[\s\S]*?\*\/)/g,'<span class="comment">$1</span>'))}(i);case".html":case".htm":return function(e){return n(e.replace(/(&lt;\/?[\w-]+)/g,'<span class="tag">$1</span>').replace(/([\w-]+)=(['"][^'"]*['"])/g,'<span class="attribute">$1</span>=<span class="string">$2</span>').replace(/(&lt;!--[\s\S]*?--&gt;)/g,'<span class="comment">$1</span>'))}(i);case".md":case".markdown":return function(e){return n(e.replace(/^(#{1,6})\s+(.*)$/gm,'<span class="header">$1</span> <span class="header-text">$2</span>').replace(/\*\*(.*?)\*\*/g,'<span class="bold">**$1**</span>').replace(/\*(.*?)\*/g,'<span class="italic">*$1*</span>').replace(/`([^`]+)`/g,'<span class="code">`$1`</span>').replace(/^\s*[-*+]\s+(.*)$/gm,'<span class="list-marker">•</span> $1'))}(i);default:return n(i)}}(t.content,t.extension);const i=e.querySelector(".file-viewer-scroll-wrapper");i&&setTimeout(()=>{const t=e.querySelector(".modal-content"),n=e.querySelector(".file-viewer-header"),o=e.querySelector(".file-viewer-toolbar"),r=(t?.offsetHeight||0)-(n?.offsetHeight||0)-(o?.offsetHeight||0)-40;i.style.maxHeight=`${r}px`,i.style.overflowY="auto"},50)}else console.warn("⚠️ Missing codeElement or file content");i&&(i.style.display="block")}(e,a)}catch(c){console.error("❌ Failed to fetch file content:",c);const n=e.querySelector(".file-viewer-loading");n&&(n.style.display="none");let o=c.message||"Unknown error occurred",r=[];c.message.includes("No socket connection")?(o="Failed to connect to the monitoring server",r=["Check if the monitoring server is running","Verify the socket connection in the dashboard","Try refreshing the page and reconnecting"]):c.message.includes("timeout")?(o="Request timed out",r=["The file may be too large to load quickly","Check your network connection","Try again in a few moments"]):c.message.includes("File does not exist")?(o="File not found",r=["The file may have been moved or deleted","Check the file path spelling","Refresh the file list to see current files"]):c.message.includes("Access denied")&&(o="Access denied",r=["The file is outside the allowed directories","File access is restricted for security reasons"]),function(e,t){const n=e.querySelector(".file-viewer-error"),i=e.querySelector(".error-message"),o=e.querySelector(".error-suggestions");let r=t.error||"Unknown error occurred";i&&(i.innerHTML=`\n <div class="error-main">${r}</div>\n ${t.file_path?`<div class="error-file">File: ${t.file_path}</div>`:""}\n ${t.working_dir?`<div class="error-dir">Working directory: ${t.working_dir}</div>`:""}\n `);o&&(t.suggestions&&t.suggestions.length>0?o.innerHTML=`\n <h4>Suggestions:</h4>\n <ul>\n ${t.suggestions.map(e=>`<li>${e}</li>`).join("")}\n </ul>\n `:o.innerHTML="");console.log("📋 Displaying file viewer error:",{originalError:t.error,processedMessage:r,suggestions:t.suggestions}),n&&(n.style.display="block")}(e,{error:o,file_path:t,working_dir:i,suggestions:r})}}function n(e){return e.split("\n").map((e,t)=>`<span class="line-number">${String(t+1).padStart(3," ")}</span> ${e||" "}`).join("\n")}function i(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}window.clearEvents=function(){window.dashboard&&window.dashboard.clearEvents()},window.exportEvents=function(){window.dashboard&&window.dashboard.exportEvents()},window.clearSelection=function(){window.dashboard&&window.dashboard.clearSelection()},window.switchTab=function(e){window.dashboard&&window.dashboard.switchTab(e)},window.copyFileContent=function(){const e=document.getElementById("file-viewer-modal");if(!e)return;const t=e.querySelector(".file-content-code");if(!t)return;const n=t.textContent;if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(n).then(()=>{const t=e.querySelector(".file-content-copy");if(t){const e=t.textContent;t.textContent="✅ Copied!",setTimeout(()=>{t.textContent=e},2e3)}}).catch(e=>{console.error("Failed to copy text:",e)});else{const t=document.createElement("textarea");t.value=n,document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t);const i=e.querySelector(".file-content-copy");if(i){const e=i.textContent;i.textContent="✅ Copied!",setTimeout(()=>{i.textContent=e},2e3)}}},window.showFileViewerModal=async function(e){console.log("[FileViewer] Opening file:",e);let n="";window.dashboard&&window.dashboard.currentWorkingDir&&(n=window.dashboard.currentWorkingDir,console.log("[FileViewer] Using working directory:",n));let i=document.getElementById("file-viewer-modal");i||(console.log("[FileViewer] Creating new modal"),i=function(){const e=document.createElement("div");return e.id="file-viewer-modal",e.className="modal file-viewer-modal",e.innerHTML='\n <div class="modal-content file-viewer-content">\n <div class="file-viewer-header">\n <h2 class="file-viewer-title">\n <span class="file-viewer-icon">📄</span>\n <span class="file-viewer-title-text">File Viewer</span>\n </h2>\n <div class="file-viewer-meta">\n <span class="file-viewer-file-path"></span>\n <span class="file-viewer-file-size"></span>\n </div>\n <button class="file-viewer-close" onclick="hideFileViewerModal()">\n <span>&times;</span>\n </button>\n </div>\n <div class="file-viewer-body">\n <div class="file-viewer-loading">\n <div class="loading-spinner"></div>\n <span>Loading file content...</span>\n </div>\n <div class="file-viewer-error" style="display: none;">\n <div class="error-icon">⚠️</div>\n <div class="error-message"></div>\n <div class="error-suggestions"></div>\n </div>\n <div class="file-viewer-content-area" style="display: none;">\n <div class="file-viewer-toolbar">\n <div class="file-viewer-info">\n <span class="file-extension"></span>\n <span class="file-encoding"></span>\n </div>\n <div class="file-viewer-actions">\n <button class="file-content-copy" onclick="copyFileContent()">\n 📋 Copy\n </button>\n </div>\n </div>\n <div class="file-viewer-scroll-wrapper">\n <pre class="file-content-display"><code class="file-content-code"></code></pre>\n </div>\n </div>\n </div>\n </div>\n ',e.addEventListener("click",t=>{t.target===e&&hideFileViewerModal()}),document.addEventListener("keydown",t=>{"Escape"===t.key&&"flex"===e.style.display&&hideFileViewerModal()}),e}(),document.body.appendChild(i),await new Promise(e=>setTimeout(e,10))),i.style.display="flex",document.body.style.overflow="hidden",t(i,e,n).catch(e=>{console.error("Error updating file viewer modal:",e),function(e,t){const n=e.querySelector(".file-viewer-error"),i=e.querySelector(".error-message"),o=e.querySelector(".error-suggestions"),r=e.querySelector(".file-viewer-loading"),s=e.querySelector(".file-viewer-content-area");r&&(r.style.display="none");s&&(s.style.display="none");n&&(n.style.display="flex");let a=t.error||"Unknown error occurred";a.includes("not found")?a="📁 File not found or not accessible":a.includes("permission")?a="🔒 Permission denied accessing this file":a.includes("too large")?a="📏 File is too large to display":a.includes("socket connection")?a="🔌 Not connected to the server. Please check your connection.":a.includes("timeout")?a="⏱️ Request timed out. The server may be busy or unresponsive.":a.includes("📁")||a.includes("🔒")||a.includes("📏")||(a=`⚠️ ${a}`);i&&(i.textContent=a);o&&(t.suggestions&&t.suggestions.length>0?o.innerHTML=`\n <h4>Suggestions:</h4>\n <ul>\n ${t.suggestions.map(e=>`<li>${e}</li>`).join("")}\n </ul>\n `:o.innerHTML="\n <h4>Try:</h4>\n <ul>\n <li>Check if the file exists and is readable</li>\n <li>Verify file permissions</li>\n <li>Ensure the monitoring server has access to this file</li>\n </ul>\n ");console.log("📋 Displaying file content error:",{originalError:t.error,processedMessage:a,suggestions:t.suggestions}),n&&(n.style.display="block")}(i,{error:e.message})})},window.hideFileViewerModal=function(){const e=document.getElementById("file-viewer-modal");e&&(e.style.display="none",document.body.style.overflow="")},window.copyFileContent=function(){const e=document.getElementById("file-viewer-modal");if(!e)return;const t=e.querySelector(".file-content-code");if(!t)return;const n=t.textContent;if(navigator.clipboard&&navigator.clipboard.writeText)navigator.clipboard.writeText(n).then(()=>{const t=e.querySelector(".file-content-copy");if(t){const e=t.textContent;t.textContent="✅ Copied!",setTimeout(()=>{t.textContent=e},2e3)}}).catch(e=>{console.error("Failed to copy text:",e)});else{const t=document.createElement("textarea");t.value=n,document.body.appendChild(t),t.select(),document.execCommand("copy"),document.body.removeChild(t);const i=e.querySelector(".file-content-copy");if(i){const e=i.textContent;i.textContent="✅ Copied!",setTimeout(()=>{i.textContent=e},2e3)}}},window.showSearchViewerModal=function(e,t){let n=document.getElementById("search-viewer-modal");n||(n=function(){const e=document.createElement("div");return e.id="search-viewer-modal",e.className="modal search-viewer-modal",e.innerHTML='\n <div class="modal-content search-viewer-content">\n <div class="search-viewer-header">\n <h2 class="search-viewer-title">\n <span class="search-viewer-icon">🔍</span>\n <span class="search-viewer-title-text">Search Results</span>\n </h2>\n <button class="search-viewer-close" onclick="hideSearchViewerModal()">\n <span>&times;</span>\n </button>\n </div>\n <div class="search-viewer-body">\n <div class="search-params-section">\n <h3>Search Parameters</h3>\n <pre class="search-params-display"></pre>\n </div>\n <div class="search-results-section">\n <h3>Search Results</h3>\n <div class="search-results-display"></div>\n </div>\n </div>\n </div>\n ',e.addEventListener("click",t=>{t.target===e&&hideSearchViewerModal()}),document.addEventListener("keydown",t=>{"Escape"===t.key&&"flex"===e.style.display&&hideSearchViewerModal()}),e}(),document.body.appendChild(n)),function(e,t,n){const o=e.querySelector(".search-params-display"),r=e.querySelector(".search-results-display");o&&t&&(o.textContent=JSON.stringify(t,null,2));if(r&&n){let e="";"string"==typeof n?e=`<pre class="search-results-text">${i(n)}</pre>`:Array.isArray(n)?(e='<ul class="search-results-list">',n.forEach(t=>{e+="object"==typeof t?`<li><pre>${JSON.stringify(t,null,2)}</pre></li>`:`<li>${i(String(t))}</li>`}),e+="</ul>"):e="object"==typeof n?`<pre class="search-results-json">${JSON.stringify(n,null,2)}</pre>`:`<div class="search-results-text">${i(String(n))}</div>`,r.innerHTML=e}}(n,e,t),n.style.display="flex",document.body.style.overflow="hidden"},window.hideSearchViewerModal=function(){const e=document.getElementById("search-viewer-modal");e&&(e.style.display="none",document.body.style.overflow="")},window.showAgentInstanceDetails=function(e){window.dashboard&&"function"==typeof window.dashboard.showAgentInstanceDetails?window.dashboard.showAgentInstanceDetails(e):console.error("Dashboard not available or method not found")},document.addEventListener("DOMContentLoaded",function(){try{window.dashboard=new e,window.dashboard&&"function"==typeof window.dashboard.postInit&&window.dashboard.postInit(),console.log("Dashboard loaded and initialized successfully"),document.dispatchEvent(new CustomEvent("dashboardReady",{detail:{dashboard:window.dashboard}}))}catch(t){console.error("Failed to initialize dashboard:",t),document.body.innerHTML=`\n <div style="padding: 20px; font-family: sans-serif;">\n <h1>Dashboard Initialization Error</h1>\n <p>The dashboard failed to load properly. Please refresh the page or check the console for details.</p>\n <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px;">${t.message}</pre>\n </div>\n `}});
2
2
  //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Browser Extension Error Handler
3
+ *
4
+ * WHY: Browser extensions (like password managers, ad blockers, etc.) often inject
5
+ * scripts that use Chrome's message passing API. When these extensions have bugs
6
+ * or async handlers that don't properly respond, they generate console errors.
7
+ *
8
+ * This module prevents those external errors from affecting our dashboard and
9
+ * provides clean error handling for known browser extension issues.
10
+ *
11
+ * DESIGN DECISION: Rather than trying to fix third-party extension bugs, we:
12
+ * 1. Detect and suppress known harmless extension errors
13
+ * 2. Log them separately for debugging if needed
14
+ * 3. Ensure our dashboard remains functional regardless of extension conflicts
15
+ */
16
+
17
+ class ExtensionErrorHandler {
18
+ constructor() {
19
+ this.extensionErrors = [];
20
+ this.suppressedPatterns = [
21
+ // Chrome extension message passing error
22
+ /listener indicated an asynchronous response.*message channel closed/i,
23
+ // Other common extension errors
24
+ /Extension context invalidated/i,
25
+ /Unchecked runtime\.lastError/i,
26
+ /Cannot access contents of url.*Extension/i,
27
+ /Blocked a frame with origin.*from accessing a cross-origin frame/i
28
+ ];
29
+
30
+ this.setupErrorHandling();
31
+ }
32
+
33
+ /**
34
+ * Set up global error handling to catch and suppress extension errors
35
+ */
36
+ setupErrorHandling() {
37
+ // Store original console.error
38
+ const originalConsoleError = console.error;
39
+
40
+ // Override console.error to filter extension errors
41
+ console.error = (...args) => {
42
+ const errorString = args.join(' ');
43
+
44
+ // Check if this is a known extension error
45
+ if (this.isExtensionError(errorString)) {
46
+ // Log to our internal list for debugging
47
+ this.extensionErrors.push({
48
+ timestamp: new Date().toISOString(),
49
+ error: errorString,
50
+ suppressed: true
51
+ });
52
+
53
+ // Optionally log with a prefix if debug mode is enabled
54
+ if (window.DEBUG_EXTENSION_ERRORS) {
55
+ originalConsoleError.call(console, '[SUPPRESSED EXTENSION ERROR]:', ...args);
56
+ }
57
+
58
+ // Don't propagate the error
59
+ return;
60
+ }
61
+
62
+ // Pass through non-extension errors
63
+ originalConsoleError.call(console, ...args);
64
+ };
65
+
66
+ // Handle uncaught promise rejections that might come from extensions
67
+ window.addEventListener('unhandledrejection', (event) => {
68
+ const errorString = event.reason?.toString() || '';
69
+
70
+ if (this.isExtensionError(errorString)) {
71
+ // Prevent the default error handling
72
+ event.preventDefault();
73
+
74
+ this.extensionErrors.push({
75
+ timestamp: new Date().toISOString(),
76
+ error: errorString,
77
+ type: 'unhandled_rejection',
78
+ suppressed: true
79
+ });
80
+
81
+ if (window.DEBUG_EXTENSION_ERRORS) {
82
+ console.warn('[SUPPRESSED EXTENSION REJECTION]:', event.reason);
83
+ }
84
+ }
85
+ });
86
+
87
+ // Add a global message event listener with proper error handling
88
+ // This prevents our app from being affected by misbehaving extensions
89
+ window.addEventListener('message', (event) => {
90
+ // Only process messages from our own origin
91
+ if (event.origin !== window.location.origin) {
92
+ return;
93
+ }
94
+
95
+ // Add timeout protection for any async operations
96
+ if (event.data && event.data.requiresResponse) {
97
+ const timeoutId = setTimeout(() => {
98
+ console.warn('Message handler timeout - no response sent');
99
+ }, 5000);
100
+
101
+ // Clear timeout when response is sent
102
+ if (event.ports && event.ports[0]) {
103
+ const originalPostMessage = event.ports[0].postMessage;
104
+ event.ports[0].postMessage = function(...args) {
105
+ clearTimeout(timeoutId);
106
+ return originalPostMessage.apply(this, args);
107
+ };
108
+ }
109
+ }
110
+ });
111
+ }
112
+
113
+ /**
114
+ * Check if an error string matches known extension error patterns
115
+ * @param {string} errorString - The error message to check
116
+ * @returns {boolean} - True if this is a known extension error
117
+ */
118
+ isExtensionError(errorString) {
119
+ return this.suppressedPatterns.some(pattern => pattern.test(errorString));
120
+ }
121
+
122
+ /**
123
+ * Get suppressed extension errors for debugging
124
+ * @returns {Array} - List of suppressed errors
125
+ */
126
+ getSuppressedErrors() {
127
+ return this.extensionErrors;
128
+ }
129
+
130
+ /**
131
+ * Clear the suppressed errors list
132
+ */
133
+ clearSuppressedErrors() {
134
+ this.extensionErrors = [];
135
+ }
136
+
137
+ /**
138
+ * Enable or disable debug logging of extension errors
139
+ * @param {boolean} enabled - Whether to enable debug logging
140
+ */
141
+ setDebugMode(enabled) {
142
+ window.DEBUG_EXTENSION_ERRORS = enabled;
143
+
144
+ if (enabled) {
145
+ console.log('Extension error debug mode enabled. Suppressed errors will be logged with [SUPPRESSED] prefix.');
146
+ console.log('Current suppressed errors:', this.getSuppressedErrors());
147
+ } else {
148
+ console.log('Extension error debug mode disabled. Extension errors will be silently suppressed.');
149
+ }
150
+ }
151
+ }
152
+
153
+ // Create and export singleton instance
154
+ const extensionErrorHandler = new ExtensionErrorHandler();
155
+
156
+ // Add to window for debugging access
157
+ window.extensionErrorHandler = extensionErrorHandler;
158
+
159
+ // Export for ES6 modules
160
+ export { ExtensionErrorHandler, extensionErrorHandler };
161
+ export default extensionErrorHandler;
162
+
163
+ // Log initialization
164
+ console.log('Extension error handler initialized. Use window.extensionErrorHandler.setDebugMode(true) to see suppressed errors.');