claude-mpm 4.1.10__py3-none-any.whl → 4.1.11__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 (48) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/cli/__init__.py +11 -0
  3. claude_mpm/cli/commands/analyze.py +2 -1
  4. claude_mpm/cli/commands/configure.py +9 -8
  5. claude_mpm/cli/commands/configure_tui.py +3 -1
  6. claude_mpm/cli/commands/dashboard.py +288 -0
  7. claude_mpm/cli/commands/debug.py +0 -1
  8. claude_mpm/cli/commands/mpm_init.py +427 -0
  9. claude_mpm/cli/commands/mpm_init_handler.py +83 -0
  10. claude_mpm/cli/parsers/base_parser.py +15 -0
  11. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  12. claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
  13. claude_mpm/constants.py +10 -0
  14. claude_mpm/dashboard/analysis_runner.py +52 -25
  15. claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
  16. claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
  17. claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
  18. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  19. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  20. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  21. claude_mpm/dashboard/static/css/code-tree.css +330 -1
  22. claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
  23. claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
  24. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  25. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  26. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  27. claude_mpm/dashboard/static/js/components/activity-tree.js +212 -13
  28. claude_mpm/dashboard/static/js/components/code-tree.js +1999 -821
  29. claude_mpm/dashboard/static/js/components/event-viewer.js +58 -19
  30. claude_mpm/dashboard/static/js/dashboard.js +15 -3
  31. claude_mpm/dashboard/static/js/socket-client.js +74 -32
  32. claude_mpm/dashboard/templates/index.html +9 -11
  33. claude_mpm/services/agents/memory/memory_format_service.py +3 -1
  34. claude_mpm/services/cli/agent_cleanup_service.py +1 -4
  35. claude_mpm/services/cli/startup_checker.py +0 -1
  36. claude_mpm/services/core/cache_manager.py +0 -1
  37. claude_mpm/services/socketio/event_normalizer.py +64 -0
  38. claude_mpm/services/socketio/handlers/code_analysis.py +502 -0
  39. claude_mpm/services/socketio/server/connection_manager.py +3 -1
  40. claude_mpm/tools/code_tree_analyzer.py +843 -25
  41. claude_mpm/tools/code_tree_builder.py +0 -1
  42. claude_mpm/tools/code_tree_events.py +113 -15
  43. {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
  44. {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +48 -41
  45. {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
  46. {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
  47. {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
  48. {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
@@ -1,2 +1,2 @@
1
- const t=window.io;class e{constructor(){this.socket=null,this.port=null,this.connectionCallbacks={connect:[],disconnect:[],error:[],event:[]},this.eventSchema={required:["source","type","subtype","timestamp","data"],optional:["event","session_id"]},this.isConnected=!1,this.isConnecting=!1,this.lastConnectTime=null,this.disconnectTime=null,this.events=[],this.sessions=new Map,this.currentSessionId=null,this.eventQueue=[],this.maxQueueSize=100,this.retryAttempts=0,this.maxRetryAttempts=5,this.retryDelays=[1e3,2e3,3e3,4e3,5e3],this.pendingEmissions=new Map,this.lastPingTime=null,this.lastPongTime=null,this.pingTimeout=9e4,this.healthCheckInterval=null,this.startStatusCheckFallback(),this.startHealthMonitoring()}connect(t="8765"){this.port=t;const e=`http://localhost:${t}`;if(this.socket&&(this.socket.connected||this.socket.connecting))return console.log("Already connected or connecting, disconnecting first..."),this.socket.disconnect(),void setTimeout(()=>this.doConnect(e),100);this.doConnect(e)}doConnect(e){if(console.log(`Connecting to Socket.IO server at ${e}`),void 0===t)return console.error("Socket.IO library not loaded! Make sure socket.io.min.js is loaded before this script."),void this.notifyConnectionStatus("Socket.IO library not loaded","error");this.isConnecting=!0,this.notifyConnectionStatus("Connecting...","connecting"),this.socket=t(e,{autoConnect:!0,reconnection:!0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,reconnectionAttempts:5,timeout:2e4,forceNew:!0,transports:["websocket","polling"],pingInterval:45e3,pingTimeout:2e4}),this.setupSocketHandlers()}setupSocketHandlers(){this.socket.on("connect",()=>{console.log("Connected to Socket.IO server");const t=this.isConnected;if(this.isConnected=!0,this.isConnecting=!1,this.lastConnectTime=Date.now(),this.retryAttempts=0,this.disconnectTime&&!1===t){const t=(Date.now()-this.disconnectTime)/1e3;console.log(`Reconnected after ${t.toFixed(1)}s downtime`),this.flushEventQueue()}this.notifyConnectionStatus("Connected","connected"),this.connectionCallbacks.connect.forEach(t=>t(this.socket.id)),this.requestStatus()}),this.socket.on("disconnect",t=>{const e={reason:t,timestamp:(new Date).toISOString(),wasConnected:this.isConnected,uptimeSeconds:this.lastConnectTime?((Date.now()-this.lastConnectTime)/1e3).toFixed(1):0,lastPing:this.lastPingTime?((Date.now()-this.lastPingTime)/1e3).toFixed(1)+"s ago":"never",lastPong:this.lastPongTime?((Date.now()-this.lastPongTime)/1e3).toFixed(1)+"s ago":"never"};console.log("Disconnected from server:",e),this.isConnected=!1,this.isConnecting=!1,this.disconnectTime=Date.now(),this.notifyConnectionStatus(`Disconnected: ${t}`,"disconnected"),this.connectionCallbacks.disconnect.forEach(e=>e(t));["transport close","ping timeout","transport error","io server disconnect"].includes(t)?(console.log(`Auto-reconnect triggered for reason: ${t}`),this.scheduleReconnect()):"io client disconnect"===t?console.log("Client-initiated disconnect, not auto-reconnecting"):(console.log(`Unknown disconnect reason: ${t}, attempting reconnect anyway`),this.scheduleReconnect())}),this.socket.on("connect_error",t=>{console.error("Connection error:",t),this.isConnecting=!1;const e=t.message||t.description||"Unknown error";this.notifyConnectionStatus(`Connection Error: ${e}`,"disconnected"),this.addEvent({type:"connection.error",timestamp:(new Date).toISOString(),data:{error:e,url:this.socket.io.uri,retry_attempt:this.retryAttempts}}),this.connectionCallbacks.error.forEach(t=>t(e)),this.scheduleReconnect()}),this.socket.on("claude_event",t=>{console.log("Received claude_event:",t);const e=this.validateEventSchema(t);if(!e)return void console.warn("Invalid event schema received:",t);const n=this.transformEvent(e);console.log("Transformed event:",n),this.addEvent(n)}),this.socket.on("ping",t=>{this.lastPingTime=Date.now(),this.socket.emit("pong",{timestamp:t.timestamp,client_time:Date.now()})}),this.socket.on("pong",t=>{this.lastPongTime=Date.now()}),this.socket.on("session.started",t=>{this.addEvent({type:"session",subtype:"started",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("session.ended",t=>{this.addEvent({type:"session",subtype:"ended",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("claude.request",t=>{this.addEvent({type:"claude",subtype:"request",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("claude.response",t=>{this.addEvent({type:"claude",subtype:"response",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("agent.loaded",t=>{this.addEvent({type:"agent",subtype:"loaded",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("agent.executed",t=>{this.addEvent({type:"agent",subtype:"executed",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("hook.pre",t=>{this.addEvent({type:"hook",subtype:"pre",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("hook.post",t=>{this.addEvent({type:"hook",subtype:"post",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("todo.updated",t=>{this.addEvent({type:"todo",subtype:"updated",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("memory.operation",t=>{this.addEvent({type:"memory",subtype:"operation",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("log.entry",t=>{this.addEvent({type:"log",subtype:"entry",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("history",t=>{console.log("Received event history:",t),t&&Array.isArray(t.events)?(console.log(`Processing ${t.events.length} historical events (${t.count} sent, ${t.total_available} total available)`),t.events.forEach(t=>{const e=this.transformEvent(t);this.addEvent(e,!1)}),this.notifyEventUpdate(),console.log(`Event history loaded: ${t.events.length} events added to dashboard`)):Array.isArray(t)&&(console.log("Received legacy event history format:",t.length,"events"),t.forEach(t=>{const e=this.transformEvent(t);this.addEvent(e,!1)}),this.notifyEventUpdate())}),this.socket.on("system.status",t=>{console.log("Received system status:",t),t.sessions&&this.updateSessions(t.sessions),t.current_session&&(this.currentSessionId=t.current_session)})}disconnect(){this.socket&&(this.socket.disconnect(),this.socket=null),this.port=null,this.isConnected=!1,this.isConnecting=!1}emitWithRetry(t,e=null,n={}){const{maxRetries:s=3,retryDelays:o=[1e3,2e3,4e3],onSuccess:i=null,onFailure:c=null}=n,a=`${t}_${Date.now()}_${Math.random()}`,l=(n=0)=>{if(this.socket&&this.socket.connected)try{this.socket.emit(t,e),console.log(`Emitted ${t} successfully`),this.pendingEmissions.delete(a),i&&i()}catch(r){if(console.error(`Failed to emit ${t} (attempt ${n+1}):`,r),n<s-1){const s=o[n]||o[o.length-1];console.log(`Retrying ${t} in ${s}ms...`),this.pendingEmissions.set(a,{event:t,data:e,attemptNum:n+1,scheduledTime:Date.now()+s}),setTimeout(()=>l(n+1),s)}else console.error(`Failed to emit ${t} after ${s} attempts`),this.pendingEmissions.delete(a),c&&c("max_retries_exceeded")}else 0===n&&(this.queueEvent(t,e),console.log(`Queued ${t} for later emission (disconnected)`),c&&c("disconnected"))};l()}queueEvent(t,e){if(this.eventQueue.length>=this.maxQueueSize){const t=this.eventQueue.shift();console.warn(`Event queue full, dropped oldest event: ${t.event}`)}this.eventQueue.push({event:t,data:e,timestamp:Date.now()})}flushEventQueue(){if(0===this.eventQueue.length)return;console.log(`Flushing ${this.eventQueue.length} queued events...`);const t=[...this.eventQueue];this.eventQueue=[],t.forEach((t,e)=>{setTimeout(()=>{this.socket&&this.socket.connected&&(this.socket.emit(t.event,t.data),console.log(`Flushed queued event: ${t.event}`))},100*e)})}scheduleReconnect(){if(this.retryAttempts>=this.maxRetryAttempts)return console.log("Max reconnection attempts reached, stopping auto-reconnect"),void this.notifyConnectionStatus("Reconnection failed","disconnected");const t=this.retryDelays[this.retryAttempts]||this.retryDelays[this.retryDelays.length-1];this.retryAttempts++,console.log(`Scheduling reconnect attempt ${this.retryAttempts}/${this.maxRetryAttempts} in ${t}ms...`),this.notifyConnectionStatus(`Reconnecting in ${t/1e3}s...`,"connecting"),setTimeout(()=>{!this.isConnected&&this.port&&(console.log(`Attempting reconnection ${this.retryAttempts}/${this.maxRetryAttempts}...`),this.connect(this.port))},t)}requestStatus(){this.socket&&this.socket.connected&&(console.log("Requesting server status..."),this.emitWithRetry("request.status",null,{maxRetries:2,retryDelays:[500,1e3]}))}requestHistory(t={}){if(this.socket&&this.socket.connected){const e={limit:t.limit||50,event_types:t.event_types||[]};console.log("Requesting event history...",e),this.emitWithRetry("get_history",e,{maxRetries:3,retryDelays:[1e3,2e3,3e3],onFailure:t=>{console.error(`Failed to request history: ${t}`)}})}else console.warn("Cannot request history: not connected to server")}addEvent(t,e=!0){if(t.timestamp||(t.timestamp=(new Date).toISOString()),t.id||(t.id=Date.now()+Math.random()),this.events.push(t),t.data&&t.data.session_id){const e=t.data.session_id;this.sessions.has(e)||this.sessions.set(e,{id:e,startTime:t.timestamp,lastActivity:t.timestamp,eventCount:0,working_directory:null,git_branch:null});const n=this.sessions.get(e);n.lastActivity=t.timestamp,n.eventCount++;const s=[t.data.cwd,t.data.working_directory,t.data.working_dir,t.data.workingDirectory,t.data.instance_info?.working_dir,t.data.instance_info?.working_directory,t.data.instance_info?.cwd,t.cwd,t.working_directory,t.working_dir];for(const t of s)if(t&&"string"==typeof t&&t.trim()){n.working_directory=t,console.log(`[SOCKET-CLIENT] Found working directory for session ${e}:`,t);break}t.data.git_branch?n.git_branch=t.data.git_branch:t.data.instance_info&&t.data.instance_info.git_branch&&(n.git_branch=t.data.instance_info.git_branch)}e&&this.notifyEventUpdate()}updateSessions(t){Array.isArray(t)&&t.forEach(t=>{this.sessions.set(t.id,t)})}clearEvents(){this.events=[],this.sessions.clear(),this.notifyEventUpdate()}refreshHistory(t={}){this.clearEvents(),this.requestHistory(t)}getEventsBySession(t=null){return t?this.events.filter(e=>e.data&&e.data.session_id===t):this.events}onConnection(t,e){this.connectionCallbacks[t]&&this.connectionCallbacks[t].push(e)}onEventUpdate(t){this.connectionCallbacks.event.push(t)}on(t,e){if(this.socket)return this.socket.on(t,e);console.warn(`Cannot subscribe to '${t}': socket not initialized`)}off(t,e){if(this.socket)return this.socket.off(t,e);console.warn(`Cannot unsubscribe from '${t}': socket not initialized`)}notifyConnectionStatus(t,e){console.log(`SocketClient: Connection status changed to '${t}' (${e})`),this.updateConnectionStatusDOM(t,e),document.dispatchEvent(new CustomEvent("socketConnectionStatus",{detail:{status:t,type:e}}))}updateConnectionStatusDOM(t,e){const n=document.getElementById("connection-status");n?(n.innerHTML=`<span>●</span> ${t}`,n.className=`status-badge status-${e}`,console.log(`SocketClient: Direct DOM update - status: '${t}' (${e})`)):console.warn("SocketClient: Could not find connection-status element in DOM")}notifyEventUpdate(){this.connectionCallbacks.event.forEach(t=>t(this.events,this.sessions)),document.dispatchEvent(new CustomEvent("socketEventUpdate",{detail:{events:this.events,sessions:this.sessions}}))}getConnectionState(){return{isConnected:this.isConnected,isConnecting:this.isConnecting,socketId:this.socket?this.socket.id:null}}validateEventSchema(t){if(!t||"object"!=typeof t)return console.warn("Event data is not an object:",t),null;const e={...t};return e.source||(e.source="system"),e.type||(e.event?e.type=e.event:e.type="unknown"),e.subtype||(e.subtype="generic"),e.timestamp||(e.timestamp=(new Date).toISOString()),e.data||(e.data={}),e.data&&"object"!=typeof e.data&&(e.data={value:e.data}),console.log("Validated event:",e),e}transformEvent(t){if(!t)return t;let e={...t};if(!t.type&&t.event){const n=t.event;"TestStart"===n||"TestEnd"===n?(e.type="test",e.subtype=n.toLowerCase().replace("test","")):"SubagentStart"===n||"SubagentStop"===n?(e.type="subagent",e.subtype=n.toLowerCase().replace("subagent","")):"ToolCall"===n?(e.type="tool",e.subtype="call"):"UserPrompt"===n?(e.type="hook",e.subtype="user_prompt"):(e.type="unknown",e.subtype=n.toLowerCase(),e.type===e.subtype&&(e.subtype="event")),delete e.event}else if(t.type){const n=t.type;if(n.startsWith("hook.")){const t=n.substring(5);e.type="hook",e.subtype=t}else if(n.includes(".")){const[t,...s]=n.split(".");e.type=t,e.subtype=s.join(".")}}else e.type="unknown",e.subtype="";if(!t.type&&t.event?e.originalEventName=t.event:t.type&&(e.originalEventName=t.type),t.data&&"object"==typeof t.data){const n=["type","subtype","timestamp","id","event","event_type","originalEventName"];Object.keys(t.data).forEach(s=>{n.includes(s)?console.warn(`Protected field '${s}' in data object was not copied to top level to preserve event structure`):"tool_parameters"===s&&"object"==typeof t.data[s]?e[s]=JSON.parse(JSON.stringify(t.data[s])):e[s]=t.data[s]}),e.data=t.data}if("hook"===e.type?"pre_tool"===e.subtype?e.hook_event_name="PreToolUse":"post_tool"===e.subtype?e.hook_event_name="PostToolUse":"subagent_start"===e.subtype?e.hook_event_name="SubagentStart":"subagent_stop"===e.subtype?e.hook_event_name="SubagentStop":"todo_write"===e.subtype?e.hook_event_name="TodoWrite":"start"===e.subtype?e.hook_event_name="Start":"stop"===e.subtype&&(e.hook_event_name="Stop"):"subagent"===e.type?"start"===e.subtype?e.hook_event_name="SubagentStart":"stop"===e.subtype&&(e.hook_event_name="SubagentStop"):"todo"===e.type&&"updated"===e.subtype&&(e.hook_event_name="TodoWrite"),"hook"===e.type&&("pre_tool"===e.subtype||"post_tool"===e.subtype)){console.log("Transformed tool event:",{type:e.type,subtype:e.subtype,hook_event_name:e.hook_event_name,tool_name:e.tool_name,has_tool_parameters:!!e.tool_parameters,tool_parameters:e.tool_parameters,has_data:!!e.data,keys:Object.keys(e).filter(t=>"data"!==t)});["Read","Write","Edit","MultiEdit","NotebookEdit"].includes(e.tool_name)&&console.log("File tool event details:",{tool_name:e.tool_name,file_path:e.tool_parameters?.file_path,path:e.tool_parameters?.path,notebook_path:e.tool_parameters?.notebook_path,full_parameters:e.tool_parameters})}return e}getState(){return{events:this.events,sessions:this.sessions,currentSessionId:this.currentSessionId}}startHealthMonitoring(){this.healthCheckInterval=setInterval(()=>{if(this.isConnected&&this.lastPingTime){const t=Date.now()-this.lastPingTime;t>this.pingTimeout&&(console.warn(`No ping from server for ${t/1e3}s, connection may be stale`),this.socket&&(console.log("Forcing reconnection due to stale connection..."),this.socket.disconnect(),setTimeout(()=>{this.port&&this.connect(this.port)},1e3)))}},1e4)}stopHealthMonitoring(){this.healthCheckInterval&&(clearInterval(this.healthCheckInterval),this.healthCheckInterval=null)}startStatusCheckFallback(){setInterval(()=>{this.checkAndUpdateStatus()},2e3),"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{setTimeout(()=>this.checkAndUpdateStatus(),100)}):setTimeout(()=>this.checkAndUpdateStatus(),100)}checkAndUpdateStatus(){let t="Disconnected",e="disconnected";this.socket&&(this.socket.connected?(t="Connected",e="connected",this.isConnected=!0,this.isConnecting=!1):this.socket.connecting||this.isConnecting?(t="Connecting...",e="connecting",this.isConnected=!1):(t="Disconnected",e="disconnected",this.isConnected=!1,this.isConnecting=!1));const n=document.getElementById("connection-status");if(n){const s=n.textContent.replace("●","").trim(),o=n.className,i=`status-badge status-${e}`;s===t&&o===i||(console.log(`SocketClient: Fallback update - was '${s}' (${o}), now '${t}' (${i})`),this.updateConnectionStatusDOM(t,e))}}destroy(){this.stopHealthMonitoring(),this.socket&&(this.socket.disconnect(),this.socket=null),this.eventQueue=[],this.pendingEmissions.clear()}getConnectionMetrics(){return{isConnected:this.isConnected,uptime:this.lastConnectTime?(Date.now()-this.lastConnectTime)/1e3:0,lastPing:this.lastPingTime?(Date.now()-this.lastPingTime)/1e3:null,queuedEvents:this.eventQueue.length,pendingEmissions:this.pendingEmissions.size,retryAttempts:this.retryAttempts}}}window.SocketClient=e;class n{constructor(){this.socketClient=null,this.connectionCallbacks=new Set,this.eventUpdateCallbacks=new Set,this.socketClient=new e,window.socketClient=this.socketClient,this.setupSocketEventHandlers(),setTimeout(()=>{this.updateInitialConnectionStatus()},100),console.log("Socket manager initialized")}setupSocketEventHandlers(){document.addEventListener("socketConnectionStatus",t=>{console.log(`SocketManager: Processing connection status update: ${t.detail.status} (${t.detail.type})`),this.handleConnectionStatusChange(t.detail.status,t.detail.type),this.connectionCallbacks.forEach(e=>{try{e(t.detail.status,t.detail.type)}catch(n){console.error("Error in connection callback:",n)}})}),this.socketClient&&this.socketClient.onEventUpdate(t=>{this.eventUpdateCallbacks.forEach(e=>{try{e(t)}catch(n){console.error("Error in event update callback:",n)}})})}handleConnectionStatusChange(t,e){this.updateConnectionStatus(t,e),"connected"===e&&this.socketClient&&this.socketClient.socket&&this.setupGitBranchListener()}updateInitialConnectionStatus(){console.log("SocketManager: Updating initial connection status"),this.socketClient&&"function"==typeof this.socketClient.checkAndUpdateStatus?(console.log("SocketManager: Using socket client checkAndUpdateStatus method"),this.socketClient.checkAndUpdateStatus()):this.socketClient&&this.socketClient.socket?(console.log("SocketManager: Checking socket state directly",{connected:this.socketClient.socket.connected,connecting:this.socketClient.socket.connecting,isConnecting:this.socketClient.isConnecting,isConnected:this.socketClient.isConnected}),this.socketClient.socket.connected?(console.log("SocketManager: Socket is already connected, updating status"),this.updateConnectionStatus("Connected","connected")):this.socketClient.isConnecting||this.socketClient.socket.connecting?(console.log("SocketManager: Socket is connecting, updating status"),this.updateConnectionStatus("Connecting...","connecting")):(console.log("SocketManager: Socket is disconnected, updating status"),this.updateConnectionStatus("Disconnected","disconnected"))):(console.log("SocketManager: No socket client or socket found, setting disconnected status"),this.updateConnectionStatus("Disconnected","disconnected")),setTimeout(()=>{console.log("SocketManager: Secondary status check after 1 second"),this.socketClient&&this.socketClient.socket&&this.socketClient.socket.connected&&(console.log("SocketManager: Socket connected in secondary check, updating status"),this.updateConnectionStatus("Connected","connected"))},1e3)}setupGitBranchListener(){this.socketClient.socket.off("git_branch_response"),this.socketClient.socket.on("git_branch_response",t=>{if(t.success){const e=document.getElementById("footer-git-branch");e&&(e.textContent=t.branch||"unknown"),e&&(e.style.display="inline")}else console.error("Git branch request failed:",t.error)})}updateConnectionStatus(t,e){const n=document.getElementById("connection-status");if(n){if(n.querySelector("span")){const e="●";n.innerHTML=`<span>${e}</span> ${t}`}else n.textContent=t;n.className=`status-badge status-${e}`,console.log(`SocketManager: UI updated - status: '${t}' (${e})`)}else console.error("SocketManager: Could not find connection-status element in DOM")}connect(t){this.socketClient&&this.socketClient.connect(t)}disconnect(){this.socketClient&&this.socketClient.disconnect()}isConnected(){return this.socketClient&&this.socketClient.isConnected}isConnecting(){return this.socketClient&&this.socketClient.isConnecting}getSocketClient(){return this.socketClient}getSocket(){return this.socketClient?this.socketClient.socket:null}onConnectionStatusChange(t){this.connectionCallbacks.add(t)}offConnectionStatusChange(t){this.connectionCallbacks.delete(t)}onEventUpdate(t){this.eventUpdateCallbacks.add(t)}offEventUpdate(t){this.eventUpdateCallbacks.delete(t)}toggleConnectionControls(){const t=document.getElementById("connection-controls-row"),e=document.getElementById("connection-toggle-btn");if(t&&e){t.classList.contains("show")?(t.classList.remove("show"),t.style.display="none",e.textContent="Connection Settings"):(t.classList.add("show"),t.style.display="block",e.textContent="Hide Settings")}}setupConnectionControls(){const t=document.getElementById("connect-btn"),e=document.getElementById("disconnect-btn"),n=document.getElementById("connection-toggle-btn");t&&t.addEventListener("click",()=>{const t=document.getElementById("port-input").value||8765;this.connect(t)}),e&&e.addEventListener("click",()=>{this.disconnect()}),n&&n.addEventListener("click",()=>{this.toggleConnectionControls()})}initializeFromURL(t){const e=t.get("port"),n=document.getElementById("port-input");let s=e;s||"http:"!==window.location.protocol||(s=window.location.port||"8765"),s||(s=n?.value||"8765"),n&&(n.value=s);!("false"!==t.get("connect"))||this.isConnected()||this.isConnecting()||(console.log(`SocketManager: Auto-connecting to port ${s}`),this.connect(s))}}class s{constructor(){this.currentTab="events",this.autoScroll=!0,this.selectedCard={tab:null,index:null,type:null,data:null},this.tabNavigation={events:{selectedIndex:-1,items:[]},agents:{selectedIndex:-1,items:[]},tools:{selectedIndex:-1,items:[]},files:{selectedIndex:-1,items:[]}},this.setupEventHandlers(),console.log("UI state manager initialized")}setupEventHandlers(){this.setupTabNavigation(),this.setupUnifiedKeyboardNavigation()}setupTabNavigation(){document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",()=>{const e=this.getTabNameFromButton(t);this.switchTab(e)})})}setupUnifiedKeyboardNavigation(){document.addEventListener("keydown",t=>{document.activeElement&&["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName)||("ArrowUp"===t.key||"ArrowDown"===t.key?(t.preventDefault(),this.handleUnifiedArrowNavigation("ArrowDown"===t.key?1:-1)):"Enter"===t.key?(t.preventDefault(),this.handleUnifiedEnterKey()):"Escape"===t.key&&this.clearUnifiedSelection())})}getTabNameFromButton(t){const e=t.textContent.toLowerCase();return e.includes("events")?"events":e.includes("activity")?"activity":e.includes("agents")?"agents":e.includes("tools")?"tools":e.includes("files")?"files":e.includes("sessions")?"sessions":e.includes("system")?"system":"events"}switchTab(t){console.log(`[DEBUG] switchTab called with tabName: ${t}`);const e=this.currentTab;this.currentTab=t,document.querySelectorAll(".tab-button").forEach(e=>{e.classList.remove("active"),this.getTabNameFromButton(e)===t&&e.classList.add("active")}),document.querySelectorAll(".tab-content").forEach(t=>{t.classList.remove("active")});const n=document.getElementById(`${t}-tab`);n&&n.classList.add("active"),this.clearUnifiedSelection(),document.dispatchEvent(new CustomEvent("tabChanged",{detail:{newTab:t,previousTab:e}})),setTimeout(()=>{this.autoScroll&&this.scrollCurrentTabToBottom()},100)}handleUnifiedArrowNavigation(t){const e=this.tabNavigation[this.currentTab];if(!e)return;let n=e.selectedIndex+t;0!==e.items.length&&(n<0?n=e.items.length-1:n>=e.items.length&&(n=0),this.selectCardByIndex(this.currentTab,n))}handleUnifiedEnterKey(){const t=this.tabNavigation[this.currentTab];if(!t||-1===t.selectedIndex)return;const e=t.items[t.selectedIndex];e&&e.onclick&&e.onclick()}clearUnifiedSelection(){Object.keys(this.tabNavigation).forEach(t=>{this.tabNavigation[t].selectedIndex=-1}),this.clearCardSelection()}updateTabNavigationItems(){const t=this.tabNavigation[this.currentTab];if(!t)return;let e;switch(this.currentTab){case"events":e="#events-list .event-item";break;case"agents":e="#agents-list .event-item";break;case"tools":e="#tools-list .event-item";break;case"files":e="#files-list .event-item"}e&&(t.items=Array.from(document.querySelectorAll(e)))}selectCardByIndex(t,e){const n=this.tabNavigation[t];if(!n||e<0||e>=n.items.length)return;n.selectedIndex=e,this.updateUnifiedSelectionUI();n.items[e]&&this.selectCard(t,e,this.getCardType(t),e),this.showCardDetails(t,e)}updateUnifiedSelectionUI(){document.querySelectorAll(".event-item.keyboard-selected").forEach(t=>{t.classList.remove("keyboard-selected")});const t=this.tabNavigation[this.currentTab];t&&-1!==t.selectedIndex&&t.items[t.selectedIndex]&&t.items[t.selectedIndex].classList.add("keyboard-selected")}showCardDetails(t,e){document.dispatchEvent(new CustomEvent("showCardDetails",{detail:{tabName:t,index:e}}))}selectCard(t,e,n,s){this.clearCardSelection(),this.selectedCard={tab:t,index:e,type:n,data:s},this.updateCardSelectionUI(),console.log("Card selected:",this.selectedCard)}clearCardSelection(){document.querySelectorAll(".event-item.selected, .file-item.selected").forEach(t=>{t.classList.remove("selected")}),this.selectedCard={tab:null,index:null,type:null,data:null}}updateCardSelectionUI(){if(!this.selectedCard.tab||null===this.selectedCard.index)return;let t;switch(this.selectedCard.tab){case"events":t=document.getElementById("events-list");break;case"agents":t=document.getElementById("agents-list");break;case"tools":t=document.getElementById("tools-list");break;case"files":t=document.getElementById("files-list")}if(t){const e=t.querySelectorAll(".event-item, .file-item");e[this.selectedCard.index]&&e[this.selectedCard.index].classList.add("selected")}}getCardType(t){switch(t){case"events":return"event";case"agents":return"agent";case"tools":return"tool";case"files":return"file";default:return"unknown"}}scrollCurrentTabToBottom(){const t=`${this.currentTab}-list`,e=document.getElementById(t);e&&this.autoScroll&&(e.scrollTop=e.scrollHeight)}clearSelection(){this.clearCardSelection(),this.clearUnifiedSelection()}getCurrentTab(){return this.currentTab}getSelectedCard(){return{...this.selectedCard}}getTabNavigation(){return{...this.tabNavigation}}setAutoScroll(t){this.autoScroll=t}getAutoScroll(){return this.autoScroll}}export{n as S,s as U};
1
+ const t=window.io;class e{constructor(){this.socket=null,this.port=null,this.connectionCallbacks={connect:[],disconnect:[],error:[],event:[]},this.eventSchema={required:["source","type","subtype","timestamp","data"],optional:["event","session_id"]},this.isConnected=!1,this.isConnecting=!1,this.lastConnectTime=null,this.disconnectTime=null,this.events=[],this.sessions=new Map,this.currentSessionId=null,this.eventQueue=[],this.maxQueueSize=100,this.retryAttempts=0,this.maxRetryAttempts=5,this.retryDelays=[1e3,2e3,3e3,4e3,5e3],this.pendingEmissions=new Map,this.lastPingTime=null,this.lastPongTime=null,this.pingTimeout=9e4,this.healthCheckInterval=null,this.startStatusCheckFallback(),this.startHealthMonitoring()}connect(t="8765"){this.port=t;const e=`http://localhost:${t}`;if(this.socket&&(this.socket.connected||this.socket.connecting))return console.log("Already connected or connecting, disconnecting first..."),this.socket.disconnect(),void setTimeout(()=>this.doConnect(e),100);this.doConnect(e)}doConnect(e){if(console.log(`Connecting to Socket.IO server at ${e}`),void 0===t)return console.error("Socket.IO library not loaded! Make sure socket.io.min.js is loaded before this script."),void this.notifyConnectionStatus("Socket.IO library not loaded","error");this.isConnecting=!0,this.notifyConnectionStatus("Connecting...","connecting"),this.socket=t(e,{autoConnect:!0,reconnection:!0,reconnectionDelay:1e3,reconnectionDelayMax:5e3,reconnectionAttempts:5,timeout:2e4,forceNew:!0,transports:["websocket","polling"],pingInterval:45e3,pingTimeout:2e4}),this.setupSocketHandlers()}setupSocketHandlers(){this.socket.on("connect",()=>{console.log("Connected to Socket.IO server");const t=this.isConnected;if(this.isConnected=!0,this.isConnecting=!1,this.lastConnectTime=Date.now(),this.retryAttempts=0,this.disconnectTime&&!1===t){const t=(Date.now()-this.disconnectTime)/1e3;console.log(`Reconnected after ${t.toFixed(1)}s downtime`),this.flushEventQueue()}this.notifyConnectionStatus("Connected","connected"),window.socket=this.socket,console.log("SocketClient: Exposed socket globally as window.socket"),this.connectionCallbacks.connect.forEach(t=>t(this.socket.id)),this.requestStatus()}),this.socket.on("disconnect",t=>{const e={reason:t,timestamp:(new Date).toISOString(),wasConnected:this.isConnected,uptimeSeconds:this.lastConnectTime?((Date.now()-this.lastConnectTime)/1e3).toFixed(1):0,lastPing:this.lastPingTime?((Date.now()-this.lastPingTime)/1e3).toFixed(1)+"s ago":"never",lastPong:this.lastPongTime?((Date.now()-this.lastPongTime)/1e3).toFixed(1)+"s ago":"never"};console.log("Disconnected from server:",e),this.isConnected=!1,this.isConnecting=!1,this.disconnectTime=Date.now(),this.notifyConnectionStatus(`Disconnected: ${t}`,"disconnected"),this.connectionCallbacks.disconnect.forEach(e=>e(t));["transport close","ping timeout","transport error","io server disconnect"].includes(t)?(console.log(`Auto-reconnect triggered for reason: ${t}`),this.scheduleReconnect()):"io client disconnect"===t?console.log("Client-initiated disconnect, not auto-reconnecting"):(console.log(`Unknown disconnect reason: ${t}, attempting reconnect anyway`),this.scheduleReconnect())}),this.socket.on("connect_error",t=>{console.error("Connection error:",t),this.isConnecting=!1;const e=t.message||t.description||"Unknown error";this.notifyConnectionStatus(`Connection Error: ${e}`,"disconnected"),this.addEvent({type:"connection.error",timestamp:(new Date).toISOString(),data:{error:e,url:this.socket.io.uri,retry_attempt:this.retryAttempts}}),this.connectionCallbacks.error.forEach(t=>t(e)),this.scheduleReconnect()}),this.socket.on("claude_event",t=>{console.log("Received claude_event:",t);const e=this.validateEventSchema(t);if(!e)return void console.warn("Invalid event schema received:",t);e.type&&e.type.startsWith("code:")&&console.log("Code analysis event received via claude_event, adding to events list for troubleshooting:",e.type);const n=this.transformEvent(e);console.log("Transformed event:",n),this.addEvent(n)}),this.socket.on("ping",t=>{this.lastPingTime=Date.now(),this.socket.emit("pong",{timestamp:t.timestamp,client_time:Date.now()})}),this.socket.on("pong",t=>{this.lastPongTime=Date.now()}),this.socket.on("session.started",t=>{this.addEvent({type:"session",subtype:"started",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("session.ended",t=>{this.addEvent({type:"session",subtype:"ended",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("claude.request",t=>{this.addEvent({type:"claude",subtype:"request",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("claude.response",t=>{this.addEvent({type:"claude",subtype:"response",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("agent.loaded",t=>{this.addEvent({type:"agent",subtype:"loaded",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("agent.executed",t=>{this.addEvent({type:"agent",subtype:"executed",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("hook.pre",t=>{this.addEvent({type:"hook",subtype:"pre",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("hook.post",t=>{this.addEvent({type:"hook",subtype:"post",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("todo.updated",t=>{this.addEvent({type:"todo",subtype:"updated",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("memory.operation",t=>{this.addEvent({type:"memory",subtype:"operation",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("log.entry",t=>{this.addEvent({type:"log",subtype:"entry",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:analysis:queued",t=>{console.log("Code analysis queued event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"analysis:queued",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:analysis:accepted",t=>{console.log("Code analysis accepted event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"analysis:accepted",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:analysis:start",t=>{console.log("Code analysis start event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"analysis:start",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:analysis:complete",t=>{console.log("Code analysis complete event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"analysis:complete",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:analysis:error",t=>{console.log("Code analysis error event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"analysis:error",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:file:start",t=>{console.log("Code file start event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"file:start",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:node:found",t=>{console.log("Code node found event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"node:found",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("code:analysis:progress",t=>{console.log("Code analysis progress event received, adding to events list for troubleshooting"),this.addEvent({type:"code",subtype:"analysis:progress",timestamp:(new Date).toISOString(),data:t})}),this.socket.on("history",t=>{console.log("Received event history:",t),t&&Array.isArray(t.events)?(console.log(`Processing ${t.events.length} historical events (${t.count} sent, ${t.total_available} total available)`),t.events.forEach(t=>{const e=this.transformEvent(t);this.addEvent(e,!1)}),this.notifyEventUpdate(),console.log(`Event history loaded: ${t.events.length} events added to dashboard`)):Array.isArray(t)&&(console.log("Received legacy event history format:",t.length,"events"),t.forEach(t=>{const e=this.transformEvent(t);this.addEvent(e,!1)}),this.notifyEventUpdate())}),this.socket.on("system.status",t=>{console.log("Received system status:",t),t.sessions&&this.updateSessions(t.sessions),t.current_session&&(this.currentSessionId=t.current_session)})}disconnect(){this.socket&&(this.socket.disconnect(),this.socket=null),this.port=null,this.isConnected=!1,this.isConnecting=!1}emitWithRetry(t,e=null,n={}){const{maxRetries:s=3,retryDelays:o=[1e3,2e3,4e3],onSuccess:i=null,onFailure:a=null}=n,c=`${t}_${Date.now()}_${Math.random()}`,l=(n=0)=>{if(this.socket&&this.socket.connected)try{this.socket.emit(t,e),console.log(`Emitted ${t} successfully`),this.pendingEmissions.delete(c),i&&i()}catch(r){if(console.error(`Failed to emit ${t} (attempt ${n+1}):`,r),n<s-1){const s=o[n]||o[o.length-1];console.log(`Retrying ${t} in ${s}ms...`),this.pendingEmissions.set(c,{event:t,data:e,attemptNum:n+1,scheduledTime:Date.now()+s}),setTimeout(()=>l(n+1),s)}else console.error(`Failed to emit ${t} after ${s} attempts`),this.pendingEmissions.delete(c),a&&a("max_retries_exceeded")}else 0===n&&(this.queueEvent(t,e),console.log(`Queued ${t} for later emission (disconnected)`),a&&a("disconnected"))};l()}queueEvent(t,e){if(this.eventQueue.length>=this.maxQueueSize){const t=this.eventQueue.shift();console.warn(`Event queue full, dropped oldest event: ${t.event}`)}this.eventQueue.push({event:t,data:e,timestamp:Date.now()})}flushEventQueue(){if(0===this.eventQueue.length)return;console.log(`Flushing ${this.eventQueue.length} queued events...`);const t=[...this.eventQueue];this.eventQueue=[],t.forEach((t,e)=>{setTimeout(()=>{this.socket&&this.socket.connected&&(this.socket.emit(t.event,t.data),console.log(`Flushed queued event: ${t.event}`))},100*e)})}scheduleReconnect(){if(this.retryAttempts>=this.maxRetryAttempts)return console.log("Max reconnection attempts reached, stopping auto-reconnect"),void this.notifyConnectionStatus("Reconnection failed","disconnected");const t=this.retryDelays[this.retryAttempts]||this.retryDelays[this.retryDelays.length-1];this.retryAttempts++,console.log(`Scheduling reconnect attempt ${this.retryAttempts}/${this.maxRetryAttempts} in ${t}ms...`),this.notifyConnectionStatus(`Reconnecting in ${t/1e3}s...`,"connecting"),setTimeout(()=>{!this.isConnected&&this.port&&(console.log(`Attempting reconnection ${this.retryAttempts}/${this.maxRetryAttempts}...`),this.connect(this.port))},t)}requestStatus(){this.socket&&this.socket.connected&&(console.log("Requesting server status..."),this.emitWithRetry("request.status",null,{maxRetries:2,retryDelays:[500,1e3]}))}requestHistory(t={}){if(this.socket&&this.socket.connected){const e={limit:t.limit||50,event_types:t.event_types||[]};console.log("Requesting event history...",e),this.emitWithRetry("get_history",e,{maxRetries:3,retryDelays:[1e3,2e3,3e3],onFailure:t=>{console.error(`Failed to request history: ${t}`)}})}else console.warn("Cannot request history: not connected to server")}addEvent(t,e=!0){if(t.timestamp||(t.timestamp=(new Date).toISOString()),t.id||(t.id=Date.now()+Math.random()),this.events.push(t),t.data&&t.data.session_id){const e=t.data.session_id;this.sessions.has(e)||this.sessions.set(e,{id:e,startTime:t.timestamp,lastActivity:t.timestamp,eventCount:0,working_directory:null,git_branch:null});const n=this.sessions.get(e);n.lastActivity=t.timestamp,n.eventCount++;const s=[t.data.cwd,t.data.working_directory,t.data.working_dir,t.data.workingDirectory,t.data.instance_info?.working_dir,t.data.instance_info?.working_directory,t.data.instance_info?.cwd,t.cwd,t.working_directory,t.working_dir];for(const t of s)if(t&&"string"==typeof t&&t.trim()){n.working_directory=t,console.log(`[SOCKET-CLIENT] Found working directory for session ${e}:`,t);break}t.data.git_branch?n.git_branch=t.data.git_branch:t.data.instance_info&&t.data.instance_info.git_branch&&(n.git_branch=t.data.instance_info.git_branch)}e&&this.notifyEventUpdate()}updateSessions(t){Array.isArray(t)&&t.forEach(t=>{this.sessions.set(t.id,t)})}clearEvents(){this.events=[],this.sessions.clear(),this.notifyEventUpdate()}refreshHistory(t={}){this.clearEvents(),this.requestHistory(t)}getEventsBySession(t=null){return t?this.events.filter(e=>e.data&&e.data.session_id===t):this.events}onConnection(t,e){this.connectionCallbacks[t]&&this.connectionCallbacks[t].push(e)}onEventUpdate(t){this.connectionCallbacks.event.push(t)}on(t,e){if(this.socket)return this.socket.on(t,e);console.warn(`Cannot subscribe to '${t}': socket not initialized`)}off(t,e){if(this.socket)return this.socket.off(t,e);console.warn(`Cannot unsubscribe from '${t}': socket not initialized`)}notifyConnectionStatus(t,e){console.log(`SocketClient: Connection status changed to '${t}' (${e})`),this.updateConnectionStatusDOM(t,e),document.dispatchEvent(new CustomEvent("socketConnectionStatus",{detail:{status:t,type:e}}))}updateConnectionStatusDOM(t,e){const n=document.getElementById("connection-status");n?(n.innerHTML=`<span>●</span> ${t}`,n.className=`status-badge status-${e}`,console.log(`SocketClient: Direct DOM update - status: '${t}' (${e})`)):console.warn("SocketClient: Could not find connection-status element in DOM")}notifyEventUpdate(){this.connectionCallbacks.event.forEach(t=>t(this.events,this.sessions)),document.dispatchEvent(new CustomEvent("socketEventUpdate",{detail:{events:this.events,sessions:this.sessions}}))}getConnectionState(){return{isConnected:this.isConnected,isConnecting:this.isConnecting,socketId:this.socket?this.socket.id:null}}validateEventSchema(t){if(!t||"object"!=typeof t)return console.warn("Event data is not an object:",t),null;const e={...t};return e.source||(e.source="system"),e.type||(e.event?e.type=e.event:e.type="unknown"),e.subtype||(e.subtype="generic"),e.timestamp||(e.timestamp=(new Date).toISOString()),e.data||(e.data={}),e.data&&"object"!=typeof e.data&&(e.data={value:e.data}),console.log("Validated event:",e),e}transformEvent(t){if(!t)return t;let e={...t};if(t.type&&t.subtype&&!t.type.includes(".")&&!t.type.includes(":"))e.originalEventName||("generic"===t.subtype||t.type===t.subtype?e.originalEventName=t.type:e.originalEventName=`${t.type}.${t.subtype}`);else if(!t.type&&t.event){const n=t.event;"TestStart"===n||"TestEnd"===n?(e.type="test",e.subtype=n.toLowerCase().replace("test","")):"SubagentStart"===n||"SubagentStop"===n?(e.type="subagent",e.subtype=n.toLowerCase().replace("subagent","")):"ToolCall"===n?(e.type="tool",e.subtype="call"):"UserPrompt"===n?(e.type="hook",e.subtype="user_prompt"):(e.type="unknown",e.subtype=n.toLowerCase(),e.type===e.subtype&&(e.subtype="event")),delete e.event,e.originalEventName=n}else if(t.type){const n=t.type;if(n.startsWith("hook.")){const t=n.substring(5);e.type="hook",e.subtype=t,e.originalEventName=n}else if(n.startsWith("code:")){e.type="code";const t=n.substring(5);e.subtype=t.replace(/:/g,"_"),e.originalEventName=n}else if(n.includes(".")){const[t,...s]=n.split(".");e.type=t,e.subtype=s.join("."),e.originalEventName=n}else if(n.includes(":")){const t=n.split(":",2);e.type=t[0],e.subtype=t.length>1?t[1].replace(/:/g,"_"):"generic",e.originalEventName=n}else t.subtype||(e.subtype="generic",e.originalEventName=n)}else e.type="unknown",e.subtype="",e.originalEventName="unknown";if(t.data&&"object"==typeof t.data){const n=["type","subtype","timestamp","id","event","event_type","originalEventName"];Object.keys(t.data).forEach(s=>{n.includes(s)?console.warn(`Protected field '${s}' in data object was not copied to top level to preserve event structure`):"tool_parameters"===s&&"object"==typeof t.data[s]?e[s]=JSON.parse(JSON.stringify(t.data[s])):e[s]=t.data[s]}),e.data=t.data}if("hook"===e.type?"pre_tool"===e.subtype?e.hook_event_name="PreToolUse":"post_tool"===e.subtype?e.hook_event_name="PostToolUse":"subagent_start"===e.subtype?e.hook_event_name="SubagentStart":"subagent_stop"===e.subtype?e.hook_event_name="SubagentStop":"todo_write"===e.subtype?e.hook_event_name="TodoWrite":"start"===e.subtype?e.hook_event_name="Start":"stop"===e.subtype&&(e.hook_event_name="Stop"):"subagent"===e.type?"start"===e.subtype?e.hook_event_name="SubagentStart":"stop"===e.subtype&&(e.hook_event_name="SubagentStop"):"todo"===e.type&&"updated"===e.subtype&&(e.hook_event_name="TodoWrite"),"hook"===e.type&&("pre_tool"===e.subtype||"post_tool"===e.subtype)){console.log("Transformed tool event:",{type:e.type,subtype:e.subtype,hook_event_name:e.hook_event_name,tool_name:e.tool_name,has_tool_parameters:!!e.tool_parameters,tool_parameters:e.tool_parameters,has_data:!!e.data,keys:Object.keys(e).filter(t=>"data"!==t)});["Read","Write","Edit","MultiEdit","NotebookEdit"].includes(e.tool_name)&&console.log("File tool event details:",{tool_name:e.tool_name,file_path:e.tool_parameters?.file_path,path:e.tool_parameters?.path,notebook_path:e.tool_parameters?.notebook_path,full_parameters:e.tool_parameters})}return e}getState(){return{events:this.events,sessions:this.sessions,currentSessionId:this.currentSessionId}}startHealthMonitoring(){this.healthCheckInterval=setInterval(()=>{if(this.isConnected&&this.lastPingTime){const t=Date.now()-this.lastPingTime;t>this.pingTimeout&&(console.warn(`No ping from server for ${t/1e3}s, connection may be stale`),this.socket&&(console.log("Forcing reconnection due to stale connection..."),this.socket.disconnect(),setTimeout(()=>{this.port&&this.connect(this.port)},1e3)))}},1e4)}stopHealthMonitoring(){this.healthCheckInterval&&(clearInterval(this.healthCheckInterval),this.healthCheckInterval=null)}startStatusCheckFallback(){setInterval(()=>{this.checkAndUpdateStatus()},2e3),"loading"===document.readyState?document.addEventListener("DOMContentLoaded",()=>{setTimeout(()=>this.checkAndUpdateStatus(),100)}):setTimeout(()=>this.checkAndUpdateStatus(),100)}checkAndUpdateStatus(){let t="Disconnected",e="disconnected";this.socket&&(this.socket.connected?(t="Connected",e="connected",this.isConnected=!0,this.isConnecting=!1):this.socket.connecting||this.isConnecting?(t="Connecting...",e="connecting",this.isConnected=!1):(t="Disconnected",e="disconnected",this.isConnected=!1,this.isConnecting=!1));const n=document.getElementById("connection-status");if(n){const s=n.textContent.replace("●","").trim(),o=n.className,i=`status-badge status-${e}`;s===t&&o===i||(console.log(`SocketClient: Fallback update - was '${s}' (${o}), now '${t}' (${i})`),this.updateConnectionStatusDOM(t,e))}}destroy(){this.stopHealthMonitoring(),this.socket&&(this.socket.disconnect(),this.socket=null),this.eventQueue=[],this.pendingEmissions.clear()}getConnectionMetrics(){return{isConnected:this.isConnected,uptime:this.lastConnectTime?(Date.now()-this.lastConnectTime)/1e3:0,lastPing:this.lastPingTime?(Date.now()-this.lastPingTime)/1e3:null,queuedEvents:this.eventQueue.length,pendingEmissions:this.pendingEmissions.size,retryAttempts:this.retryAttempts}}}window.SocketClient=e;class n{constructor(){this.socketClient=null,this.connectionCallbacks=new Set,this.eventUpdateCallbacks=new Set,this.socketClient=new e,window.socketClient=this.socketClient,this.setupSocketEventHandlers(),setTimeout(()=>{this.updateInitialConnectionStatus()},100),console.log("Socket manager initialized")}setupSocketEventHandlers(){document.addEventListener("socketConnectionStatus",t=>{console.log(`SocketManager: Processing connection status update: ${t.detail.status} (${t.detail.type})`),this.handleConnectionStatusChange(t.detail.status,t.detail.type),this.connectionCallbacks.forEach(e=>{try{e(t.detail.status,t.detail.type)}catch(n){console.error("Error in connection callback:",n)}})}),this.socketClient&&this.socketClient.onEventUpdate(t=>{this.eventUpdateCallbacks.forEach(e=>{try{e(t)}catch(n){console.error("Error in event update callback:",n)}})})}handleConnectionStatusChange(t,e){this.updateConnectionStatus(t,e),"connected"===e&&this.socketClient&&this.socketClient.socket&&(window.socket=this.socketClient.socket,console.log("SocketManager: Exposed socket globally as window.socket"),this.setupGitBranchListener())}updateInitialConnectionStatus(){console.log("SocketManager: Updating initial connection status"),this.socketClient&&"function"==typeof this.socketClient.checkAndUpdateStatus?(console.log("SocketManager: Using socket client checkAndUpdateStatus method"),this.socketClient.checkAndUpdateStatus()):this.socketClient&&this.socketClient.socket?(console.log("SocketManager: Checking socket state directly",{connected:this.socketClient.socket.connected,connecting:this.socketClient.socket.connecting,isConnecting:this.socketClient.isConnecting,isConnected:this.socketClient.isConnected}),this.socketClient.socket.connected?(console.log("SocketManager: Socket is already connected, updating status"),window.socket=this.socketClient.socket,console.log("SocketManager: Exposed socket globally as window.socket"),this.updateConnectionStatus("Connected","connected")):this.socketClient.isConnecting||this.socketClient.socket.connecting?(console.log("SocketManager: Socket is connecting, updating status"),this.updateConnectionStatus("Connecting...","connecting")):(console.log("SocketManager: Socket is disconnected, updating status"),this.updateConnectionStatus("Disconnected","disconnected"))):(console.log("SocketManager: No socket client or socket found, setting disconnected status"),this.updateConnectionStatus("Disconnected","disconnected")),setTimeout(()=>{console.log("SocketManager: Secondary status check after 1 second"),this.socketClient&&this.socketClient.socket&&this.socketClient.socket.connected&&(console.log("SocketManager: Socket connected in secondary check, updating status"),window.socket||(window.socket=this.socketClient.socket,console.log("SocketManager: Exposed socket globally as window.socket (secondary check)")),this.updateConnectionStatus("Connected","connected"))},1e3)}setupGitBranchListener(){this.socketClient.socket.off("git_branch_response"),this.socketClient.socket.on("git_branch_response",t=>{if(t.success){const e=document.getElementById("footer-git-branch");e&&(e.textContent=t.branch||"unknown"),e&&(e.style.display="inline")}else console.error("Git branch request failed:",t.error)})}updateConnectionStatus(t,e){const n=document.getElementById("connection-status");if(n){if(n.querySelector("span")){const e="●";n.innerHTML=`<span>${e}</span> ${t}`}else n.textContent=t;n.className=`status-badge status-${e}`,console.log(`SocketManager: UI updated - status: '${t}' (${e})`)}else console.error("SocketManager: Could not find connection-status element in DOM")}connect(t){this.socketClient&&this.socketClient.connect(t)}disconnect(){this.socketClient&&this.socketClient.disconnect()}isConnected(){return this.socketClient&&this.socketClient.isConnected}isConnecting(){return this.socketClient&&this.socketClient.isConnecting}getSocketClient(){return this.socketClient}getSocket(){return this.socketClient?this.socketClient.socket:null}onConnectionStatusChange(t){this.connectionCallbacks.add(t)}offConnectionStatusChange(t){this.connectionCallbacks.delete(t)}onEventUpdate(t){this.eventUpdateCallbacks.add(t)}offEventUpdate(t){this.eventUpdateCallbacks.delete(t)}toggleConnectionControls(){const t=document.getElementById("connection-controls-row"),e=document.getElementById("connection-toggle-btn");if(t&&e){t.classList.contains("show")?(t.classList.remove("show"),t.style.display="none",e.textContent="Connection Settings"):(t.classList.add("show"),t.style.display="block",e.textContent="Hide Settings")}}setupConnectionControls(){const t=document.getElementById("connect-btn"),e=document.getElementById("disconnect-btn"),n=document.getElementById("connection-toggle-btn");t&&t.addEventListener("click",()=>{const t=document.getElementById("port-input").value||8765;this.connect(t)}),e&&e.addEventListener("click",()=>{this.disconnect()}),n&&n.addEventListener("click",()=>{this.toggleConnectionControls()})}initializeFromURL(t){const e=t.get("port"),n=document.getElementById("port-input");let s=e;s||"http:"!==window.location.protocol||(s=window.location.port||"8765"),s||(s=n?.value||"8765"),n&&(n.value=s);!("false"!==t.get("connect"))||this.isConnected()||this.isConnecting()||(console.log(`SocketManager: Auto-connecting to port ${s}`),this.connect(s))}}class s{constructor(){this.currentTab="events",this.autoScroll=!0,this.selectedCard={tab:null,index:null,type:null,data:null},this.tabNavigation={events:{selectedIndex:-1,items:[]},agents:{selectedIndex:-1,items:[]},tools:{selectedIndex:-1,items:[]},files:{selectedIndex:-1,items:[]}},this.setupEventHandlers(),console.log("UI state manager initialized")}setupEventHandlers(){this.setupTabNavigation(),this.setupUnifiedKeyboardNavigation()}setupTabNavigation(){document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",()=>{const e=this.getTabNameFromButton(t);this.switchTab(e)})})}setupUnifiedKeyboardNavigation(){document.addEventListener("keydown",t=>{document.activeElement&&["INPUT","TEXTAREA","SELECT"].includes(document.activeElement.tagName)||("ArrowUp"===t.key||"ArrowDown"===t.key?(t.preventDefault(),this.handleUnifiedArrowNavigation("ArrowDown"===t.key?1:-1)):"Enter"===t.key?(t.preventDefault(),this.handleUnifiedEnterKey()):"Escape"===t.key&&this.clearUnifiedSelection())})}getTabNameFromButton(t){const e=t.textContent.toLowerCase();return e.includes("events")?"events":e.includes("activity")?"activity":e.includes("agents")?"agents":e.includes("tools")?"tools":e.includes("files")?"files":e.includes("code")?"code":e.includes("sessions")?"sessions":e.includes("system")?"system":"events"}switchTab(t){console.log(`[DEBUG] switchTab called with tabName: ${t}`);const e=this.currentTab;this.currentTab=t,document.querySelectorAll(".tab-button").forEach(e=>{e.classList.remove("active"),this.getTabNameFromButton(e)===t&&e.classList.add("active")}),document.querySelectorAll(".tab-content").forEach(t=>{t.classList.remove("active")});const n=document.getElementById(`${t}-tab`);n&&n.classList.add("active"),this.clearUnifiedSelection(),document.dispatchEvent(new CustomEvent("tabChanged",{detail:{newTab:t,previousTab:e}})),setTimeout(()=>{this.autoScroll&&this.scrollCurrentTabToBottom()},100)}handleUnifiedArrowNavigation(t){const e=this.tabNavigation[this.currentTab];if(!e)return;let n=e.selectedIndex+t;0!==e.items.length&&(n<0?n=e.items.length-1:n>=e.items.length&&(n=0),this.selectCardByIndex(this.currentTab,n))}handleUnifiedEnterKey(){const t=this.tabNavigation[this.currentTab];if(!t||-1===t.selectedIndex)return;const e=t.items[t.selectedIndex];e&&e.onclick&&e.onclick()}clearUnifiedSelection(){Object.keys(this.tabNavigation).forEach(t=>{this.tabNavigation[t].selectedIndex=-1}),this.clearCardSelection()}updateTabNavigationItems(){const t=this.tabNavigation[this.currentTab];if(!t)return;let e;switch(this.currentTab){case"events":e="#events-list .event-item";break;case"agents":e="#agents-list .event-item";break;case"tools":e="#tools-list .event-item";break;case"files":e="#files-list .event-item"}e&&(t.items=Array.from(document.querySelectorAll(e)))}selectCardByIndex(t,e){const n=this.tabNavigation[t];if(!n||e<0||e>=n.items.length)return;n.selectedIndex=e,this.updateUnifiedSelectionUI();n.items[e]&&this.selectCard(t,e,this.getCardType(t),e),this.showCardDetails(t,e)}updateUnifiedSelectionUI(){document.querySelectorAll(".event-item.keyboard-selected").forEach(t=>{t.classList.remove("keyboard-selected")});const t=this.tabNavigation[this.currentTab];t&&-1!==t.selectedIndex&&t.items[t.selectedIndex]&&t.items[t.selectedIndex].classList.add("keyboard-selected")}showCardDetails(t,e){document.dispatchEvent(new CustomEvent("showCardDetails",{detail:{tabName:t,index:e}}))}selectCard(t,e,n,s){this.clearCardSelection(),this.selectedCard={tab:t,index:e,type:n,data:s},this.updateCardSelectionUI(),console.log("Card selected:",this.selectedCard)}clearCardSelection(){document.querySelectorAll(".event-item.selected, .file-item.selected").forEach(t=>{t.classList.remove("selected")}),this.selectedCard={tab:null,index:null,type:null,data:null}}updateCardSelectionUI(){if(!this.selectedCard.tab||null===this.selectedCard.index)return;let t;switch(this.selectedCard.tab){case"events":t=document.getElementById("events-list");break;case"agents":t=document.getElementById("agents-list");break;case"tools":t=document.getElementById("tools-list");break;case"files":t=document.getElementById("files-list")}if(t){const e=t.querySelectorAll(".event-item, .file-item");e[this.selectedCard.index]&&e[this.selectedCard.index].classList.add("selected")}}getCardType(t){switch(t){case"events":return"event";case"agents":return"agent";case"tools":return"tool";case"files":return"file";default:return"unknown"}}scrollCurrentTabToBottom(){const t=`${this.currentTab}-list`,e=document.getElementById(t);e&&this.autoScroll&&(e.scrollTop=e.scrollHeight)}clearSelection(){this.clearCardSelection(),this.clearUnifiedSelection()}getCurrentTab(){return this.currentTab}getSelectedCard(){return{...this.selectedCard}}getTabNavigation(){return{...this.tabNavigation}}setAutoScroll(t){this.autoScroll=t}getAutoScroll(){return this.autoScroll}}export{n as S,s as U};
2
2
  //# sourceMappingURL=socket-client.js.map
@@ -7,6 +7,38 @@
7
7
  background: #f8f9fa;
8
8
  }
9
9
 
10
+ /* Advanced Options - Always Visible */
11
+ .code-advanced-options-visible {
12
+ background: white;
13
+ border-bottom: 1px solid #e2e8f0;
14
+ padding: 8px 12px;
15
+ }
16
+
17
+ .code-advanced-options-visible .advanced-content {
18
+ display: flex;
19
+ justify-content: space-between;
20
+ align-items: center;
21
+ gap: 20px;
22
+ }
23
+
24
+ .code-advanced-options-visible .option-group {
25
+ display: flex;
26
+ align-items: center;
27
+ gap: 10px;
28
+ }
29
+
30
+ .code-advanced-options-visible .option-group label {
31
+ display: inline-flex;
32
+ align-items: center;
33
+ gap: 4px;
34
+ font-size: 13px;
35
+ color: #4a5568;
36
+ }
37
+
38
+ .code-advanced-options-visible .option-group input[type="checkbox"] {
39
+ margin: 0;
40
+ }
41
+
10
42
  /* Compact Header Layout */
11
43
  .code-header-compact {
12
44
  display: flex;
@@ -70,9 +102,46 @@
70
102
  }
71
103
 
72
104
  .btn-compact.btn-primary {
73
- background: #3b82f6;
105
+ background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
74
106
  color: white;
75
107
  border-color: #3b82f6;
108
+ font-weight: 500;
109
+ }
110
+
111
+ .btn-compact.btn-primary:hover {
112
+ background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 100%);
113
+ transform: translateY(-1px);
114
+ box-shadow: 0 2px 4px rgba(59, 130, 246, 0.3);
115
+ }
116
+
117
+ .btn-compact.btn-primary:disabled {
118
+ background: #94a3b8;
119
+ border-color: #94a3b8;
120
+ cursor: not-allowed;
121
+ opacity: 0.7;
122
+ }
123
+
124
+ .btn-compact.btn-primary.analyzing {
125
+ background: linear-gradient(135deg, #f59e0b 0%, #f97316 100%);
126
+ border-color: #f59e0b;
127
+ animation: pulse 1.5s infinite;
128
+ position: relative;
129
+ }
130
+
131
+ .btn-compact.btn-primary.analyzing::after {
132
+ content: '';
133
+ position: absolute;
134
+ top: 0;
135
+ left: 0;
136
+ right: 0;
137
+ bottom: 0;
138
+ background: linear-gradient(90deg, transparent 0%, rgba(255,255,255,0.3) 50%, transparent 100%);
139
+ animation: shimmer 2s infinite;
140
+ }
141
+
142
+ @keyframes shimmer {
143
+ 0% { transform: translateX(-100%); }
144
+ 100% { transform: translateX(100%); }
76
145
  }
77
146
 
78
147
  .btn-compact.btn-danger {
@@ -81,6 +150,12 @@
81
150
  border-color: #ef4444;
82
151
  }
83
152
 
153
+ .btn-compact.btn-danger:hover {
154
+ background: #dc2626;
155
+ transform: translateY(-1px);
156
+ box-shadow: 0 2px 4px rgba(239, 68, 68, 0.3);
157
+ }
158
+
84
159
  .stat-compact {
85
160
  font-size: 13px;
86
161
  color: #64748b;
@@ -388,6 +463,41 @@
388
463
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
389
464
  }
390
465
 
466
+ /* Loading indicator */
467
+ #code-tree-loading {
468
+ position: absolute;
469
+ top: 50%;
470
+ left: 50%;
471
+ transform: translate(-50%, -50%);
472
+ text-align: center;
473
+ z-index: 100;
474
+ }
475
+
476
+ #code-tree-loading.hidden {
477
+ display: none;
478
+ }
479
+
480
+ .code-tree-spinner {
481
+ width: 50px;
482
+ height: 50px;
483
+ border: 5px solid #e2e8f0;
484
+ border-top: 5px solid #3b82f6;
485
+ border-radius: 50%;
486
+ animation: spin 1s linear infinite;
487
+ margin: 0 auto 15px;
488
+ }
489
+
490
+ @keyframes spin {
491
+ 0% { transform: rotate(0deg); }
492
+ 100% { transform: rotate(360deg); }
493
+ }
494
+
495
+ .code-tree-loading-text {
496
+ font-size: 14px;
497
+ color: #64748b;
498
+ font-weight: 500;
499
+ }
500
+
391
501
  #code-tree {
392
502
  width: 100%;
393
503
  height: 100%;
@@ -565,6 +675,11 @@
565
675
  color: #8b5cf6;
566
676
  }
567
677
 
678
+ .ticker-success {
679
+ color: #10b981;
680
+ font-weight: 500;
681
+ }
682
+
568
683
  .ticker-error {
569
684
  color: #ef4444;
570
685
  }
@@ -595,6 +710,42 @@
595
710
  filter: brightness(1.1);
596
711
  }
597
712
 
713
+ /* Visualization Controls */
714
+ .viz-controls {
715
+ position: absolute;
716
+ top: 10px;
717
+ left: 10px;
718
+ z-index: 100;
719
+ }
720
+
721
+ .layout-toggle {
722
+ cursor: pointer;
723
+ transition: all 0.2s;
724
+ }
725
+
726
+ .layout-toggle:hover rect {
727
+ opacity: 1;
728
+ filter: brightness(1.1);
729
+ }
730
+
731
+ /* Radial layout specific styles */
732
+ .radial-layout .link {
733
+ fill: none;
734
+ stroke: #cbd5e0;
735
+ stroke-width: 1.5px;
736
+ opacity: 0.6;
737
+ }
738
+
739
+ .radial-layout .node text {
740
+ font: 11px sans-serif;
741
+ text-anchor: middle;
742
+ }
743
+
744
+ .radial-layout .node.root text {
745
+ font-size: 14px;
746
+ font-weight: bold;
747
+ }
748
+
598
749
  .code-node text {
599
750
  font: 12px sans-serif;
600
751
  pointer-events: none;
@@ -663,6 +814,43 @@
663
814
  filter: drop-shadow(0 0 12px rgba(147, 51, 234, 0.5));
664
815
  }
665
816
 
817
+ /* Active node styling (larger icon) */
818
+ .node-circle.active {
819
+ stroke: #3b82f6 !important;
820
+ stroke-width: 3px;
821
+ filter: drop-shadow(0 0 8px rgba(59, 130, 246, 0.5));
822
+ transition: all 0.3s ease;
823
+ }
824
+
825
+ /* Parent context styling */
826
+ .node-circle.parent-context {
827
+ stroke: #10b981 !important;
828
+ stroke-width: 2px;
829
+ opacity: 0.8;
830
+ }
831
+
832
+ /* Loading pulse animation */
833
+ @keyframes nodePulse {
834
+ 0% {
835
+ transform: scale(1);
836
+ opacity: 1;
837
+ }
838
+ 50% {
839
+ transform: scale(1.3);
840
+ opacity: 0.6;
841
+ }
842
+ 100% {
843
+ transform: scale(1);
844
+ opacity: 1;
845
+ }
846
+ }
847
+
848
+ .node-circle.loading-pulse {
849
+ animation: nodePulse 1.2s ease-in-out infinite;
850
+ stroke: #f59e0b !important;
851
+ fill: #fef3c7 !important;
852
+ }
853
+
666
854
  /* Tooltips */
667
855
  .code-tooltip {
668
856
  position: absolute;
@@ -676,6 +864,69 @@
676
864
  z-index: 1000;
677
865
  }
678
866
 
867
+ /* Code tree notifications */
868
+ .code-tree-notification {
869
+ position: absolute;
870
+ top: 10px;
871
+ right: 10px;
872
+ padding: 12px 20px;
873
+ border-radius: 6px;
874
+ background: white;
875
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
876
+ font-size: 14px;
877
+ font-weight: 500;
878
+ z-index: 1000;
879
+ animation: slideInRight 0.3s ease;
880
+ max-width: 300px;
881
+ }
882
+
883
+ .code-tree-notification.info {
884
+ background: #3b82f6;
885
+ color: white;
886
+ }
887
+
888
+ .code-tree-notification.success {
889
+ background: #10b981;
890
+ color: white;
891
+ }
892
+
893
+ .code-tree-notification.warning {
894
+ background: #f59e0b;
895
+ color: white;
896
+ }
897
+
898
+ .code-tree-notification.error {
899
+ background: #ef4444;
900
+ color: white;
901
+ }
902
+
903
+ @keyframes slideInRight {
904
+ from {
905
+ transform: translateX(100%);
906
+ opacity: 0;
907
+ }
908
+ to {
909
+ transform: translateX(0);
910
+ opacity: 1;
911
+ }
912
+ }
913
+
914
+ @keyframes slideOutRight {
915
+ from {
916
+ transform: translateX(0);
917
+ opacity: 1;
918
+ }
919
+ to {
920
+ transform: translateX(100%);
921
+ opacity: 0;
922
+ }
923
+ }
924
+
925
+ /* Ensure container has relative positioning for notifications */
926
+ #code-tree-container {
927
+ position: relative;
928
+ }
929
+
679
930
  /* Code Viewer Modal Styles */
680
931
  .code-viewer-modal {
681
932
  display: none;
@@ -843,4 +1094,82 @@
843
1094
  width: 95%;
844
1095
  height: 90%;
845
1096
  }
1097
+ }
1098
+
1099
+ /* Analyze button states */
1100
+ #analyze-code {
1101
+ transition: all 0.3s ease;
1102
+ min-width: 80px;
1103
+ }
1104
+
1105
+ #analyze-code.analyzing {
1106
+ background: #f59e0b;
1107
+ border-color: #f59e0b;
1108
+ color: white;
1109
+ animation: pulse 1.5s infinite;
1110
+ }
1111
+
1112
+ #analyze-code.analyzing:before {
1113
+ content: '⏳ ';
1114
+ }
1115
+
1116
+ #analyze-code:disabled {
1117
+ opacity: 0.6;
1118
+ cursor: not-allowed;
1119
+ }
1120
+
1121
+ @keyframes pulse {
1122
+ 0% {
1123
+ box-shadow: 0 0 0 0 rgba(245, 158, 11, 0.7);
1124
+ }
1125
+ 70% {
1126
+ box-shadow: 0 0 0 10px rgba(245, 158, 11, 0);
1127
+ }
1128
+ 100% {
1129
+ box-shadow: 0 0 0 0 rgba(245, 158, 11, 0);
1130
+ }
1131
+ }
1132
+
1133
+ /* Analysis events display */
1134
+ .analysis-events {
1135
+ border-top: 2px solid #e2e8f0;
1136
+ margin-top: 15px;
1137
+ padding-top: 10px;
1138
+ max-height: 250px;
1139
+ overflow-y: auto;
1140
+ font-family: 'SF Mono', Monaco, monospace;
1141
+ font-size: 12px;
1142
+ background: linear-gradient(to bottom, #f8f9fa, #ffffff);
1143
+ border-radius: 6px;
1144
+ padding: 12px;
1145
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05);
1146
+ }
1147
+
1148
+ .analysis-event {
1149
+ padding: 6px 10px;
1150
+ margin: 3px 0;
1151
+ border-left: 3px solid #3b82f6;
1152
+ background: white;
1153
+ border-radius: 3px;
1154
+ animation: slideIn 0.3s ease;
1155
+ transition: all 0.2s ease;
1156
+ display: flex;
1157
+ align-items: center;
1158
+ gap: 8px;
1159
+ }
1160
+
1161
+ .analysis-event:hover {
1162
+ background: #f0f9ff;
1163
+ transform: translateX(2px);
1164
+ }
1165
+
1166
+ @keyframes slideIn {
1167
+ from {
1168
+ transform: translateX(-10px);
1169
+ opacity: 0;
1170
+ }
1171
+ to {
1172
+ transform: translateX(0);
1173
+ opacity: 1;
1174
+ }
846
1175
  }
@@ -1,2 +1,2 @@
1
- class t{constructor(){this.container=null,this.svg=null,this.treeData=null,this.root=null,this.treeLayout=null,this.treeGroup=null,this.events=[],this.todoWriteStack=[],this.activeAgent=null,this.activeAgentStack=[],this.margin={top:20,right:120,bottom:20,left:120},this.width=960-this.margin.left-this.margin.right,this.height=500-this.margin.top-this.margin.bottom,this.nodeId=0,this.duration=750,this.timeRange="30min",this.searchTerm="",this.tooltip=null,this.initialized=!1}initialize(){if(console.log("ActivityTree.initialize() called, initialized:",this.initialized),this.initialized)return void console.log("Activity tree already initialized, skipping");if(this.container=document.getElementById("activity-tree-container"),!this.container&&(this.container=document.getElementById("activity-tree"),!this.container))return void console.error("Activity tree container not found in DOM");console.log("Activity tree container found:",this.container);const t=document.getElementById("activity-tab");if(t){if(!t.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.setupControls(),this.initializeTreeData(),this.subscribeToEvents(),void(this.initialized=!0);this.setupControls(),this.createVisualization(),this.svg&&this.treeGroup?(this.initializeTreeData(),this.update(this.root),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")):console.error("Failed to create D3 visualization elements")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.svg||(console.log("Creating deferred visualization..."),this.createVisualization(),this.svg&&this.treeGroup&&this.update(this.root)),this.root&&this.svg&&(console.log("Updating tree with current data..."),this.update(this.root))}setupControls(){const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAll());const e=document.getElementById("collapse-all");e&&e.addEventListener("click",()=>this.collapseAll());const i=document.getElementById("reset-zoom");i&&i.addEventListener("click",()=>this.resetZoom());const o=document.getElementById("time-range");o&&o.addEventListener("change",t=>{this.timeRange=t.target.value,this.filterEventsByTime()});const n=document.getElementById("activity-search");n&&n.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.highlightSearchResults()})}createVisualization(){if("undefined"==typeof d3)return void console.error("D3.js is not loaded! Cannot create activity tree visualization.");const t=this.container.getBoundingClientRect();this.width=t.width-this.margin.left-this.margin.right,this.height=Math.max(500,t.height-this.margin.top-this.margin.bottom),console.log("Creating D3 visualization with dimensions:",{width:this.width,height:this.height}),d3.select(this.container).select("svg").remove(),this.svg=d3.select(this.container).append("svg").attr("width","100%").attr("height","100%").attr("viewBox",`0 0 ${this.width+this.margin.left+this.margin.right} ${this.height+this.margin.top+this.margin.bottom}`),this.treeGroup=this.svg.append("g").attr("class","tree-group").attr("transform",`translate(${this.margin.left},${this.margin.top})`);const e=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.call(e),this.treeLayout=d3.tree().size([this.height,this.width]),console.log("ActivityTree: Tree layout created:",this.treeLayout),this.tooltip=d3.select("body").append("div").attr("class","activity-tooltip").style("opacity",0),console.log("ActivityTree: Visualization complete, svg:",this.svg,"treeGroup:",this.treeGroup)}initializeTreeData(){console.log("ActivityTree: Initializing tree data"),this.treeData={name:"PM",type:"pm",icon:"🎯",children:[],_children:null},"undefined"!=typeof d3?(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,console.log("ActivityTree: Root node created:",this.root)):console.error("ActivityTree: D3 is not available - cannot create hierarchy!")}subscribeToEvents(){if(!window.socketClient)return console.warn("Socket client not available for activity tree"),void setTimeout(()=>this.subscribeToEvents(),1e3);console.log("ActivityTree: Setting up event subscription"),window.socketClient.onEventUpdate(t=>{console.log(`ActivityTree: onEventUpdate called with ${t.length} total events`);const e=t.length-this.events.length;if(e>0){const i=t.slice(this.events.length);console.log(`ActivityTree: Processing ${e} new events`,i),i.forEach(t=>{this.processEvent(t)}),this.events=[...t]}});const t=window.socketClient?.events||window.eventViewer?.events||[];t.length>0?(console.log(`ActivityTree: Processing ${t.length} existing events`,t),t.forEach(t=>{this.processEvent(t)}),this.events=[...t]):(console.log("ActivityTree: No existing events found"),this.events=[])}processEvent(t){if(!t)return void console.log("ActivityTree: Ignoring null event");let e=null;if(t.hook_event_name)e=t.hook_event_name;else if("hook"===t.type&&t.subtype){e={pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[t.subtype]}else"todo"===t.type&&"updated"===t.subtype?e="TodoWrite":"subagent"===t.type?"started"===t.subtype?e="SubagentStart":"stopped"===t.subtype&&(e="SubagentStop"):"start"===t.type&&(e="Start");if(!e)return void("hook"!==t.type&&"todo"!==t.type&&"subagent"!==t.type||console.log("ActivityTree: Cannot determine event type for:",t));console.log(`ActivityTree: Processing event: ${e}`,t);const i=new Date(t.timestamp);if(this.isEventInTimeRange(i)){switch(e){case"TodoWrite":this.processTodoWrite(t);break;case"SubagentStart":this.processSubagentStart(t);break;case"SubagentStop":this.processSubagentStop(t);break;case"PreToolUse":this.processToolUse(t);break;case"PostToolUse":this.updateToolStatus(t,"completed");break;case"Start":this.initializeTreeData(),this.update(this.root)}this.updateStats()}}processTodoWrite(t){console.log("ActivityTree: Processing TodoWrite event:",t);let e=t.todos||t.data?.todos||t.data||[];if(e&&"object"==typeof e&&e.todos&&(e=e.todos),!Array.isArray(e))return void console.log("ActivityTree: Invalid todos format in event:",t);if(0===e.length)return void console.log("ActivityTree: No todos in event");const i=e.find(t=>"in_progress"===t.status);if(!i)return void console.log("ActivityTree: No in-progress todo found");console.log("ActivityTree: Found active todo:",i);const o={name:i.activeForm||i.content,type:"todowrite",icon:"📝",content:i.content,status:i.status,timestamp:t.timestamp,children:[],_children:null,eventId:t.id};this.root?this.root.data?(this.root.data.children||(this.root.data.children=[]),console.log("ActivityTree: Adding TodoWrite node to root"),this.root.data.children.push(o),this.todoWriteStack.push({node:o,content:i.content}),console.log("ActivityTree: Calling update with root:",this.root),this.update(this.root),console.log("ActivityTree: Update complete")):console.error("ActivityTree: Root has no data!"):console.error("ActivityTree: No root node!")}processSubagentStart(t){const e=t.agent_name||t.data?.agent_name||t.data?.agent_type||t.agent_type||t.agent||"unknown",i={name:e,type:"agent",icon:this.getAgentIcon(e),timestamp:t.timestamp,children:[],_children:null,eventId:t.id,sessionId:t.session_id||t.data?.session_id};let o=null;if(this.todoWriteStack.length>0){const t=this.todoWriteStack[this.todoWriteStack.length-1];t.content&&t.content.toLowerCase().includes(e.toLowerCase())&&(o=t.node)}o||(o=this.root.data),o.children||(o.children=[]),o.children.push(i),this.activeAgent=i,this.activeAgentStack.push(i),this.update(this.root)}processSubagentStop(t){const e=t.session_id||t.data?.session_id;this.activeAgent&&this.activeAgent.sessionId===e&&(this.activeAgent.status="completed",this.activeAgentStack.pop(),this.activeAgent=this.activeAgentStack.length>0?this.activeAgentStack[this.activeAgentStack.length-1]:null),this.update(this.root)}processToolUse(t){const e=t.tool_name||t.data?.tool_name||t.tool||t.data?.tool||"unknown",i=this.getToolIcon(e),o=t.tool_parameters||t.data?.tool_parameters||t.parameters||t.data?.parameters||{},n={name:e,type:"tool",icon:i,timestamp:t.timestamp,status:"in_progress",children:[],_children:null,eventId:t.id};"Read"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"📄",timestamp:t.timestamp}):"Edit"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"✏️",timestamp:t.timestamp}):"Write"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"💾",timestamp:t.timestamp}):"Bash"===e&&o.command?n.children.push({name:o.command.substring(0,50)+(o.command.length>50?"...":""),type:"command",icon:"⚡",timestamp:t.timestamp}):"WebFetch"===e&&o.url&&n.children.push({name:o.url,type:"url",icon:"🌐",timestamp:t.timestamp});let s=this.activeAgent||this.root.data;s.children||(s.children=[]),s.children.push(n),this.update(this.root)}updateToolStatus(t,e){const i=o=>{if(o.eventId===t.id)return o.status=e,!0;if(o.children)for(let t of o.children)if(i(t))return!0;if(o._children)for(let t of o._children)if(i(t))return!0;return!1};i(this.root.data),this.update(this.root)}getAgentIcon(t){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️"}[t.toLowerCase()]||"🤖"}getToolIcon(t){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[t.toLowerCase()]||"🔧"}update(t){if(console.log("ActivityTree: update() called with source:",t),!this.svg||!this.treeGroup)return void console.warn("ActivityTree: Cannot update - SVG not initialized");if(!this.treeLayout)return void console.warn("ActivityTree: Cannot update - tree layout not initialized");const e=this.treeLayout(this.root),i=e.descendants(),o=e.links();console.log(`ActivityTree: Updating tree with ${i.length} nodes`),i.forEach(t=>{t.y=180*t.depth});const n=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),s=n.enter().append("g").attr("class","node").attr("transform",e=>`translate(${t.y0},${t.x0})`).on("click",(t,e)=>this.click(e));s.append("circle").attr("class",t=>`node-circle ${t.data.type}`).attr("r",1e-6).style("fill",t=>t._children?this.getNodeColor(t.data.type):"#fff").style("stroke",t=>this.getNodeColor(t.data.type)),s.append("text").attr("class","node-icon").attr("dy",".35em").attr("text-anchor","middle").style("font-size","14px").text(t=>t.data.icon||""),s.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>t.children||t._children?-25:25).attr("text-anchor",t=>t.children||t._children?"end":"start").text(t=>t.data.name).style("fill-opacity",1e-6),s.on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip());const a=s.merge(n);a.transition().duration(this.duration).attr("transform",t=>`translate(${t.y},${t.x})`),a.select("circle.node-circle").attr("r",10).style("fill",t=>"in_progress"===t.data.status||t._children?this.getNodeColor(t.data.type):"#fff").attr("class",t=>{let e=`node-circle ${t.data.type}`;return"in_progress"===t.data.status&&(e+=" pulsing"),"failed"===t.data.status&&(e+=" failed"),e}),a.select("text.node-label").style("fill-opacity",1);const r=n.exit().transition().duration(this.duration).attr("transform",e=>`translate(${t.y},${t.x})`).remove();r.select("circle").attr("r",1e-6),r.select("text").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(o,t=>t.target.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.diagonal({source:i,target:i})}).merge(l).transition().duration(this.duration).attr("d",this.diagonal),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.diagonal({source:i,target:i})}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y}),this.updateBreadcrumb(t)}diagonal(t){return`M ${t.source.y} ${t.source.x}\n C ${(t.source.y+t.target.y)/2} ${t.source.x},\n ${(t.source.y+t.target.y)/2} ${t.target.x},\n ${t.target.y} ${t.target.x}`}click(t){t.children?(t._children=t.children,t.children=null):(t.children=t._children,t._children=null),this.update(t),this.updateBreadcrumb(t)}getNodeColor(t){return{pm:"#4299e1",todowrite:"#48bb78",agent:"#ed8936",tool:"#9f7aea",file:"#38b2ac",command:"#f56565",url:"#4299e1"}[t]||"#718096"}showTooltip(t,e){const i=`\n <strong>${e.data.name}</strong><br>\n Type: ${e.data.type}<br>\n ${e.data.timestamp?`Time: ${new Date(e.data.timestamp).toLocaleTimeString()}`:""}\n ${e.data.status?`<br>Status: ${e.data.status}`:""}\n `;this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip.transition().duration(500).style("opacity",0)}expandAll(){const t=e=>{e._children&&(e.children=e._children,e._children=null),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root)}collapseAll(){const t=e=>{e.children&&(e._children=e.children,e._children.forEach(t),e.children=null)};this.root.children?.forEach(t),this.update(this.root)}resetZoom(){if(!this.svg)return void console.warn("Cannot reset zoom: SVG not initialized");const t=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.transition().duration(750).call(t.transform,d3.zoomIdentity),this.treeGroup.transition().duration(750).attr("transform",`translate(${this.margin.left},${this.margin.top})`)}isEventInTimeRange(t){if("all"===this.timeRange)return!0;const e=(new Date-t)/6e4;switch(this.timeRange){case"10min":return e<=10;case"30min":return e<=30;case"hour":return e<=60;default:return!0}}filterEventsByTime(){this.initializeTreeData(),window.eventViewer&&window.eventViewer.events&&window.eventViewer.events.forEach(t=>{this.processEvent(t)})}updateStats(){const t=this.countNodes(this.root),e=this.countActiveNodes(this.root.data),i=this.getTreeDepth(this.root);document.getElementById("node-count").textContent=t,document.getElementById("active-count").textContent=e,document.getElementById("tree-depth").textContent=i}countNodes(t){let e=1;return t.children&&t.children.forEach(t=>{e+=this.countNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countNodes(t)}),e}countActiveNodes(t){let e="in_progress"===t.status?1:0;return t.children&&t.children.forEach(t=>{e+=this.countActiveNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countActiveNodes(t)}),e}getTreeDepth(t){if(!t.children&&!t._children)return 0;const e=(t.children||t._children).map(t=>this.getTreeDepth(t));return Math.max(...e)+1}updateBreadcrumb(t){const e=[];let i=t;for(;i;)e.unshift(i.data.name),i=i.parent;const o=document.getElementById("activity-breadcrumb");o&&(o.textContent=e.join(" > "))}highlightSearchResults(){this.treeGroup.selectAll(".node-label").style("font-weight","normal").style("fill","#2d3748"),this.searchTerm&&this.treeGroup.selectAll(".node-label").style("font-weight",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"bold":"normal").style("fill",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"#e53e3e":"#2d3748")}}window.ActivityTree=t;const e=()=>{let e=null;const i=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e),setTimeout(()=>{console.log("Attempting to initialize Activity Tree visualization..."),e.initialize()},100)};document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",t=>{"activity"===t.target.getAttribute("data-tab")&&(console.log("Activity tab button clicked, initializing tree..."),i(),e&&setTimeout(()=>e.renderWhenVisible(),150))})}),document.addEventListener("tabChanged",t=>{t.detail&&"activity"===t.detail.newTab&&(console.log("Tab changed to activity, initializing tree..."),i(),e&&setTimeout(()=>e.renderWhenVisible(),150))});const o=document.querySelector(".tab-button.active");o&&"activity"===o.getAttribute("data-tab")&&i(),window.activityTree=()=>e};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e();
1
+ class t{constructor(){this.container=null,this.svg=null,this.treeData=null,this.root=null,this.treeLayout=null,this.treeGroup=null,this.events=[],this.todoWriteStack=[],this.activeAgent=null,this.activeAgentStack=[],this.margin={top:20,right:120,bottom:20,left:120},this.width=960-this.margin.left-this.margin.right,this.height=500-this.margin.top-this.margin.bottom,this.nodeId=0,this.duration=750,this.timeRange="30min",this.searchTerm="",this.tooltip=null,this.initialized=!1}initialize(){if(console.log("ActivityTree.initialize() called, initialized:",this.initialized),this.initialized)return void console.log("Activity tree already initialized, skipping");if(this.container=document.getElementById("activity-tree-container"),!this.container&&(this.container=document.getElementById("activity-tree"),!this.container))return void console.error("Activity tree container not found in DOM");this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing existing text content from container:",this.container.textContent),this.container.textContent=""),console.log("Activity tree container found:",this.container);const t=document.getElementById("activity-tab");if(t){if(!t.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.container.textContent&&this.container.textContent.trim()&&(this.container.textContent=""),this.setupControls(),this.initializeTreeData(),this.subscribeToEvents(),void(this.initialized=!0);if(this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing container text before creating visualization"),this.container.textContent=""),this.setupControls(),this.createVisualization(),!this.svg||!this.treeGroup)return console.error("Failed to create D3 visualization elements"),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ Failed to create visualization. Please refresh the page.</div>'));this.initializeTreeData(),this.root?this.update(this.root):console.warn("Root not created, skipping initial update"),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){if(console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)){if(this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing text from container:",this.container.textContent),this.container.innerHTML=""),this.svg||this.createVisualization(),this.root||this.initializeTreeData(),this.root&&this.svg&&this.treeGroup&&this.update(this.root),this.svg){const t=this.svg.node();t&&(t.style.display="block",t.style.visibility="visible")}}else console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),this.container&&this.container.textContent&&this.container.textContent.trim()&&!this.svg&&(console.log("Clearing text content before rendering:",this.container.textContent),this.container.textContent=""),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.svg||(console.log("Creating deferred visualization..."),this.createVisualization(),this.svg&&this.treeGroup&&this.root?this.update(this.root):this.root||(console.warn("No root node available, initializing tree data..."),this.initializeTreeData(),this.root&&this.svg&&this.treeGroup&&this.update(this.root))),this.root&&this.svg?(console.log("Updating tree with current data..."),this.update(this.root)):console.warn("Cannot update tree - missing components:",{hasRoot:!!this.root,hasSvg:!!this.svg,hasTreeGroup:!!this.treeGroup})}setupControls(){const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAll());const e=document.getElementById("collapse-all");e&&e.addEventListener("click",()=>this.collapseAll());const i=document.getElementById("reset-zoom");i&&i.addEventListener("click",()=>this.resetZoom());const o=document.getElementById("time-range");o&&o.addEventListener("change",t=>{this.timeRange=t.target.value,this.filterEventsByTime()});const n=document.getElementById("activity-search");n&&n.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.highlightSearchResults()})}createVisualization(){if("undefined"==typeof d3)return console.error("D3.js is not loaded! Cannot create activity tree visualization."),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ D3.js is not loaded. Cannot create visualization.</div>'));const t=this.container.getBoundingClientRect();this.width=t.width-this.margin.left-this.margin.right,this.height=Math.max(500,t.height-this.margin.top-this.margin.bottom),console.log("Creating D3 visualization with dimensions:",{width:this.width,height:this.height}),d3.select(this.container).selectAll("*").remove(),this.svg=d3.select(this.container).append("svg").attr("width","100%").attr("height","100%").attr("viewBox",`0 0 ${this.width+this.margin.left+this.margin.right} ${this.height+this.margin.top+this.margin.bottom}`),this.treeGroup=this.svg.append("g").attr("class","tree-group").attr("transform",`translate(${this.margin.left},${this.margin.top})`);const e=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.call(e),this.treeLayout=d3.tree().size([this.height,this.width]),console.log("ActivityTree: Tree layout created:",this.treeLayout),this.tooltip=d3.select("body").append("div").attr("class","activity-tooltip").style("opacity",0),console.log("ActivityTree: Visualization complete, svg:",this.svg,"treeGroup:",this.treeGroup)}initializeTreeData(){if(console.log("ActivityTree: Initializing tree data"),this.treeData={name:"PM",type:"pm",icon:"🎯",children:[],_children:null},"undefined"==typeof d3)return console.error("ActivityTree: D3 is not available - cannot create hierarchy!"),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ Waiting for D3.js to load...</div>'));this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,console.log("ActivityTree: Root node created:",this.root),this.updateStats()}subscribeToEvents(){if(!window.socketClient)return console.warn("Socket client not available for activity tree"),void setTimeout(()=>this.subscribeToEvents(),1e3);console.log("ActivityTree: Setting up event subscription"),window.socketClient.onEventUpdate(t=>{console.log(`ActivityTree: onEventUpdate called with ${t.length} total events`);const e=t.length-this.events.length;if(e>0){const i=t.slice(this.events.length);console.log(`ActivityTree: Processing ${e} new events`,i),i.forEach(t=>{this.processEvent(t)}),this.events=[...t]}});const t=window.socketClient?.events||window.eventViewer?.events||[];t.length>0?(console.log(`ActivityTree: Processing ${t.length} existing events`,t),t.forEach(t=>{this.processEvent(t)}),this.events=[...t]):(console.log("ActivityTree: No existing events found"),this.events=[])}processEvent(t){if(!t)return void console.log("ActivityTree: Ignoring null event");let e=null;if(t.hook_event_name)e=t.hook_event_name;else if("hook"===t.type&&t.subtype){e={pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[t.subtype]}else"todo"===t.type&&"updated"===t.subtype?e="TodoWrite":"subagent"===t.type?"started"===t.subtype?e="SubagentStart":"stopped"===t.subtype&&(e="SubagentStop"):"start"===t.type&&(e="Start");if(!e)return void("hook"!==t.type&&"todo"!==t.type&&"subagent"!==t.type||console.log("ActivityTree: Cannot determine event type for:",t));console.log(`ActivityTree: Processing event: ${e}`,t);const i=new Date(t.timestamp);if(this.isEventInTimeRange(i)){switch(e){case"TodoWrite":this.processTodoWrite(t);break;case"SubagentStart":this.processSubagentStart(t);break;case"SubagentStop":this.processSubagentStop(t);break;case"PreToolUse":this.processToolUse(t);break;case"PostToolUse":this.updateToolStatus(t,"completed");break;case"Start":this.initializeTreeData(),this.update(this.root)}this.updateStats()}}processTodoWrite(t){console.log("ActivityTree: Processing TodoWrite event:",t);let e=t.todos||t.data?.todos||t.data||[];if(e&&"object"==typeof e&&e.todos&&(e=e.todos),!Array.isArray(e))return void console.log("ActivityTree: Invalid todos format in event:",t);if(0===e.length)return void console.log("ActivityTree: No todos in event");const i=e.find(t=>"in_progress"===t.status);if(!i)return void console.log("ActivityTree: No in-progress todo found");console.log("ActivityTree: Found active todo:",i);const o={name:i.activeForm||i.content,type:"todowrite",icon:"📝",content:i.content,status:i.status,timestamp:t.timestamp,children:[],_children:null,eventId:t.id};this.root?this.root.data?(this.root.data.children||(this.root.data.children=[]),console.log("ActivityTree: Adding TodoWrite node to root"),this.root.data.children.push(o),this.todoWriteStack.push({node:o,content:i.content}),console.log("ActivityTree: Calling update with root:",this.root),this.update(this.root),console.log("ActivityTree: Update complete")):console.error("ActivityTree: Root has no data!"):console.error("ActivityTree: No root node!")}processSubagentStart(t){const e=t.agent_name||t.data?.agent_name||t.data?.agent_type||t.agent_type||t.agent||"unknown",i={name:e,type:"agent",icon:this.getAgentIcon(e),timestamp:t.timestamp,children:[],_children:null,eventId:t.id,sessionId:t.session_id||t.data?.session_id};let o=null;if(this.todoWriteStack.length>0){const t=this.todoWriteStack[this.todoWriteStack.length-1];t.content&&t.content.toLowerCase().includes(e.toLowerCase())&&(o=t.node)}o||(o=this.root.data),o.children||(o.children=[]),o.children.push(i),this.activeAgent=i,this.activeAgentStack.push(i),this.update(this.root)}processSubagentStop(t){const e=t.session_id||t.data?.session_id;this.activeAgent&&this.activeAgent.sessionId===e&&(this.activeAgent.status="completed",this.activeAgentStack.pop(),this.activeAgent=this.activeAgentStack.length>0?this.activeAgentStack[this.activeAgentStack.length-1]:null),this.update(this.root)}processToolUse(t){const e=t.tool_name||t.data?.tool_name||t.tool||t.data?.tool||"unknown",i=this.getToolIcon(e),o=t.tool_parameters||t.data?.tool_parameters||t.parameters||t.data?.parameters||{},n={name:e,type:"tool",icon:i,timestamp:t.timestamp,status:"in_progress",children:[],_children:null,eventId:t.id};"Read"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"📄",timestamp:t.timestamp}):"Edit"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"✏️",timestamp:t.timestamp}):"Write"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"💾",timestamp:t.timestamp}):"Bash"===e&&o.command?n.children.push({name:o.command.substring(0,50)+(o.command.length>50?"...":""),type:"command",icon:"⚡",timestamp:t.timestamp}):"WebFetch"===e&&o.url&&n.children.push({name:o.url,type:"url",icon:"🌐",timestamp:t.timestamp});let s=this.activeAgent||this.root.data;s.children||(s.children=[]),s.children.push(n),this.update(this.root)}updateToolStatus(t,e){const i=o=>{if(o.eventId===t.id)return o.status=e,!0;if(o.children)for(let t of o.children)if(i(t))return!0;if(o._children)for(let t of o._children)if(i(t))return!0;return!1};i(this.root.data),this.update(this.root)}getAgentIcon(t){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️"}[t.toLowerCase()]||"🤖"}getToolIcon(t){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[t.toLowerCase()]||"🔧"}update(t){if(console.log("ActivityTree: update() called with source:",t),"undefined"==typeof d3)return void console.error("ActivityTree: Cannot update - D3.js not loaded");if(!this.svg||!this.treeGroup){if(console.warn("ActivityTree: Cannot update - SVG not initialized"),!this.container)return;if(console.log("Attempting to create visualization from update()"),this.createVisualization(),!this.svg||!this.treeGroup)return void console.error("Failed to create visualization in update()")}if(!this.treeLayout){if(console.warn("ActivityTree: Cannot update - tree layout not initialized"),"undefined"==typeof d3)return;this.treeLayout=d3.tree().size([this.height,this.width]),console.log("Created tree layout in update()")}if(!t||!t.data)return void console.error("ActivityTree: Invalid source in update()",t);if(!this.root)return void console.error("ActivityTree: No root node available for update");let e;try{e=this.treeLayout(this.root)}catch(c){return void console.error("ActivityTree: Error computing tree layout:",c)}const i=e.descendants(),o=e.links();if(console.log(`ActivityTree: Updating tree with ${i.length} nodes`),1===i.length&&this.container){this.container.querySelector("svg")||console.warn("SVG element not found in container after update")}i.forEach(t=>{t.y=180*t.depth});const n=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),s=n.enter().append("g").attr("class","node").attr("transform",e=>`translate(${t.y0},${t.x0})`).on("click",(t,e)=>this.click(e));s.append("circle").attr("class",t=>`node-circle ${t.data.type}`).attr("r",1e-6).style("fill",t=>t._children?this.getNodeColor(t.data.type):"#fff").style("stroke",t=>this.getNodeColor(t.data.type)),s.append("text").attr("class","node-icon").attr("dy",".35em").attr("text-anchor","middle").style("font-size","14px").text(t=>t.data.icon||""),s.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>t.children||t._children?-25:25).attr("text-anchor",t=>t.children||t._children?"end":"start").text(t=>t.data.name).style("fill-opacity",1e-6),s.on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip());const r=s.merge(n);r.transition().duration(this.duration).attr("transform",t=>`translate(${t.y},${t.x})`),r.select("circle.node-circle").attr("r",10).style("fill",t=>"in_progress"===t.data.status||t._children?this.getNodeColor(t.data.type):"#fff").attr("class",t=>{let e=`node-circle ${t.data.type}`;return"in_progress"===t.data.status&&(e+=" pulsing"),"failed"===t.data.status&&(e+=" failed"),e}),r.select("text.node-label").style("fill-opacity",1);const a=n.exit().transition().duration(this.duration).attr("transform",e=>`translate(${t.y},${t.x})`).remove();a.select("circle").attr("r",1e-6),a.select("text").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(o,t=>t.target.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.diagonal({source:i,target:i})}).merge(l).transition().duration(this.duration).attr("d",this.diagonal),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.diagonal({source:i,target:i})}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y}),this.updateBreadcrumb(t)}diagonal(t){return`M ${t.source.y} ${t.source.x}\n C ${(t.source.y+t.target.y)/2} ${t.source.x},\n ${(t.source.y+t.target.y)/2} ${t.target.x},\n ${t.target.y} ${t.target.x}`}click(t){t.children?(t._children=t.children,t.children=null):(t.children=t._children,t._children=null),this.update(t),this.updateBreadcrumb(t)}getNodeColor(t){return{pm:"#4299e1",todowrite:"#48bb78",agent:"#ed8936",tool:"#9f7aea",file:"#38b2ac",command:"#f56565",url:"#4299e1"}[t]||"#718096"}showTooltip(t,e){const i=`\n <strong>${e.data.name}</strong><br>\n Type: ${e.data.type}<br>\n ${e.data.timestamp?`Time: ${new Date(e.data.timestamp).toLocaleTimeString()}`:""}\n ${e.data.status?`<br>Status: ${e.data.status}`:""}\n `;this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip.transition().duration(500).style("opacity",0)}expandAll(){const t=e=>{e._children&&(e.children=e._children,e._children=null),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root)}collapseAll(){const t=e=>{e.children&&(e._children=e.children,e._children.forEach(t),e.children=null)};this.root.children?.forEach(t),this.update(this.root)}resetZoom(){if(!this.svg)return void console.warn("Cannot reset zoom: SVG not initialized");const t=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.transition().duration(750).call(t.transform,d3.zoomIdentity),this.treeGroup.transition().duration(750).attr("transform",`translate(${this.margin.left},${this.margin.top})`)}isEventInTimeRange(t){if("all"===this.timeRange)return!0;const e=(new Date-t)/6e4;switch(this.timeRange){case"10min":return e<=10;case"30min":return e<=30;case"hour":return e<=60;default:return!0}}filterEventsByTime(){this.initializeTreeData(),window.eventViewer&&window.eventViewer.events&&window.eventViewer.events.forEach(t=>{this.processEvent(t)})}updateStats(){if(!this.root||!this.root.data){console.warn("ActivityTree: Cannot update stats - root not initialized");const t=document.getElementById("node-count"),e=document.getElementById("active-count"),i=document.getElementById("tree-depth");return t&&(t.textContent="1"),e&&(e.textContent="0"),void(i&&(i.textContent="0"))}const t=this.countNodes(this.root),e=this.countActiveNodes(this.root.data),i=this.getTreeDepth(this.root),o=document.getElementById("node-count"),n=document.getElementById("active-count"),s=document.getElementById("tree-depth");o&&(o.textContent=t),n&&(n.textContent=e),s&&(s.textContent=i),console.log(`ActivityTree: Stats updated - Nodes: ${t}, Active: ${e}, Depth: ${i}`)}countNodes(t){let e=1;return t.children&&t.children.forEach(t=>{e+=this.countNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countNodes(t)}),e}countActiveNodes(t){let e="in_progress"===t.status?1:0;return t.children&&t.children.forEach(t=>{e+=this.countActiveNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countActiveNodes(t)}),e}getTreeDepth(t){if(!t.children&&!t._children)return 0;const e=(t.children||t._children).map(t=>this.getTreeDepth(t));return Math.max(...e)+1}updateBreadcrumb(t){const e=[];let i=t;for(;i;)e.unshift(i.data.name),i=i.parent;const o=document.getElementById("activity-breadcrumb");o&&(o.textContent=e.join(" > "))}highlightSearchResults(){this.treeGroup.selectAll(".node-label").style("font-weight","normal").style("fill","#2d3748"),this.searchTerm&&this.treeGroup.selectAll(".node-label").style("font-weight",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"bold":"normal").style("fill",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"#e53e3e":"#2d3748")}}window.ActivityTree=t;const e=()=>{let e=null;const i=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e);const i=document.getElementById("activity-tree-container")||document.getElementById("activity-tree");i&&i.textContent&&i.textContent.trim()&&(console.log("Clearing text from activity tree container before init:",i.textContent),i.textContent=""),setTimeout(()=>{console.log("Attempting to initialize Activity Tree visualization..."),e.initialize()},100)};document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",t=>{"activity"===t.target.getAttribute("data-tab")&&(console.log("Activity tab button clicked, initializing tree..."),i(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))})}),document.addEventListener("tabChanged",t=>{t.detail&&"activity"===t.detail.newTab&&(console.log("Tab changed to activity, initializing tree..."),i(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))});const o=document.querySelector(".tab-button.active");o&&"activity"===o.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),i());const n=document.getElementById("activity-tab");n&&n.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),e||i()),window.activityTree=()=>e};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e();
2
2
  //# sourceMappingURL=activity-tree.js.map