claude-mpm 4.1.10__py3-none-any.whl → 4.1.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/cli/__init__.py +11 -0
- claude_mpm/cli/commands/analyze.py +2 -1
- claude_mpm/cli/commands/configure.py +9 -8
- claude_mpm/cli/commands/configure_tui.py +3 -1
- claude_mpm/cli/commands/dashboard.py +288 -0
- claude_mpm/cli/commands/debug.py +0 -1
- claude_mpm/cli/commands/mpm_init.py +427 -0
- claude_mpm/cli/commands/mpm_init_handler.py +83 -0
- claude_mpm/cli/parsers/base_parser.py +15 -0
- claude_mpm/cli/parsers/dashboard_parser.py +113 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
- claude_mpm/constants.py +10 -0
- claude_mpm/dashboard/analysis_runner.py +52 -25
- claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/css/code-tree.css +330 -1
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +212 -13
- claude_mpm/dashboard/static/js/components/code-tree.js +1999 -821
- claude_mpm/dashboard/static/js/components/event-viewer.js +58 -19
- claude_mpm/dashboard/static/js/dashboard.js +15 -3
- claude_mpm/dashboard/static/js/socket-client.js +74 -32
- claude_mpm/dashboard/templates/index.html +9 -11
- claude_mpm/services/agents/memory/memory_format_service.py +3 -1
- claude_mpm/services/cli/agent_cleanup_service.py +1 -4
- claude_mpm/services/cli/startup_checker.py +0 -1
- claude_mpm/services/core/cache_manager.py +0 -1
- claude_mpm/services/socketio/event_normalizer.py +64 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +502 -0
- claude_mpm/services/socketio/server/connection_manager.py +3 -1
- claude_mpm/tools/code_tree_analyzer.py +843 -25
- claude_mpm/tools/code_tree_builder.py +0 -1
- claude_mpm/tools/code_tree_events.py +113 -15
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +48 -41
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""
|
|
2
|
+
MPM-Init parser module for claude-mpm CLI.
|
|
3
|
+
|
|
4
|
+
WHY: This module handles the mpm-init command parser configuration,
|
|
5
|
+
providing a clean interface for initializing projects with optimal
|
|
6
|
+
Claude Code and Claude MPM standards.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def add_mpm_init_subparser(subparsers: Any) -> None:
|
|
14
|
+
"""
|
|
15
|
+
Add the mpm-init subparser to the main parser.
|
|
16
|
+
|
|
17
|
+
WHY: The mpm-init command sets up projects for optimal use with
|
|
18
|
+
Claude Code and Claude MPM by delegating to the Agentic Coder Optimizer.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
subparsers: The subparsers object to add the mpm-init command to
|
|
22
|
+
"""
|
|
23
|
+
mpm_init_parser = subparsers.add_parser(
|
|
24
|
+
"mpm-init",
|
|
25
|
+
help="Initialize project for optimal Claude Code and Claude MPM usage",
|
|
26
|
+
description=(
|
|
27
|
+
"Initialize a project with comprehensive documentation, single-path workflows, "
|
|
28
|
+
"and optimized structure for AI agent understanding. Uses the Agentic Coder "
|
|
29
|
+
"Optimizer agent to establish clear standards and remove ambiguity."
|
|
30
|
+
),
|
|
31
|
+
epilog=(
|
|
32
|
+
"Examples:\n"
|
|
33
|
+
" claude-mpm mpm-init # Initialize current directory\n"
|
|
34
|
+
" claude-mpm mpm-init --project-type web # Initialize as web project\n"
|
|
35
|
+
" claude-mpm mpm-init --framework react # Initialize with React framework\n"
|
|
36
|
+
" claude-mpm mpm-init /path/to/project --force # Force reinitialize project"
|
|
37
|
+
),
|
|
38
|
+
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# Project configuration options
|
|
42
|
+
config_group = mpm_init_parser.add_argument_group("project configuration")
|
|
43
|
+
config_group.add_argument(
|
|
44
|
+
"--project-type",
|
|
45
|
+
choices=["web", "api", "cli", "library", "mobile", "desktop", "fullstack", "data", "ml"],
|
|
46
|
+
help="Type of project to initialize (auto-detected if not specified)"
|
|
47
|
+
)
|
|
48
|
+
config_group.add_argument(
|
|
49
|
+
"--framework",
|
|
50
|
+
type=str,
|
|
51
|
+
help="Specific framework to configure (e.g., react, vue, django, fastapi, express)"
|
|
52
|
+
)
|
|
53
|
+
config_group.add_argument(
|
|
54
|
+
"--language",
|
|
55
|
+
choices=["python", "javascript", "typescript", "go", "rust", "java", "cpp"],
|
|
56
|
+
help="Primary programming language (auto-detected if not specified)"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# Initialization options
|
|
60
|
+
init_group = mpm_init_parser.add_argument_group("initialization options")
|
|
61
|
+
init_group.add_argument(
|
|
62
|
+
"--force",
|
|
63
|
+
action="store_true",
|
|
64
|
+
help="Force reinitialization even if project is already configured"
|
|
65
|
+
)
|
|
66
|
+
init_group.add_argument(
|
|
67
|
+
"--minimal",
|
|
68
|
+
action="store_true",
|
|
69
|
+
help="Create minimal configuration (CLAUDE.md only, no additional setup)"
|
|
70
|
+
)
|
|
71
|
+
init_group.add_argument(
|
|
72
|
+
"--comprehensive",
|
|
73
|
+
action="store_true",
|
|
74
|
+
help="Create comprehensive setup including CI/CD, testing, and deployment configs"
|
|
75
|
+
)
|
|
76
|
+
init_group.add_argument(
|
|
77
|
+
"--use-venv",
|
|
78
|
+
action="store_true",
|
|
79
|
+
help="Use traditional Python venv instead of mamba/conda environment"
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# Template options
|
|
83
|
+
template_group = mpm_init_parser.add_argument_group("template options")
|
|
84
|
+
template_group.add_argument(
|
|
85
|
+
"--template",
|
|
86
|
+
type=str,
|
|
87
|
+
help="Use a specific template from claude-mpm templates library"
|
|
88
|
+
)
|
|
89
|
+
template_group.add_argument(
|
|
90
|
+
"--list-templates",
|
|
91
|
+
action="store_true",
|
|
92
|
+
help="List available project templates"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Output options
|
|
96
|
+
output_group = mpm_init_parser.add_argument_group("output options")
|
|
97
|
+
output_group.add_argument(
|
|
98
|
+
"--dry-run",
|
|
99
|
+
action="store_true",
|
|
100
|
+
help="Show what would be done without making changes"
|
|
101
|
+
)
|
|
102
|
+
output_group.add_argument(
|
|
103
|
+
"--json",
|
|
104
|
+
action="store_true",
|
|
105
|
+
help="Output results in JSON format"
|
|
106
|
+
)
|
|
107
|
+
output_group.add_argument(
|
|
108
|
+
"--verbose",
|
|
109
|
+
action="store_true",
|
|
110
|
+
help="Show detailed output during initialization"
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Path argument
|
|
114
|
+
mpm_init_parser.add_argument(
|
|
115
|
+
"project_path",
|
|
116
|
+
nargs="?",
|
|
117
|
+
default=".",
|
|
118
|
+
help="Path to project directory (default: current directory)"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# Set the command handler
|
|
122
|
+
mpm_init_parser.set_defaults(command="mpm-init")
|
claude_mpm/constants.py
CHANGED
|
@@ -43,6 +43,7 @@ class CLICommands(str, Enum):
|
|
|
43
43
|
CLEANUP = "cleanup-memory"
|
|
44
44
|
MCP = "mcp"
|
|
45
45
|
DOCTOR = "doctor"
|
|
46
|
+
DASHBOARD = "dashboard"
|
|
46
47
|
|
|
47
48
|
def with_prefix(self, prefix: CLIPrefix = CLIPrefix.MPM) -> str:
|
|
48
49
|
"""Get command with prefix."""
|
|
@@ -99,6 +100,15 @@ class MonitorCommands(str, Enum):
|
|
|
99
100
|
PORT = "port"
|
|
100
101
|
|
|
101
102
|
|
|
103
|
+
class DashboardCommands(str, Enum):
|
|
104
|
+
"""Dashboard subcommand constants."""
|
|
105
|
+
|
|
106
|
+
START = "start"
|
|
107
|
+
STOP = "stop"
|
|
108
|
+
STATUS = "status"
|
|
109
|
+
OPEN = "open"
|
|
110
|
+
|
|
111
|
+
|
|
102
112
|
class ConfigCommands(str, Enum):
|
|
103
113
|
"""Config subcommand constants."""
|
|
104
114
|
|
|
@@ -239,17 +239,30 @@ class CodeAnalysisRunner:
|
|
|
239
239
|
|
|
240
240
|
# Build command
|
|
241
241
|
cmd = self._build_command(request)
|
|
242
|
+
self.logger.info(f"Starting analysis subprocess: {' '.join(cmd)}")
|
|
242
243
|
|
|
243
244
|
# Start subprocess
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
245
|
+
try:
|
|
246
|
+
self.current_process = subprocess.Popen(
|
|
247
|
+
cmd,
|
|
248
|
+
stdout=subprocess.PIPE,
|
|
249
|
+
stderr=subprocess.PIPE,
|
|
250
|
+
text=True,
|
|
251
|
+
bufsize=1,
|
|
252
|
+
universal_newlines=True,
|
|
253
|
+
env=self._get_subprocess_env(),
|
|
254
|
+
)
|
|
255
|
+
self.logger.debug(
|
|
256
|
+
f"Subprocess started with PID: {self.current_process.pid}"
|
|
257
|
+
)
|
|
258
|
+
except FileNotFoundError as e:
|
|
259
|
+
raise subprocess.SubprocessError(
|
|
260
|
+
f"Python executable not found: {cmd[0]}"
|
|
261
|
+
) from e
|
|
262
|
+
except Exception as e:
|
|
263
|
+
raise subprocess.SubprocessError(
|
|
264
|
+
f"Failed to start subprocess: {e}"
|
|
265
|
+
) from e
|
|
253
266
|
|
|
254
267
|
# Process output
|
|
255
268
|
self._process_output(request)
|
|
@@ -275,20 +288,34 @@ class CodeAnalysisRunner:
|
|
|
275
288
|
},
|
|
276
289
|
)
|
|
277
290
|
else:
|
|
278
|
-
# Failure
|
|
291
|
+
# Failure - capture any remaining stderr
|
|
292
|
+
stderr_output = ""
|
|
293
|
+
if self.current_process.stderr:
|
|
294
|
+
try:
|
|
295
|
+
# Read any remaining stderr output
|
|
296
|
+
stderr_lines = []
|
|
297
|
+
for line in self.current_process.stderr:
|
|
298
|
+
stderr_lines.append(line.strip())
|
|
299
|
+
stderr_output = "\n".join(stderr_lines)
|
|
300
|
+
except Exception as e:
|
|
301
|
+
stderr_output = f"Failed to read stderr: {e}"
|
|
302
|
+
|
|
279
303
|
self.stats["analyses_failed"] += 1
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
)
|
|
285
|
-
self._emit_error(
|
|
286
|
-
request.request_id,
|
|
287
|
-
f"Analysis failed with code {return_code}: {stderr}",
|
|
288
|
-
)
|
|
304
|
+
error_msg = f"Analysis failed with code {return_code}"
|
|
305
|
+
if stderr_output:
|
|
306
|
+
error_msg += f": {stderr_output}"
|
|
307
|
+
|
|
308
|
+
self.logger.error(f"Subprocess failed: {error_msg}")
|
|
309
|
+
self._emit_error(request.request_id, error_msg)
|
|
289
310
|
|
|
311
|
+
except subprocess.SubprocessError as e:
|
|
312
|
+
self.logger.error(f"Subprocess error for request {request.request_id}: {e}")
|
|
313
|
+
self.stats["analyses_failed"] += 1
|
|
314
|
+
self._emit_error(request.request_id, f"Failed to start analyzer: {e}")
|
|
290
315
|
except Exception as e:
|
|
291
|
-
self.logger.error(
|
|
316
|
+
self.logger.error(
|
|
317
|
+
f"Error processing request {request.request_id}: {e}", exc_info=True
|
|
318
|
+
)
|
|
292
319
|
self.stats["analyses_failed"] += 1
|
|
293
320
|
self._emit_error(request.request_id, str(e))
|
|
294
321
|
|
|
@@ -308,16 +335,16 @@ class CodeAnalysisRunner:
|
|
|
308
335
|
# Get Python executable
|
|
309
336
|
python_exe = sys.executable
|
|
310
337
|
|
|
311
|
-
# Build command - use the
|
|
338
|
+
# Build command - use the CLI analyze-code command
|
|
312
339
|
cmd = [
|
|
313
340
|
python_exe,
|
|
314
341
|
"-m",
|
|
315
|
-
"claude_mpm
|
|
316
|
-
"
|
|
342
|
+
"claude_mpm",
|
|
343
|
+
"analyze-code",
|
|
317
344
|
request.path,
|
|
318
345
|
"--emit-events",
|
|
319
|
-
"--output
|
|
320
|
-
"json
|
|
346
|
+
"--output",
|
|
347
|
+
"json",
|
|
321
348
|
]
|
|
322
349
|
|
|
323
350
|
# Add optional parameters
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
class t{constructor(){this.container=null,this.svg=null,this.treeData=null,this.root=null,this.treeLayout=null,this.treeGroup=null,this.events=[],this.todoWriteStack=[],this.activeAgent=null,this.activeAgentStack=[],this.margin={top:20,right:120,bottom:20,left:120},this.width=960-this.margin.left-this.margin.right,this.height=500-this.margin.top-this.margin.bottom,this.nodeId=0,this.duration=750,this.timeRange="30min",this.searchTerm="",this.tooltip=null,this.initialized=!1}initialize(){if(console.log("ActivityTree.initialize() called, initialized:",this.initialized),this.initialized)return void console.log("Activity tree already initialized, skipping");if(this.container=document.getElementById("activity-tree"),!this.container)return void console.error("Activity tree container (#activity-tree) not found in DOM");console.log("Activity tree container found:",this.container);const t=document.getElementById("activity-tab");if(t){if(!t.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.setupControls(),this.initializeTreeData(),this.subscribeToEvents(),void(this.initialized=!0);this.setupControls(),this.createVisualization(),this.svg&&this.treeGroup?(this.initializeTreeData(),this.update(this.root),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")):console.error("Failed to create D3 visualization elements")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.svg||(console.log("Creating deferred visualization..."),this.createVisualization(),this.svg&&this.treeGroup&&this.update(this.root)),this.root&&this.svg&&(console.log("Updating tree with current data..."),this.update(this.root))}setupControls(){const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAll());const e=document.getElementById("collapse-all");e&&e.addEventListener("click",()=>this.collapseAll());const i=document.getElementById("reset-zoom");i&&i.addEventListener("click",()=>this.resetZoom());const n=document.getElementById("time-range");n&&n.addEventListener("change",t=>{this.timeRange=t.target.value,this.filterEventsByTime()});const o=document.getElementById("activity-search");o&&o.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.highlightSearchResults()})}createVisualization(){if("undefined"==typeof d3)return void console.error("D3.js is not loaded! Cannot create activity tree visualization.");const t=this.container.getBoundingClientRect();this.width=t.width-this.margin.left-this.margin.right,this.height=Math.max(500,t.height-this.margin.top-this.margin.bottom),console.log("Creating D3 visualization with dimensions:",{width:this.width,height:this.height}),d3.select(this.container).select("svg").remove(),this.svg=d3.select(this.container).append("svg").attr("width","100%").attr("height","100%").attr("viewBox",`0 0 ${this.width+this.margin.left+this.margin.right} ${this.height+this.margin.top+this.margin.bottom}`),this.treeGroup=this.svg.append("g").attr("class","tree-group").attr("transform",`translate(${this.margin.left},${this.margin.top})`);const e=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.call(e),this.treeLayout=d3.tree().size([this.height,this.width]),this.tooltip=d3.select("body").append("div").attr("class","activity-tooltip").style("opacity",0)}initializeTreeData(){this.treeData={name:"PM",type:"pm",icon:"🎯",children:[],_children:null},this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0}subscribeToEvents(){if(!window.socketClient)return console.warn("Socket client not available for activity tree"),void setTimeout(()=>this.subscribeToEvents(),1e3);if(window.socketClient.onEventUpdate(t=>{const e=t.length-this.events.length;if(e>0){const i=t.slice(this.events.length);console.log("ActivityTree: Received new events:",i.map(t=>({type:t.type,subtype:t.subtype,hook_event_name:t.hook_event_name,tool_name:t.tool_name,originalEventName:t.originalEventName})));const n=i.filter(t=>t.hook_event_name).length,o=i.filter(t=>"hook"===t.type||"todo"===t.type||"subagent"===t.type).length;console.log(`ActivityTree: ${n}/${e} new events have hook_event_name, ${o} are hook/todo/subagent type`),i.forEach(t=>{t.hook_event_name?this.processEvent(t):"hook"!==t.type&&"todo"!==t.type&&"subagent"!==t.type||console.warn("ActivityTree: Missing hook_event_name for relevant event:",{type:t.type,subtype:t.subtype,tool_name:t.tool_name})}),this.events=[...t]}}),window.socketClient&&window.socketClient.events){console.log(`Processing ${window.socketClient.events.length} existing events for activity tree`);const t=window.socketClient.events.filter(t=>t.hook_event_name).length,e=window.socketClient.events.filter(t=>"hook"===t.type||"todo"===t.type||"subagent"===t.type).length;console.log(`ActivityTree: ${t}/${window.socketClient.events.length} existing events have hook_event_name, ${e} are hook/todo/subagent type`);const i=window.socketClient.events.slice(0,5);console.log("ActivityTree: Sample of existing events:",i.map(t=>({type:t.type,subtype:t.subtype,hook_event_name:t.hook_event_name,tool_name:t.tool_name,originalEventName:t.originalEventName}))),window.socketClient.events.forEach(t=>{t.hook_event_name&&this.processEvent(t)}),this.events=[...window.socketClient.events]}else window.eventViewer&&window.eventViewer.events?(console.log(`Processing ${window.eventViewer.events.length} existing events for activity tree (from eventViewer)`),window.eventViewer.events.forEach(t=>{t.hook_event_name&&this.processEvent(t)}),this.events=[...window.eventViewer.events]):(console.log("No existing events found for activity tree"),this.events=[])}processEvent(t){if(!t||!t.hook_event_name)return void console.log("ActivityTree: Ignoring invalid event",t);console.log(`ActivityTree: Processing event: ${t.hook_event_name}`,t);const e=t.hook_event_name,i=new Date(t.timestamp);if(this.isEventInTimeRange(i)){switch(e){case"TodoWrite":this.processTodoWrite(t);break;case"SubagentStart":this.processSubagentStart(t);break;case"SubagentStop":this.processSubagentStop(t);break;case"PreToolUse":this.processToolUse(t);break;case"PostToolUse":this.updateToolStatus(t,"completed");break;case"Start":this.initializeTreeData(),this.update(this.root)}this.updateStats()}}processTodoWrite(t){const e=t.todos||t.data?.todos||[];if(0===e.length)return;const i=e.find(t=>"in_progress"===t.status);if(!i)return;const n={name:i.activeForm||i.content,type:"todowrite",icon:"📝",content:i.content,status:i.status,timestamp:t.timestamp,children:[],_children:null,eventId:t.id};this.root.data.children||(this.root.data.children=[]),this.root.data.children.push(n),this.todoWriteStack.push({node:n,content:i.content}),this.update(this.root)}processSubagentStart(t){const e=t.agent_name||t.data?.agent_name||t.data?.agent_type||"unknown",i={name:e,type:"agent",icon:this.getAgentIcon(e),timestamp:t.timestamp,children:[],_children:null,eventId:t.id,sessionId:t.session_id||t.data?.session_id};let n=null;if(this.todoWriteStack.length>0){const t=this.todoWriteStack[this.todoWriteStack.length-1];t.content&&t.content.toLowerCase().includes(e.toLowerCase())&&(n=t.node)}n||(n=this.root.data),n.children||(n.children=[]),n.children.push(i),this.activeAgent=i,this.activeAgentStack.push(i),this.update(this.root)}processSubagentStop(t){const e=t.session_id||t.data?.session_id;this.activeAgent&&this.activeAgent.sessionId===e&&(this.activeAgent.status="completed",this.activeAgentStack.pop(),this.activeAgent=this.activeAgentStack.length>0?this.activeAgentStack[this.activeAgentStack.length-1]:null),this.update(this.root)}processToolUse(t){const e=t.tool_name||t.data?.tool_name||"unknown",i=this.getToolIcon(e),n=t.tool_parameters||t.data?.tool_parameters||t.data?.tool_params||{},o={name:e,type:"tool",icon:i,timestamp:t.timestamp,status:"in_progress",children:[],_children:null,eventId:t.id};"Read"===e&&n.file_path?o.children.push({name:n.file_path,type:"file",icon:"📄",timestamp:t.timestamp}):"Edit"===e&&n.file_path?o.children.push({name:n.file_path,type:"file",icon:"✏️",timestamp:t.timestamp}):"Write"===e&&n.file_path?o.children.push({name:n.file_path,type:"file",icon:"💾",timestamp:t.timestamp}):"Bash"===e&&n.command?o.children.push({name:n.command.substring(0,50)+(n.command.length>50?"...":""),type:"command",icon:"⚡",timestamp:t.timestamp}):"WebFetch"===e&&n.url&&o.children.push({name:n.url,type:"url",icon:"🌐",timestamp:t.timestamp});let s=this.activeAgent||this.root.data;s.children||(s.children=[]),s.children.push(o),this.update(this.root)}updateToolStatus(t,e){const i=n=>{if(n.eventId===t.id)return n.status=e,!0;if(n.children)for(let t of n.children)if(i(t))return!0;if(n._children)for(let t of n._children)if(i(t))return!0;return!1};i(this.root.data),this.update(this.root)}getAgentIcon(t){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️"}[t.toLowerCase()]||"🤖"}getToolIcon(t){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[t.toLowerCase()]||"🔧"}update(t){const e=this.treeLayout(this.root),i=e.descendants(),n=e.links();i.forEach(t=>{t.y=180*t.depth});const o=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),s=o.enter().append("g").attr("class","node").attr("transform",e=>`translate(${t.y0},${t.x0})`).on("click",(t,e)=>this.click(e));s.append("circle").attr("class",t=>`node-circle ${t.data.type}`).attr("r",1e-6).style("fill",t=>t._children?this.getNodeColor(t.data.type):"#fff").style("stroke",t=>this.getNodeColor(t.data.type)),s.append("text").attr("class","node-icon").attr("dy",".35em").attr("text-anchor","middle").style("font-size","14px").text(t=>t.data.icon||""),s.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>t.children||t._children?-25:25).attr("text-anchor",t=>t.children||t._children?"end":"start").text(t=>t.data.name).style("fill-opacity",1e-6),s.on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip());const a=s.merge(o);a.transition().duration(this.duration).attr("transform",t=>`translate(${t.y},${t.x})`),a.select("circle.node-circle").attr("r",10).style("fill",t=>"in_progress"===t.data.status||t._children?this.getNodeColor(t.data.type):"#fff").attr("class",t=>{let e=`node-circle ${t.data.type}`;return"in_progress"===t.data.status&&(e+=" pulsing"),"failed"===t.data.status&&(e+=" failed"),e}),a.select("text.node-label").style("fill-opacity",1);const r=o.exit().transition().duration(this.duration).attr("transform",e=>`translate(${t.y},${t.x})`).remove();r.select("circle").attr("r",1e-6),r.select("text").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(n,t=>t.target.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.diagonal({source:i,target:i})}).merge(l).transition().duration(this.duration).attr("d",this.diagonal),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.diagonal({source:i,target:i})}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y}),this.updateBreadcrumb(t)}diagonal(t){return`M ${t.source.y} ${t.source.x}\n C ${(t.source.y+t.target.y)/2} ${t.source.x},\n ${(t.source.y+t.target.y)/2} ${t.target.x},\n ${t.target.y} ${t.target.x}`}click(t){t.children?(t._children=t.children,t.children=null):(t.children=t._children,t._children=null),this.update(t),this.updateBreadcrumb(t)}getNodeColor(t){return{pm:"#4299e1",todowrite:"#48bb78",agent:"#ed8936",tool:"#9f7aea",file:"#38b2ac",command:"#f56565",url:"#4299e1"}[t]||"#718096"}showTooltip(t,e){const i=`\n <strong>${e.data.name}</strong><br>\n Type: ${e.data.type}<br>\n ${e.data.timestamp?`Time: ${new Date(e.data.timestamp).toLocaleTimeString()}`:""}\n ${e.data.status?`<br>Status: ${e.data.status}`:""}\n `;this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip.transition().duration(500).style("opacity",0)}expandAll(){const t=e=>{e._children&&(e.children=e._children,e._children=null),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root)}collapseAll(){const t=e=>{e.children&&(e._children=e.children,e._children.forEach(t),e.children=null)};this.root.children?.forEach(t),this.update(this.root)}resetZoom(){if(!this.svg)return void console.warn("Cannot reset zoom: SVG not initialized");const t=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.transition().duration(750).call(t.transform,d3.zoomIdentity),this.treeGroup.transition().duration(750).attr("transform",`translate(${this.margin.left},${this.margin.top})`)}isEventInTimeRange(t){if("all"===this.timeRange)return!0;const e=(new Date-t)/6e4;switch(this.timeRange){case"10min":return e<=10;case"30min":return e<=30;case"hour":return e<=60;default:return!0}}filterEventsByTime(){this.initializeTreeData(),window.eventViewer&&window.eventViewer.events&&window.eventViewer.events.forEach(t=>{this.processEvent(t)})}updateStats(){const t=this.countNodes(this.root),e=this.countActiveNodes(this.root.data),i=this.getTreeDepth(this.root);document.getElementById("node-count").textContent=t,document.getElementById("active-count").textContent=e,document.getElementById("tree-depth").textContent=i}countNodes(t){let e=1;return t.children&&t.children.forEach(t=>{e+=this.countNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countNodes(t)}),e}countActiveNodes(t){let e="in_progress"===t.status?1:0;return t.children&&t.children.forEach(t=>{e+=this.countActiveNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countActiveNodes(t)}),e}getTreeDepth(t){if(!t.children&&!t._children)return 0;const e=(t.children||t._children).map(t=>this.getTreeDepth(t));return Math.max(...e)+1}updateBreadcrumb(t){const e=[];let i=t;for(;i;)e.unshift(i.data.name),i=i.parent;const n=document.getElementById("activity-breadcrumb");n&&(n.textContent=e.join(" > "))}highlightSearchResults(){this.treeGroup.selectAll(".node-label").style("font-weight","normal").style("fill","#2d3748"),this.searchTerm&&this.treeGroup.selectAll(".node-label").style("font-weight",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"bold":"normal").style("fill",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"#e53e3e":"#2d3748")}}window.ActivityTree=t;const e=()=>{let e=null;const i=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e),setTimeout(()=>{console.log("Attempting to initialize Activity Tree visualization..."),e.initialize()},100)};document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",t=>{"activity"===t.target.getAttribute("data-tab")&&(console.log("Activity tab button clicked, initializing tree..."),i(),e&&setTimeout(()=>e.renderWhenVisible(),150))})}),document.addEventListener("tabChanged",t=>{t.detail&&"activity"===t.detail.newTab&&(console.log("Tab changed to activity, initializing tree..."),i(),e&&setTimeout(()=>e.renderWhenVisible(),150))});const n=document.querySelector(".tab-button.active");n&&"activity"===n.getAttribute("data-tab")&&i(),window.activityTree=()=>e};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e();
|
|
1
|
+
class t{constructor(){this.container=null,this.svg=null,this.treeData=null,this.root=null,this.treeLayout=null,this.treeGroup=null,this.events=[],this.todoWriteStack=[],this.activeAgent=null,this.activeAgentStack=[],this.margin={top:20,right:120,bottom:20,left:120},this.width=960-this.margin.left-this.margin.right,this.height=500-this.margin.top-this.margin.bottom,this.nodeId=0,this.duration=750,this.timeRange="30min",this.searchTerm="",this.tooltip=null,this.initialized=!1}initialize(){if(console.log("ActivityTree.initialize() called, initialized:",this.initialized),this.initialized)return void console.log("Activity tree already initialized, skipping");if(this.container=document.getElementById("activity-tree-container"),!this.container&&(this.container=document.getElementById("activity-tree"),!this.container))return void console.error("Activity tree container not found in DOM");this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing existing text content from container:",this.container.textContent),this.container.textContent=""),console.log("Activity tree container found:",this.container);const t=document.getElementById("activity-tab");if(t){if(!t.classList.contains("active"))return console.log("Activity tab not active, initializing but deferring render"),this.container.textContent&&this.container.textContent.trim()&&(this.container.textContent=""),this.setupControls(),this.initializeTreeData(),this.subscribeToEvents(),void(this.initialized=!0);if(this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing container text before creating visualization"),this.container.textContent=""),this.setupControls(),this.createVisualization(),!this.svg||!this.treeGroup)return console.error("Failed to create D3 visualization elements"),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ Failed to create visualization. Please refresh the page.</div>'));this.initializeTreeData(),this.root?this.update(this.root):console.warn("Root not created, skipping initial update"),this.subscribeToEvents(),this.initialized=!0,console.log("Activity tree initialization complete")}else console.error("Activity tab panel (#activity-tab) not found in DOM")}forceShow(){if(console.log("ActivityTree.forceShow() called"),this.container||(this.container=document.getElementById("activity-tree-container")||document.getElementById("activity-tree"),this.container)){if(this.container.textContent&&this.container.textContent.trim()&&(console.log("Clearing text from container:",this.container.textContent),this.container.innerHTML=""),this.svg||this.createVisualization(),this.root||this.initializeTreeData(),this.root&&this.svg&&this.treeGroup&&this.update(this.root),this.svg){const t=this.svg.node();t&&(t.style.display="block",t.style.visibility="visible")}}else console.error("Cannot find activity tree container")}renderWhenVisible(){if(console.log("ActivityTree.renderWhenVisible() called"),this.container&&this.container.textContent&&this.container.textContent.trim()&&!this.svg&&(console.log("Clearing text content before rendering:",this.container.textContent),this.container.textContent=""),!this.initialized)return console.log("Not initialized yet, calling initialize..."),void this.initialize();this.svg||(console.log("Creating deferred visualization..."),this.createVisualization(),this.svg&&this.treeGroup&&this.root?this.update(this.root):this.root||(console.warn("No root node available, initializing tree data..."),this.initializeTreeData(),this.root&&this.svg&&this.treeGroup&&this.update(this.root))),this.root&&this.svg?(console.log("Updating tree with current data..."),this.update(this.root)):console.warn("Cannot update tree - missing components:",{hasRoot:!!this.root,hasSvg:!!this.svg,hasTreeGroup:!!this.treeGroup})}setupControls(){const t=document.getElementById("expand-all");t&&t.addEventListener("click",()=>this.expandAll());const e=document.getElementById("collapse-all");e&&e.addEventListener("click",()=>this.collapseAll());const i=document.getElementById("reset-zoom");i&&i.addEventListener("click",()=>this.resetZoom());const o=document.getElementById("time-range");o&&o.addEventListener("change",t=>{this.timeRange=t.target.value,this.filterEventsByTime()});const n=document.getElementById("activity-search");n&&n.addEventListener("input",t=>{this.searchTerm=t.target.value.toLowerCase(),this.highlightSearchResults()})}createVisualization(){if("undefined"==typeof d3)return console.error("D3.js is not loaded! Cannot create activity tree visualization."),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ D3.js is not loaded. Cannot create visualization.</div>'));const t=this.container.getBoundingClientRect();this.width=t.width-this.margin.left-this.margin.right,this.height=Math.max(500,t.height-this.margin.top-this.margin.bottom),console.log("Creating D3 visualization with dimensions:",{width:this.width,height:this.height}),d3.select(this.container).selectAll("*").remove(),this.svg=d3.select(this.container).append("svg").attr("width","100%").attr("height","100%").attr("viewBox",`0 0 ${this.width+this.margin.left+this.margin.right} ${this.height+this.margin.top+this.margin.bottom}`),this.treeGroup=this.svg.append("g").attr("class","tree-group").attr("transform",`translate(${this.margin.left},${this.margin.top})`);const e=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.call(e),this.treeLayout=d3.tree().size([this.height,this.width]),console.log("ActivityTree: Tree layout created:",this.treeLayout),this.tooltip=d3.select("body").append("div").attr("class","activity-tooltip").style("opacity",0),console.log("ActivityTree: Visualization complete, svg:",this.svg,"treeGroup:",this.treeGroup)}initializeTreeData(){if(console.log("ActivityTree: Initializing tree data"),this.treeData={name:"PM",type:"pm",icon:"🎯",children:[],_children:null},"undefined"==typeof d3)return console.error("ActivityTree: D3 is not available - cannot create hierarchy!"),void(this.container&&(this.container.innerHTML='<div style="padding: 20px; text-align: center; color: #e53e3e;">⚠️ Waiting for D3.js to load...</div>'));this.root=d3.hierarchy(this.treeData),this.root.x0=this.height/2,this.root.y0=0,console.log("ActivityTree: Root node created:",this.root),this.updateStats()}subscribeToEvents(){if(!window.socketClient)return console.warn("Socket client not available for activity tree"),void setTimeout(()=>this.subscribeToEvents(),1e3);console.log("ActivityTree: Setting up event subscription"),window.socketClient.onEventUpdate(t=>{console.log(`ActivityTree: onEventUpdate called with ${t.length} total events`);const e=t.length-this.events.length;if(e>0){const i=t.slice(this.events.length);console.log(`ActivityTree: Processing ${e} new events`,i),i.forEach(t=>{this.processEvent(t)}),this.events=[...t]}});const t=window.socketClient?.events||window.eventViewer?.events||[];t.length>0?(console.log(`ActivityTree: Processing ${t.length} existing events`,t),t.forEach(t=>{this.processEvent(t)}),this.events=[...t]):(console.log("ActivityTree: No existing events found"),this.events=[])}processEvent(t){if(!t)return void console.log("ActivityTree: Ignoring null event");let e=null;if(t.hook_event_name)e=t.hook_event_name;else if("hook"===t.type&&t.subtype){e={pre_tool:"PreToolUse",post_tool:"PostToolUse",subagent_start:"SubagentStart",subagent_stop:"SubagentStop",todo_write:"TodoWrite"}[t.subtype]}else"todo"===t.type&&"updated"===t.subtype?e="TodoWrite":"subagent"===t.type?"started"===t.subtype?e="SubagentStart":"stopped"===t.subtype&&(e="SubagentStop"):"start"===t.type&&(e="Start");if(!e)return void("hook"!==t.type&&"todo"!==t.type&&"subagent"!==t.type||console.log("ActivityTree: Cannot determine event type for:",t));console.log(`ActivityTree: Processing event: ${e}`,t);const i=new Date(t.timestamp);if(this.isEventInTimeRange(i)){switch(e){case"TodoWrite":this.processTodoWrite(t);break;case"SubagentStart":this.processSubagentStart(t);break;case"SubagentStop":this.processSubagentStop(t);break;case"PreToolUse":this.processToolUse(t);break;case"PostToolUse":this.updateToolStatus(t,"completed");break;case"Start":this.initializeTreeData(),this.update(this.root)}this.updateStats()}}processTodoWrite(t){console.log("ActivityTree: Processing TodoWrite event:",t);let e=t.todos||t.data?.todos||t.data||[];if(e&&"object"==typeof e&&e.todos&&(e=e.todos),!Array.isArray(e))return void console.log("ActivityTree: Invalid todos format in event:",t);if(0===e.length)return void console.log("ActivityTree: No todos in event");const i=e.find(t=>"in_progress"===t.status);if(!i)return void console.log("ActivityTree: No in-progress todo found");console.log("ActivityTree: Found active todo:",i);const o={name:i.activeForm||i.content,type:"todowrite",icon:"📝",content:i.content,status:i.status,timestamp:t.timestamp,children:[],_children:null,eventId:t.id};this.root?this.root.data?(this.root.data.children||(this.root.data.children=[]),console.log("ActivityTree: Adding TodoWrite node to root"),this.root.data.children.push(o),this.todoWriteStack.push({node:o,content:i.content}),console.log("ActivityTree: Calling update with root:",this.root),this.update(this.root),console.log("ActivityTree: Update complete")):console.error("ActivityTree: Root has no data!"):console.error("ActivityTree: No root node!")}processSubagentStart(t){const e=t.agent_name||t.data?.agent_name||t.data?.agent_type||t.agent_type||t.agent||"unknown",i={name:e,type:"agent",icon:this.getAgentIcon(e),timestamp:t.timestamp,children:[],_children:null,eventId:t.id,sessionId:t.session_id||t.data?.session_id};let o=null;if(this.todoWriteStack.length>0){const t=this.todoWriteStack[this.todoWriteStack.length-1];t.content&&t.content.toLowerCase().includes(e.toLowerCase())&&(o=t.node)}o||(o=this.root.data),o.children||(o.children=[]),o.children.push(i),this.activeAgent=i,this.activeAgentStack.push(i),this.update(this.root)}processSubagentStop(t){const e=t.session_id||t.data?.session_id;this.activeAgent&&this.activeAgent.sessionId===e&&(this.activeAgent.status="completed",this.activeAgentStack.pop(),this.activeAgent=this.activeAgentStack.length>0?this.activeAgentStack[this.activeAgentStack.length-1]:null),this.update(this.root)}processToolUse(t){const e=t.tool_name||t.data?.tool_name||t.tool||t.data?.tool||"unknown",i=this.getToolIcon(e),o=t.tool_parameters||t.data?.tool_parameters||t.parameters||t.data?.parameters||{},n={name:e,type:"tool",icon:i,timestamp:t.timestamp,status:"in_progress",children:[],_children:null,eventId:t.id};"Read"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"📄",timestamp:t.timestamp}):"Edit"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"✏️",timestamp:t.timestamp}):"Write"===e&&o.file_path?n.children.push({name:o.file_path,type:"file",icon:"💾",timestamp:t.timestamp}):"Bash"===e&&o.command?n.children.push({name:o.command.substring(0,50)+(o.command.length>50?"...":""),type:"command",icon:"⚡",timestamp:t.timestamp}):"WebFetch"===e&&o.url&&n.children.push({name:o.url,type:"url",icon:"🌐",timestamp:t.timestamp});let s=this.activeAgent||this.root.data;s.children||(s.children=[]),s.children.push(n),this.update(this.root)}updateToolStatus(t,e){const i=o=>{if(o.eventId===t.id)return o.status=e,!0;if(o.children)for(let t of o.children)if(i(t))return!0;if(o._children)for(let t of o._children)if(i(t))return!0;return!1};i(this.root.data),this.update(this.root)}getAgentIcon(t){return{engineer:"👷",research:"🔬",qa:"🧪",ops:"⚙️",pm:"📊",architect:"🏗️"}[t.toLowerCase()]||"🤖"}getToolIcon(t){return{read:"👁️",write:"✍️",edit:"✏️",bash:"💻",webfetch:"🌐",grep:"🔍",glob:"📂",todowrite:"📝"}[t.toLowerCase()]||"🔧"}update(t){if(console.log("ActivityTree: update() called with source:",t),"undefined"==typeof d3)return void console.error("ActivityTree: Cannot update - D3.js not loaded");if(!this.svg||!this.treeGroup){if(console.warn("ActivityTree: Cannot update - SVG not initialized"),!this.container)return;if(console.log("Attempting to create visualization from update()"),this.createVisualization(),!this.svg||!this.treeGroup)return void console.error("Failed to create visualization in update()")}if(!this.treeLayout){if(console.warn("ActivityTree: Cannot update - tree layout not initialized"),"undefined"==typeof d3)return;this.treeLayout=d3.tree().size([this.height,this.width]),console.log("Created tree layout in update()")}if(!t||!t.data)return void console.error("ActivityTree: Invalid source in update()",t);if(!this.root)return void console.error("ActivityTree: No root node available for update");let e;try{e=this.treeLayout(this.root)}catch(c){return void console.error("ActivityTree: Error computing tree layout:",c)}const i=e.descendants(),o=e.links();if(console.log(`ActivityTree: Updating tree with ${i.length} nodes`),1===i.length&&this.container){this.container.querySelector("svg")||console.warn("SVG element not found in container after update")}i.forEach(t=>{t.y=180*t.depth});const n=this.treeGroup.selectAll("g.node").data(i,t=>t.id||(t.id=++this.nodeId)),s=n.enter().append("g").attr("class","node").attr("transform",e=>`translate(${t.y0},${t.x0})`).on("click",(t,e)=>this.click(e));s.append("circle").attr("class",t=>`node-circle ${t.data.type}`).attr("r",1e-6).style("fill",t=>t._children?this.getNodeColor(t.data.type):"#fff").style("stroke",t=>this.getNodeColor(t.data.type)),s.append("text").attr("class","node-icon").attr("dy",".35em").attr("text-anchor","middle").style("font-size","14px").text(t=>t.data.icon||""),s.append("text").attr("class","node-label").attr("dy",".35em").attr("x",t=>t.children||t._children?-25:25).attr("text-anchor",t=>t.children||t._children?"end":"start").text(t=>t.data.name).style("fill-opacity",1e-6),s.on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip());const r=s.merge(n);r.transition().duration(this.duration).attr("transform",t=>`translate(${t.y},${t.x})`),r.select("circle.node-circle").attr("r",10).style("fill",t=>"in_progress"===t.data.status||t._children?this.getNodeColor(t.data.type):"#fff").attr("class",t=>{let e=`node-circle ${t.data.type}`;return"in_progress"===t.data.status&&(e+=" pulsing"),"failed"===t.data.status&&(e+=" failed"),e}),r.select("text.node-label").style("fill-opacity",1);const a=n.exit().transition().duration(this.duration).attr("transform",e=>`translate(${t.y},${t.x})`).remove();a.select("circle").attr("r",1e-6),a.select("text").style("fill-opacity",1e-6);const l=this.treeGroup.selectAll("path.link").data(o,t=>t.target.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const i={x:t.x0,y:t.y0};return this.diagonal({source:i,target:i})}).merge(l).transition().duration(this.duration).attr("d",this.diagonal),l.exit().transition().duration(this.duration).attr("d",e=>{const i={x:t.x,y:t.y};return this.diagonal({source:i,target:i})}).remove(),i.forEach(t=>{t.x0=t.x,t.y0=t.y}),this.updateBreadcrumb(t)}diagonal(t){return`M ${t.source.y} ${t.source.x}\n C ${(t.source.y+t.target.y)/2} ${t.source.x},\n ${(t.source.y+t.target.y)/2} ${t.target.x},\n ${t.target.y} ${t.target.x}`}click(t){t.children?(t._children=t.children,t.children=null):(t.children=t._children,t._children=null),this.update(t),this.updateBreadcrumb(t)}getNodeColor(t){return{pm:"#4299e1",todowrite:"#48bb78",agent:"#ed8936",tool:"#9f7aea",file:"#38b2ac",command:"#f56565",url:"#4299e1"}[t]||"#718096"}showTooltip(t,e){const i=`\n <strong>${e.data.name}</strong><br>\n Type: ${e.data.type}<br>\n ${e.data.timestamp?`Time: ${new Date(e.data.timestamp).toLocaleTimeString()}`:""}\n ${e.data.status?`<br>Status: ${e.data.status}`:""}\n `;this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(i).style("left",t.pageX+10+"px").style("top",t.pageY-28+"px")}hideTooltip(){this.tooltip.transition().duration(500).style("opacity",0)}expandAll(){const t=e=>{e._children&&(e.children=e._children,e._children=null),e.children&&e.children.forEach(t)};t(this.root),this.update(this.root)}collapseAll(){const t=e=>{e.children&&(e._children=e.children,e._children.forEach(t),e.children=null)};this.root.children?.forEach(t),this.update(this.root)}resetZoom(){if(!this.svg)return void console.warn("Cannot reset zoom: SVG not initialized");const t=d3.zoom().scaleExtent([.1,3]).on("zoom",t=>{this.treeGroup.attr("transform",`translate(${this.margin.left+t.transform.x},${this.margin.top+t.transform.y}) scale(${t.transform.k})`)});this.svg.transition().duration(750).call(t.transform,d3.zoomIdentity),this.treeGroup.transition().duration(750).attr("transform",`translate(${this.margin.left},${this.margin.top})`)}isEventInTimeRange(t){if("all"===this.timeRange)return!0;const e=(new Date-t)/6e4;switch(this.timeRange){case"10min":return e<=10;case"30min":return e<=30;case"hour":return e<=60;default:return!0}}filterEventsByTime(){this.initializeTreeData(),window.eventViewer&&window.eventViewer.events&&window.eventViewer.events.forEach(t=>{this.processEvent(t)})}updateStats(){if(!this.root||!this.root.data){console.warn("ActivityTree: Cannot update stats - root not initialized");const t=document.getElementById("node-count"),e=document.getElementById("active-count"),i=document.getElementById("tree-depth");return t&&(t.textContent="1"),e&&(e.textContent="0"),void(i&&(i.textContent="0"))}const t=this.countNodes(this.root),e=this.countActiveNodes(this.root.data),i=this.getTreeDepth(this.root),o=document.getElementById("node-count"),n=document.getElementById("active-count"),s=document.getElementById("tree-depth");o&&(o.textContent=t),n&&(n.textContent=e),s&&(s.textContent=i),console.log(`ActivityTree: Stats updated - Nodes: ${t}, Active: ${e}, Depth: ${i}`)}countNodes(t){let e=1;return t.children&&t.children.forEach(t=>{e+=this.countNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countNodes(t)}),e}countActiveNodes(t){let e="in_progress"===t.status?1:0;return t.children&&t.children.forEach(t=>{e+=this.countActiveNodes(t)}),t._children&&t._children.forEach(t=>{e+=this.countActiveNodes(t)}),e}getTreeDepth(t){if(!t.children&&!t._children)return 0;const e=(t.children||t._children).map(t=>this.getTreeDepth(t));return Math.max(...e)+1}updateBreadcrumb(t){const e=[];let i=t;for(;i;)e.unshift(i.data.name),i=i.parent;const o=document.getElementById("activity-breadcrumb");o&&(o.textContent=e.join(" > "))}highlightSearchResults(){this.treeGroup.selectAll(".node-label").style("font-weight","normal").style("fill","#2d3748"),this.searchTerm&&this.treeGroup.selectAll(".node-label").style("font-weight",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"bold":"normal").style("fill",t=>t.data.name.toLowerCase().includes(this.searchTerm)?"#e53e3e":"#2d3748")}}window.ActivityTree=t;const e=()=>{let e=null;const i=()=>{e||(console.log("Creating new Activity Tree instance..."),e=new t,window.activityTreeInstance=e);const i=document.getElementById("activity-tree-container")||document.getElementById("activity-tree");i&&i.textContent&&i.textContent.trim()&&(console.log("Clearing text from activity tree container before init:",i.textContent),i.textContent=""),setTimeout(()=>{console.log("Attempting to initialize Activity Tree visualization..."),e.initialize()},100)};document.querySelectorAll(".tab-button").forEach(t=>{t.addEventListener("click",t=>{"activity"===t.target.getAttribute("data-tab")&&(console.log("Activity tab button clicked, initializing tree..."),i(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))})}),document.addEventListener("tabChanged",t=>{t.detail&&"activity"===t.detail.newTab&&(console.log("Tab changed to activity, initializing tree..."),i(),e&&setTimeout(()=>{e.renderWhenVisible(),e.forceShow()},150))});const o=document.querySelector(".tab-button.active");o&&"activity"===o.getAttribute("data-tab")&&(console.log("Activity tab is active on load, initializing tree..."),i());const n=document.getElementById("activity-tab");n&&n.classList.contains("active")&&(console.log("Activity panel is active on load, initializing tree..."),e||i()),window.activityTree=()=>e};"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e();
|
|
2
2
|
//# sourceMappingURL=activity-tree.js.map
|
|
@@ -0,0 +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}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 s=document.getElementById("code-expand-all");s&&s.addEventListener("click",()=>this.expandAll());const i=document.getElementById("code-collapse-all");i&&i.addEventListener("click",()=>this.collapseAll());const o=document.getElementById("code-reset-zoom");o&&o.addEventListener("click",()=>this.resetZoom());const a=document.getElementById("code-toggle-legend");a&&a.addEventListener("click",()=>this.toggleLegend());const n=document.getElementById("show-hidden-files");n&&n.addEventListener("change",()=>{this.autoDiscovered=!1,this.initializeTreeData(),this.autoDiscoverRootLevel(),this.showNotification(n.checked?"Showing hidden files":"Hiding hidden files","info")}),document.addEventListener("workingDirectoryChanged",t=>{console.log("Working directory changed to:",t.detail.directory),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(),!t||!t.node())return void console.error("Code tree container not found");const e=t.node(),s=e.clientWidth||960,i=e.clientHeight||600;this.width=s-this.margin.left-this.margin.right,this.height=i-this.margin.top-this.margin.bottom,this.radius=Math.min(this.width,this.height)/2,this.svg=t.append("svg").attr("width",s).attr("height",i);const o=s/2,a=i/2;this.isRadialLayout?this.treeGroup=this.svg.append("g").attr("transform",`translate(${o},${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),s=t.parent&&t.parent.children?.length||1,i=s>5?2:s>3?1.5:1,o=1+.2*t.depth;return e*i/(t.depth||1)*o}return 4/(t.depth||1)}):this.treeLayout=d3.tree().nodeSize([30,200]).separation((t,e)=>t.parent==e.parent?1:1.5),this.zoom=d3.zoom().scaleExtent([.1,10]).on("zoom",t=>{this.isRadialLayout?this.treeGroup.attr("transform",`translate(${o+t.transform.x},${a+t.transform.y}) scale(${t.transform.k})`):this.treeGroup.attr("transform",`translate(${this.margin.left+100+t.transform.x},${a+t.transform.y}) scale(${t.transform.k})`)}),this.svg.call(this.zoom),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")}initializeTreeData(){const t=this.getWorkingDirectory(),e=t&&t.split("/").pop()||"Project Root",s=t||".";this.treeData={name:e,path:s,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");console.log("Auto-discovering root level for:",t),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:t,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 s=[];document.querySelectorAll(".language-checkbox:checked").forEach(t=>{s.push(t.value)});const i=document.getElementById("ignore-patterns")?.value||"",o=document.getElementById("show-hidden-files")?.checked||!1;console.log("[DEBUG] Show hidden files checkbox value:",o),console.log("[DEBUG] Checkbox element:",document.getElementById("show-hidden-files"));const a={path:t,depth:"top_level",languages:s,ignore_patterns:i,show_hidden_files:o};console.log("[DEBUG] Sending discovery request with payload:",a),this.socket&&this.socket.emit("code:discover:top_level",a),this.updateStats()}analyzeCode(){this.analyzing||this.autoDiscoverRootLevel()}cancelAnalysis(){this.analyzing=!1,this.hideLoading(),this.socket&&this.socket.emit("code:analysis:cancel"),this.updateBreadcrumb("Analysis cancelled","warning"),this.showNotification("Analysis cancelled","warning"),this.addEventToDisplay("Analysis cancelled","warning")}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 s=document.getElementById("analysis-events");if(s){const i=document.createElement("div");i.className="analysis-event",i.style.borderLeftColor="warning"===e?"#f59e0b":"error"===e?"#ef4444":"#3b82f6";const o=(new Date).toLocaleTimeString();i.innerHTML=`<span style="color: #718096;">[${o}]</span> ${t}`,s.appendChild(i),s.scrollTop=s.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: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){const e=this.findNodeByPath(t.path);if(e&&t.children){const s=this.findD3NodeByPath(t.path);s&&this.loadingNodes.has(t.path)&&this.removeLoadingPulse(s),e.children=t.children.map(t=>({...t,loaded:"directory"!==t.type&&void 0,analyzed:"file"!==t.type&&void 0,expanded:!1,children:[]})),e.loaded=!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)),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.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()}onDirectoryDiscovered(t){this.updateActivityTicker(`📁 Discovered: ${t.name||"directory"}`),this.addEventToDisplay(`📁 Found ${(t.children||[]).length} items in: ${t.name||t.path}`,"info");const e=this.findNodeByPath(t.path);if(e&&t.children){e.children=t.children.map(t=>({name:t.name,path:t.path,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;const s=this.findD3NodeByPath(t.path);s&&(this.loadingNodes.has(t.path)&&this.removeLoadingPulse(s),s.data&&(s.data.children=e.children,s._children=null)),this.root&&this.svg&&(this.root=d3.hierarchy(this.treeData),this.update(this.root)),this.updateBreadcrumb(`Loaded ${e.children.length} items from ${e.name}`,"success"),this.updateStats()}else if(!e){const e=t.path?t.path.split("/").filter(t=>t):[];if(1===e.length||t.forceAdd){const s={name:t.name||e[e.length-1]||"Unknown",path:t.path,type:"directory",children:[],loaded:!1,expanded:!1,stats:t.stats||{}};this.addNodeToTree(s,t.parent||""),this.updateBreadcrumb(`Discovered: ${t.path}`,"info")}}}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 s=t.path?t.path.split("/").filter(t=>t):[],i=s.slice(0,-1).join("/"),o={name:t.name||s[s.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(o,i),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),t.path){const e=t.path.split("/").pop();this.updateActivityTicker(`🔍 Analyzed: ${e}`)}const s=this.findNodeByPath(t.path);s&&(s.analyzed=!0,s.complexity=t.complexity||0,s.lines=t.lines||0,t.elements&&Array.isArray(t.elements)&&(s.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(s=>({name:s.name,type:"method",path:`${t.path}#${e.name}.${s.name}`,line:s.line,complexity:s.complexity||1,docstring:s.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 s={name:t.name||"Unknown",type:(t.type||"unknown").toLowerCase(),path:t.path||"",line:t.line||0,complexity:t.complexity||1,docstring:t.docstring||""};s.type={class:"class",function:"function",method:"method",module:"module",file:"file",directory:"directory"}[s.type]||s.type;let i="";if(t.parent_path)i=t.parent_path;else if(t.file_path)i=t.file_path;else if(s.path.includes("/")){const t=s.path.split("/");t.pop(),i=t.join("/")}switch(s.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(s,i),this.updateStats();const o=s.type.charAt(0).toUpperCase()+s.type.slice(1);this.updateBreadcrumb(`Found ${o}: ${s.name}`,"info")}onProgressUpdate(t){const e=t.progress||0,s=t.message||`Processing... ${e}%`;this.updateBreadcrumb(s,"info");const i=document.querySelector(".code-tree-progress");i&&(i.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){if(console.log("[INFO]",t.type,t.message),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&&console.log("[DISCOVERY STATS]",t.stats)):"discovery.directory"!==t.type&&"discovery.file"!==t.type||this.updateBreadcrumb(t.message,"info");else if(t.type&&t.type.startsWith("analysis."))if("analysis.start"===t.type)this.updateBreadcrumb(t.message,"info");else if("analysis.complete"===t.type){if(this.updateBreadcrumb(t.message,"success"),t.stats){const e=`Found: ${t.stats.classes||0} classes, ${t.stats.functions||0} functions, ${t.stats.methods||0} methods`;console.log("[ANALYSIS STATS]",e)}}else("analysis.class"===t.type||"analysis.function"===t.type||"analysis.method"===t.type||"analysis.parse"===t.type)&&this.updateBreadcrumb(t.message,"info");else 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(),console.log("[EVENT LOG]",t.type,t.message)}onAnalysisCancelled(t){this.analyzing=!1,this.hideLoading();const e=t.message||"Analysis cancelled";this.updateBreadcrumb(e,"warning")}showNotification(t,e="info"){const s=document.createElement("div");s.className=`code-tree-notification ${e}`,s.textContent=t;const i=document.getElementById("code-tree-container");i&&(s.style.position="absolute",s.style.top="10px",s.style.right="10px",s.style.zIndex="1000",i.style.position&&"static"!==i.style.position||(i.style.position="relative"),i.appendChild(s),setTimeout(()=>{s.style.animation="slideOutRight 0.3s ease",setTimeout(()=>s.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 s=this.treeData;if(e&&(s=this.findNodeByPath(e),!s))return console.warn("Parent node not found, skipping node creation:",e),void console.warn("Attempted to add node:",t);const i=s.children?.find(e=>e.path===t.path||e.name===t.name&&e.type===t.type);i?Object.assign(i,t):(s.children||(s.children=[]),t.children||(t.children=[]),s.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),e.path===t)return e;if(e.children)for(const s of e.children){const e=this.findNodeByPath(t,s);if(e)return e}return null}findD3NodeByPath(t){return this.root?this.root.descendants().find(e=>e.data.path===t):null}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[s,i]of Object.entries(t)){const t=document.getElementById(s);t&&(t.textContent=i.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 s=document.getElementById("breadcrumb-content");s&&(s.textContent=t,s.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),s=e.descendants(),i=e.descendants().slice(1);this.isRadialLayout&&s.forEach(t=>{void 0===t.x0&&(t.x0=t.x,t.y0=t.y)});const o=this.treeGroup.selectAll("g.node").data(s,t=>t.id||(t.id=++this.nodeId)),a=o.enter().append("g").attr("class","node").attr("transform",e=>{if(this.isRadialLayout){const[e,s]=this.radialPoint(t.x0||0,t.y0||0);return`translate(${e},${s})`}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",2).on("mouseover",(t,e)=>this.showTooltip(t,e)).on("mouseout",()=>this.hideTooltip()),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)"),a.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");const n=a.merge(o);n.transition().duration(this.duration).attr("transform",t=>{if(this.isRadialLayout){const[e,s]=this.radialPoint(t.x,t.y);return`translate(${e},${s})`}return`translate(${t.y},${t.x})`}),n.select("circle.node-circle").attr("r",8).style("fill",t=>this.getNodeColor(t)).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 s=180*t.x/Math.PI-90;s>90||s<-90?e.attr("transform",`rotate(${s+180})`).attr("x",-15).attr("text-anchor","end").attr("dy",".35em"):e.attr("transform",`rotate(${s})`).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=o.exit().transition().duration(this.duration).attr("transform",e=>{if(this.isRadialLayout){const[e,s]=this.radialPoint(t.x,t.y);return`translate(${e},${s})`}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(i,t=>t.id);l.enter().insert("path","g").attr("class","link").attr("d",e=>{const s={x:t.x0,y:t.y0};return this.isRadialLayout?this.radialDiagonal(s,s):this.diagonal(s,s)}).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 s={x:t.x,y:t.y};return this.isRadialLayout?this.radialDiagonal(s,s):this.diagonal(s,s)}).remove(),s.forEach(t=>{t.x0=t.x,t.y0=t.y})}centerOnNode(t){if(!this.svg||!this.zoom)return;const e=d3.zoomTransform(this.svg.node()),s=-t.y*e.k+this.width/2,i=-t.x*e.k+this.height/2;this.svg.transition().duration(750).call(this.zoom.transform,d3.zoomIdentity.translate(s,i).scale(e.k))}centerOnNodeRadial(t){if(!this.svg||!this.zoom)return;const[e,s]=this.radialPoint(t.x,t.y),i=d3.zoomTransform(this.svg.node()),o=this.width/2-e*i.k,a=this.height/2-s*i.k;this.svg.transition().duration(750).call(this.zoom.transform,d3.zoomIdentity.translate(o,a).scale(i.k))}highlightActiveNode(t){this.treeGroup.selectAll("circle.node-circle").transition().duration(300).attr("r",8).classed("active",!1).classed("parent-context",!1).style("stroke",null).style("stroke-width",null).style("opacity",null),this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle").transition().duration(300).attr("r",12).classed("active",!0).style("stroke","#3b82f6").style("stroke-width",3),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).style("fill","#fb923c");const s=()=>{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)&&s()})};s()}removeLoadingPulse(t){this.loadingNodes.delete(t.data.path);this.treeGroup.selectAll("g.node").filter(e=>e===t).select("circle.node-circle").classed("loading-pulse",!1).interrupt().transition().duration(300).attr("r",this.activeNode===t?12:8).style("opacity",1).style("fill",t=>this.getNodeColor(t))}showWithParent(t){if(!t.parent)return;if(this.treeGroup.selectAll("g.node").filter(e=>e===t.parent).select("circle.node-circle").classed("parent-context",!0).style("stroke","#10b981").style("stroke-width",3).style("opacity",.8),this.isRadialLayout&&t.parent){const e=[t,t.parent];t.children?e.push(...t.children):t._children&&e.push(...t._children);const s=e.map(t=>t.x),i=e.map(t=>t.y),o=Math.min(...s),a=Math.max(...s),n=Math.max(...i),r=a-o,d=Math.min(r>0?2*Math.PI/(2*r):2.5,this.width/(2*n),2.5),l=(o+a)/2,c=n/2,h=c*Math.cos(l-Math.PI/2),p=c*Math.sin(l-Math.PI/2);this.svg.transition().duration(750).call(this.zoom.transform,d3.zoomIdentity.translate(this.width/2-h*d,this.height/2-p*d).scale(d))}}onNodeClick(t,e){t.stopPropagation(),this.isRadialLayout?this.centerOnNodeRadial(e):this.centerOnNode(e),this.highlightActiveNode(e),this.showWithParent(e);const s=[];document.querySelectorAll(".language-checkbox:checked").forEach(t=>{s.push(t.value)});const i=document.getElementById("ignore-patterns")?.value||"",o=document.getElementById("show-hidden-files")?.checked||!1;if("directory"!==e.data.type||e.data.loaded)if("file"!==e.data.type||e.data.analyzed)(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(!s.includes(t)&&"unknown"!==t)return void this.showNotification(`Skipping ${e.data.name} - ${t} not selected`,"warning");this.addLoadingPulse(e);const i=this.ensureFullPath(e.data.path),o=document.getElementById("show-hidden-files"),a=!!o&&o.checked;this.socket&&(this.socket.emit("code:analyze:file",{path:i,show_hidden_files:a}),e.data.analyzed="loading",this.updateBreadcrumb(`Analyzing ${e.data.name}...`,"info"),this.showNotification(`Analyzing: ${e.data.name}`,"info"))}else{this.addLoadingPulse(e);const t=this.ensureFullPath(e.data.path);this.socket&&(this.socket.emit("code:discover:directory",{path:t,depth:1,languages:s,ignore_patterns:i,show_hidden_files:o}),e.data.loaded="loading",this.updateBreadcrumb(`Loading ${e.data.name}...`,"info"),this.showNotification(`Loading directory: ${e.data.name}`,"info"))}this.selectedNode=e,this.highlightNode(e)}ensureFullPath(t){if(!t)return t;if(t.startsWith("/"))return t;const e=this.getWorkingDirectory();return e?"."===t||t===e?e:`${e}/${t}`.replace(/\/+/g,"/"):t}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,s=t.data.complexity||1,i={root:"#6B7280",directory:"#3B82F6",file:"#10B981",module:"#8B5CF6",class:"#F59E0B",function:"#EF4444",method:"#EC4899"}[e]||"#6B7280";return s>10?d3.color(i).darker(.5):s>5?d3.color(i).darker(.25):i}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 s=[];s.push(`<strong>${e.data.name}</strong>`),s.push(`Type: ${e.data.type}`),e.data.language&&s.push(`Language: ${e.data.language}`),e.data.complexity&&s.push(`Complexity: ${e.data.complexity}`),e.data.lines&&s.push(`Lines: ${e.data.lines}`),e.data.path&&s.push(`Path: ${e.data.path}`),"directory"!==e.data.type||e.data.loaded?"file"!==e.data.type||e.data.analyzed||s.push("<em>Click to analyze file</em>"):s.push("<em>Click to explore contents</em>"),this.tooltip.transition().duration(200).style("opacity",.9),this.tooltip.html(s.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(){this.svg&&this.zoom&&(this.svg.transition().duration(750).call(this.zoom.transform,d3.zoomIdentity),this.showNotification("Zoom reset","info"))}focusOnNode(t){if(!this.svg||!this.zoom||!t)return;const e=t.descendants?t.descendants():[t];if(this.isRadialLayout){const t=e.map(t=>t.x),s=e.map(t=>t.y),i=Math.min(...t),o=Math.max(...t),a=Math.min(...s),n=Math.max(...s),r=(i+o)/2,d=(a+n)/2,l=d*Math.cos(r-Math.PI/2),c=d*Math.sin(r-Math.PI/2),h=o-i,p=n-a;let u=1;if(h>0&&p>0){const t=2*Math.PI/h,e=this.radius/p;u=Math.min(t,e,3),u=Math.max(u,1)}this.svg.transition().duration(750).call(this.zoom.transform,d3.zoomIdentity.translate(this.width/2-l*u,this.height/2-c*u).scale(u))}else{const t=e.map(t=>t.x),s=e.map(t=>t.y),i=Math.min(...t),o=Math.max(...t),a=Math.min(...s),n=Math.max(...s),r=(i+o)/2,d=(a+n)/2,l=o-i,c=n-a,h=100;let p=1;if(l>0&&c>0){const t=(this.width-h)/l,e=(this.height-h)/c;p=Math.min(t,e,2.5),p=Math.max(p,.5)}this.svg.transition().duration(750).call(this.zoom.transform,d3.zoomIdentity.translate(this.width/2-r*p,this.height/2-d*p).scale(p))}const s=this.getNodePath(t);this.updateBreadcrumb(`Focused: ${s}`,"info")}getNodePath(t){const e=[];let s=t;for(;s;)s.data&&s.data.name&&e.unshift(s.data.name),s=s.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 s=e.querySelector(".message-icon");s&&(s.style.cssText="font-size: 48px; margin-bottom: 16px; opacity: 0.5;");const i=e.querySelector("h3");i&&(i.style.cssText="margin: 16px 0; color: #333; font-size: 20px;");const o=e.querySelector("p");o&&(o.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"}),s=URL.createObjectURL(e),i=document.createElement("a");i.href=s,i.download=`code-tree-${Date.now()}.json`,i.click(),URL.revokeObjectURL(s),this.showNotification("Tree exported successfully","success")}updateActivityTicker(t,e="info"){const s=document.getElementById("breadcrumb-content");if(s){const i="info"===e&&t.includes("...")?"⟳ ":"";s.innerHTML=`${i}${t}`,s.className=`breadcrumb-${e}`}}updateTicker(t,e="info"){const s=document.getElementById("code-tree-ticker");s&&(s.textContent=t,s.className=`ticker ticker-${e}`,"error"!==e&&setTimeout(()=>{s.style.opacity="0",setTimeout(()=>{s.style.opacity="1",s.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
|
+
//# sourceMappingURL=code-tree.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=new class{constructor(){this.modal=null,this.currentNode=null,this.socket=null,this.initialized=!1,this.codeCache=new Map}initialize(){this.initialized||(this.createModal(),this.setupEventHandlers(),this.subscribeToEvents(),this.initialized=!0,console.log("Code viewer initialized"))}createModal(){document.body.insertAdjacentHTML("beforeend",'\n <div class="code-viewer-modal" id="code-viewer-modal">\n <div class="code-viewer-content">\n <div class="code-viewer-header">\n <div class="code-viewer-title" id="code-viewer-title">\n Loading...\n </div>\n <div class="code-viewer-info">\n <span id="code-viewer-type">Type: --</span>\n <span id="code-viewer-lines">Lines: --</span>\n <span id="code-viewer-complexity">Complexity: --</span>\n </div>\n <button class="code-viewer-close" id="code-viewer-close">×</button>\n </div>\n <div class="code-viewer-body">\n <pre class="code-viewer-code line-numbers" id="code-viewer-code">\n <code class="language-python" id="code-viewer-code-content"></code>\n </pre>\n </div>\n <div class="code-viewer-navigation">\n <div class="nav-group">\n <button class="code-nav-button" id="code-nav-parent" disabled>\n ⬆️ Parent\n </button>\n <button class="code-nav-button" id="code-nav-prev" disabled>\n ⬅️ Previous\n </button>\n <button class="code-nav-button" id="code-nav-next" disabled>\n ➡️ Next\n </button>\n </div>\n <div class="nav-info">\n <span id="code-nav-position">-- / --</span>\n </div>\n <div class="nav-actions">\n <button class="code-nav-button" id="code-copy">\n 📋 Copy\n </button>\n <button class="code-nav-button" id="code-open-file">\n 📂 Open File\n </button>\n </div>\n </div>\n </div>\n </div>\n '),this.modal=document.getElementById("code-viewer-modal")}setupEventHandlers(){document.getElementById("code-viewer-close").addEventListener("click",()=>{this.hide()}),this.modal.addEventListener("click",e=>{e.target===this.modal&&this.hide()}),document.addEventListener("keydown",e=>{"Escape"===e.key&&this.modal.classList.contains("show")&&this.hide()}),document.getElementById("code-nav-parent").addEventListener("click",()=>{this.navigateToParent()}),document.getElementById("code-nav-prev").addEventListener("click",()=>{this.navigateToPrevious()}),document.getElementById("code-nav-next").addEventListener("click",()=>{this.navigateToNext()}),document.getElementById("code-copy").addEventListener("click",()=>{this.copyCode()}),document.getElementById("code-open-file").addEventListener("click",()=>{this.openInEditor()})}subscribeToEvents(){window.socket&&(this.socket=window.socket,this.socket.on("code:content:response",e=>{this.handleCodeContent(e)}))}show(e){this.initialized||this.initialize(),this.currentNode=e,this.modal.classList.add("show"),this.updateHeader(e),this.loadCode(e),this.updateNavigation(e)}hide(){this.modal.classList.remove("show"),this.currentNode=null}updateHeader(e){document.getElementById("code-viewer-title").textContent=`${e.name} (${e.path||"Unknown"})`,document.getElementById("code-viewer-type").textContent=`Type: ${e.type}`,document.getElementById("code-viewer-lines").textContent=`Lines: ${e.lines||"--"}`,document.getElementById("code-viewer-complexity").textContent=`Complexity: ${e.complexity||"--"}`}loadCode(e){const t=document.getElementById("code-viewer-code-content"),n=`${e.path}:${e.line}`;this.codeCache.has(n)?this.displayCode(this.codeCache.get(n)):(t.textContent="Loading code...",this.socket?this.socket.emit("code:content:request",{path:e.path,line:e.line,type:e.type,name:e.name}):this.displayMockCode(e))}handleCodeContent(e){if(!e.success)return void this.displayError(e.error||"Failed to load code");const t=`${e.path}:${e.line}`;this.codeCache.set(t,e.content),this.displayCode(e.content)}displayCode(e){const t=document.getElementById("code-viewer-code-content"),n=document.getElementById("code-viewer-code");t.textContent=e;const i=this.detectLanguage(this.currentNode.path);t.className=`language-${i}`,window.Prism&&(Prism.highlightElement(t),Prism.plugins&&Prism.plugins.lineNumbers&&Prism.plugins.lineNumbers.resize(n))}displayMockCode(e){let t="";switch(e.type){case"class":t=`class ${e.name}:\n """\n ${e.docstring||"A sample class implementation."}\n """\n \n def __init__(self):\n """Initialize the ${e.name} class."""\n self._data = {}\n self._initialized = False\n \n def process(self, input_data):\n """Process the input data."""\n if not self._initialized:\n self._initialize()\n return self._transform(input_data)\n \n def _initialize(self):\n """Initialize internal state."""\n self._initialized = True\n \n def _transform(self, data):\n """Transform the data."""\n return data`;break;case"function":t=`def ${e.name}(${e.params?e.params.join(", "):""}):\n """\n ${e.docstring||"A sample function implementation."}\n \n Args:\n ${e.params?e.params.map(e=>`${e}: Description of ${e}`).join("\n "):"None"}\n \n Returns:\n ${e.returns||"None"}: Return value description\n """\n # Implementation here\n result = None\n \n # Process logic\n for item in range(10):\n result = process_item(item)\n \n return result`;break;case"method":t=` def ${e.name}(self${e.params?", "+e.params.join(", "):""}):\n """\n ${e.docstring||"A sample method implementation."}\n """\n # Method implementation\n self._validate()\n result = self._process()\n return result`;break;default:t=`# ${e.name}\n# Type: ${e.type}\n# Path: ${e.path||"Unknown"}\n# Line: ${e.line||"Unknown"}\n\n# Code content would appear here\n# This is a placeholder for demonstration purposes`}this.displayCode(t)}displayError(e){const t=document.getElementById("code-viewer-code-content");t.textContent=`# Error loading code\n# ${e}`,t.className="language-python"}detectLanguage(e){if(!e)return"python";return{py:"python",js:"javascript",ts:"typescript",jsx:"jsx",tsx:"tsx",css:"css",html:"html",json:"json",yaml:"yaml",yml:"yaml",md:"markdown",sh:"bash",bash:"bash",sql:"sql",go:"go",rs:"rust",cpp:"cpp",c:"c",h:"c",hpp:"cpp",java:"java",rb:"ruby",php:"php"}[e.split(".").pop().toLowerCase()]||"plaintext"}updateNavigation(e){document.getElementById("code-nav-parent").disabled=!0,document.getElementById("code-nav-prev").disabled=!0,document.getElementById("code-nav-next").disabled=!0,document.getElementById("code-nav-position").textContent="1 / 1"}navigateToParent(){console.log("Navigate to parent node")}navigateToPrevious(){console.log("Navigate to previous sibling")}navigateToNext(){console.log("Navigate to next sibling")}async copyCode(){const e=document.getElementById("code-viewer-code-content").textContent;try{await navigator.clipboard.writeText(e);const t=document.getElementById("code-copy"),n=t.textContent;t.textContent="✅ Copied!",setTimeout(()=>{t.textContent=n},2e3)}catch(t){console.error("Failed to copy code:",t),alert("Failed to copy code to clipboard")}}openInEditor(){this.currentNode&&this.currentNode.path?(this.socket&&this.socket.emit("file:open",{path:this.currentNode.path,line:this.currentNode.line}),console.log("Opening file in editor:",this.currentNode.path)):alert("File path not available")}};"undefined"!=typeof window&&(window.CodeViewer=e,document.addEventListener("DOMContentLoaded",()=>{e.initialize()}));
|
|
2
|
+
//# sourceMappingURL=code-viewer.js.map
|