claude-mpm 4.2.9__py3-none-any.whl → 4.2.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/commands/dashboard.py +59 -126
- claude_mpm/cli/commands/monitor.py +71 -212
- claude_mpm/cli/commands/run.py +33 -33
- claude_mpm/dashboard/static/css/code-tree.css +8 -16
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/unified-data-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/code-tree.js +692 -114
- claude_mpm/dashboard/static/js/components/file-viewer.js +538 -0
- claude_mpm/dashboard/static/js/components/module-viewer.js +26 -0
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +166 -14
- claude_mpm/dashboard/static/js/dashboard.js +108 -91
- claude_mpm/dashboard/static/js/socket-client.js +9 -7
- claude_mpm/dashboard/templates/index.html +2 -7
- claude_mpm/hooks/claude_hooks/hook_handler.py +1 -11
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +54 -59
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +112 -72
- claude_mpm/services/agents/deployment/agent_template_builder.py +0 -1
- claude_mpm/services/cli/unified_dashboard_manager.py +354 -0
- claude_mpm/services/monitor/__init__.py +20 -0
- claude_mpm/services/monitor/daemon.py +256 -0
- claude_mpm/services/monitor/event_emitter.py +279 -0
- claude_mpm/services/monitor/handlers/__init__.py +20 -0
- claude_mpm/services/monitor/handlers/code_analysis.py +334 -0
- claude_mpm/services/monitor/handlers/dashboard.py +298 -0
- claude_mpm/services/monitor/handlers/hooks.py +491 -0
- claude_mpm/services/monitor/management/__init__.py +18 -0
- claude_mpm/services/monitor/management/health.py +124 -0
- claude_mpm/services/monitor/management/lifecycle.py +298 -0
- claude_mpm/services/monitor/server.py +442 -0
- claude_mpm/tools/code_tree_analyzer.py +33 -17
- {claude_mpm-4.2.9.dist-info → claude_mpm-4.2.11.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.9.dist-info → claude_mpm-4.2.11.dist-info}/RECORD +41 -36
- claude_mpm/cli/commands/socketio_monitor.py +0 -233
- claude_mpm/scripts/socketio_daemon.py +0 -571
- claude_mpm/scripts/socketio_daemon_hardened.py +0 -937
- claude_mpm/scripts/socketio_daemon_wrapper.py +0 -78
- claude_mpm/scripts/socketio_server_manager.py +0 -349
- claude_mpm/services/cli/dashboard_launcher.py +0 -423
- claude_mpm/services/cli/socketio_manager.py +0 -595
- claude_mpm/services/dashboard/stable_server.py +0 -1020
- claude_mpm/services/socketio/monitor_server.py +0 -505
- {claude_mpm-4.2.9.dist-info → claude_mpm-4.2.11.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.9.dist-info → claude_mpm-4.2.11.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.9.dist-info → claude_mpm-4.2.11.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.9.dist-info → claude_mpm-4.2.11.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dashboard Event Handler for Unified Monitor
|
|
3
|
+
===========================================
|
|
4
|
+
|
|
5
|
+
WHY: This handler manages dashboard-specific Socket.IO events for the unified
|
|
6
|
+
monitor daemon. It handles client connections, status updates, and dashboard
|
|
7
|
+
state management.
|
|
8
|
+
|
|
9
|
+
DESIGN DECISIONS:
|
|
10
|
+
- Manages client connections and session state
|
|
11
|
+
- Provides dashboard status and health information
|
|
12
|
+
- Handles real-time dashboard updates
|
|
13
|
+
- Integrates with the unified monitor architecture
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
from typing import Dict, Set
|
|
18
|
+
|
|
19
|
+
import socketio
|
|
20
|
+
|
|
21
|
+
from ....core.logging_config import get_logger
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class DashboardHandler:
|
|
25
|
+
"""Event handler for dashboard-specific functionality.
|
|
26
|
+
|
|
27
|
+
WHY: Manages dashboard client connections and provides real-time updates
|
|
28
|
+
for the unified monitor daemon.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, sio: socketio.AsyncServer):
|
|
32
|
+
"""Initialize the dashboard handler.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
sio: Socket.IO server instance
|
|
36
|
+
"""
|
|
37
|
+
self.sio = sio
|
|
38
|
+
self.logger = get_logger(__name__)
|
|
39
|
+
|
|
40
|
+
# Client management
|
|
41
|
+
self.connected_clients: Set[str] = set()
|
|
42
|
+
self.client_info: Dict[str, Dict] = {}
|
|
43
|
+
|
|
44
|
+
def register(self):
|
|
45
|
+
"""Register Socket.IO event handlers."""
|
|
46
|
+
try:
|
|
47
|
+
# Connection events
|
|
48
|
+
self.sio.on("connect", self.handle_connect)
|
|
49
|
+
self.sio.on("disconnect", self.handle_disconnect)
|
|
50
|
+
|
|
51
|
+
# Dashboard events
|
|
52
|
+
self.sio.on("dashboard:status", self.handle_get_status)
|
|
53
|
+
self.sio.on("dashboard:info", self.handle_get_info)
|
|
54
|
+
self.sio.on("dashboard:ping", self.handle_ping)
|
|
55
|
+
|
|
56
|
+
# Client management
|
|
57
|
+
self.sio.on("client:register", self.handle_client_register)
|
|
58
|
+
self.sio.on("client:list", self.handle_client_list)
|
|
59
|
+
|
|
60
|
+
self.logger.info("Dashboard event handlers registered")
|
|
61
|
+
|
|
62
|
+
except Exception as e:
|
|
63
|
+
self.logger.error(f"Error registering dashboard handlers: {e}")
|
|
64
|
+
raise
|
|
65
|
+
|
|
66
|
+
async def handle_connect(self, sid: str, environ: Dict):
|
|
67
|
+
"""Handle client connection.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
sid: Socket.IO session ID
|
|
71
|
+
environ: Connection environment
|
|
72
|
+
"""
|
|
73
|
+
try:
|
|
74
|
+
self.connected_clients.add(sid)
|
|
75
|
+
|
|
76
|
+
# Extract client info
|
|
77
|
+
client_info = {
|
|
78
|
+
"connected_at": asyncio.get_event_loop().time(),
|
|
79
|
+
"user_agent": environ.get("HTTP_USER_AGENT", "Unknown"),
|
|
80
|
+
"remote_addr": environ.get("REMOTE_ADDR", "Unknown"),
|
|
81
|
+
}
|
|
82
|
+
self.client_info[sid] = client_info
|
|
83
|
+
|
|
84
|
+
self.logger.info(f"Dashboard client connected: {sid}")
|
|
85
|
+
|
|
86
|
+
# Send welcome message
|
|
87
|
+
await self.sio.emit(
|
|
88
|
+
"dashboard:welcome",
|
|
89
|
+
{
|
|
90
|
+
"message": "Connected to Claude MPM Unified Monitor",
|
|
91
|
+
"session_id": sid,
|
|
92
|
+
"server_info": {"service": "unified-monitor", "version": "1.0.0"},
|
|
93
|
+
},
|
|
94
|
+
room=sid,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# Broadcast client count update
|
|
98
|
+
await self._broadcast_client_count()
|
|
99
|
+
|
|
100
|
+
except Exception as e:
|
|
101
|
+
self.logger.error(f"Error handling client connection: {e}")
|
|
102
|
+
|
|
103
|
+
async def handle_disconnect(self, sid: str):
|
|
104
|
+
"""Handle client disconnection.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
sid: Socket.IO session ID
|
|
108
|
+
"""
|
|
109
|
+
try:
|
|
110
|
+
self.connected_clients.discard(sid)
|
|
111
|
+
self.client_info.pop(sid, None)
|
|
112
|
+
|
|
113
|
+
self.logger.info(f"Dashboard client disconnected: {sid}")
|
|
114
|
+
|
|
115
|
+
# Broadcast client count update
|
|
116
|
+
await self._broadcast_client_count()
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
self.logger.error(f"Error handling client disconnection: {e}")
|
|
120
|
+
|
|
121
|
+
async def handle_get_status(self, sid: str, data: Dict):
|
|
122
|
+
"""Handle dashboard status request.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
sid: Socket.IO session ID
|
|
126
|
+
data: Request data
|
|
127
|
+
"""
|
|
128
|
+
try:
|
|
129
|
+
status = {
|
|
130
|
+
"service": "unified-monitor",
|
|
131
|
+
"status": "running",
|
|
132
|
+
"clients_connected": len(self.connected_clients),
|
|
133
|
+
"uptime": asyncio.get_event_loop().time(),
|
|
134
|
+
"features": {
|
|
135
|
+
"code_analysis": True,
|
|
136
|
+
"real_ast": True,
|
|
137
|
+
"file_monitoring": True,
|
|
138
|
+
"dashboard": True,
|
|
139
|
+
},
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await self.sio.emit("dashboard:status:response", status, room=sid)
|
|
143
|
+
|
|
144
|
+
except Exception as e:
|
|
145
|
+
self.logger.error(f"Error getting dashboard status: {e}")
|
|
146
|
+
await self.sio.emit(
|
|
147
|
+
"dashboard:error", {"error": f"Status error: {e!s}"}, room=sid
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
async def handle_get_info(self, sid: str, data: Dict):
|
|
151
|
+
"""Handle dashboard info request.
|
|
152
|
+
|
|
153
|
+
Args:
|
|
154
|
+
sid: Socket.IO session ID
|
|
155
|
+
data: Request data
|
|
156
|
+
"""
|
|
157
|
+
try:
|
|
158
|
+
info = {
|
|
159
|
+
"service_name": "Claude MPM Unified Monitor",
|
|
160
|
+
"description": "Single stable daemon for all monitoring functionality",
|
|
161
|
+
"features": [
|
|
162
|
+
"Real AST Analysis",
|
|
163
|
+
"Code Tree Visualization",
|
|
164
|
+
"File System Monitoring",
|
|
165
|
+
"Socket.IO Events",
|
|
166
|
+
"HTTP Dashboard",
|
|
167
|
+
],
|
|
168
|
+
"endpoints": {"dashboard": "/", "health": "/health", "api": "/api/*"},
|
|
169
|
+
"events": {
|
|
170
|
+
"code_analysis": [
|
|
171
|
+
"code:analyze:file",
|
|
172
|
+
"code:analyze:directory",
|
|
173
|
+
"code:get:tree",
|
|
174
|
+
],
|
|
175
|
+
"dashboard": [
|
|
176
|
+
"dashboard:status",
|
|
177
|
+
"dashboard:info",
|
|
178
|
+
"dashboard:ping",
|
|
179
|
+
],
|
|
180
|
+
},
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
await self.sio.emit("dashboard:info:response", info, room=sid)
|
|
184
|
+
|
|
185
|
+
except Exception as e:
|
|
186
|
+
self.logger.error(f"Error getting dashboard info: {e}")
|
|
187
|
+
await self.sio.emit(
|
|
188
|
+
"dashboard:error", {"error": f"Info error: {e!s}"}, room=sid
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
async def handle_ping(self, sid: str, data: Dict):
|
|
192
|
+
"""Handle ping request.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
sid: Socket.IO session ID
|
|
196
|
+
data: Request data
|
|
197
|
+
"""
|
|
198
|
+
try:
|
|
199
|
+
timestamp = data.get("timestamp", asyncio.get_event_loop().time())
|
|
200
|
+
|
|
201
|
+
await self.sio.emit(
|
|
202
|
+
"dashboard:pong",
|
|
203
|
+
{
|
|
204
|
+
"timestamp": timestamp,
|
|
205
|
+
"server_time": asyncio.get_event_loop().time(),
|
|
206
|
+
},
|
|
207
|
+
room=sid,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
self.logger.error(f"Error handling ping: {e}")
|
|
212
|
+
|
|
213
|
+
async def handle_client_register(self, sid: str, data: Dict):
|
|
214
|
+
"""Handle client registration.
|
|
215
|
+
|
|
216
|
+
Args:
|
|
217
|
+
sid: Socket.IO session ID
|
|
218
|
+
data: Client registration data
|
|
219
|
+
"""
|
|
220
|
+
try:
|
|
221
|
+
client_name = data.get("name", f"Client-{sid[:8]}")
|
|
222
|
+
client_type = data.get("type", "dashboard")
|
|
223
|
+
|
|
224
|
+
# Update client info
|
|
225
|
+
if sid in self.client_info:
|
|
226
|
+
self.client_info[sid].update(
|
|
227
|
+
{"name": client_name, "type": client_type, "registered": True}
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
self.logger.info(f"Client registered: {client_name} ({client_type})")
|
|
231
|
+
|
|
232
|
+
await self.sio.emit(
|
|
233
|
+
"client:registered",
|
|
234
|
+
{"name": client_name, "type": client_type, "session_id": sid},
|
|
235
|
+
room=sid,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
except Exception as e:
|
|
239
|
+
self.logger.error(f"Error registering client: {e}")
|
|
240
|
+
await self.sio.emit(
|
|
241
|
+
"dashboard:error", {"error": f"Registration error: {e!s}"}, room=sid
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
async def handle_client_list(self, sid: str, data: Dict):
|
|
245
|
+
"""Handle client list request.
|
|
246
|
+
|
|
247
|
+
Args:
|
|
248
|
+
sid: Socket.IO session ID
|
|
249
|
+
data: Request data
|
|
250
|
+
"""
|
|
251
|
+
try:
|
|
252
|
+
client_list = []
|
|
253
|
+
for client_sid, info in self.client_info.items():
|
|
254
|
+
client_list.append(
|
|
255
|
+
{
|
|
256
|
+
"session_id": client_sid,
|
|
257
|
+
"name": info.get("name", f"Client-{client_sid[:8]}"),
|
|
258
|
+
"type": info.get("type", "unknown"),
|
|
259
|
+
"connected_at": info.get("connected_at"),
|
|
260
|
+
"registered": info.get("registered", False),
|
|
261
|
+
}
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
await self.sio.emit(
|
|
265
|
+
"client:list:response",
|
|
266
|
+
{"clients": client_list, "total": len(client_list)},
|
|
267
|
+
room=sid,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
except Exception as e:
|
|
271
|
+
self.logger.error(f"Error getting client list: {e}")
|
|
272
|
+
await self.sio.emit(
|
|
273
|
+
"dashboard:error", {"error": f"Client list error: {e!s}"}, room=sid
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
async def _broadcast_client_count(self):
|
|
277
|
+
"""Broadcast client count update to all connected clients."""
|
|
278
|
+
try:
|
|
279
|
+
await self.sio.emit(
|
|
280
|
+
"dashboard:client:count", {"count": len(self.connected_clients)}
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
except Exception as e:
|
|
284
|
+
self.logger.error(f"Error broadcasting client count: {e}")
|
|
285
|
+
|
|
286
|
+
def get_stats(self) -> Dict:
|
|
287
|
+
"""Get handler statistics.
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
Dictionary with handler stats
|
|
291
|
+
"""
|
|
292
|
+
return {
|
|
293
|
+
"connected_clients": len(self.connected_clients),
|
|
294
|
+
"registered_clients": sum(
|
|
295
|
+
1 for info in self.client_info.values() if info.get("registered", False)
|
|
296
|
+
),
|
|
297
|
+
"client_types": {},
|
|
298
|
+
}
|