claude-mpm 4.1.12__py3-none-any.whl → 4.1.13__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/monitor.py +88 -627
- claude_mpm/cli/commands/mpm_init.py +7 -2
- claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/built/components/code-tree.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/activity.css +1239 -267
- claude_mpm/dashboard/static/css/dashboard.css +511 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-tree.js +2 -2593
- claude_mpm/dashboard/static/dist/components/module-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 +1193 -892
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -17
- claude_mpm/dashboard/static/js/components/module-viewer.js +21 -7
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +1066 -0
- claude_mpm/dashboard/static/js/connection-manager.js +1 -1
- claude_mpm/dashboard/static/js/dashboard.js +196 -43
- claude_mpm/dashboard/static/js/socket-client.js +2 -2
- claude_mpm/dashboard/templates/index.html +95 -25
- claude_mpm/services/cli/socketio_manager.py +1 -1
- claude_mpm/services/infrastructure/monitoring.py +1 -1
- {claude_mpm-4.1.12.dist-info → claude_mpm-4.1.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.12.dist-info → claude_mpm-4.1.13.dist-info}/RECORD +30 -29
- {claude_mpm-4.1.12.dist-info → claude_mpm-4.1.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.12.dist-info → claude_mpm-4.1.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.12.dist-info → claude_mpm-4.1.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.12.dist-info → claude_mpm-4.1.13.dist-info}/top_level.txt +0 -0
|
@@ -3,28 +3,29 @@ Monitor command implementation for claude-mpm.
|
|
|
3
3
|
|
|
4
4
|
WHY: This module provides CLI commands for managing the Socket.IO monitoring server,
|
|
5
5
|
allowing users to start, stop, restart, and check status of the monitoring infrastructure.
|
|
6
|
+
The monitor command now delegates to the unified dashboard service for consolidated operation.
|
|
6
7
|
|
|
7
8
|
DESIGN DECISIONS:
|
|
9
|
+
- Delegate to dashboard command for unified service architecture
|
|
8
10
|
- Use BaseCommand for consistent CLI patterns
|
|
9
|
-
- Leverage shared utilities for argument parsing and output formatting
|
|
10
11
|
- Maintain backward compatibility with existing Socket.IO server management
|
|
11
12
|
- Support multiple output formats (json, yaml, table, text)
|
|
12
13
|
"""
|
|
13
14
|
|
|
14
|
-
import subprocess
|
|
15
|
-
import sys
|
|
16
15
|
from typing import Optional
|
|
17
16
|
|
|
18
17
|
from ...constants import MonitorCommands
|
|
19
|
-
from ...core.logger import get_logger
|
|
20
18
|
from ..shared import BaseCommand, CommandResult
|
|
19
|
+
from .dashboard import DashboardCommand
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class MonitorCommand(BaseCommand):
|
|
24
|
-
"""Monitor command
|
|
23
|
+
"""Monitor command that delegates to the unified dashboard service."""
|
|
25
24
|
|
|
26
25
|
def __init__(self):
|
|
27
26
|
super().__init__("monitor")
|
|
27
|
+
# Create dashboard command instance for delegation
|
|
28
|
+
self.dashboard_command = DashboardCommand()
|
|
28
29
|
|
|
29
30
|
def validate_args(self, args) -> Optional[str]:
|
|
30
31
|
"""Validate command arguments."""
|
|
@@ -37,41 +38,26 @@ class MonitorCommand(BaseCommand):
|
|
|
37
38
|
return None
|
|
38
39
|
|
|
39
40
|
def run(self, args) -> CommandResult:
|
|
40
|
-
"""Execute the monitor command."""
|
|
41
|
+
"""Execute the monitor command by delegating to dashboard service."""
|
|
41
42
|
try:
|
|
42
|
-
|
|
43
|
-
from ...scripts.socketio_server_manager import ServerManager
|
|
43
|
+
self.logger.info("Monitor command delegating to unified dashboard service")
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
# Handle default case (no subcommand)
|
|
45
|
+
# Handle default case (no subcommand) - default to status
|
|
48
46
|
if not hasattr(args, "monitor_command") or not args.monitor_command:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
return
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
MonitorCommands.PORT.value: self._port_server,
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if args.monitor_command in command_map:
|
|
67
|
-
success = command_map[args.monitor_command](args, server_manager)
|
|
68
|
-
if success:
|
|
69
|
-
return CommandResult.success_result(
|
|
70
|
-
f"Monitor {args.monitor_command} completed successfully"
|
|
71
|
-
)
|
|
72
|
-
return CommandResult.error_result(
|
|
73
|
-
f"Monitor {args.monitor_command} failed"
|
|
74
|
-
)
|
|
47
|
+
return self._status_dashboard(args)
|
|
48
|
+
|
|
49
|
+
# Map monitor commands to dashboard commands
|
|
50
|
+
if args.monitor_command == MonitorCommands.START.value:
|
|
51
|
+
return self._start_dashboard(args)
|
|
52
|
+
if args.monitor_command == MonitorCommands.STOP.value:
|
|
53
|
+
return self._stop_dashboard(args)
|
|
54
|
+
if args.monitor_command == MonitorCommands.RESTART.value:
|
|
55
|
+
return self._restart_dashboard(args)
|
|
56
|
+
if args.monitor_command == MonitorCommands.STATUS.value:
|
|
57
|
+
return self._status_dashboard(args)
|
|
58
|
+
if args.monitor_command == MonitorCommands.PORT.value:
|
|
59
|
+
return self._start_dashboard_on_port(args)
|
|
60
|
+
|
|
75
61
|
return CommandResult.error_result(
|
|
76
62
|
f"Unknown monitor command: {args.monitor_command}"
|
|
77
63
|
)
|
|
@@ -80,616 +66,91 @@ class MonitorCommand(BaseCommand):
|
|
|
80
66
|
self.logger.error(f"Error executing monitor command: {e}", exc_info=True)
|
|
81
67
|
return CommandResult.error_result(f"Error executing monitor command: {e}")
|
|
82
68
|
|
|
83
|
-
def
|
|
84
|
-
"""Start the
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"""Restart the monitoring server."""
|
|
93
|
-
return _restart_server(args, server_manager)
|
|
94
|
-
|
|
95
|
-
def _status_server(self, args, server_manager) -> bool:
|
|
96
|
-
"""Get monitoring server status."""
|
|
97
|
-
return _status_server(args, server_manager)
|
|
98
|
-
|
|
99
|
-
def _port_server(self, args, server_manager) -> bool:
|
|
100
|
-
"""Start/restart server on specific port."""
|
|
101
|
-
return _port_server(args, server_manager)
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def manage_monitor(args):
|
|
105
|
-
"""
|
|
106
|
-
Main entry point for monitor command.
|
|
107
|
-
|
|
108
|
-
This function maintains backward compatibility while using the new BaseCommand pattern.
|
|
109
|
-
"""
|
|
110
|
-
command = MonitorCommand()
|
|
111
|
-
result = command.execute(args)
|
|
112
|
-
|
|
113
|
-
# Print result if structured output format is requested
|
|
114
|
-
if hasattr(args, "format") and args.format in ["json", "yaml"]:
|
|
115
|
-
command.print_result(result, args)
|
|
116
|
-
|
|
117
|
-
return result.exit_code
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def manage_monitor_legacy(args):
|
|
121
|
-
"""
|
|
122
|
-
Legacy monitor command dispatcher.
|
|
123
|
-
|
|
124
|
-
WHY: This contains the original manage_monitor logic, preserved during migration
|
|
125
|
-
to BaseCommand pattern. Will be gradually refactored into the MonitorCommand class.
|
|
126
|
-
|
|
127
|
-
DESIGN DECISION: When no subcommand is provided, we show the server status
|
|
128
|
-
as the default action, giving users a quick overview of the monitoring system.
|
|
129
|
-
|
|
130
|
-
Args:
|
|
131
|
-
args: Parsed command line arguments with monitor_command attribute
|
|
132
|
-
"""
|
|
133
|
-
logger = get_logger("cli")
|
|
134
|
-
|
|
135
|
-
try:
|
|
136
|
-
# Import ServerManager from socketio_server_manager.py
|
|
137
|
-
from ...scripts.socketio_server_manager import ServerManager
|
|
138
|
-
|
|
139
|
-
server_manager = ServerManager()
|
|
140
|
-
|
|
141
|
-
if not args.monitor_command:
|
|
142
|
-
# No subcommand - show status as default
|
|
143
|
-
# WHY: Status is the most common operation users want when running monitor without args
|
|
144
|
-
args.verbose = False # Set default for verbose flag
|
|
145
|
-
success = _status_server(args, server_manager)
|
|
146
|
-
return 0 if success else 1
|
|
147
|
-
|
|
148
|
-
if args.monitor_command == MonitorCommands.START.value:
|
|
149
|
-
success = _start_server(args, server_manager)
|
|
150
|
-
return 0 if success else 1
|
|
69
|
+
def _start_dashboard(self, args) -> CommandResult:
|
|
70
|
+
"""Start the dashboard service (unified HTTP + Socket.IO)."""
|
|
71
|
+
self.logger.info("Starting unified dashboard service (HTTP + Socket.IO)")
|
|
72
|
+
# Set default port to 8765 for unified service and background mode
|
|
73
|
+
if not hasattr(args, "port") or args.port is None:
|
|
74
|
+
args.port = 8765
|
|
75
|
+
# Monitor command defaults to background mode for better UX
|
|
76
|
+
if not hasattr(args, "background"):
|
|
77
|
+
args.background = True
|
|
151
78
|
|
|
152
|
-
|
|
153
|
-
success = _stop_server(args, server_manager)
|
|
154
|
-
return 0 if success else 1
|
|
79
|
+
return self.dashboard_command._start_dashboard(args)
|
|
155
80
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
81
|
+
def _stop_dashboard(self, args) -> CommandResult:
|
|
82
|
+
"""Stop the dashboard service."""
|
|
83
|
+
self.logger.info("Stopping unified dashboard service")
|
|
84
|
+
# Use default port if not specified
|
|
85
|
+
if not hasattr(args, "port") or args.port is None:
|
|
86
|
+
args.port = 8765
|
|
159
87
|
|
|
160
|
-
|
|
161
|
-
success = _status_server(args, server_manager)
|
|
162
|
-
return 0 if success else 1
|
|
88
|
+
return self.dashboard_command._stop_dashboard(args)
|
|
163
89
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
90
|
+
def _restart_dashboard(self, args) -> CommandResult:
|
|
91
|
+
"""Restart the dashboard service."""
|
|
92
|
+
self.logger.info("Restarting unified dashboard service")
|
|
167
93
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
except ImportError as e:
|
|
174
|
-
logger.error(f"Server manager not available: {e}")
|
|
175
|
-
print("Error: Socket.IO server manager not available")
|
|
176
|
-
print("This may indicate a missing dependency or installation issue.")
|
|
177
|
-
return 1
|
|
178
|
-
except Exception as e:
|
|
179
|
-
logger.error(f"Error managing monitor: {e}")
|
|
180
|
-
print(f"Error: {e}")
|
|
181
|
-
return 1
|
|
182
|
-
|
|
183
|
-
return 0
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
def _port_server(args, server_manager):
|
|
187
|
-
"""
|
|
188
|
-
Start or restart the Socket.IO monitoring server on a specific port.
|
|
94
|
+
# Stop first
|
|
95
|
+
stop_result = self._stop_dashboard(args)
|
|
96
|
+
if not stop_result.success:
|
|
97
|
+
self.logger.warning("Failed to stop service for restart, proceeding anyway")
|
|
189
98
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
on a different port (restart). Enhanced with smart process detection to reclaim
|
|
193
|
-
ports from debug processes.
|
|
99
|
+
# Wait a moment
|
|
100
|
+
import time
|
|
194
101
|
|
|
195
|
-
|
|
196
|
-
args: Command arguments with required port and optional host, force, reclaim flags
|
|
197
|
-
server_manager: ServerManager instance
|
|
102
|
+
time.sleep(1)
|
|
198
103
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
"""
|
|
202
|
-
port = args.port
|
|
203
|
-
host = getattr(args, "host", "localhost")
|
|
204
|
-
force = getattr(args, "force", False)
|
|
205
|
-
reclaim = getattr(args, "reclaim", True)
|
|
206
|
-
|
|
207
|
-
print(f"Managing Socket.IO monitoring server on port {port}...")
|
|
208
|
-
print(f"Target: {host}:{port}")
|
|
209
|
-
print()
|
|
210
|
-
|
|
211
|
-
try:
|
|
212
|
-
# Import PortManager to check port status
|
|
213
|
-
from ...services.port_manager import PortManager
|
|
214
|
-
|
|
215
|
-
port_manager = PortManager()
|
|
216
|
-
|
|
217
|
-
# Get detailed port status
|
|
218
|
-
port_status = port_manager.get_port_status(port)
|
|
219
|
-
|
|
220
|
-
# Check if port is in use
|
|
221
|
-
if not port_status["available"]:
|
|
222
|
-
process_info = port_status.get("process")
|
|
223
|
-
if process_info:
|
|
224
|
-
print(f"⚠️ Port {port} is in use:")
|
|
225
|
-
print(f" Process: {process_info['name']} (PID: {process_info['pid']})")
|
|
226
|
-
|
|
227
|
-
if process_info["is_ours"]:
|
|
228
|
-
if process_info["is_debug"]:
|
|
229
|
-
print(" Type: Debug/Test script (can be reclaimed)")
|
|
230
|
-
if reclaim:
|
|
231
|
-
print(" Action: Attempting to reclaim port...")
|
|
232
|
-
if port_manager.kill_process_on_port(port, force=force):
|
|
233
|
-
print(f" ✅ Successfully reclaimed port {port}")
|
|
234
|
-
else:
|
|
235
|
-
print(f" ❌ Failed to reclaim port {port}")
|
|
236
|
-
return False
|
|
237
|
-
elif process_info["is_daemon"]:
|
|
238
|
-
print(" Type: Daemon process")
|
|
239
|
-
if force:
|
|
240
|
-
print(
|
|
241
|
-
" Action: Force killing daemon (--force flag used)..."
|
|
242
|
-
)
|
|
243
|
-
if port_manager.kill_process_on_port(port, force=True):
|
|
244
|
-
print(f" ✅ Successfully killed daemon on port {port}")
|
|
245
|
-
else:
|
|
246
|
-
print(f" ❌ Failed to kill daemon on port {port}")
|
|
247
|
-
return False
|
|
248
|
-
else:
|
|
249
|
-
print(" ❌ Cannot start: Daemon already running")
|
|
250
|
-
print(f" Recommendation: {port_status['recommendation']}")
|
|
251
|
-
return False
|
|
252
|
-
else:
|
|
253
|
-
print(" Type: External process")
|
|
254
|
-
print(f" ❌ Cannot start: {port_status['recommendation']}")
|
|
255
|
-
return False
|
|
256
|
-
print()
|
|
257
|
-
|
|
258
|
-
# Check if there are any running servers
|
|
259
|
-
running_servers = server_manager.list_running_servers()
|
|
260
|
-
|
|
261
|
-
# Check if server is already running on this port after reclaim
|
|
262
|
-
server_on_port = any(server.get("port") == port for server in running_servers)
|
|
263
|
-
|
|
264
|
-
if server_on_port:
|
|
265
|
-
print(f"Server already running on port {port}. Restarting...")
|
|
266
|
-
success = server_manager.restart_server(port=port)
|
|
267
|
-
action = "restarted"
|
|
268
|
-
else:
|
|
269
|
-
# Check if servers are running on other ports
|
|
270
|
-
if running_servers:
|
|
271
|
-
print("Servers running on other ports:")
|
|
272
|
-
for server in running_servers:
|
|
273
|
-
server_port = server.get("port")
|
|
274
|
-
server_id = server.get("server_id", "unknown")
|
|
275
|
-
print(f" • Server '{server_id}' on port {server_port}")
|
|
276
|
-
print()
|
|
277
|
-
print(f"Starting new server on port {port}...")
|
|
278
|
-
else:
|
|
279
|
-
print("No servers currently running. Starting new server...")
|
|
280
|
-
|
|
281
|
-
success = server_manager.start_server(
|
|
282
|
-
port=port, host=host, server_id="monitor-server"
|
|
283
|
-
)
|
|
284
|
-
action = "started"
|
|
285
|
-
|
|
286
|
-
if success:
|
|
287
|
-
print()
|
|
288
|
-
print(f"Monitor server {action} successfully on port {port}")
|
|
289
|
-
print()
|
|
290
|
-
print("Server management commands:")
|
|
291
|
-
print(" Status: ps aux | grep socketio")
|
|
292
|
-
print(f" Stop: claude-mpm monitor stop --port {port}")
|
|
293
|
-
print(f" Restart: claude-mpm monitor restart --port {port}")
|
|
294
|
-
print()
|
|
295
|
-
print(f"WebSocket URL: ws://{host}:{port}")
|
|
296
|
-
else:
|
|
297
|
-
print(f"Failed to {action.replace('ed', '')} server on port {port}")
|
|
298
|
-
print()
|
|
299
|
-
print("Troubleshooting:")
|
|
300
|
-
print(f" • Check if port {port} is available: lsof -i :{port}")
|
|
301
|
-
print(f" • Try a different port: claude-mpm monitor port {port + 1}")
|
|
302
|
-
print(" • Check system resources: free -h && df -h")
|
|
303
|
-
|
|
304
|
-
return success
|
|
305
|
-
|
|
306
|
-
except Exception as e:
|
|
307
|
-
print(f"Error managing server on port {port}: {e}")
|
|
308
|
-
print()
|
|
309
|
-
print("Troubleshooting:")
|
|
310
|
-
print(f" • Verify port {port} is valid and available")
|
|
311
|
-
print(" • Check system resources and permissions")
|
|
312
|
-
print(" • Try manual start/stop operations")
|
|
313
|
-
return False
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
def _start_server(args, server_manager):
|
|
317
|
-
"""
|
|
318
|
-
Start the Socket.IO monitoring server.
|
|
104
|
+
# Start again
|
|
105
|
+
return self._start_dashboard(args)
|
|
319
106
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
107
|
+
def _status_dashboard(self, args) -> CommandResult:
|
|
108
|
+
"""Get dashboard service status."""
|
|
109
|
+
return self.dashboard_command._status_dashboard(args)
|
|
323
110
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
Returns:
|
|
329
|
-
bool: True if server started successfully, False otherwise
|
|
330
|
-
"""
|
|
331
|
-
port = getattr(args, "port", None)
|
|
332
|
-
host = getattr(args, "host", "localhost")
|
|
333
|
-
force = getattr(args, "force", False)
|
|
334
|
-
reclaim = getattr(args, "reclaim", True)
|
|
335
|
-
|
|
336
|
-
print("Starting Socket.IO monitoring server...")
|
|
337
|
-
|
|
338
|
-
try:
|
|
339
|
-
# Import PortManager for smart port selection
|
|
340
|
-
from ...services.port_manager import PortManager
|
|
341
|
-
|
|
342
|
-
port_manager = PortManager()
|
|
343
|
-
|
|
344
|
-
# If no port specified, find an available one with smart reclaim
|
|
345
|
-
if port is None:
|
|
346
|
-
port = port_manager.find_available_port(reclaim=reclaim)
|
|
347
|
-
if port is None:
|
|
348
|
-
print("❌ No available ports found")
|
|
349
|
-
print(
|
|
350
|
-
"Try specifying a port with --port or use --force to reclaim daemon ports"
|
|
351
|
-
)
|
|
352
|
-
return False
|
|
353
|
-
print(f"Selected port: {port}")
|
|
354
|
-
else:
|
|
355
|
-
# Check if specified port needs reclaiming
|
|
356
|
-
port_status = port_manager.get_port_status(port)
|
|
357
|
-
if not port_status["available"]:
|
|
358
|
-
process_info = port_status.get("process")
|
|
359
|
-
if process_info:
|
|
360
|
-
print(
|
|
361
|
-
f"⚠️ Port {port} is in use by {process_info['name']} (PID: {process_info['pid']})"
|
|
362
|
-
)
|
|
363
|
-
|
|
364
|
-
if process_info["is_ours"] and (process_info["is_debug"] or force):
|
|
365
|
-
if reclaim:
|
|
366
|
-
print(f"Attempting to reclaim port {port}...")
|
|
367
|
-
if not port_manager.kill_process_on_port(port, force=force):
|
|
368
|
-
print(f"❌ Failed to reclaim port {port}")
|
|
369
|
-
return False
|
|
370
|
-
print(f"✅ Successfully reclaimed port {port}")
|
|
371
|
-
else:
|
|
372
|
-
print(
|
|
373
|
-
f"❌ Port {port} unavailable and --no-reclaim specified"
|
|
374
|
-
)
|
|
375
|
-
return False
|
|
376
|
-
else:
|
|
377
|
-
print(
|
|
378
|
-
f"❌ Cannot reclaim port: {port_status['recommendation']}"
|
|
379
|
-
)
|
|
380
|
-
return False
|
|
381
|
-
|
|
382
|
-
print(f"Target: {host}:{port}")
|
|
383
|
-
print()
|
|
384
|
-
|
|
385
|
-
success = server_manager.start_server(
|
|
386
|
-
port=port, host=host, server_id="monitor-server"
|
|
111
|
+
def _start_dashboard_on_port(self, args) -> CommandResult:
|
|
112
|
+
"""Start dashboard service on specific port."""
|
|
113
|
+
self.logger.info(
|
|
114
|
+
f"Starting dashboard service on port {getattr(args, 'port', 8765)}"
|
|
387
115
|
)
|
|
116
|
+
# Ensure background mode for port-specific starts
|
|
117
|
+
if not hasattr(args, "background"):
|
|
118
|
+
args.background = True
|
|
388
119
|
|
|
389
|
-
|
|
390
|
-
print()
|
|
391
|
-
print("Monitor server management commands:")
|
|
392
|
-
print(" Status: claude-mpm monitor status")
|
|
393
|
-
print(" Stop: claude-mpm monitor stop")
|
|
394
|
-
print(" Restart: claude-mpm monitor restart")
|
|
395
|
-
print()
|
|
396
|
-
print(f"WebSocket URL: ws://{host}:{port}")
|
|
397
|
-
|
|
398
|
-
return success
|
|
120
|
+
return self.dashboard_command._start_dashboard(args)
|
|
399
121
|
|
|
400
|
-
except Exception as e:
|
|
401
|
-
print(f"Failed to start monitoring server: {e}")
|
|
402
|
-
print()
|
|
403
|
-
print("Troubleshooting:")
|
|
404
|
-
print(f" • Check if port {port} is available: lsof -i :{port}")
|
|
405
|
-
print(f" • Try a different port: claude-mpm monitor start --port {port + 1}")
|
|
406
|
-
print(" • Check system resources: free -h && df -h")
|
|
407
|
-
return False
|
|
408
122
|
|
|
409
|
-
|
|
410
|
-
def _stop_server(args, server_manager):
|
|
123
|
+
def manage_monitor(args):
|
|
411
124
|
"""
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
WHY: Users need to stop the monitoring server when it's no longer needed
|
|
415
|
-
or when troubleshooting connection issues.
|
|
416
|
-
|
|
417
|
-
Args:
|
|
418
|
-
args: Command arguments with optional port
|
|
419
|
-
server_manager: ServerManager instance
|
|
125
|
+
Main entry point for monitor command.
|
|
420
126
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
"""
|
|
424
|
-
port = getattr(args, "port", None)
|
|
425
|
-
|
|
426
|
-
print("Stopping Socket.IO monitoring server...")
|
|
427
|
-
|
|
428
|
-
try:
|
|
429
|
-
# If no port specified, try to find running servers and stop them
|
|
430
|
-
if port is None:
|
|
431
|
-
running_servers = server_manager.list_running_servers()
|
|
432
|
-
if not running_servers:
|
|
433
|
-
print("No running servers found to stop")
|
|
434
|
-
return True
|
|
435
|
-
|
|
436
|
-
# Stop the first server (or all if multiple)
|
|
437
|
-
success = True
|
|
438
|
-
for server in running_servers:
|
|
439
|
-
server_port = server.get("port")
|
|
440
|
-
server_id = server.get("server_id", "unknown")
|
|
441
|
-
print(f"Stopping server '{server_id}' on port {server_port}...")
|
|
442
|
-
|
|
443
|
-
if not server_manager.stop_server(port=server_port):
|
|
444
|
-
print(f"Failed to stop server on port {server_port}")
|
|
445
|
-
success = False
|
|
446
|
-
|
|
447
|
-
return success
|
|
448
|
-
# Stop specific server on given port
|
|
449
|
-
success = server_manager.stop_server(port=port)
|
|
450
|
-
|
|
451
|
-
if success:
|
|
452
|
-
print(f"Monitor server stopped on port {port}")
|
|
453
|
-
else:
|
|
454
|
-
print(f"Failed to stop server on port {port}")
|
|
455
|
-
print()
|
|
456
|
-
print("Troubleshooting:")
|
|
457
|
-
print(" • Check if server is running: claude-mpm monitor status")
|
|
458
|
-
print(f" • Try force kill: kill $(lsof -ti :{port})")
|
|
459
|
-
|
|
460
|
-
return success
|
|
461
|
-
|
|
462
|
-
except Exception as e:
|
|
463
|
-
print(f"Error stopping server: {e}")
|
|
464
|
-
return False
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
def _status_server(args, server_manager):
|
|
127
|
+
The monitor command now delegates to the unified dashboard service for consolidated operation.
|
|
128
|
+
Both dashboard and monitor commands now use the same underlying service on port 8765.
|
|
468
129
|
"""
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
WHY: Users need to check if the monitoring server is running, what port
|
|
472
|
-
it's using, and other diagnostic information without starting/stopping it.
|
|
473
|
-
Enhanced to show what processes are using ports.
|
|
130
|
+
command = MonitorCommand()
|
|
131
|
+
error = command.validate_args(args)
|
|
474
132
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
133
|
+
if error:
|
|
134
|
+
command.logger.error(error)
|
|
135
|
+
print(f"Error: {error}")
|
|
136
|
+
return 1
|
|
478
137
|
|
|
479
|
-
|
|
480
|
-
bool: True if status check succeeded, False otherwise
|
|
481
|
-
"""
|
|
482
|
-
verbose = getattr(args, "verbose", False)
|
|
483
|
-
show_ports = getattr(args, "show_ports", False)
|
|
484
|
-
|
|
485
|
-
print("Checking Socket.IO monitoring server status...")
|
|
486
|
-
print()
|
|
487
|
-
|
|
488
|
-
try:
|
|
489
|
-
# Check for daemon server using socketio_daemon.py
|
|
490
|
-
daemon_script = server_manager.daemon_script
|
|
491
|
-
if daemon_script and daemon_script.exists():
|
|
492
|
-
# Try to get status from daemon
|
|
493
|
-
result = subprocess.run(
|
|
494
|
-
[sys.executable, str(daemon_script), "status"],
|
|
495
|
-
capture_output=True,
|
|
496
|
-
text=True,
|
|
497
|
-
check=False,
|
|
498
|
-
)
|
|
138
|
+
result = command.run(args)
|
|
499
139
|
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
# Show additional information
|
|
506
|
-
print("\nAdditional Details:")
|
|
507
|
-
print("─" * 40)
|
|
508
|
-
|
|
509
|
-
# List all running servers from ServerManager
|
|
510
|
-
running_servers = server_manager.list_running_servers()
|
|
511
|
-
if running_servers:
|
|
512
|
-
print(f"Found {len(running_servers)} running server(s):")
|
|
513
|
-
for server in running_servers:
|
|
514
|
-
server_port = server.get("port", "unknown")
|
|
515
|
-
server_id = server.get("server_id", "unknown")
|
|
516
|
-
server_pid = server.get("pid", "unknown")
|
|
517
|
-
print(f" • Server '{server_id}'")
|
|
518
|
-
print(f" Port: {server_port}")
|
|
519
|
-
print(f" PID: {server_pid}")
|
|
520
|
-
else:
|
|
521
|
-
print("No additional servers found via ServerManager")
|
|
522
|
-
|
|
523
|
-
return True
|
|
524
|
-
|
|
525
|
-
# Fall back to ServerManager's list_running_servers
|
|
526
|
-
running_servers = server_manager.list_running_servers()
|
|
527
|
-
|
|
528
|
-
if not running_servers:
|
|
529
|
-
print("❌ No Socket.IO monitoring servers are currently running")
|
|
530
|
-
print()
|
|
531
|
-
print("To start a server:")
|
|
532
|
-
print(" claude-mpm monitor start")
|
|
533
|
-
print(" claude-mpm monitor start --port 8765")
|
|
534
|
-
return True
|
|
535
|
-
|
|
536
|
-
# Import PortManager for enhanced status
|
|
537
|
-
from ...services.port_manager import PortManager
|
|
538
|
-
|
|
539
|
-
port_manager = PortManager()
|
|
540
|
-
|
|
541
|
-
# Display server information
|
|
542
|
-
print(f"✅ Found {len(running_servers)} running server(s):")
|
|
543
|
-
print()
|
|
544
|
-
|
|
545
|
-
for server in running_servers:
|
|
546
|
-
server_port = server.get("port", "unknown")
|
|
547
|
-
server_id = server.get("server_id", "unknown")
|
|
548
|
-
server_pid = server.get("pid", "unknown")
|
|
549
|
-
server_host = server.get("host", "localhost")
|
|
550
|
-
|
|
551
|
-
print(f"Server: {server_id}")
|
|
552
|
-
print(f" • PID: {server_pid}")
|
|
553
|
-
print(f" • Port: {server_port}")
|
|
554
|
-
print(f" • Host: {server_host}")
|
|
555
|
-
print(f" • WebSocket URL: ws://{server_host}:{server_port}")
|
|
556
|
-
|
|
557
|
-
# Show port status if verbose
|
|
558
|
-
if verbose and server_port != "unknown":
|
|
559
|
-
port_status = port_manager.get_port_status(int(server_port))
|
|
560
|
-
if port_status.get("process"):
|
|
561
|
-
process = port_status["process"]
|
|
562
|
-
print(
|
|
563
|
-
f" • Process Type: {'Debug' if process['is_debug'] else 'Daemon' if process['is_daemon'] else 'Regular'}"
|
|
564
|
-
)
|
|
565
|
-
|
|
566
|
-
if verbose:
|
|
567
|
-
# Check if port is actually listening
|
|
568
|
-
try:
|
|
569
|
-
import socket
|
|
570
|
-
|
|
571
|
-
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
572
|
-
result = sock.connect_ex((server_host, server_port))
|
|
573
|
-
sock.close()
|
|
574
|
-
if result == 0:
|
|
575
|
-
print(" • Status: ✅ Listening")
|
|
576
|
-
else:
|
|
577
|
-
print(" • Status: ⚠️ Not responding on port")
|
|
578
|
-
except Exception as e:
|
|
579
|
-
print(f" • Status: ❌ Error checking: {e}")
|
|
580
|
-
|
|
581
|
-
print()
|
|
582
|
-
|
|
583
|
-
# Show port range status if requested
|
|
584
|
-
if show_ports or verbose:
|
|
585
|
-
print("\nPort Range Status (8765-8785):")
|
|
586
|
-
print("─" * 40)
|
|
587
|
-
for check_port in range(8765, 8771): # Show first 6 ports
|
|
588
|
-
status = port_manager.get_port_status(check_port)
|
|
589
|
-
if status["available"]:
|
|
590
|
-
print(f" Port {check_port}: ✅ Available")
|
|
591
|
-
else:
|
|
592
|
-
process = status.get("process")
|
|
593
|
-
if process:
|
|
594
|
-
if process["is_ours"]:
|
|
595
|
-
if process["is_debug"]:
|
|
596
|
-
print(
|
|
597
|
-
f" Port {check_port}: 🔧 Debug script (PID: {process['pid']})"
|
|
598
|
-
)
|
|
599
|
-
elif process["is_daemon"]:
|
|
600
|
-
print(
|
|
601
|
-
f" Port {check_port}: 🚀 Daemon (PID: {process['pid']})"
|
|
602
|
-
)
|
|
603
|
-
else:
|
|
604
|
-
print(
|
|
605
|
-
f" Port {check_port}: 📦 Our process (PID: {process['pid']})"
|
|
606
|
-
)
|
|
607
|
-
else:
|
|
608
|
-
print(
|
|
609
|
-
f" Port {check_port}: ⛔ External ({process['name']})"
|
|
610
|
-
)
|
|
611
|
-
else:
|
|
612
|
-
print(f" Port {check_port}: ❓ In use (unknown process)")
|
|
613
|
-
print()
|
|
614
|
-
|
|
615
|
-
print("Server management commands:")
|
|
616
|
-
print(" Stop all: claude-mpm monitor stop")
|
|
617
|
-
print(" Restart: claude-mpm monitor restart")
|
|
618
|
-
print(" Reclaim: claude-mpm monitor start --force # Kill debug scripts")
|
|
619
|
-
if len(running_servers) == 1:
|
|
620
|
-
port = running_servers[0].get("port", 8765)
|
|
621
|
-
print(f" Stop this: claude-mpm monitor stop --port {port}")
|
|
622
|
-
|
|
623
|
-
return True
|
|
624
|
-
|
|
625
|
-
except Exception as e:
|
|
626
|
-
print(f"Error checking server status: {e}")
|
|
627
|
-
print()
|
|
628
|
-
print("Try manual checks:")
|
|
629
|
-
print(" • Process list: ps aux | grep socketio")
|
|
630
|
-
print(" • Port usage: lsof -i :8765")
|
|
631
|
-
return False
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
def _restart_server(args, server_manager):
|
|
635
|
-
"""
|
|
636
|
-
Restart the Socket.IO monitoring server.
|
|
140
|
+
if result.success:
|
|
141
|
+
if result.message:
|
|
142
|
+
print(result.message)
|
|
143
|
+
if result.data and getattr(args, "verbose", False):
|
|
144
|
+
import json
|
|
637
145
|
|
|
638
|
-
|
|
639
|
-
|
|
146
|
+
print(json.dumps(result.data, indent=2))
|
|
147
|
+
return 0
|
|
148
|
+
if result.message:
|
|
149
|
+
print(f"Error: {result.message}")
|
|
150
|
+
return 1
|
|
640
151
|
|
|
641
|
-
Args:
|
|
642
|
-
args: Command arguments with optional port
|
|
643
|
-
server_manager: ServerManager instance
|
|
644
152
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
print("Restarting Socket.IO monitoring server...")
|
|
651
|
-
|
|
652
|
-
try:
|
|
653
|
-
# If no port specified, find running servers to restart
|
|
654
|
-
if port is None:
|
|
655
|
-
running_servers = server_manager.list_running_servers()
|
|
656
|
-
if not running_servers:
|
|
657
|
-
print(
|
|
658
|
-
"No running servers found. Starting new server on default port..."
|
|
659
|
-
)
|
|
660
|
-
return _start_server(args, server_manager)
|
|
661
|
-
|
|
662
|
-
# Restart the first server found
|
|
663
|
-
server = running_servers[0]
|
|
664
|
-
port = server.get("port", 8765)
|
|
665
|
-
|
|
666
|
-
print(f"Using port {port} for restart...")
|
|
667
|
-
|
|
668
|
-
# Use ServerManager's restart method
|
|
669
|
-
success = server_manager.restart_server(port=port)
|
|
670
|
-
|
|
671
|
-
if success:
|
|
672
|
-
print(f"Monitor server restarted successfully on port {port}")
|
|
673
|
-
print()
|
|
674
|
-
print("Server management commands:")
|
|
675
|
-
print(" Status: claude-mpm monitor status")
|
|
676
|
-
print(f" Stop: claude-mpm monitor stop --port {port}")
|
|
677
|
-
print(f" Start: claude-mpm monitor start --port {port}")
|
|
678
|
-
else:
|
|
679
|
-
print(f"Failed to restart server on port {port}")
|
|
680
|
-
print()
|
|
681
|
-
print("Troubleshooting:")
|
|
682
|
-
print(" • Try stopping and starting manually:")
|
|
683
|
-
print(f" claude-mpm monitor stop --port {port}")
|
|
684
|
-
print(f" claude-mpm monitor start --port {port}")
|
|
685
|
-
print(" • Check server logs for errors")
|
|
686
|
-
|
|
687
|
-
return success
|
|
688
|
-
|
|
689
|
-
except Exception as e:
|
|
690
|
-
print(f"Error restarting server: {e}")
|
|
691
|
-
print()
|
|
692
|
-
print("Fallback options:")
|
|
693
|
-
print(" • Manual restart: stop then start")
|
|
694
|
-
print(" • Check system resources and try again")
|
|
695
|
-
return False
|
|
153
|
+
# All legacy functions have been removed.
|
|
154
|
+
# The monitor command now delegates to the unified dashboard service.
|
|
155
|
+
# This consolidation provides a single service that handles both HTTP (port 8765)
|
|
156
|
+
# and Socket.IO (also on port 8765) rather than separate services on different ports.
|