claude-mpm 4.1.8__py3-none-any.whl → 4.1.10__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/INSTRUCTIONS.md +26 -1
- claude_mpm/agents/agents_metadata.py +57 -0
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
- claude_mpm/agents/templates/agent-manager.json +263 -17
- claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
- claude_mpm/agents/templates/code_analyzer.json +18 -8
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/cli/__init__.py +4 -0
- claude_mpm/cli/commands/__init__.py +6 -0
- claude_mpm/cli/commands/analyze.py +547 -0
- claude_mpm/cli/commands/analyze_code.py +524 -0
- claude_mpm/cli/commands/configure.py +77 -28
- claude_mpm/cli/commands/configure_tui.py +60 -60
- claude_mpm/cli/commands/debug.py +1387 -0
- claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
- claude_mpm/cli/parsers/analyze_parser.py +135 -0
- claude_mpm/cli/parsers/base_parser.py +29 -0
- claude_mpm/cli/parsers/debug_parser.py +319 -0
- claude_mpm/constants.py +3 -1
- claude_mpm/core/framework_loader.py +148 -6
- claude_mpm/core/log_manager.py +16 -13
- claude_mpm/core/logger.py +1 -1
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
- claude_mpm/dashboard/analysis_runner.py +428 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/working-directory.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 +549 -0
- claude_mpm/dashboard/static/css/code-tree.css +846 -0
- claude_mpm/dashboard/static/css/dashboard.css +245 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/working-directory.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 +1139 -0
- claude_mpm/dashboard/static/js/components/code-tree.js +1357 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +11 -0
- claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
- claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
- claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
- claude_mpm/dashboard/static/js/dashboard.js +39 -0
- claude_mpm/dashboard/static/js/socket-client.js +414 -20
- claude_mpm/dashboard/templates/index.html +184 -4
- claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
- claude_mpm/hooks/claude_hooks/installer.py +386 -113
- claude_mpm/scripts/claude-hook-handler.sh +161 -0
- claude_mpm/scripts/socketio_daemon.py +121 -8
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
- claude_mpm/services/agents/memory/memory_format_service.py +1 -5
- claude_mpm/services/cli/agent_cleanup_service.py +1 -2
- claude_mpm/services/cli/agent_dependency_service.py +1 -1
- claude_mpm/services/cli/agent_validation_service.py +3 -4
- claude_mpm/services/cli/dashboard_launcher.py +2 -3
- claude_mpm/services/cli/startup_checker.py +0 -10
- claude_mpm/services/core/cache_manager.py +1 -2
- claude_mpm/services/core/path_resolver.py +1 -4
- claude_mpm/services/core/service_container.py +2 -2
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
- claude_mpm/services/infrastructure/monitoring.py +11 -11
- claude_mpm/services/project/architecture_analyzer.py +1 -1
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/language_analyzer.py +3 -3
- claude_mpm/services/project/metrics_collector.py +3 -6
- claude_mpm/services/socketio/handlers/__init__.py +2 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +170 -0
- claude_mpm/services/socketio/handlers/registry.py +2 -0
- claude_mpm/services/socketio/server/connection_manager.py +4 -4
- claude_mpm/services/socketio/server/core.py +100 -11
- claude_mpm/services/socketio/server/main.py +8 -2
- claude_mpm/services/visualization/__init__.py +19 -0
- claude_mpm/services/visualization/mermaid_generator.py +938 -0
- claude_mpm/tools/__main__.py +208 -0
- claude_mpm/tools/code_tree_analyzer.py +778 -0
- claude_mpm/tools/code_tree_builder.py +632 -0
- claude_mpm/tools/code_tree_events.py +318 -0
- claude_mpm/tools/socketio_debug.py +671 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/RECORD +102 -73
- claude_mpm/agents/schema/agent_schema.json +0 -314
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,1387 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Debug command for claude-mpm CLI.
|
|
3
|
+
|
|
4
|
+
This module provides comprehensive debugging tools for developers, including:
|
|
5
|
+
- Service debugging (status, dependencies, health)
|
|
6
|
+
- Agent debugging (deployed, memory, trace)
|
|
7
|
+
- Hook system debugging (list, trace, performance)
|
|
8
|
+
- Cache inspection and management
|
|
9
|
+
- Performance profiling and analysis
|
|
10
|
+
- SocketIO event monitoring
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import contextlib
|
|
14
|
+
import json
|
|
15
|
+
import time
|
|
16
|
+
from collections import defaultdict
|
|
17
|
+
from datetime import datetime
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Any, Dict
|
|
20
|
+
|
|
21
|
+
from ...core.logger import get_logger
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def manage_debug(args):
|
|
25
|
+
"""
|
|
26
|
+
Main entry point for debug commands.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
args: Parsed command-line arguments
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
int: Exit code (0 for success, non-zero for failure)
|
|
33
|
+
"""
|
|
34
|
+
# Get logger (it will use the logging level set by main CLI)
|
|
35
|
+
logger = get_logger("debug")
|
|
36
|
+
|
|
37
|
+
# Dispatch to appropriate subcommand
|
|
38
|
+
if args.debug_command == "socketio":
|
|
39
|
+
return debug_socketio(args, logger)
|
|
40
|
+
if args.debug_command == "events":
|
|
41
|
+
# Alias for socketio
|
|
42
|
+
return debug_socketio(args, logger)
|
|
43
|
+
if args.debug_command == "connections":
|
|
44
|
+
return debug_connections(args, logger)
|
|
45
|
+
if args.debug_command == "services":
|
|
46
|
+
return debug_services(args, logger)
|
|
47
|
+
if args.debug_command == "agents":
|
|
48
|
+
return debug_agents(args, logger)
|
|
49
|
+
if args.debug_command == "hooks":
|
|
50
|
+
return debug_hooks(args, logger)
|
|
51
|
+
if args.debug_command == "cache":
|
|
52
|
+
return debug_cache(args, logger)
|
|
53
|
+
if args.debug_command == "performance":
|
|
54
|
+
return debug_performance(args, logger)
|
|
55
|
+
logger.error(f"Unknown debug command: {args.debug_command}")
|
|
56
|
+
return 1
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def debug_socketio(args, logger):
|
|
60
|
+
"""
|
|
61
|
+
Debug SocketIO events using the professional debugging tool.
|
|
62
|
+
|
|
63
|
+
Args:
|
|
64
|
+
args: Parsed command-line arguments
|
|
65
|
+
logger: Logger instance
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
int: Exit code
|
|
69
|
+
"""
|
|
70
|
+
try:
|
|
71
|
+
from ...tools.socketio_debug import DisplayMode, SocketIODebugger
|
|
72
|
+
|
|
73
|
+
logger.info("Starting SocketIO debugger...")
|
|
74
|
+
|
|
75
|
+
# Map display mode from args
|
|
76
|
+
mode = DisplayMode.LIVE # Default
|
|
77
|
+
if args.summary:
|
|
78
|
+
mode = DisplayMode.SUMMARY
|
|
79
|
+
elif args.raw:
|
|
80
|
+
mode = DisplayMode.RAW
|
|
81
|
+
elif args.pretty:
|
|
82
|
+
mode = DisplayMode.PRETTY
|
|
83
|
+
elif args.filter_types:
|
|
84
|
+
mode = DisplayMode.FILTERED
|
|
85
|
+
|
|
86
|
+
# Create debugger instance
|
|
87
|
+
debugger = SocketIODebugger(
|
|
88
|
+
host=args.host,
|
|
89
|
+
port=args.port,
|
|
90
|
+
mode=mode,
|
|
91
|
+
filter_types=args.filter_types,
|
|
92
|
+
output_file=Path(args.output) if args.output else None,
|
|
93
|
+
quiet=args.quiet,
|
|
94
|
+
show_raw=args.raw,
|
|
95
|
+
max_reconnect_attempts=getattr(args, "max_reconnect", 10),
|
|
96
|
+
reconnect_delay=getattr(args, "reconnect_delay", 1.0),
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Run the debugger
|
|
100
|
+
success = debugger.run()
|
|
101
|
+
|
|
102
|
+
if success:
|
|
103
|
+
logger.info("SocketIO debugger stopped successfully")
|
|
104
|
+
return 0
|
|
105
|
+
logger.error("SocketIO debugger encountered an error")
|
|
106
|
+
return 1
|
|
107
|
+
|
|
108
|
+
except ImportError as e:
|
|
109
|
+
logger.error(f"Failed to import debugging tool: {e}")
|
|
110
|
+
print(
|
|
111
|
+
"❌ Debugging tool not available. Please ensure all dependencies are installed."
|
|
112
|
+
)
|
|
113
|
+
return 1
|
|
114
|
+
except KeyboardInterrupt:
|
|
115
|
+
logger.info("SocketIO debugger interrupted by user")
|
|
116
|
+
return 0
|
|
117
|
+
except Exception as e:
|
|
118
|
+
logger.error(f"Unexpected error in SocketIO debugger: {e}", exc_info=True)
|
|
119
|
+
return 1
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def debug_connections(args, logger):
|
|
123
|
+
"""
|
|
124
|
+
Debug active SocketIO connections and server status.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
args: Parsed command-line arguments
|
|
128
|
+
logger: Logger instance
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
int: Exit code
|
|
132
|
+
"""
|
|
133
|
+
try:
|
|
134
|
+
import json
|
|
135
|
+
|
|
136
|
+
from ...services.port_manager import PortManager
|
|
137
|
+
|
|
138
|
+
logger.info("Checking SocketIO connections...")
|
|
139
|
+
|
|
140
|
+
# Get port manager
|
|
141
|
+
port_manager = PortManager()
|
|
142
|
+
|
|
143
|
+
# Clean up dead instances
|
|
144
|
+
port_manager.cleanup_dead_instances()
|
|
145
|
+
|
|
146
|
+
# Get active instances
|
|
147
|
+
active_instances = port_manager.list_active_instances()
|
|
148
|
+
|
|
149
|
+
if not active_instances:
|
|
150
|
+
print("No active SocketIO servers found")
|
|
151
|
+
return 0
|
|
152
|
+
|
|
153
|
+
print(f"\n📡 Active SocketIO Servers ({len(active_instances)}):")
|
|
154
|
+
print("-" * 60)
|
|
155
|
+
|
|
156
|
+
for instance in active_instances:
|
|
157
|
+
port = instance.get("port", "unknown")
|
|
158
|
+
pid = instance.get("pid", "unknown")
|
|
159
|
+
start_time = instance.get("start_time", "unknown")
|
|
160
|
+
|
|
161
|
+
print(f"\n🔌 Server on port {port}")
|
|
162
|
+
print(f" PID: {pid}")
|
|
163
|
+
print(f" Started: {start_time}")
|
|
164
|
+
|
|
165
|
+
# Try to check if it's actually responding
|
|
166
|
+
import socket
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
170
|
+
s.settimeout(1.0)
|
|
171
|
+
result = s.connect_ex(("127.0.0.1", port))
|
|
172
|
+
if result == 0:
|
|
173
|
+
print(" Status: ✅ Responding")
|
|
174
|
+
else:
|
|
175
|
+
print(" Status: ⚠️ Not responding (may be stale)")
|
|
176
|
+
except Exception as e:
|
|
177
|
+
print(f" Status: ❌ Error checking: {e}")
|
|
178
|
+
|
|
179
|
+
print("\n" + "-" * 60)
|
|
180
|
+
print(f"Total: {len(active_instances)} server(s)")
|
|
181
|
+
|
|
182
|
+
# If verbose, show full JSON
|
|
183
|
+
if getattr(args, "verbose", False):
|
|
184
|
+
print("\nFull instance data:")
|
|
185
|
+
print(json.dumps(active_instances, indent=2, default=str))
|
|
186
|
+
|
|
187
|
+
return 0
|
|
188
|
+
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.error(f"Failed to check connections: {e}", exc_info=True)
|
|
191
|
+
return 1
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def debug_services(args, logger):
|
|
195
|
+
"""
|
|
196
|
+
Debug services: list, status, dependencies, and health.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
args: Parsed command-line arguments
|
|
200
|
+
logger: Logger instance
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
int: Exit code
|
|
204
|
+
"""
|
|
205
|
+
try:
|
|
206
|
+
# Import service-related modules
|
|
207
|
+
from ...core.container import DIContainer
|
|
208
|
+
|
|
209
|
+
logger.info("Debugging services...")
|
|
210
|
+
|
|
211
|
+
# Get the global container if available
|
|
212
|
+
container = None
|
|
213
|
+
try:
|
|
214
|
+
# Try to get a container instance if it has the method
|
|
215
|
+
if hasattr(DIContainer, "get_instance"):
|
|
216
|
+
container = DIContainer.get_instance()
|
|
217
|
+
else:
|
|
218
|
+
container = DIContainer()
|
|
219
|
+
except:
|
|
220
|
+
# Create a new container if none exists
|
|
221
|
+
container = DIContainer()
|
|
222
|
+
logger.warning("No active container found, created new instance")
|
|
223
|
+
|
|
224
|
+
if args.list:
|
|
225
|
+
# List all registered services
|
|
226
|
+
print("\n📦 Registered Services:")
|
|
227
|
+
print("=" * 60)
|
|
228
|
+
|
|
229
|
+
services = container._services if hasattr(container, "_services") else {}
|
|
230
|
+
if not services:
|
|
231
|
+
print("No services registered")
|
|
232
|
+
else:
|
|
233
|
+
for service_type, registration in services.items():
|
|
234
|
+
service_name = (
|
|
235
|
+
service_type.__name__
|
|
236
|
+
if hasattr(service_type, "__name__")
|
|
237
|
+
else str(service_type)
|
|
238
|
+
)
|
|
239
|
+
impl_name = (
|
|
240
|
+
registration.implementation.__name__
|
|
241
|
+
if hasattr(registration.implementation, "__name__")
|
|
242
|
+
else str(registration.implementation)
|
|
243
|
+
)
|
|
244
|
+
print(f"\n🔧 {service_name}")
|
|
245
|
+
print(f" Implementation: {impl_name}")
|
|
246
|
+
print(f" Lifetime: {registration.lifetime.value}")
|
|
247
|
+
if registration.instance:
|
|
248
|
+
print(" Status: ✅ Instantiated")
|
|
249
|
+
else:
|
|
250
|
+
print(" Status: ⏸️ Not instantiated")
|
|
251
|
+
|
|
252
|
+
elif args.status:
|
|
253
|
+
# Show service status and health
|
|
254
|
+
print("\n🏥 Service Health Status:")
|
|
255
|
+
print("=" * 60)
|
|
256
|
+
|
|
257
|
+
# Try to get monitoring service
|
|
258
|
+
try:
|
|
259
|
+
from ...services.infrastructure.monitoring import MonitoringService
|
|
260
|
+
|
|
261
|
+
monitor = MonitoringService()
|
|
262
|
+
|
|
263
|
+
# Collect health metrics
|
|
264
|
+
metrics = monitor.collect_metrics()
|
|
265
|
+
|
|
266
|
+
print("\n📊 System Metrics:")
|
|
267
|
+
print(f" CPU Usage: {metrics.get('cpu_percent', 'N/A')}%")
|
|
268
|
+
print(f" Memory Usage: {metrics.get('memory_percent', 'N/A')}%")
|
|
269
|
+
print(f" Disk Usage: {metrics.get('disk_percent', 'N/A')}%")
|
|
270
|
+
|
|
271
|
+
if "network" in metrics:
|
|
272
|
+
net = metrics["network"]
|
|
273
|
+
print("\n🌐 Network:")
|
|
274
|
+
print(f" Bytes Sent: {net.get('bytes_sent', 0):,}")
|
|
275
|
+
print(f" Bytes Received: {net.get('bytes_recv', 0):,}")
|
|
276
|
+
|
|
277
|
+
except Exception as e:
|
|
278
|
+
logger.warning(f"Could not get monitoring metrics: {e}")
|
|
279
|
+
print("⚠️ Monitoring service not available")
|
|
280
|
+
|
|
281
|
+
elif args.dependencies:
|
|
282
|
+
# Show service dependency graph
|
|
283
|
+
print("\n🕸️ Service Dependencies:")
|
|
284
|
+
print("=" * 60)
|
|
285
|
+
|
|
286
|
+
services = container._services if hasattr(container, "_services") else {}
|
|
287
|
+
if not services:
|
|
288
|
+
print("No services registered")
|
|
289
|
+
else:
|
|
290
|
+
# Build dependency graph
|
|
291
|
+
for service_type, registration in services.items():
|
|
292
|
+
service_name = (
|
|
293
|
+
service_type.__name__
|
|
294
|
+
if hasattr(service_type, "__name__")
|
|
295
|
+
else str(service_type)
|
|
296
|
+
)
|
|
297
|
+
print(f"\n📌 {service_name}")
|
|
298
|
+
|
|
299
|
+
if registration.dependencies:
|
|
300
|
+
for dep_name, dep_type in registration.dependencies.items():
|
|
301
|
+
dep_type_name = (
|
|
302
|
+
dep_type.__name__
|
|
303
|
+
if hasattr(dep_type, "__name__")
|
|
304
|
+
else str(dep_type)
|
|
305
|
+
)
|
|
306
|
+
print(f" └─> {dep_name}: {dep_type_name}")
|
|
307
|
+
else:
|
|
308
|
+
print(" └─> No dependencies")
|
|
309
|
+
|
|
310
|
+
elif args.trace:
|
|
311
|
+
# Trace service resolution
|
|
312
|
+
service_name = args.trace
|
|
313
|
+
print(f"\n🔍 Tracing service resolution for: {service_name}")
|
|
314
|
+
print("=" * 60)
|
|
315
|
+
|
|
316
|
+
# Try to find and resolve the service
|
|
317
|
+
services = container._services if hasattr(container, "_services") else {}
|
|
318
|
+
found = False
|
|
319
|
+
|
|
320
|
+
for service_type, registration in services.items():
|
|
321
|
+
type_name = (
|
|
322
|
+
service_type.__name__
|
|
323
|
+
if hasattr(service_type, "__name__")
|
|
324
|
+
else str(service_type)
|
|
325
|
+
)
|
|
326
|
+
if service_name in type_name:
|
|
327
|
+
found = True
|
|
328
|
+
print(f"\n✅ Found service: {type_name}")
|
|
329
|
+
print(f" Implementation: {registration.implementation}")
|
|
330
|
+
print(f" Lifetime: {registration.lifetime.value}")
|
|
331
|
+
|
|
332
|
+
# Try to resolve
|
|
333
|
+
try:
|
|
334
|
+
instance = container.resolve(service_type)
|
|
335
|
+
print(" Resolution: ✅ Success")
|
|
336
|
+
print(f" Instance Type: {type(instance).__name__}")
|
|
337
|
+
except Exception as e:
|
|
338
|
+
print(" Resolution: ❌ Failed")
|
|
339
|
+
print(f" Error: {e}")
|
|
340
|
+
break
|
|
341
|
+
|
|
342
|
+
if not found:
|
|
343
|
+
print(f"❌ Service '{service_name}' not found")
|
|
344
|
+
|
|
345
|
+
else:
|
|
346
|
+
# Default: show summary
|
|
347
|
+
print("\n📊 Services Summary:")
|
|
348
|
+
print("=" * 60)
|
|
349
|
+
services = container._services if hasattr(container, "_services") else {}
|
|
350
|
+
print(f"Total Registered: {len(services)}")
|
|
351
|
+
|
|
352
|
+
# Count by lifetime
|
|
353
|
+
lifetime_counts = defaultdict(int)
|
|
354
|
+
instantiated = 0
|
|
355
|
+
|
|
356
|
+
for registration in services.values():
|
|
357
|
+
lifetime_counts[registration.lifetime.value] += 1
|
|
358
|
+
if registration.instance:
|
|
359
|
+
instantiated += 1
|
|
360
|
+
|
|
361
|
+
print("\nLifetime Distribution:")
|
|
362
|
+
for lifetime, count in lifetime_counts.items():
|
|
363
|
+
print(f" {lifetime}: {count}")
|
|
364
|
+
|
|
365
|
+
print(f"\nInstantiated: {instantiated}/{len(services)}")
|
|
366
|
+
|
|
367
|
+
return 0
|
|
368
|
+
|
|
369
|
+
except Exception as e:
|
|
370
|
+
logger.error(f"Failed to debug services: {e}", exc_info=True)
|
|
371
|
+
return 1
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def debug_agents(args, logger):
|
|
375
|
+
"""
|
|
376
|
+
Debug agents: deployed agents, memory, and tracing.
|
|
377
|
+
|
|
378
|
+
Args:
|
|
379
|
+
args: Parsed command-line arguments
|
|
380
|
+
logger: Logger instance
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
int: Exit code
|
|
384
|
+
"""
|
|
385
|
+
try:
|
|
386
|
+
logger.info("Debugging agents...")
|
|
387
|
+
|
|
388
|
+
if args.deployed:
|
|
389
|
+
# List deployed agents
|
|
390
|
+
from pathlib import Path
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
print("\n🤖 Deployed Agents:")
|
|
394
|
+
print("=" * 60)
|
|
395
|
+
|
|
396
|
+
# Check different deployment locations
|
|
397
|
+
locations = [
|
|
398
|
+
Path.home() / ".claude" / "agents",
|
|
399
|
+
Path.cwd() / ".claude" / "agents",
|
|
400
|
+
]
|
|
401
|
+
|
|
402
|
+
total_agents = 0
|
|
403
|
+
for location in locations:
|
|
404
|
+
if location.exists():
|
|
405
|
+
print(f"\n📁 Location: {location}")
|
|
406
|
+
agent_files = list(location.glob("*.md"))
|
|
407
|
+
if agent_files:
|
|
408
|
+
for agent_file in agent_files:
|
|
409
|
+
agent_name = agent_file.stem
|
|
410
|
+
size = agent_file.stat().st_size
|
|
411
|
+
modified = datetime.fromtimestamp(
|
|
412
|
+
agent_file.stat().st_mtime
|
|
413
|
+
)
|
|
414
|
+
print(f" • {agent_name}")
|
|
415
|
+
print(f" Size: {size:,} bytes")
|
|
416
|
+
print(
|
|
417
|
+
f" Modified: {modified.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
418
|
+
)
|
|
419
|
+
total_agents += 1
|
|
420
|
+
else:
|
|
421
|
+
print(" No agents found")
|
|
422
|
+
|
|
423
|
+
print(f"\nTotal Agents: {total_agents}")
|
|
424
|
+
|
|
425
|
+
elif args.memory:
|
|
426
|
+
# Show agent memory status
|
|
427
|
+
from ...services.agents.memory import get_memory_manager
|
|
428
|
+
|
|
429
|
+
print("\n🧠 Agent Memory Status:")
|
|
430
|
+
print("=" * 60)
|
|
431
|
+
|
|
432
|
+
try:
|
|
433
|
+
get_memory_manager()
|
|
434
|
+
|
|
435
|
+
# List all memory files
|
|
436
|
+
memory_dir = Path.home() / ".claude" / "memory"
|
|
437
|
+
if not memory_dir.exists():
|
|
438
|
+
memory_dir = Path.cwd() / ".claude" / "memory"
|
|
439
|
+
|
|
440
|
+
if memory_dir.exists():
|
|
441
|
+
memory_files = list(memory_dir.glob("*.json"))
|
|
442
|
+
|
|
443
|
+
total_size = 0
|
|
444
|
+
for mem_file in memory_files:
|
|
445
|
+
agent_name = mem_file.stem
|
|
446
|
+
size = mem_file.stat().st_size
|
|
447
|
+
|
|
448
|
+
# Try to load and analyze memory
|
|
449
|
+
try:
|
|
450
|
+
with open(mem_file) as f:
|
|
451
|
+
memory_data = json.load(f)
|
|
452
|
+
|
|
453
|
+
entry_count = (
|
|
454
|
+
len(memory_data) if isinstance(memory_data, list) else 1
|
|
455
|
+
)
|
|
456
|
+
print(f"\n📝 Agent: {agent_name}")
|
|
457
|
+
print(f" File: {mem_file}")
|
|
458
|
+
print(f" Size: {size:,} bytes")
|
|
459
|
+
print(f" Entries: {entry_count}")
|
|
460
|
+
total_size += size
|
|
461
|
+
|
|
462
|
+
# Show recent entries if requested
|
|
463
|
+
if (
|
|
464
|
+
args.verbose
|
|
465
|
+
and isinstance(memory_data, list)
|
|
466
|
+
and memory_data
|
|
467
|
+
):
|
|
468
|
+
print(" Recent entries:")
|
|
469
|
+
for entry in memory_data[-3:]:
|
|
470
|
+
timestamp = entry.get("timestamp", "N/A")
|
|
471
|
+
category = entry.get("category", "N/A")
|
|
472
|
+
print(f" - [{timestamp}] {category}")
|
|
473
|
+
|
|
474
|
+
except Exception as e:
|
|
475
|
+
print(f"\n📝 Agent: {agent_name}")
|
|
476
|
+
print(f" ⚠️ Could not parse memory: {e}")
|
|
477
|
+
|
|
478
|
+
print("\n📊 Summary:")
|
|
479
|
+
print(f" Total Memory Files: {len(memory_files)}")
|
|
480
|
+
print(f" Total Size: {total_size:,} bytes")
|
|
481
|
+
else:
|
|
482
|
+
print("No memory directory found")
|
|
483
|
+
|
|
484
|
+
except Exception as e:
|
|
485
|
+
logger.warning(f"Could not access memory manager: {e}")
|
|
486
|
+
print("⚠️ Memory manager not available")
|
|
487
|
+
|
|
488
|
+
elif args.trace:
|
|
489
|
+
# Trace agent execution
|
|
490
|
+
agent_name = args.trace
|
|
491
|
+
print(f"\n🔍 Tracing agent: {agent_name}")
|
|
492
|
+
print("=" * 60)
|
|
493
|
+
|
|
494
|
+
# Look for the agent
|
|
495
|
+
from pathlib import Path
|
|
496
|
+
|
|
497
|
+
# Check different locations
|
|
498
|
+
locations = [
|
|
499
|
+
Path.home() / ".claude" / "agents",
|
|
500
|
+
Path.cwd() / ".claude" / "agents",
|
|
501
|
+
]
|
|
502
|
+
|
|
503
|
+
found = False
|
|
504
|
+
for location in locations:
|
|
505
|
+
agent_file = location / f"{agent_name}.md"
|
|
506
|
+
if agent_file.exists():
|
|
507
|
+
found = True
|
|
508
|
+
print(f"✅ Agent found: {agent_name}")
|
|
509
|
+
print(f" Location: {agent_file}")
|
|
510
|
+
print(f" Size: {agent_file.stat().st_size:,} bytes")
|
|
511
|
+
|
|
512
|
+
# Read first few lines for type detection
|
|
513
|
+
with open(agent_file) as f:
|
|
514
|
+
lines = f.readlines()[:10]
|
|
515
|
+
for line in lines:
|
|
516
|
+
if "role:" in line.lower():
|
|
517
|
+
print(f" Role: {line.split(':')[1].strip()}")
|
|
518
|
+
elif "type:" in line.lower():
|
|
519
|
+
print(f" Type: {line.split(':')[1].strip()}")
|
|
520
|
+
break
|
|
521
|
+
|
|
522
|
+
if not found:
|
|
523
|
+
print(f"❌ Agent '{agent_name}' not found")
|
|
524
|
+
|
|
525
|
+
else:
|
|
526
|
+
# Default: show summary
|
|
527
|
+
print("\n📊 Agents Summary:")
|
|
528
|
+
print("=" * 60)
|
|
529
|
+
|
|
530
|
+
# Count agents in different locations
|
|
531
|
+
locations = [
|
|
532
|
+
(Path.home() / ".claude" / "agents", "User"),
|
|
533
|
+
(Path.cwd() / ".claude" / "agents", "Project"),
|
|
534
|
+
]
|
|
535
|
+
|
|
536
|
+
total = 0
|
|
537
|
+
for location, label in locations:
|
|
538
|
+
if location.exists():
|
|
539
|
+
count = len(list(location.glob("*.md")))
|
|
540
|
+
print(f"{label} Agents: {count}")
|
|
541
|
+
total += count
|
|
542
|
+
|
|
543
|
+
print(f"\nTotal Agents: {total}")
|
|
544
|
+
|
|
545
|
+
return 0
|
|
546
|
+
|
|
547
|
+
except Exception as e:
|
|
548
|
+
logger.error(f"Failed to debug agents: {e}", exc_info=True)
|
|
549
|
+
return 1
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def debug_hooks(args, logger):
|
|
553
|
+
"""
|
|
554
|
+
Debug hook system: list hooks, trace execution, analyze performance.
|
|
555
|
+
|
|
556
|
+
Args:
|
|
557
|
+
args: Parsed command-line arguments
|
|
558
|
+
logger: Logger instance
|
|
559
|
+
|
|
560
|
+
Returns:
|
|
561
|
+
int: Exit code
|
|
562
|
+
"""
|
|
563
|
+
try:
|
|
564
|
+
from ...services.hook_service import HookService
|
|
565
|
+
|
|
566
|
+
logger.info("Debugging hooks...")
|
|
567
|
+
|
|
568
|
+
# Try to get the hook service
|
|
569
|
+
hook_service = HookService()
|
|
570
|
+
|
|
571
|
+
if args.list:
|
|
572
|
+
# List all registered hooks
|
|
573
|
+
print("\n🪝 Registered Hooks:")
|
|
574
|
+
print("=" * 60)
|
|
575
|
+
|
|
576
|
+
print("\n📥 Pre-Delegation Hooks:")
|
|
577
|
+
if hook_service.pre_delegation_hooks:
|
|
578
|
+
for hook in hook_service.pre_delegation_hooks:
|
|
579
|
+
print(f" • {hook.name}")
|
|
580
|
+
print(f" Priority: {hook.priority}")
|
|
581
|
+
print(f" Enabled: {hook.enabled}")
|
|
582
|
+
if hasattr(hook, "description"):
|
|
583
|
+
print(f" Description: {hook.description}")
|
|
584
|
+
else:
|
|
585
|
+
print(" No pre-delegation hooks registered")
|
|
586
|
+
|
|
587
|
+
print("\n📤 Post-Delegation Hooks:")
|
|
588
|
+
if hook_service.post_delegation_hooks:
|
|
589
|
+
for hook in hook_service.post_delegation_hooks:
|
|
590
|
+
print(f" • {hook.name}")
|
|
591
|
+
print(f" Priority: {hook.priority}")
|
|
592
|
+
print(f" Enabled: {hook.enabled}")
|
|
593
|
+
if hasattr(hook, "description"):
|
|
594
|
+
print(f" Description: {hook.description}")
|
|
595
|
+
else:
|
|
596
|
+
print(" No post-delegation hooks registered")
|
|
597
|
+
|
|
598
|
+
# Show statistics
|
|
599
|
+
print("\n📊 Hook Statistics:")
|
|
600
|
+
print(
|
|
601
|
+
f" Pre-delegation executed: {hook_service.stats.get('pre_delegation_executed', 0)}"
|
|
602
|
+
)
|
|
603
|
+
print(
|
|
604
|
+
f" Post-delegation executed: {hook_service.stats.get('post_delegation_executed', 0)}"
|
|
605
|
+
)
|
|
606
|
+
print(f" Errors: {hook_service.stats.get('errors', 0)}")
|
|
607
|
+
|
|
608
|
+
elif args.trace:
|
|
609
|
+
# Trace hook execution
|
|
610
|
+
hook_name = args.trace
|
|
611
|
+
print(f"\n🔍 Tracing hook: {hook_name}")
|
|
612
|
+
print("=" * 60)
|
|
613
|
+
|
|
614
|
+
found = False
|
|
615
|
+
|
|
616
|
+
# Search in pre-delegation hooks
|
|
617
|
+
for hook in hook_service.pre_delegation_hooks:
|
|
618
|
+
if hook_name.lower() in hook.name.lower():
|
|
619
|
+
found = True
|
|
620
|
+
print(f"\n✅ Found pre-delegation hook: {hook.name}")
|
|
621
|
+
print(f" Priority: {hook.priority}")
|
|
622
|
+
print(f" Enabled: {hook.enabled}")
|
|
623
|
+
print(f" Type: {type(hook).__name__}")
|
|
624
|
+
|
|
625
|
+
# Test execution
|
|
626
|
+
if args.test:
|
|
627
|
+
print("\n🧪 Test Execution:")
|
|
628
|
+
from ...hooks.base_hook import HookContext
|
|
629
|
+
|
|
630
|
+
test_context = HookContext(
|
|
631
|
+
agent_name="test_agent",
|
|
632
|
+
task="test_task",
|
|
633
|
+
metadata={"test": True},
|
|
634
|
+
)
|
|
635
|
+
|
|
636
|
+
try:
|
|
637
|
+
start_time = time.time()
|
|
638
|
+
result = hook.execute(test_context)
|
|
639
|
+
elapsed = time.time() - start_time
|
|
640
|
+
|
|
641
|
+
print(" Status: ✅ Success")
|
|
642
|
+
print(f" Execution Time: {elapsed:.3f}s")
|
|
643
|
+
print(f" Modified: {result.context_modified}")
|
|
644
|
+
if result.error:
|
|
645
|
+
print(f" Error: {result.error}")
|
|
646
|
+
except Exception as e:
|
|
647
|
+
print(" Status: ❌ Failed")
|
|
648
|
+
print(f" Error: {e}")
|
|
649
|
+
break
|
|
650
|
+
|
|
651
|
+
# Search in post-delegation hooks
|
|
652
|
+
for hook in hook_service.post_delegation_hooks:
|
|
653
|
+
if hook_name.lower() in hook.name.lower():
|
|
654
|
+
found = True
|
|
655
|
+
print(f"\n✅ Found post-delegation hook: {hook.name}")
|
|
656
|
+
print(f" Priority: {hook.priority}")
|
|
657
|
+
print(f" Enabled: {hook.enabled}")
|
|
658
|
+
print(f" Type: {type(hook).__name__}")
|
|
659
|
+
break
|
|
660
|
+
|
|
661
|
+
if not found:
|
|
662
|
+
print(f"❌ Hook '{hook_name}' not found")
|
|
663
|
+
|
|
664
|
+
elif args.performance:
|
|
665
|
+
# Analyze hook performance
|
|
666
|
+
print("\n⚡ Hook Performance Analysis:")
|
|
667
|
+
print("=" * 60)
|
|
668
|
+
|
|
669
|
+
# Performance test each hook
|
|
670
|
+
print("\n📥 Pre-Delegation Hooks Performance:")
|
|
671
|
+
for hook in hook_service.pre_delegation_hooks:
|
|
672
|
+
from ...hooks.base_hook import HookContext
|
|
673
|
+
|
|
674
|
+
test_context = HookContext(
|
|
675
|
+
agent_name="perf_test", task="performance test", metadata={}
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
# Run multiple iterations
|
|
679
|
+
iterations = 10
|
|
680
|
+
times = []
|
|
681
|
+
|
|
682
|
+
for _ in range(iterations):
|
|
683
|
+
try:
|
|
684
|
+
start = time.time()
|
|
685
|
+
hook.execute(test_context)
|
|
686
|
+
elapsed = time.time() - start
|
|
687
|
+
times.append(elapsed)
|
|
688
|
+
except:
|
|
689
|
+
pass
|
|
690
|
+
|
|
691
|
+
if times:
|
|
692
|
+
avg_time = sum(times) / len(times)
|
|
693
|
+
min_time = min(times)
|
|
694
|
+
max_time = max(times)
|
|
695
|
+
|
|
696
|
+
print(f"\n {hook.name}:")
|
|
697
|
+
print(f" Average: {avg_time*1000:.2f}ms")
|
|
698
|
+
print(f" Min: {min_time*1000:.2f}ms")
|
|
699
|
+
print(f" Max: {max_time*1000:.2f}ms")
|
|
700
|
+
|
|
701
|
+
else:
|
|
702
|
+
# Default: show summary
|
|
703
|
+
print("\n📊 Hooks Summary:")
|
|
704
|
+
print("=" * 60)
|
|
705
|
+
print(f"Pre-delegation hooks: {len(hook_service.pre_delegation_hooks)}")
|
|
706
|
+
print(f"Post-delegation hooks: {len(hook_service.post_delegation_hooks)}")
|
|
707
|
+
print("\nExecution Statistics:")
|
|
708
|
+
print(
|
|
709
|
+
f" Pre-delegation executed: {hook_service.stats.get('pre_delegation_executed', 0)}"
|
|
710
|
+
)
|
|
711
|
+
print(
|
|
712
|
+
f" Post-delegation executed: {hook_service.stats.get('post_delegation_executed', 0)}"
|
|
713
|
+
)
|
|
714
|
+
print(f" Total errors: {hook_service.stats.get('errors', 0)}")
|
|
715
|
+
|
|
716
|
+
return 0
|
|
717
|
+
|
|
718
|
+
except Exception as e:
|
|
719
|
+
logger.error(f"Failed to debug hooks: {e}", exc_info=True)
|
|
720
|
+
return 1
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
def debug_cache(args, logger):
|
|
724
|
+
"""
|
|
725
|
+
Debug cache: inspect, clear, and analyze cache performance.
|
|
726
|
+
|
|
727
|
+
Args:
|
|
728
|
+
args: Parsed command-line arguments
|
|
729
|
+
logger: Logger instance
|
|
730
|
+
|
|
731
|
+
Returns:
|
|
732
|
+
int: Exit code
|
|
733
|
+
"""
|
|
734
|
+
try:
|
|
735
|
+
from ...services.core.cache_manager import CacheManager
|
|
736
|
+
|
|
737
|
+
logger.info("Debugging cache...")
|
|
738
|
+
|
|
739
|
+
if args.inspect:
|
|
740
|
+
# Inspect cache contents
|
|
741
|
+
print("\n🗄️ Cache Inspection:")
|
|
742
|
+
print("=" * 60)
|
|
743
|
+
|
|
744
|
+
# Get cache directory
|
|
745
|
+
cache_dir = Path.home() / ".cache" / "claude-mpm"
|
|
746
|
+
if not cache_dir.exists():
|
|
747
|
+
print("No cache directory found")
|
|
748
|
+
return 0
|
|
749
|
+
|
|
750
|
+
# Analyze cache files
|
|
751
|
+
cache_files = list(cache_dir.rglob("*"))
|
|
752
|
+
total_size = 0
|
|
753
|
+
file_count = 0
|
|
754
|
+
|
|
755
|
+
categories = defaultdict(list)
|
|
756
|
+
|
|
757
|
+
for file_path in cache_files:
|
|
758
|
+
if file_path.is_file():
|
|
759
|
+
file_count += 1
|
|
760
|
+
size = file_path.stat().st_size
|
|
761
|
+
total_size += size
|
|
762
|
+
|
|
763
|
+
# Categorize by parent directory
|
|
764
|
+
category = file_path.parent.name
|
|
765
|
+
categories[category].append((file_path.name, size))
|
|
766
|
+
|
|
767
|
+
print("\n📊 Cache Statistics:")
|
|
768
|
+
print(f" Location: {cache_dir}")
|
|
769
|
+
print(f" Total Files: {file_count}")
|
|
770
|
+
print(
|
|
771
|
+
f" Total Size: {total_size:,} bytes ({total_size/1024/1024:.2f} MB)"
|
|
772
|
+
)
|
|
773
|
+
|
|
774
|
+
print("\n📁 Categories:")
|
|
775
|
+
for category, files in categories.items():
|
|
776
|
+
cat_size = sum(size for _, size in files)
|
|
777
|
+
print(f"\n {category}:")
|
|
778
|
+
print(f" Files: {len(files)}")
|
|
779
|
+
print(f" Size: {cat_size:,} bytes")
|
|
780
|
+
|
|
781
|
+
if args.verbose:
|
|
782
|
+
# Show individual files
|
|
783
|
+
for name, size in sorted(files, key=lambda x: x[1], reverse=True)[
|
|
784
|
+
:5
|
|
785
|
+
]:
|
|
786
|
+
print(f" • {name}: {size:,} bytes")
|
|
787
|
+
|
|
788
|
+
elif args.clear:
|
|
789
|
+
# Clear cache
|
|
790
|
+
print("\n🧹 Clearing cache...")
|
|
791
|
+
print("=" * 60)
|
|
792
|
+
|
|
793
|
+
cache_dir = Path.home() / ".cache" / "claude-mpm"
|
|
794
|
+
|
|
795
|
+
if not cache_dir.exists():
|
|
796
|
+
print("No cache to clear")
|
|
797
|
+
return 0
|
|
798
|
+
|
|
799
|
+
# Count files before clearing
|
|
800
|
+
files_before = list(cache_dir.rglob("*"))
|
|
801
|
+
file_count = len([f for f in files_before if f.is_file()])
|
|
802
|
+
|
|
803
|
+
if (
|
|
804
|
+
args.confirm
|
|
805
|
+
or input(f"Clear {file_count} cache files? (y/N): ").lower() == "y"
|
|
806
|
+
):
|
|
807
|
+
# Clear cache
|
|
808
|
+
import shutil
|
|
809
|
+
|
|
810
|
+
try:
|
|
811
|
+
shutil.rmtree(cache_dir)
|
|
812
|
+
print(f"✅ Cleared {file_count} cache files")
|
|
813
|
+
except Exception as e:
|
|
814
|
+
print(f"❌ Failed to clear cache: {e}")
|
|
815
|
+
return 1
|
|
816
|
+
else:
|
|
817
|
+
print("Cache clear cancelled")
|
|
818
|
+
|
|
819
|
+
elif args.stats:
|
|
820
|
+
# Show cache performance statistics
|
|
821
|
+
print("\n📈 Cache Performance Statistics:")
|
|
822
|
+
print("=" * 60)
|
|
823
|
+
|
|
824
|
+
# Try to get cache manager
|
|
825
|
+
cache_manager = CacheManager()
|
|
826
|
+
|
|
827
|
+
# Simulate cache operations to gather stats
|
|
828
|
+
print("\n🔄 Cache TTL Configuration:")
|
|
829
|
+
print(f" Capabilities TTL: {cache_manager.capabilities_ttl}s")
|
|
830
|
+
print(f" Deployed Agents TTL: {cache_manager.deployed_agents_ttl}s")
|
|
831
|
+
print(f" Metadata TTL: {cache_manager.metadata_ttl}s")
|
|
832
|
+
print(f" Memories TTL: {cache_manager.memories_ttl}s")
|
|
833
|
+
|
|
834
|
+
# Check cache status
|
|
835
|
+
current_time = time.time()
|
|
836
|
+
|
|
837
|
+
print("\n⏱️ Cache Status:")
|
|
838
|
+
|
|
839
|
+
# Check capabilities cache
|
|
840
|
+
if cache_manager._capabilities_cache:
|
|
841
|
+
age = current_time - cache_manager._capabilities_cache_time
|
|
842
|
+
status = (
|
|
843
|
+
"✅ Valid" if age < cache_manager.capabilities_ttl else "❌ Expired"
|
|
844
|
+
)
|
|
845
|
+
print(f" Capabilities: {status} (age: {age:.1f}s)")
|
|
846
|
+
else:
|
|
847
|
+
print(" Capabilities: ⚫ Empty")
|
|
848
|
+
|
|
849
|
+
# Check deployed agents cache
|
|
850
|
+
if cache_manager._deployed_agents_cache:
|
|
851
|
+
age = current_time - cache_manager._deployed_agents_cache_time
|
|
852
|
+
status = (
|
|
853
|
+
"✅ Valid"
|
|
854
|
+
if age < cache_manager.deployed_agents_ttl
|
|
855
|
+
else "❌ Expired"
|
|
856
|
+
)
|
|
857
|
+
print(f" Deployed Agents: {status} (age: {age:.1f}s)")
|
|
858
|
+
else:
|
|
859
|
+
print(" Deployed Agents: ⚫ Empty")
|
|
860
|
+
|
|
861
|
+
else:
|
|
862
|
+
# Default: show summary
|
|
863
|
+
print("\n📊 Cache Summary:")
|
|
864
|
+
print("=" * 60)
|
|
865
|
+
|
|
866
|
+
cache_dir = Path.home() / ".cache" / "claude-mpm"
|
|
867
|
+
|
|
868
|
+
if cache_dir.exists():
|
|
869
|
+
cache_files = list(cache_dir.rglob("*"))
|
|
870
|
+
file_count = len([f for f in cache_files if f.is_file()])
|
|
871
|
+
total_size = sum(f.stat().st_size for f in cache_files if f.is_file())
|
|
872
|
+
|
|
873
|
+
print(f"Location: {cache_dir}")
|
|
874
|
+
print(f"Files: {file_count}")
|
|
875
|
+
print(f"Size: {total_size:,} bytes ({total_size/1024/1024:.2f} MB)")
|
|
876
|
+
else:
|
|
877
|
+
print("No cache found")
|
|
878
|
+
|
|
879
|
+
return 0
|
|
880
|
+
|
|
881
|
+
except Exception as e:
|
|
882
|
+
logger.error(f"Failed to debug cache: {e}", exc_info=True)
|
|
883
|
+
return 1
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def debug_performance(args, logger):
|
|
887
|
+
"""
|
|
888
|
+
Debug performance: profile operations, analyze bottlenecks.
|
|
889
|
+
|
|
890
|
+
Args:
|
|
891
|
+
args: Parsed command-line arguments
|
|
892
|
+
logger: Logger instance
|
|
893
|
+
|
|
894
|
+
Returns:
|
|
895
|
+
int: Exit code
|
|
896
|
+
"""
|
|
897
|
+
try:
|
|
898
|
+
logger.info("Running performance analysis...")
|
|
899
|
+
|
|
900
|
+
print("\n⚡ Performance Analysis:")
|
|
901
|
+
print("=" * 60)
|
|
902
|
+
|
|
903
|
+
if args.profile:
|
|
904
|
+
# Profile specific operation
|
|
905
|
+
operation = args.profile
|
|
906
|
+
print(f"\n🔍 Profiling operation: {operation}")
|
|
907
|
+
|
|
908
|
+
import cProfile
|
|
909
|
+
import pstats
|
|
910
|
+
from io import StringIO
|
|
911
|
+
|
|
912
|
+
profiler = cProfile.Profile()
|
|
913
|
+
|
|
914
|
+
# Map operation to actual function
|
|
915
|
+
operations = {
|
|
916
|
+
"agent_load": lambda: _profile_agent_load(),
|
|
917
|
+
"service_init": lambda: _profile_service_init(),
|
|
918
|
+
"cache_ops": lambda: _profile_cache_operations(),
|
|
919
|
+
"memory_ops": lambda: _profile_memory_operations(),
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
if operation in operations:
|
|
923
|
+
print("Starting profile...")
|
|
924
|
+
|
|
925
|
+
profiler.enable()
|
|
926
|
+
start_time = time.time()
|
|
927
|
+
|
|
928
|
+
try:
|
|
929
|
+
operations[operation]()
|
|
930
|
+
except Exception as e:
|
|
931
|
+
print(f"⚠️ Operation failed: {e}")
|
|
932
|
+
|
|
933
|
+
elapsed = time.time() - start_time
|
|
934
|
+
profiler.disable()
|
|
935
|
+
|
|
936
|
+
# Print statistics
|
|
937
|
+
print(f"\n✅ Profile complete (elapsed: {elapsed:.3f}s)")
|
|
938
|
+
|
|
939
|
+
s = StringIO()
|
|
940
|
+
ps = pstats.Stats(profiler, stream=s).sort_stats("cumulative")
|
|
941
|
+
ps.print_stats(20) # Top 20 functions
|
|
942
|
+
|
|
943
|
+
print("\n📊 Top Functions by Cumulative Time:")
|
|
944
|
+
print(s.getvalue())
|
|
945
|
+
else:
|
|
946
|
+
print(f"❌ Unknown operation: {operation}")
|
|
947
|
+
print(" Available: agent_load, service_init, cache_ops, memory_ops")
|
|
948
|
+
|
|
949
|
+
elif args.benchmark:
|
|
950
|
+
# Run benchmarks
|
|
951
|
+
print("\n🏃 Running benchmarks...")
|
|
952
|
+
|
|
953
|
+
benchmarks = [
|
|
954
|
+
("Service Container Resolution", _benchmark_service_resolution),
|
|
955
|
+
("Cache Operations", _benchmark_cache_operations),
|
|
956
|
+
("Agent Loading", _benchmark_agent_loading),
|
|
957
|
+
("Hook Execution", _benchmark_hook_execution),
|
|
958
|
+
]
|
|
959
|
+
|
|
960
|
+
results = []
|
|
961
|
+
|
|
962
|
+
for name, benchmark_func in benchmarks:
|
|
963
|
+
print(f"\n▶️ {name}...")
|
|
964
|
+
try:
|
|
965
|
+
result = benchmark_func()
|
|
966
|
+
results.append((name, result))
|
|
967
|
+
print(f" Time: {result['time']:.3f}s")
|
|
968
|
+
print(f" Ops/sec: {result.get('ops_per_sec', 'N/A')}")
|
|
969
|
+
except Exception as e:
|
|
970
|
+
print(f" ❌ Failed: {e}")
|
|
971
|
+
results.append((name, {"error": str(e)}))
|
|
972
|
+
|
|
973
|
+
# Summary
|
|
974
|
+
print("\n📊 Benchmark Summary:")
|
|
975
|
+
print("=" * 60)
|
|
976
|
+
for name, result in results:
|
|
977
|
+
if "error" in result:
|
|
978
|
+
print(f"{name}: ❌ Failed")
|
|
979
|
+
else:
|
|
980
|
+
print(f"{name}: {result['time']:.3f}s")
|
|
981
|
+
|
|
982
|
+
else:
|
|
983
|
+
# Default: show system performance
|
|
984
|
+
print("\n📊 System Performance:")
|
|
985
|
+
|
|
986
|
+
try:
|
|
987
|
+
import psutil
|
|
988
|
+
except ImportError:
|
|
989
|
+
print("⚠️ psutil not installed. Install with: pip install psutil")
|
|
990
|
+
return 0
|
|
991
|
+
|
|
992
|
+
# CPU info
|
|
993
|
+
print("\n🖥️ CPU:")
|
|
994
|
+
print(f" Usage: {psutil.cpu_percent(interval=1)}%")
|
|
995
|
+
print(
|
|
996
|
+
f" Cores: {psutil.cpu_count(logical=False)} physical, {psutil.cpu_count()} logical"
|
|
997
|
+
)
|
|
998
|
+
|
|
999
|
+
# Memory info
|
|
1000
|
+
mem = psutil.virtual_memory()
|
|
1001
|
+
print("\n💾 Memory:")
|
|
1002
|
+
print(f" Total: {mem.total/1024/1024/1024:.2f} GB")
|
|
1003
|
+
print(f" Used: {mem.used/1024/1024/1024:.2f} GB ({mem.percent}%)")
|
|
1004
|
+
print(f" Available: {mem.available/1024/1024/1024:.2f} GB")
|
|
1005
|
+
|
|
1006
|
+
# Disk info
|
|
1007
|
+
disk = psutil.disk_usage("/")
|
|
1008
|
+
print("\n💿 Disk:")
|
|
1009
|
+
print(f" Total: {disk.total/1024/1024/1024:.2f} GB")
|
|
1010
|
+
print(f" Used: {disk.used/1024/1024/1024:.2f} GB ({disk.percent}%)")
|
|
1011
|
+
print(f" Free: {disk.free/1024/1024/1024:.2f} GB")
|
|
1012
|
+
|
|
1013
|
+
# Process info
|
|
1014
|
+
process = psutil.Process()
|
|
1015
|
+
print("\n📦 Current Process:")
|
|
1016
|
+
print(f" PID: {process.pid}")
|
|
1017
|
+
print(f" Memory: {process.memory_info().rss/1024/1024:.2f} MB")
|
|
1018
|
+
print(f" CPU: {process.cpu_percent()}%")
|
|
1019
|
+
print(f" Threads: {process.num_threads()}")
|
|
1020
|
+
|
|
1021
|
+
return 0
|
|
1022
|
+
|
|
1023
|
+
except Exception as e:
|
|
1024
|
+
logger.error(f"Failed to run performance analysis: {e}", exc_info=True)
|
|
1025
|
+
return 1
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
# Helper functions for profiling
|
|
1029
|
+
def _profile_agent_load():
|
|
1030
|
+
"""Profile agent loading operation."""
|
|
1031
|
+
from ...services.agents.deployment import AgentDeploymentService
|
|
1032
|
+
|
|
1033
|
+
service = AgentDeploymentService()
|
|
1034
|
+
# Simulate loading agents
|
|
1035
|
+
for _ in range(10):
|
|
1036
|
+
with contextlib.suppress(Exception):
|
|
1037
|
+
service.list_agents()
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
def _profile_service_init():
|
|
1041
|
+
"""Profile service initialization."""
|
|
1042
|
+
from ...core.container import DIContainer
|
|
1043
|
+
|
|
1044
|
+
container = DIContainer()
|
|
1045
|
+
# Register and resolve services
|
|
1046
|
+
|
|
1047
|
+
class TestService:
|
|
1048
|
+
pass
|
|
1049
|
+
|
|
1050
|
+
for i in range(20):
|
|
1051
|
+
container.register(f"TestService{i}", TestService)
|
|
1052
|
+
container.resolve(f"TestService{i}")
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
def _profile_cache_operations():
|
|
1056
|
+
"""Profile cache operations."""
|
|
1057
|
+
from ...services.core.cache_manager import CacheManager
|
|
1058
|
+
|
|
1059
|
+
cache = CacheManager()
|
|
1060
|
+
|
|
1061
|
+
# Simulate cache operations
|
|
1062
|
+
for i in range(100):
|
|
1063
|
+
cache.set_capabilities(f"test_cap_{i}")
|
|
1064
|
+
cache.get_capabilities()
|
|
1065
|
+
cache.invalidate_capabilities()
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
def _profile_memory_operations():
|
|
1069
|
+
"""Profile memory operations."""
|
|
1070
|
+
from ...services.agents.memory import AgentMemoryManager
|
|
1071
|
+
|
|
1072
|
+
memory = AgentMemoryManager("test_agent")
|
|
1073
|
+
|
|
1074
|
+
# Simulate memory operations
|
|
1075
|
+
for i in range(50):
|
|
1076
|
+
try:
|
|
1077
|
+
memory.add_memory(f"category_{i}", {"data": f"test_{i}"})
|
|
1078
|
+
memory.get_memories()
|
|
1079
|
+
except:
|
|
1080
|
+
pass
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
# Helper functions for benchmarking
|
|
1084
|
+
def _benchmark_service_resolution() -> Dict[str, Any]:
|
|
1085
|
+
"""Benchmark service container resolution."""
|
|
1086
|
+
from ...core.container import DIContainer
|
|
1087
|
+
|
|
1088
|
+
container = DIContainer()
|
|
1089
|
+
|
|
1090
|
+
class TestService:
|
|
1091
|
+
pass
|
|
1092
|
+
|
|
1093
|
+
container.register(TestService, TestService)
|
|
1094
|
+
|
|
1095
|
+
iterations = 1000
|
|
1096
|
+
start = time.time()
|
|
1097
|
+
|
|
1098
|
+
for _ in range(iterations):
|
|
1099
|
+
container.resolve(TestService)
|
|
1100
|
+
|
|
1101
|
+
elapsed = time.time() - start
|
|
1102
|
+
|
|
1103
|
+
return {
|
|
1104
|
+
"time": elapsed,
|
|
1105
|
+
"iterations": iterations,
|
|
1106
|
+
"ops_per_sec": iterations / elapsed,
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
def _benchmark_cache_operations() -> Dict[str, Any]:
|
|
1111
|
+
"""Benchmark cache operations."""
|
|
1112
|
+
from ...services.core.cache_manager import CacheManager
|
|
1113
|
+
|
|
1114
|
+
cache = CacheManager()
|
|
1115
|
+
iterations = 1000
|
|
1116
|
+
|
|
1117
|
+
start = time.time()
|
|
1118
|
+
|
|
1119
|
+
for i in range(iterations):
|
|
1120
|
+
cache.set_capabilities(f"test_{i}")
|
|
1121
|
+
cache.get_capabilities()
|
|
1122
|
+
|
|
1123
|
+
elapsed = time.time() - start
|
|
1124
|
+
|
|
1125
|
+
return {
|
|
1126
|
+
"time": elapsed,
|
|
1127
|
+
"iterations": iterations * 2, # set + get
|
|
1128
|
+
"ops_per_sec": (iterations * 2) / elapsed,
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
def _benchmark_agent_loading() -> Dict[str, Any]:
|
|
1133
|
+
"""Benchmark agent loading."""
|
|
1134
|
+
from pathlib import Path
|
|
1135
|
+
|
|
1136
|
+
iterations = 100
|
|
1137
|
+
start = time.time()
|
|
1138
|
+
|
|
1139
|
+
for _ in range(iterations):
|
|
1140
|
+
# Simulate agent discovery
|
|
1141
|
+
agent_dir = Path.home() / ".claude" / "agents"
|
|
1142
|
+
if agent_dir.exists():
|
|
1143
|
+
list(agent_dir.glob("*.md"))
|
|
1144
|
+
|
|
1145
|
+
elapsed = time.time() - start
|
|
1146
|
+
|
|
1147
|
+
return {
|
|
1148
|
+
"time": elapsed,
|
|
1149
|
+
"iterations": iterations,
|
|
1150
|
+
"ops_per_sec": iterations / elapsed,
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
|
|
1154
|
+
def _benchmark_hook_execution() -> Dict[str, Any]:
|
|
1155
|
+
"""Benchmark hook execution."""
|
|
1156
|
+
from ...hooks.base_hook import HookContext, HookResult, PreDelegationHook
|
|
1157
|
+
|
|
1158
|
+
class TestHook(PreDelegationHook):
|
|
1159
|
+
def execute(self, context: HookContext) -> HookResult:
|
|
1160
|
+
return HookResult(context=context)
|
|
1161
|
+
|
|
1162
|
+
hook = TestHook(name="test", priority=0)
|
|
1163
|
+
context = HookContext(agent_name="test", task="test", metadata={})
|
|
1164
|
+
|
|
1165
|
+
iterations = 1000
|
|
1166
|
+
start = time.time()
|
|
1167
|
+
|
|
1168
|
+
for _ in range(iterations):
|
|
1169
|
+
hook.execute(context)
|
|
1170
|
+
|
|
1171
|
+
elapsed = time.time() - start
|
|
1172
|
+
|
|
1173
|
+
return {
|
|
1174
|
+
"time": elapsed,
|
|
1175
|
+
"iterations": iterations,
|
|
1176
|
+
"ops_per_sec": iterations / elapsed,
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
def add_debug_parser(subparsers):
|
|
1181
|
+
"""
|
|
1182
|
+
Add the debug subparser with debugging commands.
|
|
1183
|
+
|
|
1184
|
+
This function is called by the main parser to add debug commands.
|
|
1185
|
+
|
|
1186
|
+
Args:
|
|
1187
|
+
subparsers: The subparsers object from the main parser
|
|
1188
|
+
|
|
1189
|
+
Returns:
|
|
1190
|
+
The configured debug subparser
|
|
1191
|
+
"""
|
|
1192
|
+
|
|
1193
|
+
# Main debug parser
|
|
1194
|
+
debug_parser = subparsers.add_parser(
|
|
1195
|
+
"debug",
|
|
1196
|
+
help="Development debugging tools",
|
|
1197
|
+
description="Tools for debugging and monitoring claude-mpm components",
|
|
1198
|
+
)
|
|
1199
|
+
|
|
1200
|
+
# Add debug subcommands
|
|
1201
|
+
debug_subparsers = debug_parser.add_subparsers(
|
|
1202
|
+
dest="debug_command", help="Debug commands", metavar="SUBCOMMAND"
|
|
1203
|
+
)
|
|
1204
|
+
|
|
1205
|
+
# SocketIO debugging
|
|
1206
|
+
socketio_parser = debug_subparsers.add_parser(
|
|
1207
|
+
"socketio",
|
|
1208
|
+
help="Debug SocketIO events in real-time",
|
|
1209
|
+
aliases=["events"],
|
|
1210
|
+
description="Professional SocketIO event monitoring and analysis tool",
|
|
1211
|
+
)
|
|
1212
|
+
|
|
1213
|
+
# Connection options
|
|
1214
|
+
socketio_parser.add_argument(
|
|
1215
|
+
"--host", default="localhost", help="SocketIO server host (default: localhost)"
|
|
1216
|
+
)
|
|
1217
|
+
socketio_parser.add_argument(
|
|
1218
|
+
"--port", type=int, default=8765, help="SocketIO server port (default: 8765)"
|
|
1219
|
+
)
|
|
1220
|
+
|
|
1221
|
+
# Display options
|
|
1222
|
+
display_group = socketio_parser.add_mutually_exclusive_group()
|
|
1223
|
+
display_group.add_argument(
|
|
1224
|
+
"--live",
|
|
1225
|
+
action="store_true",
|
|
1226
|
+
default=True,
|
|
1227
|
+
help="Live event monitoring (default)",
|
|
1228
|
+
)
|
|
1229
|
+
display_group.add_argument(
|
|
1230
|
+
"--summary", action="store_true", help="Show aggregated statistics and summary"
|
|
1231
|
+
)
|
|
1232
|
+
display_group.add_argument(
|
|
1233
|
+
"--raw", action="store_true", help="Display raw JSON output"
|
|
1234
|
+
)
|
|
1235
|
+
display_group.add_argument(
|
|
1236
|
+
"--pretty", action="store_true", help="Enhanced formatted output with colors"
|
|
1237
|
+
)
|
|
1238
|
+
|
|
1239
|
+
# Filtering
|
|
1240
|
+
socketio_parser.add_argument(
|
|
1241
|
+
"--filter",
|
|
1242
|
+
nargs="+",
|
|
1243
|
+
dest="filter_types",
|
|
1244
|
+
help="Filter specific event types (e.g., PreToolUse PostToolUse)",
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
# Output options
|
|
1248
|
+
socketio_parser.add_argument(
|
|
1249
|
+
"--output", "-o", help="Save events to file (JSONL format)"
|
|
1250
|
+
)
|
|
1251
|
+
socketio_parser.add_argument(
|
|
1252
|
+
"--quiet",
|
|
1253
|
+
"-q",
|
|
1254
|
+
action="store_true",
|
|
1255
|
+
help="Suppress output except errors (useful with --output)",
|
|
1256
|
+
)
|
|
1257
|
+
|
|
1258
|
+
# Connection resilience
|
|
1259
|
+
socketio_parser.add_argument(
|
|
1260
|
+
"--max-reconnect",
|
|
1261
|
+
type=int,
|
|
1262
|
+
default=10,
|
|
1263
|
+
help="Maximum reconnection attempts (default: 10)",
|
|
1264
|
+
)
|
|
1265
|
+
socketio_parser.add_argument(
|
|
1266
|
+
"--reconnect-delay",
|
|
1267
|
+
type=float,
|
|
1268
|
+
default=1.0,
|
|
1269
|
+
help="Reconnection delay in seconds (default: 1.0)",
|
|
1270
|
+
)
|
|
1271
|
+
|
|
1272
|
+
# Connection debugging
|
|
1273
|
+
connections_parser = debug_subparsers.add_parser(
|
|
1274
|
+
"connections",
|
|
1275
|
+
help="Show active SocketIO server connections",
|
|
1276
|
+
description="Display information about active SocketIO servers and their status",
|
|
1277
|
+
)
|
|
1278
|
+
connections_parser.add_argument(
|
|
1279
|
+
"--verbose",
|
|
1280
|
+
"-v",
|
|
1281
|
+
action="store_true",
|
|
1282
|
+
help="Show detailed connection information",
|
|
1283
|
+
)
|
|
1284
|
+
|
|
1285
|
+
# Services debugging
|
|
1286
|
+
services_parser = debug_subparsers.add_parser(
|
|
1287
|
+
"services",
|
|
1288
|
+
help="Debug service container and dependencies",
|
|
1289
|
+
description="Inspect services, dependencies, and health status",
|
|
1290
|
+
)
|
|
1291
|
+
services_group = services_parser.add_mutually_exclusive_group()
|
|
1292
|
+
services_group.add_argument(
|
|
1293
|
+
"--list", action="store_true", help="List all registered services"
|
|
1294
|
+
)
|
|
1295
|
+
services_group.add_argument(
|
|
1296
|
+
"--status", action="store_true", help="Show service health status"
|
|
1297
|
+
)
|
|
1298
|
+
services_group.add_argument(
|
|
1299
|
+
"--dependencies", action="store_true", help="Show service dependency graph"
|
|
1300
|
+
)
|
|
1301
|
+
services_group.add_argument(
|
|
1302
|
+
"--trace",
|
|
1303
|
+
metavar="SERVICE",
|
|
1304
|
+
help="Trace service resolution for specific service",
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
# Agents debugging
|
|
1308
|
+
agents_parser = debug_subparsers.add_parser(
|
|
1309
|
+
"agents",
|
|
1310
|
+
help="Debug deployed agents and memory",
|
|
1311
|
+
description="Inspect deployed agents, memory, and traces",
|
|
1312
|
+
)
|
|
1313
|
+
agents_group = agents_parser.add_mutually_exclusive_group()
|
|
1314
|
+
agents_group.add_argument(
|
|
1315
|
+
"--deployed", action="store_true", help="List all deployed agents"
|
|
1316
|
+
)
|
|
1317
|
+
agents_group.add_argument(
|
|
1318
|
+
"--memory", action="store_true", help="Show agent memory status"
|
|
1319
|
+
)
|
|
1320
|
+
agents_group.add_argument(
|
|
1321
|
+
"--trace", metavar="AGENT", help="Trace specific agent execution"
|
|
1322
|
+
)
|
|
1323
|
+
agents_parser.add_argument(
|
|
1324
|
+
"--verbose", "-v", action="store_true", help="Show detailed information"
|
|
1325
|
+
)
|
|
1326
|
+
|
|
1327
|
+
# Hooks debugging
|
|
1328
|
+
hooks_parser = debug_subparsers.add_parser(
|
|
1329
|
+
"hooks",
|
|
1330
|
+
help="Debug hook system",
|
|
1331
|
+
description="List hooks, trace execution, analyze performance",
|
|
1332
|
+
)
|
|
1333
|
+
hooks_group = hooks_parser.add_mutually_exclusive_group()
|
|
1334
|
+
hooks_group.add_argument(
|
|
1335
|
+
"--list", action="store_true", help="List all registered hooks"
|
|
1336
|
+
)
|
|
1337
|
+
hooks_group.add_argument(
|
|
1338
|
+
"--trace", metavar="HOOK", help="Trace specific hook execution"
|
|
1339
|
+
)
|
|
1340
|
+
hooks_group.add_argument(
|
|
1341
|
+
"--performance", action="store_true", help="Analyze hook performance"
|
|
1342
|
+
)
|
|
1343
|
+
hooks_parser.add_argument(
|
|
1344
|
+
"--test", action="store_true", help="Run test execution when tracing"
|
|
1345
|
+
)
|
|
1346
|
+
|
|
1347
|
+
# Cache debugging
|
|
1348
|
+
cache_parser = debug_subparsers.add_parser(
|
|
1349
|
+
"cache",
|
|
1350
|
+
help="Debug cache system",
|
|
1351
|
+
description="Inspect, clear, and analyze cache",
|
|
1352
|
+
)
|
|
1353
|
+
cache_group = cache_parser.add_mutually_exclusive_group()
|
|
1354
|
+
cache_group.add_argument(
|
|
1355
|
+
"--inspect", action="store_true", help="Inspect cache contents"
|
|
1356
|
+
)
|
|
1357
|
+
cache_group.add_argument("--clear", action="store_true", help="Clear all cache")
|
|
1358
|
+
cache_group.add_argument(
|
|
1359
|
+
"--stats", action="store_true", help="Show cache performance statistics"
|
|
1360
|
+
)
|
|
1361
|
+
cache_parser.add_argument(
|
|
1362
|
+
"--verbose", "-v", action="store_true", help="Show detailed cache information"
|
|
1363
|
+
)
|
|
1364
|
+
cache_parser.add_argument(
|
|
1365
|
+
"--confirm",
|
|
1366
|
+
"-y",
|
|
1367
|
+
action="store_true",
|
|
1368
|
+
help="Skip confirmation for clear operation",
|
|
1369
|
+
)
|
|
1370
|
+
|
|
1371
|
+
# Performance debugging
|
|
1372
|
+
performance_parser = debug_subparsers.add_parser(
|
|
1373
|
+
"performance",
|
|
1374
|
+
help="Performance profiling and analysis",
|
|
1375
|
+
description="Profile operations and analyze bottlenecks",
|
|
1376
|
+
)
|
|
1377
|
+
perf_group = performance_parser.add_mutually_exclusive_group()
|
|
1378
|
+
perf_group.add_argument(
|
|
1379
|
+
"--profile",
|
|
1380
|
+
metavar="OPERATION",
|
|
1381
|
+
help="Profile specific operation (agent_load, service_init, cache_ops, memory_ops)",
|
|
1382
|
+
)
|
|
1383
|
+
perf_group.add_argument(
|
|
1384
|
+
"--benchmark", action="store_true", help="Run performance benchmarks"
|
|
1385
|
+
)
|
|
1386
|
+
|
|
1387
|
+
return debug_parser
|