claude-mpm 4.2.1__py3-none-any.whl → 4.2.3__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/agents/templates/agent-manager.json +1 -1
- claude_mpm/agents/templates/agentic_coder_optimizer.json +1 -1
- claude_mpm/agents/templates/api_qa.json +1 -1
- claude_mpm/agents/templates/code_analyzer.json +1 -1
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +1 -1
- claude_mpm/agents/templates/engineer.json +2 -2
- claude_mpm/agents/templates/gcp_ops_agent.json +14 -9
- claude_mpm/agents/templates/imagemagick.json +1 -1
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +1 -1
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +2 -2
- claude_mpm/agents/templates/refactoring_engineer.json +1 -1
- claude_mpm/agents/templates/research.json +3 -3
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/test-non-mpm.json +20 -0
- claude_mpm/agents/templates/ticketing.json +1 -1
- claude_mpm/agents/templates/vercel_ops_agent.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -8
- claude_mpm/agents/templates/web_ui.json +1 -1
- claude_mpm/cli/commands/agents.py +3 -0
- claude_mpm/cli/commands/dashboard.py +3 -3
- claude_mpm/cli/commands/monitor.py +227 -64
- claude_mpm/core/config.py +25 -0
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/dashboard/static/css/code-tree.css +220 -1
- claude_mpm/dashboard/static/css/dashboard.css +286 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/js/components/code-simple.js +507 -15
- claude_mpm/dashboard/static/js/components/code-tree.js +2044 -124
- claude_mpm/dashboard/static/js/socket-client.js +5 -2
- claude_mpm/dashboard/templates/code_simple.html +79 -0
- claude_mpm/dashboard/templates/index.html +42 -41
- claude_mpm/services/agents/deployment/agent_deployment.py +4 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +101 -2
- claude_mpm/services/agents/deployment/agent_format_converter.py +53 -9
- claude_mpm/services/agents/deployment/agent_template_builder.py +355 -25
- claude_mpm/services/agents/deployment/agent_validator.py +11 -6
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +83 -15
- claude_mpm/services/agents/deployment/validation/template_validator.py +51 -40
- claude_mpm/services/cli/agent_listing_service.py +2 -2
- claude_mpm/services/dashboard/stable_server.py +389 -0
- claude_mpm/services/socketio/client_proxy.py +16 -0
- claude_mpm/services/socketio/dashboard_server.py +360 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +27 -5
- claude_mpm/services/socketio/monitor_client.py +366 -0
- claude_mpm/services/socketio/monitor_server.py +505 -0
- claude_mpm/tools/code_tree_analyzer.py +95 -17
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/RECORD +57 -52
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.1.dist-info → claude_mpm-4.2.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dashboard Server with Monitor Client Integration for claude-mpm.
|
|
3
|
+
|
|
4
|
+
WHY: This module provides a dashboard server that connects to the independent
|
|
5
|
+
monitor server as a client, enabling decoupled architecture where:
|
|
6
|
+
- Dashboard provides UI on port 8765
|
|
7
|
+
- Dashboard connects to monitor server on port 8766 for events
|
|
8
|
+
- Dashboard can restart without affecting event collection
|
|
9
|
+
- Multiple dashboards can connect to the same monitor
|
|
10
|
+
|
|
11
|
+
DESIGN DECISIONS:
|
|
12
|
+
- Extends existing SocketIOServer with monitor client integration
|
|
13
|
+
- Provides UI functionality (HTTP server, static files, dashboard endpoints)
|
|
14
|
+
- Graceful degradation when monitor server is unavailable
|
|
15
|
+
- Event relay from monitor client to dashboard clients
|
|
16
|
+
- Maintains backward compatibility with existing dashboard clients
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
from typing import Any, Dict, List, Optional
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
import aiohttp
|
|
24
|
+
import socketio
|
|
25
|
+
from aiohttp import web
|
|
26
|
+
|
|
27
|
+
SOCKETIO_AVAILABLE = True
|
|
28
|
+
except ImportError:
|
|
29
|
+
SOCKETIO_AVAILABLE = False
|
|
30
|
+
socketio = None
|
|
31
|
+
aiohttp = None
|
|
32
|
+
web = None
|
|
33
|
+
|
|
34
|
+
from ...core.config import Config
|
|
35
|
+
from ...core.logging_config import get_logger
|
|
36
|
+
from ..core.interfaces.communication import SocketIOServiceInterface
|
|
37
|
+
from .monitor_client import MonitorClient
|
|
38
|
+
from .server.main import SocketIOServer
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DashboardServer(SocketIOServiceInterface):
|
|
42
|
+
"""Dashboard server that connects to monitor server and provides UI.
|
|
43
|
+
|
|
44
|
+
WHY: This server provides the dashboard UI while staying connected to
|
|
45
|
+
the monitor server for event data. This decoupling allows:
|
|
46
|
+
- Stable event collection in monitor server
|
|
47
|
+
- Dashboard can be restarted for updates without losing events
|
|
48
|
+
- Multiple dashboard instances can share the same monitor
|
|
49
|
+
- Dashboard focuses on UI, monitor focuses on event collection
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def __init__(
|
|
53
|
+
self,
|
|
54
|
+
host: str = None,
|
|
55
|
+
port: int = None,
|
|
56
|
+
monitor_host: str = None,
|
|
57
|
+
monitor_port: int = None,
|
|
58
|
+
):
|
|
59
|
+
# Load configuration
|
|
60
|
+
config = Config()
|
|
61
|
+
dashboard_config = config.get("dashboard_server", {})
|
|
62
|
+
|
|
63
|
+
self.host = host or dashboard_config.get("host", "localhost")
|
|
64
|
+
self.port = port or dashboard_config.get("port", 8765)
|
|
65
|
+
self.monitor_host = monitor_host or dashboard_config.get(
|
|
66
|
+
"monitor_host", "localhost"
|
|
67
|
+
)
|
|
68
|
+
self.monitor_port = monitor_port or dashboard_config.get("monitor_port", 8766)
|
|
69
|
+
|
|
70
|
+
# Configuration-based settings
|
|
71
|
+
self.auto_connect_monitor = dashboard_config.get("auto_connect_monitor", True)
|
|
72
|
+
self.monitor_reconnect = dashboard_config.get("monitor_reconnect", True)
|
|
73
|
+
self.fallback_standalone = dashboard_config.get("fallback_standalone", True)
|
|
74
|
+
|
|
75
|
+
self.logger = get_logger(__name__ + ".DashboardServer")
|
|
76
|
+
|
|
77
|
+
# Dashboard server (provides UI and serves dashboard clients)
|
|
78
|
+
self.dashboard_server = SocketIOServer(host=self.host, port=self.port)
|
|
79
|
+
|
|
80
|
+
# Monitor client (connects to monitor server for events)
|
|
81
|
+
self.monitor_client = MonitorClient(
|
|
82
|
+
monitor_host=self.monitor_host,
|
|
83
|
+
monitor_port=self.monitor_port,
|
|
84
|
+
auto_reconnect=self.monitor_reconnect,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
# Server state
|
|
88
|
+
self.running = False
|
|
89
|
+
self.stats = {
|
|
90
|
+
"start_time": None,
|
|
91
|
+
"dashboard_clients": 0,
|
|
92
|
+
"monitor_connected": False,
|
|
93
|
+
"events_relayed": 0,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Setup event relay from monitor client to dashboard clients
|
|
97
|
+
self._setup_event_relay()
|
|
98
|
+
|
|
99
|
+
def start_sync(self):
|
|
100
|
+
"""Start the dashboard server and connect to monitor."""
|
|
101
|
+
if not SOCKETIO_AVAILABLE:
|
|
102
|
+
self.logger.error("SocketIO not available - dashboard server cannot start")
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
self.logger.info(f"Starting dashboard server on {self.host}:{self.port}")
|
|
106
|
+
self.logger.info(
|
|
107
|
+
f"Connecting to monitor server at {self.monitor_host}:{self.monitor_port}"
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
# Start the dashboard server (UI server)
|
|
111
|
+
self.dashboard_server.start_sync()
|
|
112
|
+
|
|
113
|
+
# Connect to monitor server for events (if auto-connect enabled)
|
|
114
|
+
monitor_connected = False
|
|
115
|
+
if self.auto_connect_monitor:
|
|
116
|
+
monitor_connected = self.monitor_client.start()
|
|
117
|
+
else:
|
|
118
|
+
self.logger.info("Auto-connect to monitor disabled by configuration")
|
|
119
|
+
|
|
120
|
+
if not monitor_connected:
|
|
121
|
+
self.logger.warning(
|
|
122
|
+
"Could not connect to monitor server - dashboard will run in standalone mode"
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Update state
|
|
126
|
+
self.running = self.dashboard_server.is_running()
|
|
127
|
+
if self.running:
|
|
128
|
+
self.stats["start_time"] = datetime.now().isoformat()
|
|
129
|
+
self.stats["monitor_connected"] = monitor_connected
|
|
130
|
+
|
|
131
|
+
self.logger.info(
|
|
132
|
+
f"Dashboard server started successfully on {self.host}:{self.port} "
|
|
133
|
+
f"(monitor connected: {monitor_connected})"
|
|
134
|
+
)
|
|
135
|
+
return self.running
|
|
136
|
+
|
|
137
|
+
def stop_sync(self):
|
|
138
|
+
"""Stop the dashboard server and disconnect from monitor."""
|
|
139
|
+
self.logger.info("Stopping dashboard server")
|
|
140
|
+
|
|
141
|
+
# Stop monitor client first
|
|
142
|
+
self.monitor_client.stop()
|
|
143
|
+
|
|
144
|
+
# Stop dashboard server
|
|
145
|
+
self.dashboard_server.stop_sync()
|
|
146
|
+
|
|
147
|
+
self.running = False
|
|
148
|
+
self.logger.info("Dashboard server stopped")
|
|
149
|
+
|
|
150
|
+
def _setup_event_relay(self):
|
|
151
|
+
"""Setup event relay from monitor client to dashboard clients."""
|
|
152
|
+
|
|
153
|
+
# Register handlers for all events we want to relay from monitor to dashboard
|
|
154
|
+
relay_events = [
|
|
155
|
+
"session_started",
|
|
156
|
+
"session_ended",
|
|
157
|
+
"claude_status",
|
|
158
|
+
"claude_output",
|
|
159
|
+
"agent_delegated",
|
|
160
|
+
"todos_updated",
|
|
161
|
+
"ticket_created",
|
|
162
|
+
"memory_loaded",
|
|
163
|
+
"memory_created",
|
|
164
|
+
"memory_updated",
|
|
165
|
+
"memory_injected",
|
|
166
|
+
"file_changed",
|
|
167
|
+
"git_status_changed",
|
|
168
|
+
"project_analyzed",
|
|
169
|
+
"connection_status",
|
|
170
|
+
"heartbeat",
|
|
171
|
+
]
|
|
172
|
+
|
|
173
|
+
for event_name in relay_events:
|
|
174
|
+
self.monitor_client.add_event_handler(
|
|
175
|
+
event_name, self._create_relay_handler(event_name)
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def _create_relay_handler(self, event_name: str):
|
|
179
|
+
"""Create a relay handler for a specific event."""
|
|
180
|
+
|
|
181
|
+
def relay_handler(data):
|
|
182
|
+
"""Relay event from monitor to dashboard clients."""
|
|
183
|
+
self.stats["events_relayed"] += 1
|
|
184
|
+
self.logger.debug(f"Relaying event from monitor to dashboard: {event_name}")
|
|
185
|
+
|
|
186
|
+
# Broadcast to all dashboard clients
|
|
187
|
+
self.dashboard_server.broadcast_event(event_name, data)
|
|
188
|
+
|
|
189
|
+
return relay_handler
|
|
190
|
+
|
|
191
|
+
# Delegate SocketIOServiceInterface methods to dashboard server
|
|
192
|
+
def broadcast_event(self, event_type: str, data: Dict[str, Any]):
|
|
193
|
+
"""Broadcast an event to all connected dashboard clients."""
|
|
194
|
+
self.dashboard_server.broadcast_event(event_type, data)
|
|
195
|
+
|
|
196
|
+
def send_to_client(
|
|
197
|
+
self, client_id: str, event_type: str, data: Dict[str, Any]
|
|
198
|
+
) -> bool:
|
|
199
|
+
"""Send an event to a specific dashboard client."""
|
|
200
|
+
return self.dashboard_server.send_to_client(client_id, event_type, data)
|
|
201
|
+
|
|
202
|
+
def get_connection_count(self) -> int:
|
|
203
|
+
"""Get number of connected dashboard clients."""
|
|
204
|
+
return self.dashboard_server.get_connection_count()
|
|
205
|
+
|
|
206
|
+
def is_running(self) -> bool:
|
|
207
|
+
"""Check if dashboard server is running."""
|
|
208
|
+
return self.running
|
|
209
|
+
|
|
210
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
211
|
+
"""Get dashboard server statistics."""
|
|
212
|
+
dashboard_stats = (
|
|
213
|
+
self.dashboard_server.get_stats()
|
|
214
|
+
if hasattr(self.dashboard_server, "get_stats")
|
|
215
|
+
else {}
|
|
216
|
+
)
|
|
217
|
+
monitor_stats = self.monitor_client.get_stats()
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
**self.stats,
|
|
221
|
+
"dashboard_clients": self.get_connection_count(),
|
|
222
|
+
"monitor_connected": self.monitor_client.is_connected(),
|
|
223
|
+
"dashboard_stats": dashboard_stats,
|
|
224
|
+
"monitor_stats": monitor_stats,
|
|
225
|
+
"uptime": (
|
|
226
|
+
(
|
|
227
|
+
datetime.now() - datetime.fromisoformat(self.stats["start_time"])
|
|
228
|
+
).total_seconds()
|
|
229
|
+
if self.stats["start_time"]
|
|
230
|
+
else 0
|
|
231
|
+
),
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
# Session tracking methods - these now send events to monitor server
|
|
235
|
+
def session_started(self, session_id: str, launch_method: str, working_dir: str):
|
|
236
|
+
"""Track session start - send to monitor server."""
|
|
237
|
+
# Send to monitor server if connected
|
|
238
|
+
self.monitor_client.send_to_monitor(
|
|
239
|
+
"session_started",
|
|
240
|
+
{
|
|
241
|
+
"session_id": session_id,
|
|
242
|
+
"launch_method": launch_method,
|
|
243
|
+
"working_dir": working_dir,
|
|
244
|
+
},
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
# Also update dashboard server for local tracking
|
|
248
|
+
self.dashboard_server.session_started(session_id, launch_method, working_dir)
|
|
249
|
+
|
|
250
|
+
def session_ended(self):
|
|
251
|
+
"""Track session end - send to monitor server."""
|
|
252
|
+
self.monitor_client.send_to_monitor("session_ended", {})
|
|
253
|
+
self.dashboard_server.session_ended()
|
|
254
|
+
|
|
255
|
+
def claude_status_changed(
|
|
256
|
+
self, status: str, pid: Optional[int] = None, message: str = ""
|
|
257
|
+
):
|
|
258
|
+
"""Track Claude status changes - send to monitor server."""
|
|
259
|
+
self.monitor_client.send_to_monitor(
|
|
260
|
+
"claude_status", {"status": status, "pid": pid, "message": message}
|
|
261
|
+
)
|
|
262
|
+
self.dashboard_server.claude_status_changed(status, pid, message)
|
|
263
|
+
|
|
264
|
+
def claude_output(self, content: str, stream: str = "stdout"):
|
|
265
|
+
"""Relay Claude output - send to monitor server."""
|
|
266
|
+
self.monitor_client.send_to_monitor(
|
|
267
|
+
"claude_output", {"content": content, "stream": stream}
|
|
268
|
+
)
|
|
269
|
+
self.dashboard_server.claude_output(content, stream)
|
|
270
|
+
|
|
271
|
+
def agent_delegated(self, agent: str, task: str, status: str = "started"):
|
|
272
|
+
"""Track agent delegation - send to monitor server."""
|
|
273
|
+
self.monitor_client.send_to_monitor(
|
|
274
|
+
"agent_delegated", {"agent": agent, "task": task, "status": status}
|
|
275
|
+
)
|
|
276
|
+
self.dashboard_server.agent_delegated(agent, task, status)
|
|
277
|
+
|
|
278
|
+
def todo_updated(self, todos: List[Dict[str, Any]]):
|
|
279
|
+
"""Relay todo updates - send to monitor server."""
|
|
280
|
+
self.monitor_client.send_to_monitor("todos_updated", {"todos": todos})
|
|
281
|
+
self.dashboard_server.todo_updated(todos)
|
|
282
|
+
|
|
283
|
+
def ticket_created(self, ticket_id: str, title: str, priority: str = "medium"):
|
|
284
|
+
"""Relay ticket creation - send to monitor server."""
|
|
285
|
+
self.monitor_client.send_to_monitor(
|
|
286
|
+
"ticket_created",
|
|
287
|
+
{"ticket_id": ticket_id, "title": title, "priority": priority},
|
|
288
|
+
)
|
|
289
|
+
self.dashboard_server.ticket_created(ticket_id, title, priority)
|
|
290
|
+
|
|
291
|
+
def memory_loaded(self, agent_id: str, memory_size: int, sections_count: int):
|
|
292
|
+
"""Relay memory loaded event - send to monitor server."""
|
|
293
|
+
self.monitor_client.send_to_monitor(
|
|
294
|
+
"memory_loaded",
|
|
295
|
+
{
|
|
296
|
+
"agent_id": agent_id,
|
|
297
|
+
"memory_size": memory_size,
|
|
298
|
+
"sections_count": sections_count,
|
|
299
|
+
},
|
|
300
|
+
)
|
|
301
|
+
self.dashboard_server.memory_loaded(agent_id, memory_size, sections_count)
|
|
302
|
+
|
|
303
|
+
def memory_created(self, agent_id: str, template_type: str):
|
|
304
|
+
"""Relay memory created event - send to monitor server."""
|
|
305
|
+
self.monitor_client.send_to_monitor(
|
|
306
|
+
"memory_created", {"agent_id": agent_id, "template_type": template_type}
|
|
307
|
+
)
|
|
308
|
+
self.dashboard_server.memory_created(agent_id, template_type)
|
|
309
|
+
|
|
310
|
+
def memory_updated(
|
|
311
|
+
self, agent_id: str, learning_type: str, content: str, section: str
|
|
312
|
+
):
|
|
313
|
+
"""Relay memory update event - send to monitor server."""
|
|
314
|
+
self.monitor_client.send_to_monitor(
|
|
315
|
+
"memory_updated",
|
|
316
|
+
{
|
|
317
|
+
"agent_id": agent_id,
|
|
318
|
+
"learning_type": learning_type,
|
|
319
|
+
"content": content,
|
|
320
|
+
"section": section,
|
|
321
|
+
},
|
|
322
|
+
)
|
|
323
|
+
self.dashboard_server.memory_updated(agent_id, learning_type, content, section)
|
|
324
|
+
|
|
325
|
+
def memory_injected(self, agent_id: str, context_size: int):
|
|
326
|
+
"""Relay memory injection event - send to monitor server."""
|
|
327
|
+
self.monitor_client.send_to_monitor(
|
|
328
|
+
"memory_injected", {"agent_id": agent_id, "context_size": context_size}
|
|
329
|
+
)
|
|
330
|
+
self.dashboard_server.memory_injected(agent_id, context_size)
|
|
331
|
+
|
|
332
|
+
def get_active_sessions(self) -> List[Dict[str, Any]]:
|
|
333
|
+
"""Get list of active sessions from dashboard server."""
|
|
334
|
+
return self.dashboard_server.get_active_sessions()
|
|
335
|
+
|
|
336
|
+
# Provide access to underlying dashboard server properties
|
|
337
|
+
@property
|
|
338
|
+
def sio(self):
|
|
339
|
+
"""Access to the dashboard Socket.IO server instance."""
|
|
340
|
+
return self.dashboard_server.sio
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
def clients(self):
|
|
344
|
+
"""Access to connected dashboard clients."""
|
|
345
|
+
return getattr(self.dashboard_server, "connected_clients", set())
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
def connected_clients(self):
|
|
349
|
+
"""Access to connected dashboard clients set."""
|
|
350
|
+
return getattr(self.dashboard_server, "connected_clients", set())
|
|
351
|
+
|
|
352
|
+
@property
|
|
353
|
+
def file_handler(self):
|
|
354
|
+
"""Access to file handler for HTTP endpoints."""
|
|
355
|
+
return getattr(self.dashboard_server, "file_handler", None)
|
|
356
|
+
|
|
357
|
+
@property
|
|
358
|
+
def git_handler(self):
|
|
359
|
+
"""Access to git handler for HTTP endpoints."""
|
|
360
|
+
return getattr(self.dashboard_server, "git_handler", None)
|
|
@@ -591,8 +591,11 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
591
591
|
return
|
|
592
592
|
|
|
593
593
|
try:
|
|
594
|
+
self.logger.info(f"Starting file analysis for: {path}")
|
|
595
|
+
|
|
594
596
|
# Ensure analyzer exists
|
|
595
597
|
if not self.code_analyzer:
|
|
598
|
+
self.logger.info("Creating new CodeTreeAnalyzer instance")
|
|
596
599
|
emitter = CodeTreeEventEmitter(use_stdout=False)
|
|
597
600
|
# Override emit method to send to Socket.IO
|
|
598
601
|
original_emit = emitter.emit
|
|
@@ -630,23 +633,42 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
630
633
|
self.code_analyzer = CodeTreeAnalyzer(
|
|
631
634
|
emit_events=False, emitter=emitter
|
|
632
635
|
)
|
|
636
|
+
self.logger.info("CodeTreeAnalyzer created successfully")
|
|
633
637
|
|
|
634
638
|
# Analyze file
|
|
639
|
+
self.logger.info(f"Calling analyze_file for: {path}")
|
|
635
640
|
result = self.code_analyzer.analyze_file(path)
|
|
641
|
+
self.logger.info(
|
|
642
|
+
f"Analysis complete. Result keys: {list(result.keys()) if result else 'None'}"
|
|
643
|
+
)
|
|
644
|
+
|
|
645
|
+
if result:
|
|
646
|
+
self.logger.info(
|
|
647
|
+
f"Analysis result: elements={len(result.get('elements', []))}, nodes={len(result.get('nodes', []))}"
|
|
648
|
+
)
|
|
649
|
+
else:
|
|
650
|
+
self.logger.warning("Analysis returned None or empty result")
|
|
636
651
|
|
|
637
652
|
# Send result with correct event name (using colons, not dots!)
|
|
653
|
+
response_data = {
|
|
654
|
+
"request_id": request_id,
|
|
655
|
+
"path": path,
|
|
656
|
+
**result,
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
self.logger.info(f"Emitting code:file:analyzed event to {sid}")
|
|
638
660
|
await self.server.core.sio.emit(
|
|
639
661
|
"code:file:analyzed",
|
|
640
|
-
|
|
641
|
-
"request_id": request_id,
|
|
642
|
-
"path": path,
|
|
643
|
-
**result,
|
|
644
|
-
},
|
|
662
|
+
response_data,
|
|
645
663
|
room=sid,
|
|
646
664
|
)
|
|
665
|
+
self.logger.info("Event emitted successfully")
|
|
647
666
|
|
|
648
667
|
except Exception as e:
|
|
649
668
|
self.logger.error(f"Error analyzing file {path}: {e}")
|
|
669
|
+
import traceback
|
|
670
|
+
|
|
671
|
+
self.logger.error(f"Full traceback: {traceback.format_exc()}")
|
|
650
672
|
await self.server.core.sio.emit(
|
|
651
673
|
"code:analysis:error",
|
|
652
674
|
{
|