claude-mpm 4.1.25__py3-none-any.whl → 4.1.27__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.
claude_mpm/VERSION CHANGED
@@ -1 +1 @@
1
- 4.1.25
1
+ 4.1.27
@@ -1,2 +1,2 @@
1
- import{U as e}from"./unified-data-viewer.js";class t{constructor(){this.container=null,this.events=[],this.processedEventIds=new Set,this.sessions=new Map,this.currentSession=null,this.selectedSessionFilter="all",this.timeRange="30min",this.searchTerm="",this.initialized=!1,this.expandedSessions=new Set,this.expandedAgents=new Set,this.expandedTools=new Set,this.selectedItem=null,this.renderTreeDebounced=this.debounce(()=>this.renderTree(),100)}debounce(e,t){let s;return function(...n){clearTimeout(s),s=setTimeout(()=>{clearTimeout(s),e(...n)},t)}}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");const e=document.getElementById("activity-tab");if(e){if(!e.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.setupControls(),this.subscribeToEvents(),void(this.initialized=!0);this.setupControls(),this.createLinearTreeView(),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)?(this.createLinearTreeView(),this.renderTree()):console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.createLinearTreeView(),this.renderTree()}setupControls(){const e=document.getElementById("time-range");e&&e.addEventListener("change",e=>{this.timeRange=e.target.value,console.log(`ActivityTree: Time range changed to: ${this.timeRange}`),this.renderTree()}),document.addEventListener("sessionFilterChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session filter changed to: ${this.selectedSessionFilter} (from SessionManager)`),this.renderTree()}),document.addEventListener("sessionChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session changed to: ${this.selectedSessionFilter} (from SessionManager - backward compat)`),this.renderTree()}),setTimeout(()=>{if(window.sessionManager){const e=window.sessionManager.getCurrentFilter();e!==this.selectedSessionFilter&&(this.selectedSessionFilter=e||"all",console.log(`ActivityTree: Initialized with current session filter: ${this.selectedSessionFilter}`),this.renderTree())}},100);const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAllSessions());const s=document.getElementById("collapse-all");s&&s.addEventListener("click",()=>this.collapseAllSessions());const n=document.getElementById("reset-zoom");n&&(n.style.display="inline-block",n.addEventListener("click",()=>this.resetZoom()));const o=document.getElementById("activity-search");o&&o.addEventListener("input",e=>{this.searchTerm=e.target.value.toLowerCase(),this.renderTree()})}createLinearTreeView(){console.log("Creating linear tree view"),this.container.innerHTML="";const e=document.createElement("div");e.id="linear-tree",e.className="linear-tree",this.container.appendChild(e),console.log("Linear tree view created")}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((e,t)=>{console.log(`ActivityTree: onEventUpdate called with ${e.length} total events and ${t.size} sessions`);for(const[n,o]of t.entries())if(this.sessions.has(n)){const e=this.sessions.get(n);e.timestamp=new Date(o.lastActivity||o.startTime||e.timestamp),e.eventCount=o.eventCount,e.status=o.status||e.status,e.working_directory=o.working_directory||e.working_directory,e.git_branch=o.git_branch||e.git_branch}else{const e={id:n,timestamp:new Date(o.lastActivity||o.startTime||new Date),expanded:this.expandedSessions.has(n)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],toolsMap:new Map,status:"active",currentTodoTool:null,working_directory:o.working_directory,git_branch:o.git_branch,eventCount:o.eventCount};this.sessions.set(n,e)}const s=e.filter(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;return!this.processedEventIds.has(t)});s.length>0&&(console.log(`ActivityTree: Processing ${s.length} new events`,s),s.forEach(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;this.processedEventIds.add(t),this.processEvent(e)})),this.events=[...e],this.renderTreeDebounced(),console.log("ActivityTree: Sessions after sync with socket client:",Array.from(this.sessions.entries()))});const e=window.socketClient?.getState();if(e&&e.events.length>0){console.log(`ActivityTree: Loading existing data - ${e.events.length} events, ${e.sessions.size} sessions`);for(const[s,n]of e.sessions.entries())if(!this.sessions.has(s)){const e={id:s,timestamp:new Date(n.lastActivity||n.startTime||new Date),expanded:this.expandedSessions.has(s)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],toolsMap:new Map,status:"active",currentTodoTool:null,working_directory:n.working_directory,git_branch:n.git_branch,eventCount:n.eventCount};this.sessions.set(s,e)}const t=e.events.filter(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;return!this.processedEventIds.has(t)});t.length>0&&(console.log(`ActivityTree: Processing ${t.length} unprocessed events from initial load`),t.forEach(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;this.processedEventIds.add(t),this.processEvent(e)})),this.events=[...e.events],this.renderTree(),console.log("ActivityTree: Initial sessions state:",Array.from(this.sessions.entries()))}else console.log("ActivityTree: No existing events found"),this.events=[],this.sessions.clear(),this.renderTree()}processEvent(e){if(!e)return void console.log("ActivityTree: Ignoring null event");let t,s=this.getEventType(e);if(!s)return;console.log(`ActivityTree: Processing event: ${s}`,e),e.timestamp?(t=new Date(e.timestamp),isNaN(t.getTime())&&(console.warn("ActivityTree: Invalid timestamp, using current time:",e.timestamp),t=new Date)):(console.warn("ActivityTree: No timestamp found, using current time"),t=new Date);const n=e.session_id||e.data?.session_id;if(!n)return void console.log(`ActivityTree: Skipping event without session_id: ${s}`);if(!this.sessions.has(n))return void console.warn(`ActivityTree: Session ${n} not found in authoritative sessions - skipping event`);const o=this.sessions.get(n);switch(s){case"Start":this.currentSession=o;break;case"user_prompt":this.processUserInstruction(e,o);break;case"TodoWrite":break;case"SubagentStart":this.processSubagentStart(e,o);break;case"SubagentStop":this.processSubagentStop(e,o);break;case"PreToolUse":this.processToolUse(e,o);break;case"PostToolUse":this.updateToolStatus(e,o,"completed")}this.updateStats()}getEventType(e){if(e.hook_event_name)return e.hook_event_name;if("hook"===e.type&&e.subtype){return{pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[e.subtype]}if("todo"===e.type&&"updated"===e.subtype)return"TodoWrite";if("subagent"===e.type){if("started"===e.subtype)return"SubagentStart";if("stopped"===e.subtype)return"SubagentStop"}return"start"===e.type?"Start":"user_prompt"===e.type||"user_prompt"===e.subtype?"user_prompt":null}processUserInstruction(e,t){const s=e.prompt_text||e.data?.prompt_text||e.prompt||"";if(!s)return;const n={id:`instruction-${t.id}-${Date.now()}`,text:s,preview:s.length>100?s.substring(0,100)+"...":s,timestamp:e.timestamp||(new Date).toISOString(),type:"user_instruction"};if(t.agents.size>0){console.log("ActivityTree: New user prompt detected, collapsing previous agents");for(let e of t.agents.values())"active"===e.status&&(e.status="completed"),this.expandedAgents.delete(e.id)}t.currentActiveAgent=null,t.userInstructions.push(n),t.userInstructions.length>5&&(t.userInstructions=t.userInstructions.slice(-5))}processTodoWrite(e,t){let s=e.todos||e.data?.todos||e.data||[];if(s&&"object"==typeof s&&s.todos&&(s=s.todos),!Array.isArray(s)||0===s.length)return;t.currentTodos=s.map(t=>({content:t.content,activeForm:t.activeForm,status:t.status,timestamp:e.timestamp}));let n=t.currentActiveAgent;if(!n){const e=this.getAllAgents(t).filter(e=>"active"===e.status||"in_progress"===e.status).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));if(e.length>0)n=e[0];else{const e=this.getAllAgents(t),s=e.find(e=>e.isPM);s?n=s:e.length>0&&(n=e[0])}}if(n){n.todoWritesMap||(n.todoWritesMap=new Map),n.todoWrites||(n.todoWrites=[]);const t=n.todoWritesMap.get("TodoWrite");if(t)t.todos=s,t.timestamp=e.timestamp,t.updateCount=(t.updateCount||1)+1;else{const t={id:`todowrite-${n.id}-${Date.now()}`,name:"TodoWrite",type:"todowrite",icon:"📝",timestamp:e.timestamp,status:"completed",todos:s,params:{todos:s},updateCount:1};n.todoWritesMap.set("TodoWrite",t),n.todoWrites=[t]}n.currentTodos=s}else{t.todoWrites||(t.todoWrites=[]),t.todoWritesMap||(t.todoWritesMap=new Map);const n=t.todoWritesMap.get("TodoWrite");if(n)n.todos=s,n.timestamp=e.timestamp,n.updateCount=(n.updateCount||1)+1;else{const n={id:`todowrite-session-${Date.now()}`,name:"TodoWrite",type:"todowrite",icon:"📝",timestamp:e.timestamp,status:"completed",todos:s,updateCount:1};t.todoWritesMap.set("TodoWrite",n),t.todoWrites=[n]}}}processSubagentStart(e,t){const s=e.agent_name||e.data?.agent_name||e.data?.agent_type||e.agent_type||e.agent||"unknown",n=e.session_id||e.data?.session_id,o=e.parent_agent||e.data?.parent_agent,i=`${s}-${n||"no-session"}`;let a=null;let r;if(a=this.getAllAgents(t).find(e=>e.name===s&&e.sessionId===n&&"active"===e.status),a)r=a,r.timestamp=e.timestamp,r.instanceCount=(r.instanceCount||1)+1,this.expandedAgents.add(r.id);else{if(r={id:`agent-${i}-${Date.now()}`,name:s,type:"agent",icon:this.getAgentIcon(s),timestamp:e.timestamp,status:"active",tools:[],subagents:new Map,sessionId:n,parentAgent:o,isPM:"pm"===s.toLowerCase()||s.toLowerCase().includes("project manager"),instanceCount:1,toolsMap:new Map},o){let e=null;for(let[s,n]of t.agents.entries())if(n.sessionId===o||n.name===o){e=n;break}e?(e.subagents||(e.subagents=new Map),e.subagents.set(r.id,r)):t.agents.set(r.id,r)}else t.agents.set(r.id,r);this.expandedAgents.add(r.id)}t.currentActiveAgent=r}processSubagentStop(e,t){const s=e.session_id||e.data?.session_id;if(s&&t.agents.has(s)){t.agents.get(s).status="completed"}}processToolUse(e,t){const s=e.tool_name||e.data?.tool_name||e.tool||e.data?.tool||"unknown",n=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},o=e.session_id||e.data?.session_id;let i=t.currentActiveAgent;if(!i){const e=this.getAllAgents(t);i=e.find(e=>e.sessionId===o)||e.find(e=>"active"===e.status)||e[0]}if(i){i.toolsMap||(i.toolsMap=new Map),i.tools||(i.tools=[]);const t=this.getToolKey(s,n);let o=i.toolsMap.get(t);if(o)o.params=n,o.timestamp=e.timestamp,o.status="in_progress",o.eventId=e.id,o.callCount=(o.callCount||1)+1,i.currentTool=o;else{const o={id:`tool-${i.id}-${s}-${Date.now()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id,callCount:1,createdAt:e.timestamp};"Task"===s&&n.subagent_type&&(o.isSubagentTask=!0,o.subagentType=n.subagent_type),i.toolsMap.set(t,o),"TodoWrite"===s?i.tools.unshift(o):i.tools.push(o),i.currentTool=o}}else{t.tools||(t.tools=[]),t.toolsMap||(t.toolsMap=new Map);const o=this.getToolKey(s,n);let i=t.toolsMap.get(o);if(i)i.params=n,i.timestamp=e.timestamp,i.status="in_progress",i.eventId=e.id,i.callCount=(i.callCount||1)+1,t.currentTool=i;else{const i={id:`tool-session-${s}-${Date.now()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id,callCount:1,createdAt:e.timestamp};t.toolsMap.set(o,i),"TodoWrite"===s?t.tools.unshift(i):t.tools.push(i),t.currentTool=i}}}getToolKey(e,t){if("TodoWrite"===e)return"TodoWrite";let s=e;return"Edit"!==e&&"Write"!==e&&"Read"!==e||t.file_path&&(s+=`-${t.file_path}`),"Grep"!==e&&"Glob"!==e||!t.pattern||(s+=`-${t.pattern.substring(0,20)}`),s}updateToolStatus(e,t,s){const n=e.tool_name||e.data?.tool_name||e.tool||"unknown",o=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},i=e.session_id||e.data?.session_id,a=this.getToolKey(n,o);let r=t.currentActiveAgent;if(!r){const e=this.getAllAgents(t);r=e.find(e=>e.sessionId===i)||e.find(e=>"active"===e.status)}if(r&&r.toolsMap){const t=r.toolsMap.get(a);if(t)return t.status=s,t.completedAt=e.timestamp,(e.data?.result||e.result)&&(t.result=e.data?.result||e.result),void(e.data?.duration_ms&&(t.duration=e.data.duration_ms))}if(t.toolsMap){const n=t.toolsMap.get(a);if(n)return n.status=s,n.completedAt=e.timestamp,(e.data?.result||e.result)&&(n.result=e.data?.result||e.result),void(e.data?.duration_ms&&(n.duration=e.data.duration_ms))}console.log(`ActivityTree: Could not find tool to update status for ${n} with key ${a} (event ${e.id})`)}renderTree(){const e=document.getElementById("linear-tree");if(!e)return;e.innerHTML="";const t=Array.from(this.sessions.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let s of t){if("all"!==this.selectedSessionFilter&&this.selectedSessionFilter!==s.id)continue;const t=this.createSessionElement(s);e.appendChild(t)}}createSessionElement(e){const t=this.expandedSessions.has(e.id)||e.expanded;let s;try{const t=e.timestamp instanceof Date?e.timestamp:new Date(e.timestamp);isNaN(t.getTime())?(s="Invalid Date",console.warn("ActivityTree: Invalid session timestamp:",e.timestamp)):s=t.toLocaleString()}catch(l){s="Invalid Date",console.error("ActivityTree: Error formatting session timestamp:",l,e.timestamp)}const n=document.createElement("div");n.className="tree-node session",n.dataset.sessionId=e.id;const o=t?"▼":"▶",i=this.getAllAgents(e).length,a=e.currentTodos?e.currentTodos.length:0,r=e.userInstructions?e.userInstructions.length:0;return console.log(`ActivityTree: Rendering session ${e.id}: ${i} agents, ${r} instructions, ${a} todos at ${s}`),n.innerHTML=`\n <div class="tree-node-content" onclick="window.activityTreeInstance.toggleSession('${e.id}')">\n <span class="tree-expand-icon">${o}</span>\n <span class="tree-icon">🎯</span>\n <span class="tree-label">PM Session</span>\n <span class="tree-meta">${s} • ${i} agent(s) • ${r} instruction(s) • ${a} todo(s)</span>\n </div>\n <div class="tree-children" style="display: ${t?"block":"none"}">\n ${this.renderSessionContent(e)}\n </div>\n `,n}renderSessionContent(e){let t="";if(e.userInstructions&&e.userInstructions.length>0)for(let n of e.userInstructions.slice(-3))t+=this.renderUserInstructionElement(n,1);if(e.tools&&e.tools.length>0)for(let n of e.tools)t+=this.renderToolElement(n,1);const s=Array.from(e.agents.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let n of s)t+=this.renderAgentElement(n,1);return t}renderUserInstructionElement(e,t){return`\n <div class="tree-node user-instruction ${this.selectedItem&&"instruction"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">💬</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'instruction', event)">User: "${this.escapeHtml(e.preview)}"</span>\n <span class="tree-status status-active">instruction</span>\n </div>\n </div>\n `}renderTodoChecklistElement(e,t){const s=`checklist-${Date.now()}`,n=!1!==this.expandedTools.has(s),o=n?"▼":"▶";let i=0,a=0;e.forEach(e=>{"completed"===e.status?i++:"in_progress"===e.status&&a++});let r="";r=a>0?`${a} in progress, ${i} completed`:i===e.length&&e.length>0?`All ${e.length} completed`:`${e.length} todo(s)`;let l=`\n <div class="tree-node todo-checklist" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">☑️</span>\n <span class="tree-label">TODOs</span>\n <span class="tree-params">${r}</span>\n <span class="tree-status status-active">checklist</span>\n </div>\n `;if(n){l+='<div class="tree-children">';for(let s of e){const e=this.getCheckboxIcon(s.status),n=`status-${s.status}`,o="in_progress"===s.status?s.activeForm:s.content;l+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${s.status.replace("_"," ")}</span>\n </div>\n </div>\n `}l+="</div>"}return l+="</div>",l}renderAgentElement(e,t){const s="active"===e.status?"status-active":"status-completed",n=this.expandedAgents.has(e.id),o=e.tools&&e.tools.length>0,i=e.subagents&&e.subagents.size>0,a=o||i,r=a?n?"▼":"▶":"",l=this.selectedItem&&"agent"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":"",c=e.instanceCount>1?` (${e.instanceCount}x)`:"";let d="";if(!n&&a){const t=[];if(e.currentTodos&&e.currentTodos.length>0){const s=e.currentTodos.find(e=>"in_progress"===e.status);s&&t.push(`📝 ${s.activeForm||s.content}`)}e.currentTool&&t.push(`${e.currentTool.icon} ${e.currentTool.name}`),t.length>0&&(d=` • ${t.join(" • ")}`)}let p=`\n <div class="tree-node agent ${s} ${l}" data-level="${t}">\n <div class="tree-node-content">\n ${r?`<span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleAgent('${e.id}'); event.stopPropagation();">${r}</span>`:'<span class="tree-expand-icon"></span>'}\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'agent', event)">${e.name}${c}${d}</span>\n <span class="tree-status ${s}">${e.status}</span>\n </div>\n `;if(a&&n){if(p+='<div class="tree-children">',o)for(let s of e.tools)p+=this.renderToolElement(s,t+1);if(i){const s=Array.from(e.subagents.values());for(let e of s)p+=this.renderAgentElement(e,t+1)}p+="</div>"}return p+="</div>",p}renderToolElement(e,t){const s=`status-${e.status}`,n=this.getToolParams(e),o=this.selectedItem&&"tool"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":"",i=this.getToolStatusIcon(e.status),a=this.getToolStatusLabel(e.status),r=e.callCount>1?` (${e.callCount} calls)`:"";return`\n <div class="tree-node tool ${s} ${o}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-status-icon">${i}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'tool', event)">${e.name}${r}</span>\n <span class="tree-params">${n}</span>\n <span class="tree-status ${s}">${a}</span>\n </div>\n </div>\n `}getToolParams(e){if(!e.params)return"";if("Read"===e.name&&e.params.file_path)return e.params.file_path;if("Edit"===e.name&&e.params.file_path)return e.params.file_path;if("Write"===e.name&&e.params.file_path)return e.params.file_path;if("Bash"===e.name&&e.params.command){const t=e.params.command;return t.length>50?t.substring(0,50)+"...":t}return"WebFetch"===e.name&&e.params.url?e.params.url:""}getStatusIcon(e){return{pending:"⏸️",in_progress:"🔄",completed:"✅"}[e]||"❓"}getCheckboxIcon(e){return{pending:"⏳",in_progress:"🔄",completed:"✅"}[e]||"❓"}getAgentIcon(e){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️","project manager":"📊"}[e.toLowerCase()]||"🤖"}getAllAgents(e){const t=[],s=e=>{if(e)for(let n of e.values())t.push(n),n.subagents&&n.subagents.size>0&&s(n.subagents)};return s(e.agents),t}renderTodoWriteElement(e,t){const s=e.id,n=this.expandedTools.has(s),o=n?"▼":"▶",i=e.todos||[];let a=0,r=0;i.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&r++});const l=i.find(e=>"in_progress"===e.status),c=l?` • 🔄 ${l.activeForm||l.content}`:"";let d="";d=r>0?`${r} in progress, ${a}/${i.length} done`:a===i.length&&i.length>0?`All ${i.length} completed ✅`:`${a}/${i.length} done`;let p=`\n <div class="tree-node todowrite ${l?"has-active":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoWrite('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">📝</span>\n <span class="tree-label">TodoWrite${e.updateCount>1?` (${e.updateCount} updates)`:""}${n?"":c}</span>\n <span class="tree-params">${d}</span>\n <span class="tree-status status-active">todos</span>\n </div>\n `;if(n&&i.length>0){p+='<div class="tree-children">';for(let e of i){const s=this.getCheckboxIcon(e.status),n=`status-${e.status}`,o="in_progress"===e.status?e.activeForm:e.content;p+=`\n <div class="tree-node todo-item ${n} ${e===l?"current-active":""}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${s}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}p+="</div>"}return p+="</div>",p}toggleTodoWrite(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}getToolIcon(e){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[e.toLowerCase()]||"🔧"}getToolStatusIcon(e){return{in_progress:"⏳",completed:"✅",failed:"❌",error:"❌",pending:"⏸️",active:"🔄"}[e]||"❓"}getToolStatusLabel(e){return{in_progress:"in progress",completed:"completed",failed:"failed",error:"error",pending:"pending",active:"active"}[e]||e}toggleSession(e){this.expandedSessions.has(e)?this.expandedSessions.delete(e):this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=this.expandedSessions.has(e)),this.renderTree()}expandAllSessions(){for(let e of this.sessions.keys()){this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=!0)}this.renderTree()}collapseAllSessions(){this.expandedSessions.clear();for(let e of this.sessions.values())e.expanded=!1;this.renderTree()}updateStats(){const e=this.countTotalNodes(),t=this.countActiveNodes(),s=this.calculateMaxDepth(),n=document.getElementById("node-count"),o=document.getElementById("active-count"),i=document.getElementById("tree-depth");n&&(n.textContent=e),o&&(o.textContent=t),i&&(i.textContent=s),console.log(`ActivityTree: Stats updated - Nodes: ${e}, Active: ${t}, Depth: ${s}`)}countTotalNodes(){let e=0;for(let t of this.sessions.values()){e+=1,e+=t.agents.size,t.userInstructions&&(e+=t.userInstructions.length),t.todos&&(e+=t.todos.length),t.tools&&(e+=t.tools.length);for(let s of t.agents.values())s.tools&&(e+=s.tools.length)}return e}countActiveNodes(){let e=0;for(let t of this.sessions.values()){if("active"===t.status&&e++,t.todos)for(let s of t.todos)"in_progress"===s.status&&e++;if(t.tools)for(let s of t.tools)"in_progress"===s.status&&e++;for(let s of t.agents.values())if("active"===s.status&&e++,s.tools)for(let t of s.tools)"in_progress"===t.status&&e++}return e}calculateMaxDepth(){let e=0;for(let t of this.sessions.values()){let s=1;t.userInstructions&&t.userInstructions.length>0&&(s=Math.max(s,2)),t.todos&&t.todos.length>0&&(s=Math.max(s,3)),t.tools&&t.tools.length>0&&(s=Math.max(s,2));for(let e of t.agents.values())e.tools&&e.tools.length>0&&(s=Math.max(s,3));e=Math.max(e,s)}return e}toggleAgent(e){this.expandedAgents.has(e)?this.expandedAgents.delete(e):this.expandedAgents.add(e),this.renderTree()}toggleTool(e){console.log("Tool expansion is disabled. Tools now show data in the left pane when clicked.")}toggleTodoChecklist(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}renderPinnedTodosElement(e,t){const s=`pinned-todos-${Date.now()}`,n=!1!==this.expandedTools.has(s),o=n?"▼":"▶",i=e.todos||[];let a=0,r=0;i.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&r++});let l="";l=r>0?`${r} in progress, ${a} completed`:a===i.length&&i.length>0?`All ${i.length} completed`:`${i.length} todo(s)`;let c=`\n <div class="tree-node pinned-todos" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">📌</span>\n <span class="tree-label">Pinned TODOs</span>\n <span class="tree-params">${l}</span>\n <span class="tree-status status-active">pinned</span>\n </div>\n `;if(n){c+='<div class="tree-children">';for(let e of i){const s=this.getCheckboxIcon(e.status),n=`status-${e.status}`,o="in_progress"===e.status?e.activeForm:e.content;c+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${s}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}c+="</div>"}return c+="</div>",c}selectItem(e,t,s){s&&s.stopPropagation(),this.selectedItem={data:e,type:t},this.displayItemData(e,t),this.renderTree()}displayItemData(t,s){this.unifiedViewer||(this.unifiedViewer=new e("module-data-content")),this.unifiedViewer.display(t,s);const n=document.querySelector(".module-data-header h5");if(n){const e={agent:"🤖",tool:"🔧",instruction:"💬",session:"🎯",todo:"📝"}[s]||"📊",o=t.name||t.agentName||t.tool_name||"Item";n.textContent=`${e} ${s}: ${o}`}}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}resetZoom(){this.svg&&this.zoom&&this.svg.transition().duration(this.duration).call(this.zoom.transform,d3.zoomIdentity)}escapeJson(e){return JSON.stringify(e).replace(/'/g,"&apos;").replace(/"/g,"&quot;")}}window.ActivityTree=t;const s=()=>{let e=null;const s=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e,window.activityTree=()=>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..."),s(),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..."),s(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))});const n=document.querySelector(".tab-button.active");n&&"activity"===n.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),s());const o=document.getElementById("activity-tab");o&&o.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),e||s())};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",s):s();
1
+ import{U as e}from"./unified-data-viewer.js";class t{constructor(){this.container=null,this.events=[],this.processedEventIds=new Set,this.sessions=new Map,this.currentSession=null,this.selectedSessionFilter="all",this.timeRange="30min",this.searchTerm="",this.initialized=!1,this.expandedSessions=new Set,this.expandedAgents=new Set,this.expandedTools=new Set,this.selectedItem=null,this.sessionFilterInitialized=!1,this.renderTreeDebounced=this.debounce(()=>this.renderTree(),100)}debounce(e,t){let s;return function(...n){clearTimeout(s),s=setTimeout(()=>{clearTimeout(s),e(...n)},t)}}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");const e=document.getElementById("activity-tab");if(e){if(!e.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.setupControls(),this.subscribeToEvents(),void(this.initialized=!0);this.setupControls(),this.createLinearTreeView(),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)?(this.createLinearTreeView(),this.renderTree()):console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.createLinearTreeView(),this.renderTree()}setupControls(){const e=document.getElementById("time-range");e&&e.addEventListener("change",e=>{this.timeRange=e.target.value,console.log(`ActivityTree: Time range changed to: ${this.timeRange}`),this.renderTree()}),document.addEventListener("sessionFilterChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session filter changed to: ${this.selectedSessionFilter} (from SessionManager)`),this.renderTree()}),document.addEventListener("sessionChanged",e=>{this.selectedSessionFilter=e.detail.sessionId||"all",console.log(`ActivityTree: Session changed to: ${this.selectedSessionFilter} (from SessionManager - backward compat)`),this.renderTree()}),setTimeout(()=>{if(window.sessionManager&&!this.sessionFilterInitialized){const e=window.sessionManager.getCurrentFilter();e!==this.selectedSessionFilter&&(this.selectedSessionFilter=e||"all",console.log(`ActivityTree: Initialized with current session filter: ${this.selectedSessionFilter}`),this.sessionFilterInitialized=!0,this.renderTree())}},100);const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAllSessions());const s=document.getElementById("collapse-all");s&&s.addEventListener("click",()=>this.collapseAllSessions());const n=document.getElementById("reset-zoom");n&&(n.style.display="inline-block",n.addEventListener("click",()=>this.resetZoom()));const o=document.getElementById("activity-search");o&&o.addEventListener("input",e=>{this.searchTerm=e.target.value.toLowerCase(),this.renderTree()})}createLinearTreeView(){console.log("Creating linear tree view"),this.container.innerHTML="";const e=document.createElement("div");e.id="linear-tree",e.className="linear-tree",this.container.appendChild(e),console.log("Linear tree view created")}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((e,t)=>{console.log(`ActivityTree: onEventUpdate called with ${e.length} total events and ${t.size} sessions`);for(const[n,o]of t.entries())if(this.sessions.has(n)){const e=this.sessions.get(n);e.timestamp=new Date(o.lastActivity||o.startTime||e.timestamp),e.eventCount=o.eventCount,e.status=o.status||e.status,e.working_directory=o.working_directory||e.working_directory,e.git_branch=o.git_branch||e.git_branch}else{const e={id:n,timestamp:new Date(o.lastActivity||o.startTime||new Date),expanded:this.expandedSessions.has(n)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],toolsMap:new Map,status:"active",currentTodoTool:null,working_directory:o.working_directory,git_branch:o.git_branch,eventCount:o.eventCount};this.sessions.set(n,e)}const s=e.filter(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;return!this.processedEventIds.has(t)});s.length>0&&(console.log(`ActivityTree: Processing ${s.length} new events`,s),s.forEach(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;this.processedEventIds.add(t),this.processEvent(e)})),this.events=[...e],this.renderTreeDebounced(),console.log("ActivityTree: Sessions after sync with socket client:",Array.from(this.sessions.entries()))});const e=window.socketClient?.getState();if(e&&e.events.length>0){console.log(`ActivityTree: Loading existing data - ${e.events.length} events, ${e.sessions.size} sessions`);for(const[s,n]of e.sessions.entries())if(!this.sessions.has(s)){const e={id:s,timestamp:new Date(n.lastActivity||n.startTime||new Date),expanded:this.expandedSessions.has(s)||!0,agents:new Map,todos:[],userInstructions:[],tools:[],toolsMap:new Map,status:"active",currentTodoTool:null,working_directory:n.working_directory,git_branch:n.git_branch,eventCount:n.eventCount};this.sessions.set(s,e)}const t=e.events.filter(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;return!this.processedEventIds.has(t)});t.length>0&&(console.log(`ActivityTree: Processing ${t.length} unprocessed events from initial load`),t.forEach(e=>{const t=e.id||`${e.type}-${e.timestamp}-${Math.random()}`;this.processedEventIds.add(t),this.processEvent(e)})),this.events=[...e.events],this.renderTree(),console.log("ActivityTree: Initial sessions state:",Array.from(this.sessions.entries()))}else console.log("ActivityTree: No existing events found"),this.events=[],this.sessions.clear(),this.renderTree()}processEvent(e){if(!e)return void console.log("ActivityTree: Ignoring null event");let t,s=this.getEventType(e);if(!s)return;console.log(`ActivityTree: Processing event: ${s}`,e),e.timestamp?(t=new Date(e.timestamp),isNaN(t.getTime())&&(console.warn("ActivityTree: Invalid timestamp, using current time:",e.timestamp),t=new Date)):(console.warn("ActivityTree: No timestamp found, using current time"),t=new Date);const n=e.session_id||e.data?.session_id;if(!n)return void console.log(`ActivityTree: Skipping event without session_id: ${s}`);if(!this.sessions.has(n))return void console.warn(`ActivityTree: Session ${n} not found in authoritative sessions - skipping event`);const o=this.sessions.get(n);switch(s){case"Start":this.currentSession=o;break;case"user_prompt":this.processUserInstruction(e,o);break;case"TodoWrite":break;case"SubagentStart":this.processSubagentStart(e,o);break;case"SubagentStop":this.processSubagentStop(e,o);break;case"PreToolUse":this.processToolUse(e,o);break;case"PostToolUse":this.updateToolStatus(e,o,"completed")}this.updateStats()}getEventType(e){if(e.hook_event_name)return e.hook_event_name;if("hook"===e.type&&e.subtype){return{pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[e.subtype]}if("todo"===e.type&&"updated"===e.subtype)return"TodoWrite";if("subagent"===e.type){if("started"===e.subtype)return"SubagentStart";if("stopped"===e.subtype)return"SubagentStop"}return"start"===e.type?"Start":"user_prompt"===e.type||"user_prompt"===e.subtype?"user_prompt":null}processUserInstruction(e,t){const s=e.prompt_text||e.data?.prompt_text||e.prompt||"";if(!s)return;const n={id:`instruction-${t.id}-${Date.now()}`,text:s,preview:s.length>100?s.substring(0,100)+"...":s,timestamp:e.timestamp||(new Date).toISOString(),type:"user_instruction"};if(t.agents.size>0){console.log("ActivityTree: New user prompt detected, collapsing previous agents");for(let e of t.agents.values())"active"===e.status&&(e.status="completed"),this.expandedAgents.delete(e.id)}t.currentActiveAgent=null,t.userInstructions.push(n),t.userInstructions.length>5&&(t.userInstructions=t.userInstructions.slice(-5))}processTodoWrite(e,t){let s=e.todos||e.data?.todos||e.data||[];if(s&&"object"==typeof s&&s.todos&&(s=s.todos),!Array.isArray(s)||0===s.length)return;t.currentTodos=s.map(t=>({content:t.content,activeForm:t.activeForm,status:t.status,timestamp:e.timestamp}));let n=t.currentActiveAgent;if(!n){const e=this.getAllAgents(t).filter(e=>"active"===e.status||"in_progress"===e.status).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));if(e.length>0)n=e[0];else{const e=this.getAllAgents(t),s=e.find(e=>e.isPM);s?n=s:e.length>0&&(n=e[0])}}if(n){n.todoWritesMap||(n.todoWritesMap=new Map),n.todoWrites||(n.todoWrites=[]);const t=n.todoWritesMap.get("TodoWrite");if(t)t.todos=s,t.timestamp=e.timestamp,t.updateCount=(t.updateCount||1)+1;else{const t={id:`todowrite-${n.id}-${Date.now()}`,name:"TodoWrite",type:"todowrite",icon:"📝",timestamp:e.timestamp,status:"completed",todos:s,params:{todos:s},updateCount:1};n.todoWritesMap.set("TodoWrite",t),n.todoWrites=[t]}n.currentTodos=s}else{t.todoWrites||(t.todoWrites=[]),t.todoWritesMap||(t.todoWritesMap=new Map);const n=t.todoWritesMap.get("TodoWrite");if(n)n.todos=s,n.timestamp=e.timestamp,n.updateCount=(n.updateCount||1)+1;else{const n={id:`todowrite-session-${Date.now()}`,name:"TodoWrite",type:"todowrite",icon:"📝",timestamp:e.timestamp,status:"completed",todos:s,updateCount:1};t.todoWritesMap.set("TodoWrite",n),t.todoWrites=[n]}}}processSubagentStart(e,t){const s=e.agent_name||e.data?.agent_name||e.data?.agent_type||e.agent_type||e.agent||"unknown",n=e.session_id||e.data?.session_id,o=e.parent_agent||e.data?.parent_agent,i=`${s}-${n||"no-session"}`;let a=null;let r;if(a=this.getAllAgents(t).find(e=>e.name===s&&e.sessionId===n&&"active"===e.status),a)r=a,r.timestamp=e.timestamp,r.instanceCount=(r.instanceCount||1)+1,this.expandedAgents.add(r.id);else{if(r={id:`agent-${i}-${Date.now()}`,name:s,type:"agent",icon:this.getAgentIcon(s),timestamp:e.timestamp,status:"active",tools:[],subagents:new Map,sessionId:n,parentAgent:o,isPM:"pm"===s.toLowerCase()||s.toLowerCase().includes("project manager"),instanceCount:1,toolsMap:new Map},o){let e=null;for(let[s,n]of t.agents.entries())if(n.sessionId===o||n.name===o){e=n;break}e?(e.subagents||(e.subagents=new Map),e.subagents.set(r.id,r)):t.agents.set(r.id,r)}else t.agents.set(r.id,r);this.expandedAgents.add(r.id)}t.currentActiveAgent=r}processSubagentStop(e,t){const s=e.session_id||e.data?.session_id;if(s&&t.agents.has(s)){t.agents.get(s).status="completed"}}processToolUse(e,t){const s=e.tool_name||e.data?.tool_name||e.tool||e.data?.tool||"unknown",n=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},o=e.session_id||e.data?.session_id;let i=t.currentActiveAgent;if(!i){const e=this.getAllAgents(t);i=e.find(e=>e.sessionId===o)||e.find(e=>"active"===e.status)||e[0]}if(i){i.toolsMap||(i.toolsMap=new Map),i.tools||(i.tools=[]);const t=this.getToolKey(s,n);let o=i.toolsMap.get(t);if(o)o.params=n,o.timestamp=e.timestamp,o.status="in_progress",o.eventId=e.id,o.callCount=(o.callCount||1)+1,i.currentTool=o;else{const o={id:`tool-${i.id}-${s}-${Date.now()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id,callCount:1,createdAt:e.timestamp};"Task"===s&&n.subagent_type&&(o.isSubagentTask=!0,o.subagentType=n.subagent_type),i.toolsMap.set(t,o),"TodoWrite"===s?i.tools.unshift(o):i.tools.push(o),i.currentTool=o}}else{t.tools||(t.tools=[]),t.toolsMap||(t.toolsMap=new Map);const o=this.getToolKey(s,n);let i=t.toolsMap.get(o);if(i)i.params=n,i.timestamp=e.timestamp,i.status="in_progress",i.eventId=e.id,i.callCount=(i.callCount||1)+1,t.currentTool=i;else{const i={id:`tool-session-${s}-${Date.now()}`,name:s,type:"tool",icon:this.getToolIcon(s),timestamp:e.timestamp,status:"in_progress",params:n,eventId:e.id,callCount:1,createdAt:e.timestamp};t.toolsMap.set(o,i),"TodoWrite"===s?t.tools.unshift(i):t.tools.push(i),t.currentTool=i}}}getToolKey(e,t){if("TodoWrite"===e)return"TodoWrite";let s=e;return"Edit"!==e&&"Write"!==e&&"Read"!==e||t.file_path&&(s+=`-${t.file_path}`),"Grep"!==e&&"Glob"!==e||!t.pattern||(s+=`-${t.pattern.substring(0,20)}`),s}updateToolStatus(e,t,s){const n=e.tool_name||e.data?.tool_name||e.tool||"unknown",o=e.tool_parameters||e.data?.tool_parameters||e.parameters||e.data?.parameters||{},i=e.session_id||e.data?.session_id,a=this.getToolKey(n,o);let r=t.currentActiveAgent;if(!r){const e=this.getAllAgents(t);r=e.find(e=>e.sessionId===i)||e.find(e=>"active"===e.status)}if(r&&r.toolsMap){const t=r.toolsMap.get(a);if(t)return t.status=s,t.completedAt=e.timestamp,(e.data?.result||e.result)&&(t.result=e.data?.result||e.result),void(e.data?.duration_ms&&(t.duration=e.data.duration_ms))}if(t.toolsMap){const n=t.toolsMap.get(a);if(n)return n.status=s,n.completedAt=e.timestamp,(e.data?.result||e.result)&&(n.result=e.data?.result||e.result),void(e.data?.duration_ms&&(n.duration=e.data.duration_ms))}console.log(`ActivityTree: Could not find tool to update status for ${n} with key ${a} (event ${e.id})`)}renderTree(){const e=document.getElementById("linear-tree");if(!e)return;e.innerHTML="";const t=Array.from(this.sessions.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let s of t){if("all"!==this.selectedSessionFilter&&this.selectedSessionFilter!==s.id)continue;const t=this.createSessionElement(s);e.appendChild(t)}}createSessionElement(e){const t=this.expandedSessions.has(e.id)||e.expanded;let s;try{const t=e.timestamp instanceof Date?e.timestamp:new Date(e.timestamp);isNaN(t.getTime())?(s="Invalid Date",console.warn("ActivityTree: Invalid session timestamp:",e.timestamp)):s=t.toLocaleString()}catch(l){s="Invalid Date",console.error("ActivityTree: Error formatting session timestamp:",l,e.timestamp)}const n=document.createElement("div");n.className="tree-node session",n.dataset.sessionId=e.id;const o=t?"▼":"▶",i=this.getAllAgents(e).length,a=e.currentTodos?e.currentTodos.length:0,r=e.userInstructions?e.userInstructions.length:0;return console.log(`ActivityTree: Rendering session ${e.id}: ${i} agents, ${r} instructions, ${a} todos at ${s}`),n.innerHTML=`\n <div class="tree-node-content" onclick="window.activityTreeInstance.toggleSession('${e.id}')">\n <span class="tree-expand-icon">${o}</span>\n <span class="tree-icon">🎯</span>\n <span class="tree-label">PM Session</span>\n <span class="tree-meta">${s} • ${i} agent(s) • ${r} instruction(s) • ${a} todo(s)</span>\n </div>\n <div class="tree-children" style="display: ${t?"block":"none"}">\n ${this.renderSessionContent(e)}\n </div>\n `,n}renderSessionContent(e){let t="";if(e.userInstructions&&e.userInstructions.length>0)for(let n of e.userInstructions.slice(-3))t+=this.renderUserInstructionElement(n,1);if(e.tools&&e.tools.length>0)for(let n of e.tools)t+=this.renderToolElement(n,1);const s=Array.from(e.agents.values()).sort((e,t)=>new Date(t.timestamp)-new Date(e.timestamp));for(let n of s)t+=this.renderAgentElement(n,1);return t}renderUserInstructionElement(e,t){return`\n <div class="tree-node user-instruction ${this.selectedItem&&"instruction"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">💬</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'instruction', event)">User: "${this.escapeHtml(e.preview)}"</span>\n <span class="tree-status status-active">instruction</span>\n </div>\n </div>\n `}renderTodoChecklistElement(e,t){const s=`checklist-${Date.now()}`,n=!1!==this.expandedTools.has(s),o=n?"▼":"▶";let i=0,a=0;e.forEach(e=>{"completed"===e.status?i++:"in_progress"===e.status&&a++});let r="";r=a>0?`${a} in progress, ${i} completed`:i===e.length&&e.length>0?`All ${e.length} completed`:`${e.length} todo(s)`;let l=`\n <div class="tree-node todo-checklist" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">☑️</span>\n <span class="tree-label">TODOs</span>\n <span class="tree-params">${r}</span>\n <span class="tree-status status-active">checklist</span>\n </div>\n `;if(n){l+='<div class="tree-children">';for(let s of e){const e=this.getCheckboxIcon(s.status),n=`status-${s.status}`,o="in_progress"===s.status?s.activeForm:s.content;l+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${s.status.replace("_"," ")}</span>\n </div>\n </div>\n `}l+="</div>"}return l+="</div>",l}renderAgentElement(e,t){const s="active"===e.status?"status-active":"status-completed",n=this.expandedAgents.has(e.id),o=e.tools&&e.tools.length>0,i=e.subagents&&e.subagents.size>0,a=o||i,r=a?n?"▼":"▶":"",l=this.selectedItem&&"agent"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":"",c=e.instanceCount>1?` (${e.instanceCount}x)`:"";let d="";if(!n&&a){const t=[];if(e.currentTodos&&e.currentTodos.length>0){const s=e.currentTodos.find(e=>"in_progress"===e.status);s&&t.push(`📝 ${s.activeForm||s.content}`)}e.currentTool&&t.push(`${e.currentTool.icon} ${e.currentTool.name}`),t.length>0&&(d=` • ${t.join(" • ")}`)}let p=`\n <div class="tree-node agent ${s} ${l}" data-level="${t}">\n <div class="tree-node-content">\n ${r?`<span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleAgent('${e.id}'); event.stopPropagation();">${r}</span>`:'<span class="tree-expand-icon"></span>'}\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'agent', event)">${e.name}${c}${d}</span>\n <span class="tree-status ${s}">${e.status}</span>\n </div>\n `;if(a&&n){if(p+='<div class="tree-children">',o)for(let s of e.tools)p+=this.renderToolElement(s,t+1);if(i){const s=Array.from(e.subagents.values());for(let e of s)p+=this.renderAgentElement(e,t+1)}p+="</div>"}return p+="</div>",p}renderToolElement(e,t){const s=`status-${e.status}`,n=this.getToolParams(e),o=this.selectedItem&&"tool"===this.selectedItem.type&&this.selectedItem.data.id===e.id?"selected":"",i=this.getToolStatusIcon(e.status),a=this.getToolStatusLabel(e.status),r=e.callCount>1?` (${e.callCount} calls)`:"";return`\n <div class="tree-node tool ${s} ${o}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${e.icon}</span>\n <span class="tree-status-icon">${i}</span>\n <span class="tree-label clickable" onclick="window.activityTreeInstance.selectItem(${this.escapeJson(e)}, 'tool', event)">${e.name}${r}</span>\n <span class="tree-params">${n}</span>\n <span class="tree-status ${s}">${a}</span>\n </div>\n </div>\n `}getToolParams(e){if(!e.params)return"";if("Read"===e.name&&e.params.file_path)return e.params.file_path;if("Edit"===e.name&&e.params.file_path)return e.params.file_path;if("Write"===e.name&&e.params.file_path)return e.params.file_path;if("Bash"===e.name&&e.params.command){const t=e.params.command;return t.length>50?t.substring(0,50)+"...":t}return"WebFetch"===e.name&&e.params.url?e.params.url:""}getStatusIcon(e){return{pending:"⏸️",in_progress:"🔄",completed:"✅"}[e]||"❓"}getCheckboxIcon(e){return{pending:"⏳",in_progress:"🔄",completed:"✅"}[e]||"❓"}getAgentIcon(e){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️","project manager":"📊"}[e.toLowerCase()]||"🤖"}getAllAgents(e){const t=[],s=e=>{if(e)for(let n of e.values())t.push(n),n.subagents&&n.subagents.size>0&&s(n.subagents)};return s(e.agents),t}renderTodoWriteElement(e,t){const s=e.id,n=this.expandedTools.has(s),o=n?"▼":"▶",i=e.todos||[];let a=0,r=0;i.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&r++});const l=i.find(e=>"in_progress"===e.status),c=l?` • 🔄 ${l.activeForm||l.content}`:"";let d="";d=r>0?`${r} in progress, ${a}/${i.length} done`:a===i.length&&i.length>0?`All ${i.length} completed ✅`:`${a}/${i.length} done`;let p=`\n <div class="tree-node todowrite ${l?"has-active":""}" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoWrite('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">📝</span>\n <span class="tree-label">TodoWrite${e.updateCount>1?` (${e.updateCount} updates)`:""}${n?"":c}</span>\n <span class="tree-params">${d}</span>\n <span class="tree-status status-active">todos</span>\n </div>\n `;if(n&&i.length>0){p+='<div class="tree-children">';for(let e of i){const s=this.getCheckboxIcon(e.status),n=`status-${e.status}`,o="in_progress"===e.status?e.activeForm:e.content;p+=`\n <div class="tree-node todo-item ${n} ${e===l?"current-active":""}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${s}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}p+="</div>"}return p+="</div>",p}toggleTodoWrite(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}getToolIcon(e){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[e.toLowerCase()]||"🔧"}getToolStatusIcon(e){return{in_progress:"⏳",completed:"✅",failed:"❌",error:"❌",pending:"⏸️",active:"🔄"}[e]||"❓"}getToolStatusLabel(e){return{in_progress:"in progress",completed:"completed",failed:"failed",error:"error",pending:"pending",active:"active"}[e]||e}toggleSession(e){this.expandedSessions.has(e)?this.expandedSessions.delete(e):this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=this.expandedSessions.has(e)),this.renderTree()}expandAllSessions(){for(let e of this.sessions.keys()){this.expandedSessions.add(e);const t=this.sessions.get(e);t&&(t.expanded=!0)}this.renderTree()}collapseAllSessions(){this.expandedSessions.clear();for(let e of this.sessions.values())e.expanded=!1;this.renderTree()}updateStats(){const e=this.countTotalNodes(),t=this.countActiveNodes(),s=this.calculateMaxDepth(),n=document.getElementById("node-count"),o=document.getElementById("active-count"),i=document.getElementById("tree-depth");n&&(n.textContent=e),o&&(o.textContent=t),i&&(i.textContent=s),console.log(`ActivityTree: Stats updated - Nodes: ${e}, Active: ${t}, Depth: ${s}`)}countTotalNodes(){let e=0;for(let t of this.sessions.values()){e+=1,e+=t.agents.size,t.userInstructions&&(e+=t.userInstructions.length),t.todos&&(e+=t.todos.length),t.tools&&(e+=t.tools.length);for(let s of t.agents.values())s.tools&&(e+=s.tools.length)}return e}countActiveNodes(){let e=0;for(let t of this.sessions.values()){if("active"===t.status&&e++,t.todos)for(let s of t.todos)"in_progress"===s.status&&e++;if(t.tools)for(let s of t.tools)"in_progress"===s.status&&e++;for(let s of t.agents.values())if("active"===s.status&&e++,s.tools)for(let t of s.tools)"in_progress"===t.status&&e++}return e}calculateMaxDepth(){let e=0;for(let t of this.sessions.values()){let s=1;t.userInstructions&&t.userInstructions.length>0&&(s=Math.max(s,2)),t.todos&&t.todos.length>0&&(s=Math.max(s,3)),t.tools&&t.tools.length>0&&(s=Math.max(s,2));for(let e of t.agents.values())e.tools&&e.tools.length>0&&(s=Math.max(s,3));e=Math.max(e,s)}return e}toggleAgent(e){this.expandedAgents.has(e)?this.expandedAgents.delete(e):this.expandedAgents.add(e),this.renderTree()}toggleTool(e){console.log("Tool expansion is disabled. Tools now show data in the left pane when clicked.")}toggleTodoChecklist(e){this.expandedTools.has(e)?this.expandedTools.delete(e):this.expandedTools.add(e),this.renderTree()}renderPinnedTodosElement(e,t){const s=`pinned-todos-${Date.now()}`,n=!1!==this.expandedTools.has(s),o=n?"▼":"▶",i=e.todos||[];let a=0,r=0;i.forEach(e=>{"completed"===e.status?a++:"in_progress"===e.status&&r++});let l="";l=r>0?`${r} in progress, ${a} completed`:a===i.length&&i.length>0?`All ${i.length} completed`:`${i.length} todo(s)`;let c=`\n <div class="tree-node pinned-todos" data-level="${t}">\n <div class="tree-node-content">\n <span class="tree-expand-icon" onclick="window.activityTreeInstance.toggleTodoChecklist('${s}'); event.stopPropagation();">${o}</span>\n <span class="tree-icon">📌</span>\n <span class="tree-label">Pinned TODOs</span>\n <span class="tree-params">${l}</span>\n <span class="tree-status status-active">pinned</span>\n </div>\n `;if(n){c+='<div class="tree-children">';for(let e of i){const s=this.getCheckboxIcon(e.status),n=`status-${e.status}`,o="in_progress"===e.status?e.activeForm:e.content;c+=`\n <div class="tree-node todo-item ${n}" data-level="${t+1}">\n <div class="tree-node-content">\n <span class="tree-expand-icon"></span>\n <span class="tree-icon">${s}</span>\n <span class="tree-label">${this.escapeHtml(o)}</span>\n <span class="tree-status ${n}">${e.status.replace("_"," ")}</span>\n </div>\n </div>\n `}c+="</div>"}return c+="</div>",c}selectItem(e,t,s){s&&s.stopPropagation(),this.selectedItem={data:e,type:t},this.displayItemData(e,t),this.renderTree()}displayItemData(t,s){this.unifiedViewer||(this.unifiedViewer=new e("module-data-content")),this.unifiedViewer.display(t,s);const n=document.querySelector(".module-data-header h5");if(n){const e={agent:"🤖",tool:"🔧",instruction:"💬",session:"🎯",todo:"📝"}[s]||"📊",o=t.name||t.agentName||t.tool_name||"Item";n.textContent=`${e} ${s}: ${o}`}}escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}resetZoom(){this.svg&&this.zoom&&this.svg.transition().duration(this.duration).call(this.zoom.transform,d3.zoomIdentity)}escapeJson(e){return JSON.stringify(e).replace(/'/g,"&apos;").replace(/"/g,"&quot;")}}window.ActivityTree=t;const s=()=>{let e=null;const s=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e,window.activityTree=()=>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..."),s(),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..."),s(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))});const n=document.querySelector(".tab-button.active");n&&"activity"===n.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),s());const o=document.getElementById("activity-tab");o&&o.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),e||s())};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",s):s();
2
2
  //# sourceMappingURL=activity-tree.js.map
@@ -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.nodes=new Map,this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.isRadialLayout=!0,this.margin={top:20,right:20,bottom:20,left:20},this.width=960-this.margin.left-this.margin.right,this.height=600-this.margin.top-this.margin.bottom,this.radius=Math.min(this.width,this.height)/2,this.nodeId=0,this.duration=750,this.languageFilter="all",this.searchTerm="",this.tooltip=null,this.initialized=!1,this.analyzing=!1,this.selectedNode=null,this.socket=null,this.autoDiscovered=!1,this.zoom=null,this.activeNode=null,this.loadingNodes=new Set,this.bulkLoadMode=!1,this.expandedPaths=new Set}initialize(){if(this.initialized)return;if(this.container=document.getElementById("code-tree-container"),!this.container)return void console.error("Code tree container not found");const t=document.getElementById("code-tab");if(!t)return void console.error("Code tab panel not found");const e=this.getWorkingDirectory();if(!e||"Loading..."===e||"Not selected"===e)return this.showNoWorkingDirectoryMessage(),void(this.initialized=!0);this.setupControls(),this.initializeTreeData(),this.subscribeToEvents();document.getElementById("breadcrumb-content")&&!this.analyzing&&this.updateActivityTicker("Loading project structure...","info"),t.classList.contains("active")&&(this.createVisualization(),this.root&&this.svg&&this.update(this.root),this.autoDiscoverRootLevel()),this.initialized=!0}renderWhenVisible(){const t=this.getWorkingDirectory();t&&"Loading..."!==t&&"Not selected"!==t?(this.removeNoWorkingDirectoryMessage(),this.initialized?(this.svg?this.root&&this.svg&&this.update(this.root):(this.createVisualization(),this.svg&&this.treeGroup&&this.update(this.root)),this.autoDiscovered||this.autoDiscoverRootLevel()):this.initialize()):this.showNoWorkingDirectoryMessage()}setupControls(){const t=document.getElementById("language-filter");t&&t.addEventListener("change",t=>{this.languageFilter=t.target.value,this.filterTree()});const e=document.getElementById("code-search");e&&e.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.filterTree()});const i=document.getElementById("code-expand-all");i&&i.addEventListener("click",()=>this.expandAll());const o=document.getElementById("code-collapse-all");o&&o.addEventListener("click",()=>this.collapseAll());const s=document.getElementById("code-reset-zoom");s&&s.addEventListener("click",()=>this.resetZoom());const a=document.getElementById("code-toggle-legend");a&&a.addEventListener("click",()=>this.toggleLegend()),document.addEventListener("workingDirectoryChanged",t=>{this.onWorkingDirectoryChanged(t.detail.directory)})}onWorkingDirectoryChanged(t){if(!t||"Loading..."===t||"Not selected"===t)return this.showNoWorkingDirectoryMessage(),this.autoDiscovered=!1,this.analyzing=!1,this.nodes.clear(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},void this.updateStats();this.removeNoWorkingDirectoryMessage(),this.autoDiscovered=!1,this.analyzing=!1,this.nodes.clear(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.initializeTreeData(),this.svg&&this.update(this.root);const e=document.getElementById("code-tab");e&&e.classList.contains("active")&&this.autoDiscoverRootLevel(),this.updateStats()}showLoading(){let t=document.getElementById("code-tree-loading");if(!t){const e=document.getElementById("code-tree-container");e&&(t=document.createElement("div"),t.id="code-tree-loading",t.innerHTML='\n <div class="code-tree-spinner"></div>\n <div class="code-tree-loading-text">Analyzing code structure...</div>\n ',e.appendChild(t))}t&&t.classList.remove("hidden")}hideLoading(){const t=document.getElementById("code-tree-loading");t&&t.classList.add("hidden")}createVisualization(){if("undefined"==typeof d3)return void console.error("D3.js is not loaded");const t=d3.select("#code-tree-container");if(t.selectAll("*").remove(),this.addTreeControls(),this.addBreadcrumb(),!t||!t.node())return void console.error("Code tree container not found");const e=t.node(),i=e.clientWidth||960,o=e.clientHeight||600;this.width=i-this.margin.left-this.margin.right,this.height=o-this.margin.top-this.margin.bottom,this.radius=Math.min(this.width,this.height)/2,this.svg=t.append("svg").attr("width",i).attr("height",o);const s=i/2,a=o/2;this.isRadialLayout?this.treeGroup=this.svg.append("g").attr("transform",`translate(${s},${a})`):this.treeGroup=this.svg.append("g").attr("transform",`translate(${this.margin.left+100},${a})`),this.isRadialLayout?this.treeLayout=d3.cluster().size([2*Math.PI,this.radius-100]).separation((t,e)=>{if(t.parent==e.parent){const e=Math.max(1,4-t.depth),i=t.parent&&t.parent.children?.length||1,o=i>5?2:i>3?1.5:1,s=1+.2*t.depth;return e*o/(t.depth||1)*s}return 4/(t.depth||1)}):this.treeLayout=d3.tree().nodeSize([30,200]).separation((t,e)=>t.parent==e.parent?1:1.5),this.zoom=null,console.log("[CodeTree] All zoom and pan behavior disabled - tree is now completely stationary"),this.addVisualizationControls(),this.tooltip=d3.select("body").append("div").attr("class","code-tree-tooltip").style("opacity",0).style("position","absolute").style("background","rgba(0, 0, 0, 0.8)").style("color","white").style("padding","8px").style("border-radius","4px").style("font-size","12px").style("pointer-events","none")}clearD3Visualization(){this.treeGroup&&(this.treeGroup.selectAll("g.node").remove(),this.treeGroup.selectAll("path.link").remove()),this.nodeId=0}initializeTreeData(){const t=this.getWorkingDirectory(),e=t&&t.split("/").pop()||"Project Root";this.treeData={name:e,path:".",type:"root",children:[],loaded:!1,expanded:!0},"undefined"!=typeof d3&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0)}subscribeToEvents(){this.socket||(window.socket?(this.socket=window.socket,this.setupEventHandlers()):window.dashboard?.socketClient?.socket?(this.socket=window.dashboard.socketClient.socket,this.setupEventHandlers()):window.socketClient?.socket&&(this.socket=window.socketClient.socket,this.setupEventHandlers()))}autoDiscoverRootLevel(){if(this.autoDiscovered||this.analyzing)return;this.updateActivityTicker("🔍 Discovering project structure...","info");const t=this.getWorkingDirectory();if(!t||"Loading..."===t||"Not selected"===t)return console.warn("Cannot auto-discover: no working directory set"),void this.showNoWorkingDirectoryMessage();if(!t.startsWith("/")&&!t.match(/^[A-Z]:\\/))return console.error("Working directory is not absolute:",t),void this.showNotification("Invalid working directory path","error");this.autoDiscovered=!0,this.analyzing=!0,this.nodes.clear(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.socket&&!this.socket.hasListeners("code:node:found")&&this.setupEventHandlers();const e=t.split("/").pop()||"Project Root";this.treeData={name:e,path:".",type:"root",children:[],loaded:!1,expanded:!0},"undefined"!=typeof d3&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0),this.showLoading(),this.updateBreadcrumb(`Discovering structure in ${e}...`,"info");const i=[];document.querySelectorAll(".language-checkbox:checked").forEach(t=>{i.push(t.value)});const o=document.getElementById("ignore-patterns")?.value||"",s={path:t,depth:"top_level",languages:i,ignore_patterns:o,request_id:`discover_${Date.now()}`};this.socket&&this.socket.emit("code:discover:top_level",s),this.updateStats()}analyzeCode(){this.analyzing||this.autoDiscoverRootLevel()}cancelAnalysis(){this.analyzing=!1,this.hideLoading(),this.socket&&this.socket.emit("code:analysis:cancel")}addTreeControls(){const t=d3.select("#code-tree-container");t.select(".tree-controls-toolbar").remove();const e=t.append("div").attr("class","tree-controls-toolbar");e.append("button").attr("class","tree-control-btn").attr("title","Expand all loaded directories").text("⊞").on("click",()=>this.expandAll()),e.append("button").attr("class","tree-control-btn").attr("title","Collapse all directories").text("⊟").on("click",()=>this.collapseAll()),e.append("button").attr("class","tree-control-btn").attr("id","bulk-load-toggle").attr("title","Toggle bulk loading (load 2 levels at once)").text("↕").on("click",()=>this.toggleBulkLoad()),e.append("button").attr("class","tree-control-btn").attr("title","Toggle between radial and linear layouts").text("◎").on("click",()=>this.toggleLayout()),e.append("input").attr("class","tree-control-btn").attr("type","text").attr("placeholder","Search...").attr("title","Search for files and directories").style("width","120px").style("text-align","left").on("input",t=>this.searchTree(t.target.value)).on("keydown",t=>{"Escape"===t.key&&(t.target.value="",this.searchTree(""))})}addBreadcrumb(){const t=d3.select("#code-tree-container");t.select(".tree-breadcrumb").remove();t.append("div").attr("class","tree-breadcrumb").append("div").attr("class","breadcrumb-path").attr("id","tree-breadcrumb-path"),this.updateBreadcrumbPath("/")}updateBreadcrumbPath(t){const e=d3.select("#tree-breadcrumb-path");e.selectAll("*").remove();const i=this.getWorkingDirectory();if(!i||"Loading..."===i||"Not selected"===i)return void e.text("No project selected");const o="/"===t?[i.split("/").pop()||"Root"]:t.split("/").filter(t=>t.length>0);o.forEach((t,i)=>{i>0&&e.append("span").attr("class","breadcrumb-separator").text("/"),e.append("span").attr("class",i===o.length-1?"breadcrumb-segment current":"breadcrumb-segment").text(t).on("click",()=>{if(i<o.length-1){const t=o.slice(0,i+1).join("/");this.navigateToPath(t)}})})}expandAll(){if(!this.root)return;const t=e=>{"directory"===e.data.type&&!0===e.data.loaded&&e._children&&(e.children=e._children,e._children=null,e.data.expanded=!0),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root),this.showNotification("Expanded all loaded directories","success")}collapseAll(){if(!this.root)return;const t=e=>{"directory"===e.data.type&&e.children&&(e._children=e.children,e.children=null,e.data.expanded=!1),e._children&&e._children.forEach(t)};t(this.root),this.update(this.root),this.showNotification("Collapsed all directories","info")}toggleBulkLoad(){this.bulkLoadMode=!this.bulkLoadMode;const t=d3.select("#bulk-load-toggle");this.bulkLoadMode?(t.classed("active",!0),this.showNotification("Bulk load enabled - will load 2 levels deep","info")):(t.classed("active",!1),this.showNotification("Bulk load disabled - load 1 level at a time","info"))}navigateToPath(t){this.updateBreadcrumbPath(t),this.showNotification(`Navigating to: ${t}`,"info")}searchTree(t){if(!this.root||!this.treeGroup)return;const e=t.toLowerCase().trim();if(this.treeGroup.selectAll(".code-node").classed("search-match",!1),!e)return;const i=[],o=t=>{const s=(t.data.name||"").toLowerCase(),a=(t.data.path||"").toLowerCase();(s.includes(e)||a.includes(e))&&i.push(t),t.children&&t.children.forEach(o),t._children&&t._children.forEach(o)};o(this.root),i.length>0?(this.treeGroup.selectAll(".code-node").data(),i.forEach(t=>{this.treeGroup.selectAll(".code-node").filter(e=>e.data.path===t.data.path).classed("search-match",!0),this.expandPathToNode(t)}),this.showNotification(`Found ${i.length} matches`,"success")):this.showNotification("No matches found","info")}expandPathToNode(t){const e=[];let i=t.parent;for(;i&&i!==this.root;)e.unshift(i),i=i.parent;e.forEach(t=>{"directory"===t.data.type&&t._children&&(t.children=t._children,t._children=null,t.data.expanded=!0)}),e.length>0&&this.update(this.root)}createEventsDisplay(){let t=document.getElementById("analysis-events");if(!t){const e=document.getElementById("code-tree-container");e&&(t=document.createElement("div"),t.id="analysis-events",t.className="analysis-events",t.style.display="none",e.appendChild(t))}}clearEventsDisplay(){const t=document.getElementById("analysis-events");t&&(t.innerHTML="",t.style.display="block")}addEventToDisplay(t,e="info"){const i=document.getElementById("analysis-events");if(i){const o=document.createElement("div");o.className="analysis-event",o.style.borderLeftColor="warning"===e?"#f59e0b":"error"===e?"#ef4444":"#3b82f6";const s=(new Date).toLocaleTimeString();o.innerHTML=`<span style="color: #718096;">[${s}]</span> ${t}`,i.appendChild(o),i.scrollTop=i.scrollHeight}}setupEventHandlers(){this.socket&&(this.socket.on("code:analysis:accepted",t=>this.onAnalysisAccepted(t)),this.socket.on("code:analysis:queued",t=>this.onAnalysisQueued(t)),this.socket.on("code:analysis:start",t=>this.onAnalysisStart(t)),this.socket.on("code:analysis:complete",t=>this.onAnalysisComplete(t)),this.socket.on("code:analysis:cancelled",t=>this.onAnalysisCancelled(t)),this.socket.on("code:analysis:error",t=>this.onAnalysisError(t)),this.socket.on("code:top_level:discovered",t=>this.onTopLevelDiscovered(t)),this.socket.on("code:directory:discovered",t=>this.onDirectoryDiscovered(t)),this.socket.on("code:file:discovered",t=>this.onFileDiscovered(t)),this.socket.on("code:file:analyzed",t=>this.onFileAnalyzed(t)),this.socket.on("code:node:found",t=>this.onNodeFound(t)),this.socket.on("code:analysis:progress",t=>this.onProgressUpdate(t)),this.socket.on("code:directory:contents",t=>{if(t.path){let e=t.path;const i=this.getWorkingDirectory();i&&e.startsWith(i)&&(e=e.substring(i.length).replace(/^\//,""),e||(e="."));const o=this.findNodeByPath(e);if(o&&t.children){const i=this.findD3NodeByPath(e);if(i&&this.loadingNodes.has(e)&&(this.removeLoadingPulse(i),this.loadingNodes.delete(e),console.log("🎯 [SUBDIRECTORY LOADING] Successfully completed and removed from loading set:",e)),o.children=t.children.map(t=>{let i;if("."===e||""===e)i=t.name||t.path;else{const o=t.name||t.path;i=`${e}/${o}`}return{...t,path:i,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:[]}}),o.loaded=!0,o.expanded=!0,this.root&&this.svg){const t=this.root;this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.preserveExpansionState(t,this.root);const i=this.findD3NodeByPath(e);i&&(i.children=i._children||i.children,i._children=null,i.data.expanded=!0),this.update(this.root)}t.stats&&(this.stats.files+=t.stats.files||0,this.stats.directories+=t.stats.directories||0,this.updateStats()),this.updateBreadcrumb(`Loaded ${t.path}`,"success"),this.hideLoading()}}}),this.socket.on("code:top_level:discovered",t=>{t.items&&Array.isArray(t.items)&&(this.treeData.children=t.items.map(t=>({name:t.name,path:t.path,type:t.type,language:"file"===t.type?this.detectLanguage(t.path):void 0,size:t.size,lines:t.lines,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:[]})),this.treeData.loaded=!0,t.stats&&(this.stats={...this.stats,...t.stats},this.updateStats()),"undefined"!=typeof d3&&(this.clearD3Visualization(),this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.svg&&this.update(this.root)),this.analyzing=!1,this.hideLoading(),this.updateBreadcrumb(`Discovered ${t.items.length} root items`,"success"),this.showNotification(`Found ${t.items.length} items in project root`,"success"))}))}onAnalysisStart(t){this.analyzing=!0;const e=t.message||"Starting code analysis...";this.updateActivityTicker("🚀 Starting analysis...","info"),this.updateBreadcrumb(e,"info"),this.addEventToDisplay(`🚀 ${e}`,"info"),this.treeData&&0!==this.treeData.children.length||this.initializeTreeData(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.updateStats()}onTopLevelDiscovered(t){this.updateActivityTicker(`📁 Discovered ${(t.items||[]).length} top-level items`,"success"),this.addEventToDisplay(`📁 Found ${(t.items||[]).length} top-level items in project root`,"info");const e=this.findNodeByPath(".");console.log('🔎 Looking for root node with path ".", found:',e?{name:e.name,path:e.path,currentChildren:e.children?e.children.length:0}:"NOT FOUND"),e&&t.items?(console.log("🌳 Populating root node with children"),e.children=t.items.map(t=>{const e=t.name;return console.log(` Adding child: ${t.name} with path: ${e}`),{name:t.name,path:e,type:t.type,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:"directory"===t.type?[]:void 0,size:t.size,has_code:t.has_code}}),e.loaded=!0,e.expanded=!0,this.root&&this.svg&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.update(this.root)),this.hideLoading(),this.updateBreadcrumb(`Discovered ${t.items.length} items`,"success"),this.showNotification(`Found ${t.items.length} top-level items`,"success")):(console.error("❌ Could not find root node to populate"),this.showNotification("Failed to populate root directory","error")),this.analyzing=!1}onDirectoryDiscovered(t){this.updateActivityTicker(`📁 Discovered: ${t.name||"directory"}`),this.addEventToDisplay(`📁 Found ${(t.children||[]).length} items in: ${t.name||t.path}`,"info"),console.log("✅ [SUBDIRECTORY LOADING] Received directory discovery response:",{path:t.path,name:t.name,childrenCount:(t.children||[]).length,children:(t.children||[]).map(t=>({name:t.name,type:t.type})),workingDir:this.getWorkingDirectory(),fullEventData:t});let e=t.path;const i=this.getWorkingDirectory();i&&e.startsWith(i)&&(e=e.substring(i.length).replace(/^\//,""),e||(e=".")),console.log("🔎 Searching for node with path:",e);const o=this.findNodeByPath(e);if(o&&t.children){o.children=t.children.map(t=>{let i;if("."===e||""===e)i=t.name||t.path;else{const o=t.name||t.path;i=`${e}/${o}`}return{name:t.name,path:i,type:t.type,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:"directory"===t.type?[]:void 0,size:t.size,has_code:t.has_code}}),o.loaded=!0,o.expanded=!0;const i=this.findD3NodeByPath(e);if(i&&this.loadingNodes.has(e)&&(this.removeLoadingPulse(i),this.loadingNodes.delete(e),console.log("🎯 [SUBDIRECTORY LOADING] Successfully completed and removed from loading set (hierarchy update):",e)),this.root&&this.svg){const t=this.root;this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.preserveExpansionState(t,this.root);const i=this.findD3NodeByPath(e);i&&i.data.children&&i.data.children.length>0&&(i.children=i._children||i.children,i._children=null,i.data.expanded=!0),this.update(this.root)}0===o.children.length?(this.updateBreadcrumb(`Empty directory: ${o.name}`,"info"),this.showNotification(`Directory "${o.name}" is empty`,"info")):(this.updateBreadcrumb(`Loaded ${o.children.length} items from ${o.name}`,"success"),this.showNotification(`Loaded ${o.children.length} items from "${o.name}"`,"success")),this.updateStats()}else if(o){if(o&&!t.children){console.warn("⚠️ [SUBDIRECTORY LOADING] Directory response has no children:",{path:t.path,searchPath:e,nodeExists:!!o,dataKeys:Object.keys(t),fullData:t});const i=t.path?t.path.split("/").filter(t=>t):[];if(1===i.length||t.forceAdd){const e={name:t.name||i[i.length-1]||"Unknown",path:t.path,type:"directory",children:[],loaded:!1,expanded:!1,stats:t.stats||{}};this.addNodeToTree(e,t.parent||""),this.updateBreadcrumb(`Discovered: ${t.path}`,"info")}}}else console.error("❌ [SUBDIRECTORY LOADING] Node not found for path:",{searchPath:e,originalPath:t.path,workingDir:this.getWorkingDirectory(),allTreePaths:this.getAllTreePaths(this.treeData)}),this.showNotification(`Could not find directory "${e}" in tree`,"error"),this.logAllPaths(this.treeData)}onFileDiscovered(t){const e=t.name||(t.path?t.path.split("/").pop():"file");this.updateActivityTicker(`📄 Found: ${e}`),this.addEventToDisplay(`📄 Discovered: ${t.path||"Unknown file"}`,"info");const i=t.path?t.path.split("/").filter(t=>t):[],o=i.slice(0,-1).join("/"),s={name:t.name||i[i.length-1]||"Unknown",path:t.path,type:"file",language:t.language||this.detectLanguage(t.path),size:t.size||0,lines:t.lines||0,children:[],analyzed:!1};this.addNodeToTree(s,o),this.stats.files++,this.updateStats(),this.updateBreadcrumb(`Found: ${t.path}`,"info")}onFileAnalyzed(t){const e=this.findD3NodeByPath(t.path);if(e&&this.loadingNodes.has(t.path)&&(this.removeLoadingPulse(e),this.loadingNodes.delete(t.path)),t.path){const e=t.path.split("/").pop();this.updateActivityTicker(`🔍 Analyzed: ${e}`)}const i=this.findNodeByPath(t.path);i&&(i.analyzed=!0,i.complexity=t.complexity||0,i.lines=t.lines||0,t.elements&&Array.isArray(t.elements)&&(i.children=t.elements.map(e=>({name:e.name,type:e.type.toLowerCase(),path:`${t.path}#${e.name}`,line:e.line,complexity:e.complexity||1,docstring:e.docstring||"",children:e.methods?e.methods.map(i=>({name:i.name,type:"method",path:`${t.path}#${e.name}.${i.name}`,line:i.line,complexity:i.complexity||1,docstring:i.docstring||""})):[]}))),t.stats&&(this.stats.classes+=t.stats.classes||0,this.stats.functions+=t.stats.functions||0,this.stats.methods+=t.stats.methods||0,this.stats.lines+=t.stats.lines||0),this.updateStats(),this.root&&this.update(this.root),this.updateBreadcrumb(`Analyzed: ${t.path}`,"success"))}onNodeFound(t){const e="class"===t.type?"🏛️":"function"===t.type?"⚡":"method"===t.type?"🔧":"📦";this.addEventToDisplay(`${e} Found ${t.type||"node"}: ${t.name||"Unknown"}`);const i={name:t.name||"Unknown",type:(t.type||"unknown").toLowerCase(),path:t.path||"",line:t.line||0,complexity:t.complexity||1,docstring:t.docstring||""};i.type={class:"class",function:"function",method:"method",module:"module",file:"file",directory:"directory"}[i.type]||i.type;let o="";if(t.parent_path)o=t.parent_path;else if(t.file_path)o=t.file_path;else if(i.path.includes("/")){const t=i.path.split("/");t.pop(),o=t.join("/")}switch(i.type){case"class":this.stats.classes++;break;case"function":this.stats.functions++;break;case"method":this.stats.methods++;break;case"file":this.stats.files++}this.addNodeToTree(i,o),this.updateStats();const s=i.type.charAt(0).toUpperCase()+i.type.slice(1);this.updateBreadcrumb(`Found ${s}: ${i.name}`,"info")}onProgressUpdate(t){const e=t.progress||0,i=t.message||`Processing... ${e}%`;this.updateBreadcrumb(i,"info");const o=document.querySelector(".code-tree-progress");o&&(o.style.width=`${e}%`)}onAnalysisComplete(t){this.analyzing=!1,this.hideLoading(),this.updateActivityTicker("✅ Ready","success"),this.addEventToDisplay("✅ Analysis complete!","success"),this.root&&this.svg&&this.update(this.root),t.stats&&(this.stats={...this.stats,...t.stats},this.updateStats());const e=t.message||`Analysis complete: ${this.stats.files} files, ${this.stats.classes} classes, ${this.stats.functions} functions`;this.updateBreadcrumb(e,"success"),this.showNotification(e,"success")}onAnalysisError(t){this.analyzing=!1,this.hideLoading();const e=t.message||t.error||"Analysis failed";this.updateBreadcrumb(e,"error"),this.showNotification(e,"error")}onAnalysisAccepted(t){const e=t.message||"Analysis request accepted";this.updateBreadcrumb(e,"info")}onAnalysisQueued(t){const e=`Analysis queued (position ${t.position||0})`;this.updateBreadcrumb(e,"warning"),this.showNotification(e,"info")}onInfoEvent(t){t.type&&t.type.startsWith("discovery.")?"discovery.start"===t.type?this.updateBreadcrumb(t.message,"info"):"discovery.complete"===t.type?(this.updateBreadcrumb(t.message,"success"),t.stats):"discovery.directory"!==t.type&&"discovery.file"!==t.type||this.updateBreadcrumb(t.message,"info"):t.type&&t.type.startsWith("analysis.")?"analysis.start"===t.type?this.updateBreadcrumb(t.message,"info"):"analysis.complete"===t.type?(this.updateBreadcrumb(t.message,"success"),t.stats&&(t.stats.classes,t.stats.functions,t.stats.methods)):("analysis.class"===t.type||"analysis.function"===t.type||"analysis.method"===t.type||"analysis.parse"===t.type)&&this.updateBreadcrumb(t.message,"info"):t.type&&t.type.startsWith("filter.")?(window.debugMode||this.showFilterEvents)&&(console.debug("[FILTER]",t.type,t.path,t.reason),this.showFilterEvents&&this.updateBreadcrumb(t.message,"warning")):t.type&&t.type.startsWith("cache.")&&("cache.hit"===t.type?(console.debug("[CACHE HIT]",t.file),this.showCacheEvents&&this.updateBreadcrumb(t.message,"info")):"cache.miss"===t.type&&console.debug("[CACHE MISS]",t.file)),this.eventLogEnabled&&t.message&&this.addEventToDisplay(t)}addEventToDisplay(t){this.recentEvents||(this.recentEvents=[]),this.recentEvents.unshift({timestamp:t.timestamp||(new Date).toISOString(),type:t.type,message:t.message,data:t}),this.recentEvents.length>100&&this.recentEvents.pop()}onAnalysisCancelled(t){this.analyzing=!1,this.hideLoading();const e=t.message||"Analysis cancelled";this.updateBreadcrumb(e,"warning")}showNotification(t,e="info"){const i=document.createElement("div");i.className=`code-tree-notification ${e}`,i.textContent=t;const o=document.getElementById("code-tree-container");o&&(i.style.position="absolute",i.style.top="10px",i.style.right="10px",i.style.zIndex="1000",o.style.position&&"static"!==o.style.position||(o.style.position="relative"),o.appendChild(i),setTimeout(()=>{i.style.animation="slideOutRight 0.3s ease",setTimeout(()=>i.remove(),300)},3e3))}addNodeToTree(t,e=""){if(t.path&&t.path.startsWith("/"))return void console.error("Absolute path detected in node, skipping:",t.path);if(e&&e.startsWith("/"))return void console.error("Absolute path detected in parent, skipping:",e);let i=this.treeData;if(e&&(i=this.findNodeByPath(e),!i))return console.warn("Parent node not found, skipping node creation:",e),void console.warn("Attempted to add node:",t);const o=i.children?.find(e=>e.path===t.path||e.name===t.name&&e.type===t.type);o?Object.assign(o,t):(i.children||(i.children=[]),t.children||(t.children=[]),i.children.push(t),this.nodes.set(t.path,t),this.root&&this.svg&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,(this.nodes.size<1e3||this.nodes.size%100==0)&&this.update(this.root)))}findNodeByPath(t,e=null){if(e||(e=this.treeData,console.log("🔍 [SUBDIRECTORY LOADING] Starting search for path:",t)),e.path===t)return console.log("✅ [SUBDIRECTORY LOADING] Found node for path:",t),e;if(e.children)for(const i of e.children){const e=this.findNodeByPath(t,i);if(e)return e}return e.parent||e!==this.treeData||console.warn("❌ [SUBDIRECTORY LOADING] Path not found in tree:",t),null}logAllPaths(t,e=""){if(console.log(`${e}${t.path} (${t.name})`),t.children)for(const i of t.children)this.logAllPaths(i,e+" ")}getAllTreePaths(t){const e=[t.path];if(t.children)for(const i of t.children)e.push(...this.getAllTreePaths(i));return e}findD3NodeByPath(t){return this.root?this.root.descendants().find(e=>e.data.path===t):null}preserveExpansionState(t,e){if(!t||!e)return;const i=new Map;t.descendants().forEach(t=>{(t.data.expanded||t.children&&!t._children)&&i.set(t.data.path,!0)}),e.descendants().forEach(t=>{i.has(t.data.path)&&(t.children=t._children||t.children,t._children=null,t.data.expanded=!0)})}updateStats(){const t={"file-count":this.stats.files,"class-count":this.stats.classes,"function-count":this.stats.functions,"line-count":this.stats.lines};for(const[i,o]of Object.entries(t)){const t=document.getElementById(i);t&&(t.textContent=o.toLocaleString())}const e=document.getElementById("code-progress-text");if(e){const t=this.analyzing?`Analyzing... ${this.stats.files} files processed`:`Ready - ${this.stats.files} files in tree`;e.textContent=t}}updateBreadcrumb(t,e="info"){const i=document.getElementById("breadcrumb-content");i&&(i.textContent=t,i.className=`breadcrumb-${e}`)}detectLanguage(t){return{py:"python",js:"javascript",ts:"typescript",jsx:"javascript",tsx:"typescript",java:"java",cpp:"cpp",c:"c",cs:"csharp",rb:"ruby",go:"go",rs:"rust",php:"php",swift:"swift",kt:"kotlin",scala:"scala",r:"r",sh:"bash",ps1:"powershell"}[t.split(".").pop().toLowerCase()]||"unknown"}addVisualizationControls(){const t=this.svg.append("g").attr("class","viz-controls").attr("transform","translate(10, 10)").append("g").attr("class","layout-toggle").style("cursor","pointer").on("click",()=>this.toggleLayout());t.append("rect").attr("width",120).attr("height",30).attr("rx",5).attr("fill","#3b82f6").attr("opacity",.8),t.append("text").attr("x",60).attr("y",20).attr("text-anchor","middle").attr("fill","white").style("font-size","12px").text(this.isRadialLayout?"Switch to Linear":"Switch to Radial")}toggleLayout(){this.isRadialLayout=!this.isRadialLayout,this.createVisualization(),this.root&&this.update(this.root),this.showNotification(this.isRadialLayout?"Switched to radial layout":"Switched to linear layout","info")}radialPoint(t,e){return[(e=+e)*Math.cos(t-=Math.PI/2),e*Math.sin(t)]}update(t){if(!this.treeLayout||!this.treeGroup||!t)return;const e=this.treeLayout(this.root),i=e.descendants(),o=e.descendants().slice(1);this.isRadialLayout&&i.forEach(t=>{void 0===t.x0&&(t.x0=t.x,t.y0=t.y)});const s=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),a=s.enter().append("g").attr("class",t=>{let e=["node","code-node"];return"directory"===t.data.type?(e.push("directory"),!0===t.data.loaded&&t.children&&e.push("expanded"),"loading"===t.data.loaded&&e.push("loading"),t.data.children&&0===t.data.children.length&&e.push("empty")):"file"===t.data.type&&e.push("file"),e.join(" ")}).attr("transform",e=>{if(this.isRadialLayout){const[e,i]=this.radialPoint(t.x0||0,t.y0||0);return`translate(${e},${i})`}return`translate(${t.y0},${t.x0})`}).on("click",(t,e)=>this.onNodeClick(t,e));a.append("circle").attr("class","node-circle").attr("r",1e-6).style("fill",t=>this.getNodeColor(t)).style("stroke",t=>this.getNodeStrokeColor(t)).style("stroke-width",t=>"directory"===t.data.type?2:1.5).style("cursor","pointer").on("click",(t,e)=>this.onNodeClick(t,e)).on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip()),a.filter(t=>"directory"===t.data.type).append("text").attr("class","expand-icon").attr("x",0).attr("y",0).attr("text-anchor","middle").attr("dominant-baseline","central").text(t=>"loading"===t.data.loaded?"⟳":!0===t.data.loaded&&t.children?"▼":"▶").style("font-size","10px").style("pointer-events","none"),a.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>this.isRadialLayout?0:t.children||t._children?-13:13).attr("text-anchor",t=>this.isRadialLayout?"start":t.children||t._children?"end":"start").text(t=>{const e=t.data.name||"";return e.length>20?e.substring(0,17)+"...":e}).style("fill-opacity",1e-6).style("font-size","12px").style("font-family",'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif').style("text-shadow","1px 1px 2px rgba(255,255,255,0.8), -1px -1px 2px rgba(255,255,255,0.8)").on("click",(t,e)=>this.onNodeClick(t,e)).style("cursor","pointer"),a.filter(t=>"directory"!==t.data.type).append("text").attr("class","node-icon").attr("dy",".35em").attr("x",0).attr("text-anchor","middle").text(t=>this.getNodeIcon(t)).style("font-size","10px").style("fill","white").on("click",(t,e)=>this.onNodeClick(t,e)).style("cursor","pointer"),a.filter(t=>"directory"===t.data.type&&t.data.children).append("text").attr("class","item-count-badge").attr("x",12).attr("y",-8).attr("text-anchor","middle").text(t=>{const e=t.data.children?t.data.children.length:0;return e>0?e:""}).style("font-size","9px").style("opacity",.7).on("click",(t,e)=>this.onNodeClick(t,e)).style("cursor","pointer");const n=a.merge(s);n.on("click",(t,e)=>this.onNodeClick(t,e)),n.transition().duration(this.duration).attr("transform",t=>{if(this.isRadialLayout){const[e,i]=this.radialPoint(t.x,t.y);return`translate(${e},${i})`}return`translate(${t.y},${t.x})`}),n.attr("class",t=>{let e=["node","code-node"];return"directory"===t.data.type?(e.push("directory"),!0===t.data.loaded&&t.children&&e.push("expanded"),"loading"===t.data.loaded&&e.push("loading"),t.data.children&&0===t.data.children.length&&e.push("empty")):"file"===t.data.type&&e.push("file"),e.join(" ")}),n.select("circle.node-circle").attr("r",t=>"directory"===t.data.type?10:8).style("fill",t=>this.getNodeColor(t)),n.select(".expand-icon").text(t=>"loading"===t.data.loaded?"⟳":!0===t.data.loaded&&t.children?"▼":"▶"),n.select(".item-count-badge").text(t=>{if("directory"!==t.data.type)return"";const e=t.data.children?t.data.children.length:0;return e>0?e:""}).style("stroke",t=>this.getNodeStrokeColor(t)).attr("cursor","pointer");const r=this.isRadialLayout;n.select("text.node-label").style("fill-opacity",1).style("fill","#333").each(function(t){const e=d3.select(this);if(r){const i=180*t.x/Math.PI-90;i>90||i<-90?e.attr("transform",`rotate(${i+180})`).attr("x",-15).attr("text-anchor","end").attr("dy",".35em"):e.attr("transform",`rotate(${i})`).attr("x",15).attr("text-anchor","start").attr("dy",".35em")}else e.attr("transform",null).attr("x",t.children||t._children?-13:13).attr("text-anchor",t.children||t._children?"end":"start").attr("dy",".35em")});const d=s.exit().transition().duration(this.duration).attr("transform",e=>{if(this.isRadialLayout){const[e,i]=this.radialPoint(t.x,t.y);return`translate(${e},${i})`}return`translate(${t.y},${t.x})`}).remove();d.select("circle").attr("r",1e-6),d.select("text.node-label").style("fill-opacity",1e-6),d.select("text.node-icon").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(o,t=>t.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.isRadialLayout?this.radialDiagonal(i,i):this.diagonal(i,i)}).style("fill","none").style("stroke","#ccc").style("stroke-width",2).merge(l).transition().duration(this.duration).attr("d",t=>this.isRadialLayout?this.radialDiagonal(t,t.parent):this.diagonal(t,t.parent)),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.isRadialLayout?this.radialDiagonal(i,i):this.diagonal(i,i)}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y})}centerOnNode(t){console.log("[CodeTree] centerOnNode called but disabled - no centering will occur")}centerOnNodeRadial(t){console.log("[CodeTree] centerOnNodeRadial called but disabled - no centering will occur")}highlightActiveNode(t){const e=this.treeGroup.selectAll("circle.node-circle");e.classed("active",!1).classed("parent-context",!1),e.transition().duration(300).attr("r",8).style("stroke",null).style("stroke-width",null).style("opacity",null),this.treeGroup.selectAll("text.node-label").style("font-weight","normal").style("font-size","12px");const i=this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle");i.classed("active",!0),i.transition().duration(300).attr("r",20).style("stroke","#3b82f6").style("stroke-width",5).style("filter","drop-shadow(0 0 15px rgba(59, 130, 246, 0.6))"),this.treeGroup.selectAll("g.node").filter(e=>e===t).select("text.node-label").style("font-weight","bold").style("font-size","14px"),this.activeNode=t}addLoadingPulse(t){const e=this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle");this.loadingNodes.add(t.data.path),e.classed("loading-pulse",!0),e.style("fill","#fb923c");const i=()=>{this.loadingNodes.has(t.data.path)&&e.transition().duration(600).attr("r",14).style("opacity",.6).transition().duration(600).attr("r",10).style("opacity",1).on("end",()=>{this.loadingNodes.has(t.data.path)&&i()})};i()}removeLoadingPulse(t){this.loadingNodes.delete(t.data.path);const e=this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle");e.classed("loading-pulse",!1),e.interrupt().transition().duration(300).attr("r",this.activeNode===t?20:8).style("opacity",1).style("fill",t=>this.getNodeColor(t))}showWithParent(t){if(!t.parent)return;const e=this.treeGroup.selectAll("g.node").filter(e=>e===t.parent).select("circle.node-circle");e.classed("parent-context",!0),e.style("stroke","#10b981").style("stroke-width",3).style("opacity",.8)}onNodeClick(t,e){if(t)try{"function"==typeof t.stopPropagation&&t.stopPropagation()}catch(a){console.error("[CodeTree] ERROR calling stopPropagation:",a)}if(!e)return void console.error("[CodeTree] ERROR: d is null/undefined, cannot continue");if(!e.data)return void console.error("[CodeTree] ERROR: d.data is null/undefined, cannot continue");try{"function"==typeof this.highlightActiveNode?this.highlightActiveNode(e):console.error("[CodeTree] highlightActiveNode is not a function!")}catch(a){console.error("[CodeTree] ERROR during highlightActiveNode:",a,a.stack)}try{"function"==typeof this.showWithParent?this.showWithParent(e):console.error("[CodeTree] showWithParent is not a function!")}catch(a){console.error("[CodeTree] ERROR during showWithParent:",a,a.stack)}if("directory"===e.data.type&&!e.data.loaded)try{"function"==typeof this.addLoadingPulse?this.addLoadingPulse(e):console.error("[CodeTree] addLoadingPulse is not a function!")}catch(a){console.error("[CodeTree] ERROR during addLoadingPulse:",a,a.stack)}const i=[];document.querySelectorAll(".language-checkbox:checked").forEach(t=>{i.push(t.value)});const o=document.getElementById("ignore-patterns"),s=o?.value||"";if("directory"!==e.data.type||e.data.loaded)if("file"!==e.data.type||e.data.analyzed)if("directory"===e.data.type&&!0===e.data.loaded){if(e.children)e._children=e.children,e.children=null,e.data.expanded=!1;else if(e._children)e.children=e._children,e._children=null,e.data.expanded=!0;else if(e.data.children&&e.data.children.length>0){this.root=d3.hierarchy(this.treeData);const t=this.findD3NodeByPath(e.data.path);t&&(t.children=t._children||t.children,t._children=null,t.data.expanded=!0)}this.update(this.root)}else(e.children||e._children)&&(e.children?(e._children=e.children,e.children=null,e.data.expanded=!1):(e.children=e._children,e._children=null,e.data.expanded=!0),this.update(e));else{const t=this.detectLanguage(e.data.path);if(!i.includes(t)&&"unknown"!==t)return void this.showNotification(`Skipping ${e.data.name} - ${t} not selected`,"warning");this.addLoadingPulse(e),e.data.analyzed="loading";const o=this.ensureFullPath(e.data.path);setTimeout(()=>{this.socket&&(this.socket.emit("code:analyze:file",{path:o}),this.updateBreadcrumb(`Analyzing ${e.data.name}...`,"info"),this.showNotification(`Analyzing: ${e.data.name}`,"info"))},100)}else{if(this.loadingNodes.has(e.data.path))return void this.showNotification(`Already loading: ${e.data.name}`,"warning");e.data.loaded="loading",this.loadingNodes.add(e.data.path);const t=this.ensureFullPath(e.data.path);console.log("🚀 [SUBDIRECTORY LOADING] Attempting to load:",{originalPath:e.data.path,fullPath:t,nodeType:e.data.type,loaded:e.data.loaded,hasSocket:!!this.socket,workingDir:this.getWorkingDirectory()}),setTimeout(()=>{this.socket?(console.log("📡 [SUBDIRECTORY LOADING] Emitting WebSocket request:",{event:"code:discover:directory",data:{path:t,depth:this.bulkLoadMode?2:1,languages:i,ignore_patterns:s}}),this.socket.emit("code:discover:directory",{path:t,depth:this.bulkLoadMode?2:1,languages:i,ignore_patterns:s}),this.updateBreadcrumb(`Loading ${e.data.name}...`,"info"),this.showNotification(`Loading directory: ${e.data.name}`,"info")):(console.error("❌ [SUBDIRECTORY LOADING] No WebSocket connection available!"),this.showNotification("Cannot load directory: No connection","error"))},100)}this.selectedNode=e;try{this.highlightNode(e)}catch(a){console.error("[CodeTree] ERROR during highlightNode:",a)}}ensureFullPath(t){if(console.log("🔗 ensureFullPath called with:",t),!t)return t;if(t.startsWith("/"))return console.log(" → Already absolute, returning:",t),t;const e=this.getWorkingDirectory();if(console.log(" → Working directory:",e),!e)return console.log(" → No working directory, returning original:",t),t;if("."===t)return console.log(" → Root path detected, returning working dir:",e),e;if(t===e)return console.log(" → Path equals working directory, returning:",e),e;const i=`${e}/${t}`.replace(/\/+/g,"/");return console.log(" → Combining with working dir, result:",i),i}highlightNode(t){this.treeGroup.selectAll("circle.node-circle").style("stroke-width",2).classed("selected",!1),this.treeGroup.selectAll("circle.node-circle").filter(e=>e===t).style("stroke-width",4).classed("selected",!0)}diagonal(t,e){return`M ${t.y} ${t.x}\n C ${(t.y+e.y)/2} ${t.x},\n ${(t.y+e.y)/2} ${e.x},\n ${e.y} ${e.x}`}radialDiagonal(t,e){return d3.linkRadial().angle(t=>t.x).radius(t=>t.y)({source:t,target:e})}getNodeColor(t){const e=t.data.type,i=t.data.complexity||1,o={root:"#6B7280",directory:"#3B82F6",file:"#10B981",module:"#8B5CF6",class:"#F59E0B",function:"#EF4444",method:"#EC4899"}[e]||"#6B7280";return i>10?d3.color(o).darker(.5):i>5?d3.color(o).darker(.25):o}getNodeStrokeColor(t){return"loading"===t.data.loaded||"loading"===t.data.analyzed?"#FCD34D":"directory"!==t.data.type||t.data.loaded?"file"!==t.data.type||t.data.analyzed?this.getNodeColor(t):"#CBD5E1":"#94A3B8"}getNodeIcon(t){return{root:"📦",directory:"📁",file:"📄",module:"📦",class:"C",function:"ƒ",method:"m"}[t.data.type]||"•"}showTooltip(t,e){if(!this.tooltip)return;const i=[];i.push(`<strong>${e.data.name}</strong>`),i.push(`Type: ${e.data.type}`),e.data.language&&i.push(`Language: ${e.data.language}`),e.data.complexity&&i.push(`Complexity: ${e.data.complexity}`),e.data.lines&&i.push(`Lines: ${e.data.lines}`),e.data.path&&i.push(`Path: ${e.data.path}`),"directory"!==e.data.type||e.data.loaded?"file"!==e.data.type||e.data.analyzed||i.push("<em>Click to analyze file</em>"):i.push("<em>Click to explore contents</em>"),this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i.join("<br>")).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip&&this.tooltip.transition().duration(500).style("opacity",0)}filterTree(){this.root&&(this.root.descendants().forEach(t=>{t.data._hidden=!1,"all"!==this.languageFilter&&"file"===t.data.type&&t.data.language!==this.languageFilter&&(t.data._hidden=!0),this.searchTerm&&(t.data.name.toLowerCase().includes(this.searchTerm)||(t.data._hidden=!0))}),this.update(this.root))}expandAll(){if(!this.root)return;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),this.showNotification("All nodes expanded","info")}collapseAll(){if(!this.root)return;const t=e=>{e.children&&(e._children=e.children,e.children=null),e._children&&e._children.forEach(t)};this.root.children?.forEach(t),this.update(this.root),this.showNotification("All nodes collapsed","info")}resetZoom(){console.log("[CodeTree] resetZoom called but disabled - no zoom reset will occur"),this.showNotification("Zoom reset disabled - tree remains stationary","info")}focusOnNode(t){console.log("[CodeTree] focusOnNode called but disabled - no focusing will occur")}getNodePath(t){const e=[];let i=t;for(;i;)i.data&&i.data.name&&e.unshift(i.data.name),i=i.parent;return e.join(" / ")}toggleLegend(){const t=document.getElementById("tree-legend");t&&("none"===t.style.display?t.style.display="block":t.style.display="none")}getWorkingDirectory(){if(window.dashboard&&window.dashboard.workingDirectoryManager)return window.dashboard.workingDirectoryManager.getCurrentWorkingDir();const t=document.getElementById("working-dir-path");if(t){const e=t.textContent.trim();if(e&&"Loading..."!==e&&"Not selected"!==e)return e}return null}showNoWorkingDirectoryMessage(){const t=document.getElementById("code-tree-container");if(!t)return;this.removeNoWorkingDirectoryMessage(),this.hideLoading();const e=document.createElement("div");e.id="no-working-dir-message",e.className="no-working-dir-message",e.innerHTML='\n <div class="message-icon">📁</div>\n <h3>No Working Directory Selected</h3>\n <p>Please select a working directory from the top menu to analyze code.</p>\n <button id="select-working-dir-btn" class="btn btn-primary">\n Select Working Directory\n </button>\n ',e.style.cssText="\n text-align: center;\n padding: 40px;\n color: #666;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n ";const i=e.querySelector(".message-icon");i&&(i.style.cssText="font-size: 48px; margin-bottom: 16px; opacity: 0.5;");const o=e.querySelector("h3");o&&(o.style.cssText="margin: 16px 0; color: #333; font-size: 20px;");const s=e.querySelector("p");s&&(s.style.cssText="margin: 16px 0; color: #666; font-size: 14px;");const a=e.querySelector("button");a&&(a.style.cssText="\n margin-top: 20px;\n padding: 10px 20px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n transition: background 0.2s;\n ",a.addEventListener("mouseenter",()=>{a.style.background="#2563eb"}),a.addEventListener("mouseleave",()=>{a.style.background="#3b82f6"}),a.addEventListener("click",()=>{const t=document.getElementById("change-dir-btn");t?t.click():window.dashboard&&window.dashboard.workingDirectoryManager&&window.dashboard.workingDirectoryManager.showChangeDirDialog()})),t.appendChild(e),this.updateBreadcrumb("Please select a working directory","warning")}removeNoWorkingDirectoryMessage(){const t=document.getElementById("no-working-dir-message");t&&t.remove()}exportTree(){const t={timestamp:(new Date).toISOString(),workingDirectory:this.getWorkingDirectory(),stats:this.stats,tree:this.treeData},e=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),i=URL.createObjectURL(e),o=document.createElement("a");o.href=i,o.download=`code-tree-${Date.now()}.json`,o.click(),URL.revokeObjectURL(i),this.showNotification("Tree exported successfully","success")}updateActivityTicker(t,e="info"){const i=document.getElementById("breadcrumb-content");if(i){const o="info"===e&&t.includes("...")?"⟳ ":"";i.innerHTML=`${o}${t}`,i.className=`breadcrumb-${e}`}}updateTicker(t,e="info"){const i=document.getElementById("code-tree-ticker");i&&(i.textContent=t,i.className=`ticker ticker-${e}`,"error"!==e&&setTimeout(()=>{i.style.opacity="0",setTimeout(()=>{i.style.opacity="1",i.textContent=""},300)},5e3))}}window.CodeTree=t,document.addEventListener("DOMContentLoaded",()=>{document.getElementById("code-tree-container")&&(window.codeTree=new t,document.addEventListener("click",t=>{t.target.matches('[data-tab="code"]')&&setTimeout(()=>{window.codeTree&&!window.codeTree.initialized?window.codeTree.initialize():window.codeTree&&window.codeTree.renderWhenVisible()},100)}))});
1
+ class t{constructor(){this.container=null,this.svg=null,this.treeData=null,this.root=null,this.treeLayout=null,this.treeGroup=null,this.nodes=new Map,this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.isRadialLayout=!0,this.margin={top:20,right:20,bottom:20,left:20},this.width=960-this.margin.left-this.margin.right,this.height=600-this.margin.top-this.margin.bottom,this.radius=Math.min(this.width,this.height)/2,this.nodeId=0,this.duration=750,this.languageFilter="all",this.searchTerm="",this.tooltip=null,this.initialized=!1,this.analyzing=!1,this.selectedNode=null,this.socket=null,this.autoDiscovered=!1,this.zoom=null,this.activeNode=null,this.loadingNodes=new Set,this.bulkLoadMode=!1,this.expandedPaths=new Set}initialize(){if(this.initialized)return;if(this.container=document.getElementById("code-tree-container"),!this.container)return void console.error("Code tree container not found");const t=document.getElementById("code-tab");if(!t)return void console.error("Code tab panel not found");const e=this.getWorkingDirectory();if(!e||"Loading..."===e||"Not selected"===e)return this.showNoWorkingDirectoryMessage(),void(this.initialized=!0);this.setupControls(),this.initializeTreeData(),this.subscribeToEvents();document.getElementById("breadcrumb-content")&&!this.analyzing&&this.updateActivityTicker("Loading project structure...","info"),t.classList.contains("active")&&(this.createVisualization(),this.root&&this.svg&&this.update(this.root),this.autoDiscoverRootLevel()),this.initialized=!0}renderWhenVisible(){const t=this.getWorkingDirectory();t&&"Loading..."!==t&&"Not selected"!==t?(this.removeNoWorkingDirectoryMessage(),this.initialized?(this.svg?this.root&&this.svg&&this.update(this.root):(this.createVisualization(),this.svg&&this.treeGroup&&this.update(this.root)),this.autoDiscovered||this.autoDiscoverRootLevel()):this.initialize()):this.showNoWorkingDirectoryMessage()}setupControls(){const t=document.getElementById("language-filter");t&&t.addEventListener("change",t=>{this.languageFilter=t.target.value,this.filterTree()});const e=document.getElementById("code-search");e&&e.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.filterTree()});const i=document.getElementById("code-expand-all");i&&i.addEventListener("click",()=>this.expandAll());const o=document.getElementById("code-collapse-all");o&&o.addEventListener("click",()=>this.collapseAll());const s=document.getElementById("code-reset-zoom");s&&s.addEventListener("click",()=>this.resetZoom());const a=document.getElementById("code-toggle-legend");a&&a.addEventListener("click",()=>this.toggleLegend()),document.addEventListener("workingDirectoryChanged",t=>{this.onWorkingDirectoryChanged(t.detail.directory)})}onWorkingDirectoryChanged(t){if(!t||"Loading..."===t||"Not selected"===t)return this.showNoWorkingDirectoryMessage(),this.autoDiscovered=!1,this.analyzing=!1,this.nodes.clear(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},void this.updateStats();this.removeNoWorkingDirectoryMessage(),this.autoDiscovered=!1,this.analyzing=!1,this.nodes.clear(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.initializeTreeData(),this.svg&&this.update(this.root);const e=document.getElementById("code-tab");e&&e.classList.contains("active")&&this.autoDiscoverRootLevel(),this.updateStats()}showLoading(){let t=document.getElementById("code-tree-loading");if(!t){const e=document.getElementById("code-tree-container");e&&(t=document.createElement("div"),t.id="code-tree-loading",t.innerHTML='\n <div class="code-tree-spinner"></div>\n <div class="code-tree-loading-text">Analyzing code structure...</div>\n ',e.appendChild(t))}t&&t.classList.remove("hidden")}hideLoading(){const t=document.getElementById("code-tree-loading");t&&t.classList.add("hidden")}createVisualization(){if("undefined"==typeof d3)return void console.error("D3.js is not loaded");const t=d3.select("#code-tree-container");if(t.selectAll("*").remove(),this.addTreeControls(),this.addBreadcrumb(),!t||!t.node())return void console.error("Code tree container not found");const e=t.node(),i=e.clientWidth||960,o=e.clientHeight||600;this.width=i-this.margin.left-this.margin.right,this.height=o-this.margin.top-this.margin.bottom,this.radius=Math.min(this.width,this.height)/2,this.svg=t.append("svg").attr("width",i).attr("height",o);const s=i/2,a=o/2;this.isRadialLayout?this.treeGroup=this.svg.append("g").attr("transform",`translate(${s},${a})`):this.treeGroup=this.svg.append("g").attr("transform",`translate(${this.margin.left+100},${a})`),this.isRadialLayout?this.treeLayout=d3.cluster().size([2*Math.PI,this.radius-100]).separation((t,e)=>{if(t.parent==e.parent){const e=Math.max(1,4-t.depth),i=t.parent&&t.parent.children?.length||1,o=i>5?2:i>3?1.5:1,s=1+.2*t.depth;return e*o/(t.depth||1)*s}return 4/(t.depth||1)}):this.treeLayout=d3.tree().nodeSize([30,200]).separation((t,e)=>t.parent==e.parent?1:1.5),this.zoom=null,console.log("[CodeTree] All zoom and pan behavior disabled - tree is now completely stationary"),this.addVisualizationControls(),this.tooltip=d3.select("body").append("div").attr("class","code-tree-tooltip").style("opacity",0).style("position","absolute").style("background","rgba(0, 0, 0, 0.8)").style("color","white").style("padding","8px").style("border-radius","4px").style("font-size","12px").style("pointer-events","none")}clearD3Visualization(){this.treeGroup&&(this.treeGroup.selectAll("g.node").remove(),this.treeGroup.selectAll("path.link").remove()),this.nodeId=0}initializeTreeData(){const t=this.getWorkingDirectory(),e=t&&t.split("/").pop()||"Project Root";this.treeData={name:e,path:".",type:"root",children:[],loaded:!1,expanded:!0},"undefined"!=typeof d3&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0)}subscribeToEvents(){this.socket||(window.socket?(this.socket=window.socket,this.setupEventHandlers()):window.dashboard?.socketClient?.socket?(this.socket=window.dashboard.socketClient.socket,this.setupEventHandlers()):window.socketClient?.socket&&(this.socket=window.socketClient.socket,this.setupEventHandlers()))}autoDiscoverRootLevel(){if(this.autoDiscovered||this.analyzing)return;this.updateActivityTicker("🔍 Discovering project structure...","info");const t=this.getWorkingDirectory();if(!t||"Loading..."===t||"Not selected"===t)return console.warn("Cannot auto-discover: no working directory set"),void this.showNoWorkingDirectoryMessage();if(!t.startsWith("/")&&!t.match(/^[A-Z]:\\/))return console.error("Working directory is not absolute:",t),void this.showNotification("Invalid working directory path","error");this.autoDiscovered=!0,this.analyzing=!0,this.nodes.clear(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.socket&&!this.socket.hasListeners("code:node:found")&&this.setupEventHandlers();const e=t.split("/").pop()||"Project Root";this.treeData={name:e,path:".",type:"root",children:[],loaded:!1,expanded:!0},"undefined"!=typeof d3&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0),this.showLoading(),this.updateBreadcrumb(`Discovering structure in ${e}...`,"info");const i=[];document.querySelectorAll(".language-checkbox:checked").forEach(t=>{i.push(t.value)});const o=document.getElementById("ignore-patterns")?.value||"",s={path:t,depth:"top_level",languages:i,ignore_patterns:o,request_id:`discover_${Date.now()}`};this.socket&&this.socket.emit("code:discover:top_level",s),this.updateStats()}analyzeCode(){this.analyzing||this.autoDiscoverRootLevel()}cancelAnalysis(){this.analyzing=!1,this.hideLoading(),this.socket&&this.socket.emit("code:analysis:cancel")}addTreeControls(){const t=d3.select("#code-tree-container");t.select(".tree-controls-toolbar").remove();const e=t.append("div").attr("class","tree-controls-toolbar");e.append("button").attr("class","tree-control-btn").attr("title","Expand all loaded directories").text("⊞").on("click",()=>this.expandAll()),e.append("button").attr("class","tree-control-btn").attr("title","Collapse all directories").text("⊟").on("click",()=>this.collapseAll()),e.append("button").attr("class","tree-control-btn").attr("id","bulk-load-toggle").attr("title","Toggle bulk loading (load 2 levels at once)").text("↕").on("click",()=>this.toggleBulkLoad()),e.append("button").attr("class","tree-control-btn").attr("title","Toggle between radial and linear layouts").text("◎").on("click",()=>this.toggleLayout()),e.append("input").attr("class","tree-control-btn").attr("type","text").attr("placeholder","Search...").attr("title","Search for files and directories").style("width","120px").style("text-align","left").on("input",t=>this.searchTree(t.target.value)).on("keydown",t=>{"Escape"===t.key&&(t.target.value="",this.searchTree(""))})}addBreadcrumb(){const t=d3.select("#code-tree-container");t.select(".tree-breadcrumb").remove();t.append("div").attr("class","tree-breadcrumb").append("div").attr("class","breadcrumb-path").attr("id","tree-breadcrumb-path"),this.updateBreadcrumbPath("/")}updateBreadcrumbPath(t){const e=d3.select("#tree-breadcrumb-path");e.selectAll("*").remove();const i=this.getWorkingDirectory();if(!i||"Loading..."===i||"Not selected"===i)return void e.text("No project selected");const o="/"===t?[i.split("/").pop()||"Root"]:t.split("/").filter(t=>t.length>0);o.forEach((t,i)=>{i>0&&e.append("span").attr("class","breadcrumb-separator").text("/"),e.append("span").attr("class",i===o.length-1?"breadcrumb-segment current":"breadcrumb-segment").text(t).on("click",()=>{if(i<o.length-1){const t=o.slice(0,i+1).join("/");this.navigateToPath(t)}})})}expandAll(){if(!this.root)return;const t=e=>{"directory"===e.data.type&&!0===e.data.loaded&&e._children&&(e.children=e._children,e._children=null,e.data.expanded=!0),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root),this.showNotification("Expanded all loaded directories","success")}collapseAll(){if(!this.root)return;const t=e=>{"directory"===e.data.type&&e.children&&(e._children=e.children,e.children=null,e.data.expanded=!1),e._children&&e._children.forEach(t)};t(this.root),this.update(this.root),this.showNotification("Collapsed all directories","info")}toggleBulkLoad(){this.bulkLoadMode=!this.bulkLoadMode;const t=d3.select("#bulk-load-toggle");this.bulkLoadMode?(t.classed("active",!0),this.showNotification("Bulk load enabled - will load 2 levels deep","info")):(t.classed("active",!1),this.showNotification("Bulk load disabled - load 1 level at a time","info"))}navigateToPath(t){this.updateBreadcrumbPath(t),this.showNotification(`Navigating to: ${t}`,"info")}searchTree(t){if(!this.root||!this.treeGroup)return;const e=t.toLowerCase().trim();if(this.treeGroup.selectAll(".code-node").classed("search-match",!1),!e)return;const i=[],o=t=>{const s=(t.data.name||"").toLowerCase(),a=(t.data.path||"").toLowerCase();(s.includes(e)||a.includes(e))&&i.push(t),t.children&&t.children.forEach(o),t._children&&t._children.forEach(o)};o(this.root),i.length>0?(this.treeGroup.selectAll(".code-node").data(),i.forEach(t=>{this.treeGroup.selectAll(".code-node").filter(e=>e.data.path===t.data.path).classed("search-match",!0),this.expandPathToNode(t)}),this.showNotification(`Found ${i.length} matches`,"success")):this.showNotification("No matches found","info")}expandPathToNode(t){const e=[];let i=t.parent;for(;i&&i!==this.root;)e.unshift(i),i=i.parent;e.forEach(t=>{"directory"===t.data.type&&t._children&&(t.children=t._children,t._children=null,t.data.expanded=!0)}),e.length>0&&this.update(this.root)}createEventsDisplay(){let t=document.getElementById("analysis-events");if(!t){const e=document.getElementById("code-tree-container");e&&(t=document.createElement("div"),t.id="analysis-events",t.className="analysis-events",t.style.display="none",e.appendChild(t))}}clearEventsDisplay(){const t=document.getElementById("analysis-events");t&&(t.innerHTML="",t.style.display="block")}addEventToDisplay(t,e="info"){const i=document.getElementById("analysis-events");if(i){const o=document.createElement("div");o.className="analysis-event",o.style.borderLeftColor="warning"===e?"#f59e0b":"error"===e?"#ef4444":"#3b82f6";const s=(new Date).toLocaleTimeString();o.innerHTML=`<span style="color: #718096;">[${s}]</span> ${t}`,i.appendChild(o),i.scrollTop=i.scrollHeight}}setupEventHandlers(){this.socket&&(this.socket.on("code:analysis:accepted",t=>this.onAnalysisAccepted(t)),this.socket.on("code:analysis:queued",t=>this.onAnalysisQueued(t)),this.socket.on("code:analysis:start",t=>this.onAnalysisStart(t)),this.socket.on("code:analysis:complete",t=>this.onAnalysisComplete(t)),this.socket.on("code:analysis:cancelled",t=>this.onAnalysisCancelled(t)),this.socket.on("code:analysis:error",t=>this.onAnalysisError(t)),this.socket.on("code:top_level:discovered",t=>this.onTopLevelDiscovered(t)),this.socket.on("code:directory:discovered",t=>this.onDirectoryDiscovered(t)),this.socket.on("code:file:discovered",t=>this.onFileDiscovered(t)),this.socket.on("code:file:analyzed",t=>this.onFileAnalyzed(t)),this.socket.on("code:node:found",t=>this.onNodeFound(t)),this.socket.on("code:analysis:progress",t=>this.onProgressUpdate(t)),this.socket.on("code:directory:contents",t=>{if(t.path){let e=t.path;const i=this.getWorkingDirectory();i&&e.startsWith(i)&&(e=e.substring(i.length).replace(/^\//,""),e||(e="."));const o=this.findNodeByPath(e);if(o&&t.children){const i=this.findD3NodeByPath(e);if(i&&this.loadingNodes.has(e)&&(this.removeLoadingPulse(i),this.loadingNodes.delete(e),console.log("🎯 [SUBDIRECTORY LOADING] Successfully completed and removed from loading set:",e)),o.children=t.children.map(t=>{let i;if("."===e||""===e)i=t.name||t.path;else{const o=t.name||t.path;i=`${e}/${o}`}return{...t,path:i,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:[]}}),o.loaded=!0,o.expanded=!0,this.root&&this.svg){const t=this.root;this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.preserveExpansionState(t,this.root);const i=this.findD3NodeByPath(e);i&&(i.children=i._children||i.children,i._children=null,i.data.expanded=!0),this.update(this.root)}t.stats&&(this.stats.files+=t.stats.files||0,this.stats.directories+=t.stats.directories||0,this.updateStats()),this.updateBreadcrumb(`Loaded ${t.path}`,"success"),this.hideLoading()}}}),this.socket.on("code:top_level:discovered",t=>{t.items&&Array.isArray(t.items)&&(this.treeData.children=t.items.map(t=>({name:t.name,path:t.path,type:t.type,language:"file"===t.type?this.detectLanguage(t.path):void 0,size:t.size,lines:t.lines,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:[]})),this.treeData.loaded=!0,t.stats&&(this.stats={...this.stats,...t.stats},this.updateStats()),"undefined"!=typeof d3&&(this.clearD3Visualization(),this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.svg&&this.update(this.root)),this.analyzing=!1,this.hideLoading(),this.updateBreadcrumb(`Discovered ${t.items.length} root items`,"success"),this.showNotification(`Found ${t.items.length} items in project root`,"success"))}))}onAnalysisStart(t){this.analyzing=!0;const e=t.message||"Starting code analysis...";this.updateActivityTicker("🚀 Starting analysis...","info"),this.updateBreadcrumb(e,"info"),this.addEventToDisplay(`🚀 ${e}`,"info"),this.treeData&&0!==this.treeData.children.length||this.initializeTreeData(),this.stats={files:0,classes:0,functions:0,methods:0,lines:0},this.updateStats()}onTopLevelDiscovered(t){this.updateActivityTicker(`📁 Discovered ${(t.items||[]).length} top-level items`,"success"),this.addEventToDisplay(`📁 Found ${(t.items||[]).length} top-level items in project root`,"info");const e=this.findNodeByPath(".");console.log('🔎 Looking for root node with path ".", found:',e?{name:e.name,path:e.path,currentChildren:e.children?e.children.length:0}:"NOT FOUND"),e&&t.items?(console.log("🌳 Populating root node with children"),e.children=t.items.map(t=>{const e=t.name;return console.log(` Adding child: ${t.name} with path: ${e}`),{name:t.name,path:e,type:t.type,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:"directory"===t.type?[]:void 0,size:t.size,has_code:t.has_code}}),e.loaded=!0,e.expanded=!0,this.root&&this.svg&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.update(this.root)),this.hideLoading(),this.updateBreadcrumb(`Discovered ${t.items.length} items`,"success"),this.showNotification(`Found ${t.items.length} top-level items`,"success")):(console.error("❌ Could not find root node to populate"),this.showNotification("Failed to populate root directory","error")),this.analyzing=!1}onDirectoryDiscovered(t){this.updateActivityTicker(`📁 Discovered: ${t.name||"directory"}`),this.addEventToDisplay(`📁 Found ${(t.children||[]).length} items in: ${t.name||t.path}`,"info"),console.log("✅ [SUBDIRECTORY LOADING] Received directory discovery response:",{path:t.path,name:t.name,childrenCount:(t.children||[]).length,children:(t.children||[]).map(t=>({name:t.name,type:t.type})),workingDir:this.getWorkingDirectory(),fullEventData:t});let e=t.path;const i=this.getWorkingDirectory();i&&e.startsWith(i)&&(e=e.substring(i.length).replace(/^\//,""),e||(e=".")),console.log("🔎 Searching for node with path:",e);const o=this.findNodeByPath(e);if(console.log("🔍 Node search result:",{searchPath:e,nodeFound:!!o,nodeName:o?.name,nodePath:o?.path,nodeChildren:o?.children?.length,dataHasChildren:!!t.children,dataChildrenLength:t.children?.length}),o||(console.warn("Node not found! Logging all paths in tree:"),this.logAllPaths(this.treeData)),o){if(console.log("📦 Node found, checking children:",{nodeFound:!0,dataHasChildren:"children"in t,dataChildrenIsArray:Array.isArray(t.children),dataChildrenLength:t.children?.length,dataChildrenValue:t.children}),t.children){console.log(`📂 Updating node ${o.name} with ${t.children.length} children`),o.children=t.children.map(t=>{let i;if("."===e||""===e)i=t.name||t.path;else{const o=t.name||t.path;i=`${e}/${o}`}return{name:t.name,path:i,type:t.type,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:"directory"===t.type?[]:void 0,size:t.size,has_code:t.has_code}}),o.loaded=!0,o.expanded=!0;const i=this.findD3NodeByPath(e);if(i&&this.loadingNodes.has(e)&&(this.removeLoadingPulse(i),this.loadingNodes.delete(e),console.log("🎯 [SUBDIRECTORY LOADING] Successfully completed and removed from loading set (hierarchy update):",e)),this.root&&this.svg){const t=this.root;this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,this.preserveExpansionState(t,this.root);const i=this.findD3NodeByPath(e);i&&i.data.children&&i.data.children.length>0&&(i.children=i._children||i.children,i._children=null,i.data.expanded=!0),this.update(this.root)}0===o.children.length?(this.updateBreadcrumb(`Empty directory: ${o.name}`,"info"),this.showNotification(`Directory "${o.name}" is empty`,"info")):(this.updateBreadcrumb(`Loaded ${o.children.length} items from ${o.name}`,"success"),this.showNotification(`Loaded ${o.children.length} items from "${o.name}"`,"success"))}else console.error("❌ No children data received for directory:",{path:e,dataKeys:Object.keys(t),fullData:t}),this.updateBreadcrumb(`Error loading ${o.name}`,"error"),this.showNotification("Failed to load directory contents","error");this.updateStats()}else if(o){if(o&&!t.children){console.warn("⚠️ [SUBDIRECTORY LOADING] Directory response has no children:",{path:t.path,searchPath:e,nodeExists:!!o,dataKeys:Object.keys(t),fullData:t});const i=t.path?t.path.split("/").filter(t=>t):[];if(1===i.length||t.forceAdd){const e={name:t.name||i[i.length-1]||"Unknown",path:t.path,type:"directory",children:[],loaded:!1,expanded:!1,stats:t.stats||{}};this.addNodeToTree(e,t.parent||""),this.updateBreadcrumb(`Discovered: ${t.path}`,"info")}}}else console.error("❌ [SUBDIRECTORY LOADING] Node not found for path:",{searchPath:e,originalPath:t.path,workingDir:this.getWorkingDirectory(),allTreePaths:this.getAllTreePaths(this.treeData)}),this.showNotification(`Could not find directory "${e}" in tree`,"error"),this.logAllPaths(this.treeData)}onFileDiscovered(t){const e=t.name||(t.path?t.path.split("/").pop():"file");this.updateActivityTicker(`📄 Found: ${e}`),this.addEventToDisplay(`📄 Discovered: ${t.path||"Unknown file"}`,"info");const i=t.path?t.path.split("/").filter(t=>t):[],o=i.slice(0,-1).join("/"),s={name:t.name||i[i.length-1]||"Unknown",path:t.path,type:"file",language:t.language||this.detectLanguage(t.path),size:t.size||0,lines:t.lines||0,children:[],analyzed:!1};this.addNodeToTree(s,o),this.stats.files++,this.updateStats(),this.updateBreadcrumb(`Found: ${t.path}`,"info")}onFileAnalyzed(t){const e=this.findD3NodeByPath(t.path);if(e&&this.loadingNodes.has(t.path)&&(this.removeLoadingPulse(e),this.loadingNodes.delete(t.path)),t.path){const e=t.path.split("/").pop();this.updateActivityTicker(`🔍 Analyzed: ${e}`)}const i=this.findNodeByPath(t.path);i&&(i.analyzed=!0,i.complexity=t.complexity||0,i.lines=t.lines||0,t.elements&&Array.isArray(t.elements)&&(i.children=t.elements.map(e=>({name:e.name,type:e.type.toLowerCase(),path:`${t.path}#${e.name}`,line:e.line,complexity:e.complexity||1,docstring:e.docstring||"",children:e.methods?e.methods.map(i=>({name:i.name,type:"method",path:`${t.path}#${e.name}.${i.name}`,line:i.line,complexity:i.complexity||1,docstring:i.docstring||""})):[]}))),t.stats&&(this.stats.classes+=t.stats.classes||0,this.stats.functions+=t.stats.functions||0,this.stats.methods+=t.stats.methods||0,this.stats.lines+=t.stats.lines||0),this.updateStats(),this.root&&this.update(this.root),this.updateBreadcrumb(`Analyzed: ${t.path}`,"success"))}onNodeFound(t){const e="class"===t.type?"🏛️":"function"===t.type?"⚡":"method"===t.type?"🔧":"📦";this.addEventToDisplay(`${e} Found ${t.type||"node"}: ${t.name||"Unknown"}`);const i={name:t.name||"Unknown",type:(t.type||"unknown").toLowerCase(),path:t.path||"",line:t.line||0,complexity:t.complexity||1,docstring:t.docstring||""};i.type={class:"class",function:"function",method:"method",module:"module",file:"file",directory:"directory"}[i.type]||i.type;let o="";if(t.parent_path)o=t.parent_path;else if(t.file_path)o=t.file_path;else if(i.path.includes("/")){const t=i.path.split("/");t.pop(),o=t.join("/")}switch(i.type){case"class":this.stats.classes++;break;case"function":this.stats.functions++;break;case"method":this.stats.methods++;break;case"file":this.stats.files++}this.addNodeToTree(i,o),this.updateStats();const s=i.type.charAt(0).toUpperCase()+i.type.slice(1);this.updateBreadcrumb(`Found ${s}: ${i.name}`,"info")}onProgressUpdate(t){const e=t.progress||0,i=t.message||`Processing... ${e}%`;this.updateBreadcrumb(i,"info");const o=document.querySelector(".code-tree-progress");o&&(o.style.width=`${e}%`)}onAnalysisComplete(t){this.analyzing=!1,this.hideLoading(),this.updateActivityTicker("✅ Ready","success"),this.addEventToDisplay("✅ Analysis complete!","success"),this.root&&this.svg&&this.update(this.root),t.stats&&(this.stats={...this.stats,...t.stats},this.updateStats());const e=t.message||`Analysis complete: ${this.stats.files} files, ${this.stats.classes} classes, ${this.stats.functions} functions`;this.updateBreadcrumb(e,"success"),this.showNotification(e,"success")}onAnalysisError(t){this.analyzing=!1,this.hideLoading();const e=t.message||t.error||"Analysis failed";this.updateBreadcrumb(e,"error"),this.showNotification(e,"error")}onAnalysisAccepted(t){const e=t.message||"Analysis request accepted";this.updateBreadcrumb(e,"info")}onAnalysisQueued(t){const e=`Analysis queued (position ${t.position||0})`;this.updateBreadcrumb(e,"warning"),this.showNotification(e,"info")}onInfoEvent(t){t.type&&t.type.startsWith("discovery.")?"discovery.start"===t.type?this.updateBreadcrumb(t.message,"info"):"discovery.complete"===t.type?(this.updateBreadcrumb(t.message,"success"),t.stats):"discovery.directory"!==t.type&&"discovery.file"!==t.type||this.updateBreadcrumb(t.message,"info"):t.type&&t.type.startsWith("analysis.")?"analysis.start"===t.type?this.updateBreadcrumb(t.message,"info"):"analysis.complete"===t.type?(this.updateBreadcrumb(t.message,"success"),t.stats&&(t.stats.classes,t.stats.functions,t.stats.methods)):("analysis.class"===t.type||"analysis.function"===t.type||"analysis.method"===t.type||"analysis.parse"===t.type)&&this.updateBreadcrumb(t.message,"info"):t.type&&t.type.startsWith("filter.")?(window.debugMode||this.showFilterEvents)&&(console.debug("[FILTER]",t.type,t.path,t.reason),this.showFilterEvents&&this.updateBreadcrumb(t.message,"warning")):t.type&&t.type.startsWith("cache.")&&("cache.hit"===t.type?(console.debug("[CACHE HIT]",t.file),this.showCacheEvents&&this.updateBreadcrumb(t.message,"info")):"cache.miss"===t.type&&console.debug("[CACHE MISS]",t.file)),this.eventLogEnabled&&t.message&&this.addEventToDisplay(t)}addEventToDisplay(t){this.recentEvents||(this.recentEvents=[]),this.recentEvents.unshift({timestamp:t.timestamp||(new Date).toISOString(),type:t.type,message:t.message,data:t}),this.recentEvents.length>100&&this.recentEvents.pop()}onAnalysisCancelled(t){this.analyzing=!1,this.hideLoading();const e=t.message||"Analysis cancelled";this.updateBreadcrumb(e,"warning")}showNotification(t,e="info"){const i=document.createElement("div");i.className=`code-tree-notification ${e}`,i.textContent=t;const o=document.getElementById("code-tree-container");o&&(i.style.position="absolute",i.style.top="10px",i.style.right="10px",i.style.zIndex="1000",o.style.position&&"static"!==o.style.position||(o.style.position="relative"),o.appendChild(i),setTimeout(()=>{i.style.animation="slideOutRight 0.3s ease",setTimeout(()=>i.remove(),300)},3e3))}addNodeToTree(t,e=""){if(t.path&&t.path.startsWith("/"))return void console.error("Absolute path detected in node, skipping:",t.path);if(e&&e.startsWith("/"))return void console.error("Absolute path detected in parent, skipping:",e);let i=this.treeData;if(e&&(i=this.findNodeByPath(e),!i))return console.warn("Parent node not found, skipping node creation:",e),void console.warn("Attempted to add node:",t);const o=i.children?.find(e=>e.path===t.path||e.name===t.name&&e.type===t.type);o?Object.assign(o,t):(i.children||(i.children=[]),t.children||(t.children=[]),i.children.push(t),this.nodes.set(t.path,t),this.root&&this.svg&&(this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,(this.nodes.size<1e3||this.nodes.size%100==0)&&this.update(this.root)))}findNodeByPath(t,e=null){if(e||(e=this.treeData,console.log("🔍 [SUBDIRECTORY LOADING] Starting search for path:",t)),e.path===t)return console.log("✅ [SUBDIRECTORY LOADING] Found node for path:",t),e;if(e.children)for(const i of e.children){const e=this.findNodeByPath(t,i);if(e)return e}return e.parent||e!==this.treeData||console.warn("❌ [SUBDIRECTORY LOADING] Path not found in tree:",t),null}logAllPaths(t,e=""){if(console.log(`${e}${t.path} (${t.name})`),t.children)for(const i of t.children)this.logAllPaths(i,e+" ")}getAllTreePaths(t){const e=[t.path];if(t.children)for(const i of t.children)e.push(...this.getAllTreePaths(i));return e}findD3NodeByPath(t){return this.root?this.root.descendants().find(e=>e.data.path===t):null}preserveExpansionState(t,e){if(!t||!e)return;const i=new Map;t.descendants().forEach(t=>{(t.data.expanded||t.children&&!t._children)&&i.set(t.data.path,!0)}),e.descendants().forEach(t=>{i.has(t.data.path)&&(t.children=t._children||t.children,t._children=null,t.data.expanded=!0)})}updateStats(){const t={"file-count":this.stats.files,"class-count":this.stats.classes,"function-count":this.stats.functions,"line-count":this.stats.lines};for(const[i,o]of Object.entries(t)){const t=document.getElementById(i);t&&(t.textContent=o.toLocaleString())}const e=document.getElementById("code-progress-text");if(e){const t=this.analyzing?`Analyzing... ${this.stats.files} files processed`:`Ready - ${this.stats.files} files in tree`;e.textContent=t}}updateBreadcrumb(t,e="info"){const i=document.getElementById("breadcrumb-content");i&&(i.textContent=t,i.className=`breadcrumb-${e}`)}detectLanguage(t){return{py:"python",js:"javascript",ts:"typescript",jsx:"javascript",tsx:"typescript",java:"java",cpp:"cpp",c:"c",cs:"csharp",rb:"ruby",go:"go",rs:"rust",php:"php",swift:"swift",kt:"kotlin",scala:"scala",r:"r",sh:"bash",ps1:"powershell"}[t.split(".").pop().toLowerCase()]||"unknown"}addVisualizationControls(){const t=this.svg.append("g").attr("class","viz-controls").attr("transform","translate(10, 10)").append("g").attr("class","layout-toggle").style("cursor","pointer").on("click",()=>this.toggleLayout());t.append("rect").attr("width",120).attr("height",30).attr("rx",5).attr("fill","#3b82f6").attr("opacity",.8),t.append("text").attr("x",60).attr("y",20).attr("text-anchor","middle").attr("fill","white").style("font-size","12px").text(this.isRadialLayout?"Switch to Linear":"Switch to Radial")}toggleLayout(){this.isRadialLayout=!this.isRadialLayout,this.createVisualization(),this.root&&this.update(this.root),this.showNotification(this.isRadialLayout?"Switched to radial layout":"Switched to linear layout","info")}radialPoint(t,e){return[(e=+e)*Math.cos(t-=Math.PI/2),e*Math.sin(t)]}update(t){if(!this.treeLayout||!this.treeGroup||!t)return;const e=this.treeLayout(this.root),i=e.descendants(),o=e.descendants().slice(1);this.isRadialLayout&&i.forEach(t=>{void 0===t.x0&&(t.x0=t.x,t.y0=t.y)});const s=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),a=s.enter().append("g").attr("class",t=>{let e=["node","code-node"];return"directory"===t.data.type?(e.push("directory"),!0===t.data.loaded&&t.children&&e.push("expanded"),"loading"===t.data.loaded&&e.push("loading"),t.data.children&&0===t.data.children.length&&e.push("empty")):"file"===t.data.type&&e.push("file"),e.join(" ")}).attr("transform",e=>{if(this.isRadialLayout){const[e,i]=this.radialPoint(t.x0||0,t.y0||0);return`translate(${e},${i})`}return`translate(${t.y0},${t.x0})`}).on("click",(t,e)=>this.onNodeClick(t,e));a.append("circle").attr("class","node-circle").attr("r",1e-6).style("fill",t=>this.getNodeColor(t)).style("stroke",t=>this.getNodeStrokeColor(t)).style("stroke-width",t=>"directory"===t.data.type?2:1.5).style("cursor","pointer").on("click",(t,e)=>this.onNodeClick(t,e)).on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip()),a.filter(t=>"directory"===t.data.type).append("text").attr("class","expand-icon").attr("x",0).attr("y",0).attr("text-anchor","middle").attr("dominant-baseline","central").text(t=>"loading"===t.data.loaded?"⟳":!0===t.data.loaded&&t.children?"▼":"▶").style("font-size","10px").style("pointer-events","none"),a.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>this.isRadialLayout?0:t.children||t._children?-13:13).attr("text-anchor",t=>this.isRadialLayout?"start":t.children||t._children?"end":"start").text(t=>{const e=t.data.name||"";return e.length>20?e.substring(0,17)+"...":e}).style("fill-opacity",1e-6).style("font-size","12px").style("font-family",'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif').style("text-shadow","1px 1px 2px rgba(255,255,255,0.8), -1px -1px 2px rgba(255,255,255,0.8)").on("click",(t,e)=>this.onNodeClick(t,e)).style("cursor","pointer"),a.filter(t=>"directory"!==t.data.type).append("text").attr("class","node-icon").attr("dy",".35em").attr("x",0).attr("text-anchor","middle").text(t=>this.getNodeIcon(t)).style("font-size","10px").style("fill","white").on("click",(t,e)=>this.onNodeClick(t,e)).style("cursor","pointer"),a.filter(t=>"directory"===t.data.type&&t.data.children).append("text").attr("class","item-count-badge").attr("x",12).attr("y",-8).attr("text-anchor","middle").text(t=>{const e=t.data.children?t.data.children.length:0;return e>0?e:""}).style("font-size","9px").style("opacity",.7).on("click",(t,e)=>this.onNodeClick(t,e)).style("cursor","pointer");const n=a.merge(s);n.on("click",(t,e)=>this.onNodeClick(t,e)),n.transition().duration(this.duration).attr("transform",t=>{if(this.isRadialLayout){const[e,i]=this.radialPoint(t.x,t.y);return`translate(${e},${i})`}return`translate(${t.y},${t.x})`}),n.attr("class",t=>{let e=["node","code-node"];return"directory"===t.data.type?(e.push("directory"),!0===t.data.loaded&&t.children&&e.push("expanded"),"loading"===t.data.loaded&&e.push("loading"),t.data.children&&0===t.data.children.length&&e.push("empty")):"file"===t.data.type&&e.push("file"),e.join(" ")}),n.select("circle.node-circle").attr("r",t=>"directory"===t.data.type?10:8).style("fill",t=>this.getNodeColor(t)),n.select(".expand-icon").text(t=>"loading"===t.data.loaded?"⟳":!0===t.data.loaded&&t.children?"▼":"▶"),n.select(".item-count-badge").text(t=>{if("directory"!==t.data.type)return"";const e=t.data.children?t.data.children.length:0;return e>0?e:""}).style("stroke",t=>this.getNodeStrokeColor(t)).attr("cursor","pointer");const r=this.isRadialLayout;n.select("text.node-label").style("fill-opacity",1).style("fill","#333").each(function(t){const e=d3.select(this);if(r){const i=180*t.x/Math.PI-90;i>90||i<-90?e.attr("transform",`rotate(${i+180})`).attr("x",-15).attr("text-anchor","end").attr("dy",".35em"):e.attr("transform",`rotate(${i})`).attr("x",15).attr("text-anchor","start").attr("dy",".35em")}else e.attr("transform",null).attr("x",t.children||t._children?-13:13).attr("text-anchor",t.children||t._children?"end":"start").attr("dy",".35em")});const d=s.exit().transition().duration(this.duration).attr("transform",e=>{if(this.isRadialLayout){const[e,i]=this.radialPoint(t.x,t.y);return`translate(${e},${i})`}return`translate(${t.y},${t.x})`}).remove();d.select("circle").attr("r",1e-6),d.select("text.node-label").style("fill-opacity",1e-6),d.select("text.node-icon").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(o,t=>t.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.isRadialLayout?this.radialDiagonal(i,i):this.diagonal(i,i)}).style("fill","none").style("stroke","#ccc").style("stroke-width",2).merge(l).transition().duration(this.duration).attr("d",t=>this.isRadialLayout?this.radialDiagonal(t,t.parent):this.diagonal(t,t.parent)),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.isRadialLayout?this.radialDiagonal(i,i):this.diagonal(i,i)}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y})}centerOnNode(t){console.log("[CodeTree] centerOnNode called but disabled - no centering will occur")}centerOnNodeRadial(t){console.log("[CodeTree] centerOnNodeRadial called but disabled - no centering will occur")}highlightActiveNode(t){const e=this.treeGroup.selectAll("circle.node-circle");e.classed("active",!1).classed("parent-context",!1),e.transition().duration(300).attr("r",8).style("stroke",null).style("stroke-width",null).style("opacity",null),this.treeGroup.selectAll("text.node-label").style("font-weight","normal").style("font-size","12px");const i=this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle");i.classed("active",!0),i.transition().duration(300).attr("r",20).style("stroke","#3b82f6").style("stroke-width",5).style("filter","drop-shadow(0 0 15px rgba(59, 130, 246, 0.6))"),this.treeGroup.selectAll("g.node").filter(e=>e===t).select("text.node-label").style("font-weight","bold").style("font-size","14px"),this.activeNode=t}addLoadingPulse(t){const e=this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle");this.loadingNodes.add(t.data.path),e.classed("loading-pulse",!0),e.style("fill","#fb923c");const i=()=>{this.loadingNodes.has(t.data.path)&&e.transition().duration(600).attr("r",14).style("opacity",.6).transition().duration(600).attr("r",10).style("opacity",1).on("end",()=>{this.loadingNodes.has(t.data.path)&&i()})};i()}removeLoadingPulse(t){this.loadingNodes.delete(t.data.path);const e=this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle");e.classed("loading-pulse",!1),e.interrupt().transition().duration(300).attr("r",this.activeNode===t?20:8).style("opacity",1).style("fill",t=>this.getNodeColor(t))}showWithParent(t){if(!t.parent)return;const e=this.treeGroup.selectAll("g.node").filter(e=>e===t.parent).select("circle.node-circle");e.classed("parent-context",!0),e.style("stroke","#10b981").style("stroke-width",3).style("opacity",.8)}onNodeClick(t,e){if(t)try{"function"==typeof t.stopPropagation&&t.stopPropagation()}catch(a){console.error("[CodeTree] ERROR calling stopPropagation:",a)}if(!e)return void console.error("[CodeTree] ERROR: d is null/undefined, cannot continue");if(!e.data)return void console.error("[CodeTree] ERROR: d.data is null/undefined, cannot continue");try{"function"==typeof this.highlightActiveNode?this.highlightActiveNode(e):console.error("[CodeTree] highlightActiveNode is not a function!")}catch(a){console.error("[CodeTree] ERROR during highlightActiveNode:",a,a.stack)}try{"function"==typeof this.showWithParent?this.showWithParent(e):console.error("[CodeTree] showWithParent is not a function!")}catch(a){console.error("[CodeTree] ERROR during showWithParent:",a,a.stack)}if("directory"===e.data.type&&!e.data.loaded)try{"function"==typeof this.addLoadingPulse?this.addLoadingPulse(e):console.error("[CodeTree] addLoadingPulse is not a function!")}catch(a){console.error("[CodeTree] ERROR during addLoadingPulse:",a,a.stack)}const i=[];document.querySelectorAll(".language-checkbox:checked").forEach(t=>{i.push(t.value)});const o=document.getElementById("ignore-patterns"),s=o?.value||"";if("directory"!==e.data.type||e.data.loaded)if("file"!==e.data.type||e.data.analyzed)if("directory"===e.data.type&&!0===e.data.loaded){if(e.children)e._children=e.children,e.children=null,e.data.expanded=!1;else if(e._children)e.children=e._children,e._children=null,e.data.expanded=!0;else if(e.data.children&&e.data.children.length>0){this.root=d3.hierarchy(this.treeData);const t=this.findD3NodeByPath(e.data.path);t&&(t.children=t._children||t.children,t._children=null,t.data.expanded=!0)}this.update(this.root)}else(e.children||e._children)&&(e.children?(e._children=e.children,e.children=null,e.data.expanded=!1):(e.children=e._children,e._children=null,e.data.expanded=!0),this.update(e));else{const t=this.detectLanguage(e.data.path);if(!i.includes(t)&&"unknown"!==t)return void this.showNotification(`Skipping ${e.data.name} - ${t} not selected`,"warning");this.addLoadingPulse(e),e.data.analyzed="loading";const o=this.ensureFullPath(e.data.path);setTimeout(()=>{this.socket&&(this.socket.emit("code:analyze:file",{path:o}),this.updateBreadcrumb(`Analyzing ${e.data.name}...`,"info"),this.showNotification(`Analyzing: ${e.data.name}`,"info"))},100)}else{if(this.loadingNodes.has(e.data.path))return void this.showNotification(`Already loading: ${e.data.name}`,"warning");e.data.loaded="loading",this.loadingNodes.add(e.data.path);const t=this.ensureFullPath(e.data.path);console.log("🚀 [SUBDIRECTORY LOADING] Attempting to load:",{originalPath:e.data.path,fullPath:t,nodeType:e.data.type,loaded:e.data.loaded,hasSocket:!!this.socket,workingDir:this.getWorkingDirectory()}),setTimeout(()=>{this.socket?(console.log("📡 [SUBDIRECTORY LOADING] Emitting WebSocket request:",{event:"code:discover:directory",data:{path:t,depth:this.bulkLoadMode?2:1,languages:i,ignore_patterns:s}}),this.socket.emit("code:discover:directory",{path:t,depth:this.bulkLoadMode?2:1,languages:i,ignore_patterns:s}),this.updateBreadcrumb(`Loading ${e.data.name}...`,"info"),this.showNotification(`Loading directory: ${e.data.name}`,"info")):(console.error("❌ [SUBDIRECTORY LOADING] No WebSocket connection available!"),this.showNotification("Cannot load directory: No connection","error"))},100)}this.selectedNode=e;try{this.highlightNode(e)}catch(a){console.error("[CodeTree] ERROR during highlightNode:",a)}}ensureFullPath(t){if(console.log("🔗 ensureFullPath called with:",t),!t)return t;if(t.startsWith("/"))return console.log(" → Already absolute, returning:",t),t;const e=this.getWorkingDirectory();if(console.log(" → Working directory:",e),!e)return console.log(" → No working directory, returning original:",t),t;if("."===t)return console.log(" → Root path detected, returning working dir:",e),e;if(t===e)return console.log(" → Path equals working directory, returning:",e),e;const i=`${e}/${t}`.replace(/\/+/g,"/");return console.log(" → Combining with working dir, result:",i),i}highlightNode(t){this.treeGroup.selectAll("circle.node-circle").style("stroke-width",2).classed("selected",!1),this.treeGroup.selectAll("circle.node-circle").filter(e=>e===t).style("stroke-width",4).classed("selected",!0)}diagonal(t,e){return`M ${t.y} ${t.x}\n C ${(t.y+e.y)/2} ${t.x},\n ${(t.y+e.y)/2} ${e.x},\n ${e.y} ${e.x}`}radialDiagonal(t,e){return d3.linkRadial().angle(t=>t.x).radius(t=>t.y)({source:t,target:e})}getNodeColor(t){const e=t.data.type,i=t.data.complexity||1,o={root:"#6B7280",directory:"#3B82F6",file:"#10B981",module:"#8B5CF6",class:"#F59E0B",function:"#EF4444",method:"#EC4899"}[e]||"#6B7280";return i>10?d3.color(o).darker(.5):i>5?d3.color(o).darker(.25):o}getNodeStrokeColor(t){return"loading"===t.data.loaded||"loading"===t.data.analyzed?"#FCD34D":"directory"!==t.data.type||t.data.loaded?"file"!==t.data.type||t.data.analyzed?this.getNodeColor(t):"#CBD5E1":"#94A3B8"}getNodeIcon(t){return{root:"📦",directory:"📁",file:"📄",module:"📦",class:"C",function:"ƒ",method:"m"}[t.data.type]||"•"}showTooltip(t,e){if(!this.tooltip)return;const i=[];i.push(`<strong>${e.data.name}</strong>`),i.push(`Type: ${e.data.type}`),e.data.language&&i.push(`Language: ${e.data.language}`),e.data.complexity&&i.push(`Complexity: ${e.data.complexity}`),e.data.lines&&i.push(`Lines: ${e.data.lines}`),e.data.path&&i.push(`Path: ${e.data.path}`),"directory"!==e.data.type||e.data.loaded?"file"!==e.data.type||e.data.analyzed||i.push("<em>Click to analyze file</em>"):i.push("<em>Click to explore contents</em>"),this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i.join("<br>")).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip&&this.tooltip.transition().duration(500).style("opacity",0)}filterTree(){this.root&&(this.root.descendants().forEach(t=>{t.data._hidden=!1,"all"!==this.languageFilter&&"file"===t.data.type&&t.data.language!==this.languageFilter&&(t.data._hidden=!0),this.searchTerm&&(t.data.name.toLowerCase().includes(this.searchTerm)||(t.data._hidden=!0))}),this.update(this.root))}expandAll(){if(!this.root)return;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),this.showNotification("All nodes expanded","info")}collapseAll(){if(!this.root)return;const t=e=>{e.children&&(e._children=e.children,e.children=null),e._children&&e._children.forEach(t)};this.root.children?.forEach(t),this.update(this.root),this.showNotification("All nodes collapsed","info")}resetZoom(){console.log("[CodeTree] resetZoom called but disabled - no zoom reset will occur"),this.showNotification("Zoom reset disabled - tree remains stationary","info")}focusOnNode(t){console.log("[CodeTree] focusOnNode called but disabled - no focusing will occur")}getNodePath(t){const e=[];let i=t;for(;i;)i.data&&i.data.name&&e.unshift(i.data.name),i=i.parent;return e.join(" / ")}toggleLegend(){const t=document.getElementById("tree-legend");t&&("none"===t.style.display?t.style.display="block":t.style.display="none")}getWorkingDirectory(){if(window.dashboard&&window.dashboard.workingDirectoryManager)return window.dashboard.workingDirectoryManager.getCurrentWorkingDir();const t=document.getElementById("working-dir-path");if(t){const e=t.textContent.trim();if(e&&"Loading..."!==e&&"Not selected"!==e)return e}return null}showNoWorkingDirectoryMessage(){const t=document.getElementById("code-tree-container");if(!t)return;this.removeNoWorkingDirectoryMessage(),this.hideLoading();const e=document.createElement("div");e.id="no-working-dir-message",e.className="no-working-dir-message",e.innerHTML='\n <div class="message-icon">📁</div>\n <h3>No Working Directory Selected</h3>\n <p>Please select a working directory from the top menu to analyze code.</p>\n <button id="select-working-dir-btn" class="btn btn-primary">\n Select Working Directory\n </button>\n ',e.style.cssText="\n text-align: center;\n padding: 40px;\n color: #666;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n ";const i=e.querySelector(".message-icon");i&&(i.style.cssText="font-size: 48px; margin-bottom: 16px; opacity: 0.5;");const o=e.querySelector("h3");o&&(o.style.cssText="margin: 16px 0; color: #333; font-size: 20px;");const s=e.querySelector("p");s&&(s.style.cssText="margin: 16px 0; color: #666; font-size: 14px;");const a=e.querySelector("button");a&&(a.style.cssText="\n margin-top: 20px;\n padding: 10px 20px;\n background: #3b82f6;\n color: white;\n border: none;\n border-radius: 6px;\n cursor: pointer;\n font-size: 14px;\n transition: background 0.2s;\n ",a.addEventListener("mouseenter",()=>{a.style.background="#2563eb"}),a.addEventListener("mouseleave",()=>{a.style.background="#3b82f6"}),a.addEventListener("click",()=>{const t=document.getElementById("change-dir-btn");t?t.click():window.dashboard&&window.dashboard.workingDirectoryManager&&window.dashboard.workingDirectoryManager.showChangeDirDialog()})),t.appendChild(e),this.updateBreadcrumb("Please select a working directory","warning")}removeNoWorkingDirectoryMessage(){const t=document.getElementById("no-working-dir-message");t&&t.remove()}exportTree(){const t={timestamp:(new Date).toISOString(),workingDirectory:this.getWorkingDirectory(),stats:this.stats,tree:this.treeData},e=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),i=URL.createObjectURL(e),o=document.createElement("a");o.href=i,o.download=`code-tree-${Date.now()}.json`,o.click(),URL.revokeObjectURL(i),this.showNotification("Tree exported successfully","success")}updateActivityTicker(t,e="info"){const i=document.getElementById("breadcrumb-content");if(i){const o="info"===e&&t.includes("...")?"⟳ ":"";i.innerHTML=`${o}${t}`,i.className=`breadcrumb-${e}`}}updateTicker(t,e="info"){const i=document.getElementById("code-tree-ticker");i&&(i.textContent=t,i.className=`ticker ticker-${e}`,"error"!==e&&setTimeout(()=>{i.style.opacity="0",setTimeout(()=>{i.style.opacity="1",i.textContent=""},300)},5e3))}}window.CodeTree=t,document.addEventListener("DOMContentLoaded",()=>{document.getElementById("code-tree-container")&&(window.codeTree=new t,document.addEventListener("click",t=>{t.target.matches('[data-tab="code"]')&&setTimeout(()=>{window.codeTree&&!window.codeTree.initialized?window.codeTree.initialize():window.codeTree&&window.codeTree.renderWhenVisible()},100)}))});
2
2
  //# sourceMappingURL=code-tree.js.map