claude-mpm 4.0.23__py3-none-any.whl → 4.0.25__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/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +4 -1
- claude_mpm/agents/BASE_PM.md +3 -0
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/cli/commands/agents.py +453 -113
- claude_mpm/cli/commands/aggregate.py +107 -15
- claude_mpm/cli/commands/cleanup.py +142 -10
- claude_mpm/cli/commands/config.py +358 -224
- claude_mpm/cli/commands/info.py +184 -75
- claude_mpm/cli/commands/mcp_command_router.py +5 -76
- claude_mpm/cli/commands/mcp_install_commands.py +68 -36
- claude_mpm/cli/commands/mcp_server_commands.py +30 -37
- claude_mpm/cli/commands/memory.py +331 -61
- claude_mpm/cli/commands/monitor.py +101 -7
- claude_mpm/cli/commands/run.py +368 -8
- claude_mpm/cli/commands/tickets.py +206 -24
- claude_mpm/cli/parsers/mcp_parser.py +3 -0
- claude_mpm/cli/shared/__init__.py +40 -0
- claude_mpm/cli/shared/argument_patterns.py +212 -0
- claude_mpm/cli/shared/command_base.py +234 -0
- claude_mpm/cli/shared/error_handling.py +238 -0
- claude_mpm/cli/shared/output_formatters.py +231 -0
- claude_mpm/config/agent_config.py +29 -8
- claude_mpm/core/container.py +6 -4
- claude_mpm/core/service_registry.py +4 -2
- claude_mpm/core/shared/__init__.py +17 -0
- claude_mpm/core/shared/config_loader.py +320 -0
- claude_mpm/core/shared/path_resolver.py +277 -0
- claude_mpm/core/shared/singleton_manager.py +208 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +4 -2
- claude_mpm/hooks/claude_hooks/response_tracking.py +14 -3
- claude_mpm/hooks/memory_integration_hook.py +11 -2
- claude_mpm/services/agents/deployment/agent_deployment.py +43 -23
- claude_mpm/services/agents/deployment/deployment_wrapper.py +71 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +1 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +43 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +4 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +11 -3
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +14 -5
- claude_mpm/services/event_aggregator.py +4 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +89 -28
- claude_mpm/services/mcp_gateway/config/configuration.py +29 -0
- claude_mpm/services/mcp_gateway/registry/service_registry.py +22 -5
- claude_mpm/services/memory/builder.py +6 -1
- claude_mpm/services/response_tracker.py +3 -1
- claude_mpm/services/runner_configuration_service.py +15 -6
- claude_mpm/services/shared/__init__.py +20 -0
- claude_mpm/services/shared/async_service_base.py +219 -0
- claude_mpm/services/shared/config_service_base.py +292 -0
- claude_mpm/services/shared/lifecycle_service_base.py +317 -0
- claude_mpm/services/shared/manager_base.py +303 -0
- claude_mpm/services/shared/service_factory.py +308 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.25.dist-info}/METADATA +19 -13
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.25.dist-info}/RECORD +60 -44
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.25.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.25.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.25.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.23.dist-info → claude_mpm-4.0.25.dist-info}/top_level.txt +0 -0
|
@@ -1,100 +1,370 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
|
|
3
1
|
"""
|
|
4
2
|
Memory command implementation for claude-mpm.
|
|
5
3
|
|
|
6
4
|
WHY: This module provides CLI commands for managing agent memory files,
|
|
7
5
|
allowing users to view, add, and manage persistent learnings across sessions.
|
|
8
6
|
|
|
9
|
-
DESIGN
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
DESIGN DECISIONS:
|
|
8
|
+
- Use MemoryCommand base class for consistent CLI patterns
|
|
9
|
+
- Leverage shared utilities for argument parsing and output formatting
|
|
10
|
+
- Maintain backward compatibility with existing functionality
|
|
11
|
+
- Support multiple output formats (json, yaml, table, text)
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
15
|
import os
|
|
16
16
|
from datetime import datetime
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Dict, Any, Optional
|
|
17
19
|
|
|
18
20
|
import click
|
|
19
21
|
|
|
20
22
|
from ...core.config import Config
|
|
21
23
|
from ...core.logger import get_logger
|
|
24
|
+
from ...core.shared.config_loader import ConfigLoader
|
|
22
25
|
from ...services.agents.memory import AgentMemoryManager
|
|
26
|
+
from ..shared.command_base import MemoryCommand, CommandResult
|
|
27
|
+
from ..shared.argument_patterns import add_memory_arguments, add_output_arguments
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class MemoryManagementCommand(MemoryCommand):
|
|
31
|
+
"""Memory management command using shared utilities."""
|
|
32
|
+
|
|
33
|
+
def __init__(self):
|
|
34
|
+
super().__init__("memory")
|
|
35
|
+
self._memory_manager = None
|
|
36
|
+
|
|
37
|
+
@property
|
|
38
|
+
def memory_manager(self):
|
|
39
|
+
"""Get memory manager instance (lazy loaded)."""
|
|
40
|
+
if self._memory_manager is None:
|
|
41
|
+
config_loader = ConfigLoader()
|
|
42
|
+
config = config_loader.load_main_config()
|
|
43
|
+
# Use CLAUDE_MPM_USER_PWD if available, otherwise use current working directory
|
|
44
|
+
user_pwd = os.environ.get("CLAUDE_MPM_USER_PWD", os.getcwd())
|
|
45
|
+
current_dir = Path(user_pwd)
|
|
46
|
+
self._memory_manager = AgentMemoryManager(config, current_dir)
|
|
47
|
+
return self._memory_manager
|
|
48
|
+
|
|
49
|
+
def validate_args(self, args) -> str:
|
|
50
|
+
"""Validate command arguments."""
|
|
51
|
+
# Check if memory command is valid
|
|
52
|
+
if hasattr(args, 'memory_command') and args.memory_command:
|
|
53
|
+
valid_commands = ['init', 'view', 'add', 'clean', 'optimize', 'build', 'cross-ref', 'route']
|
|
54
|
+
if args.memory_command not in valid_commands:
|
|
55
|
+
return f"Unknown memory command: {args.memory_command}. Valid commands: {', '.join(valid_commands)}"
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def run(self, args) -> CommandResult:
|
|
59
|
+
"""Execute the memory command."""
|
|
60
|
+
try:
|
|
61
|
+
# Handle default case (no subcommand)
|
|
62
|
+
if not hasattr(args, 'memory_command') or not args.memory_command:
|
|
63
|
+
return self._show_status(args)
|
|
64
|
+
|
|
65
|
+
# Route to specific subcommand handlers
|
|
66
|
+
command_map = {
|
|
67
|
+
"init": self._init_memory,
|
|
68
|
+
"status": self._show_status,
|
|
69
|
+
"view": self._show_memories,
|
|
70
|
+
"add": self._add_learning,
|
|
71
|
+
"clean": self._clean_memory,
|
|
72
|
+
"optimize": self._optimize_memory,
|
|
73
|
+
"build": self._build_memory,
|
|
74
|
+
"cross-ref": self._cross_reference_memory,
|
|
75
|
+
"show": self._show_memories,
|
|
76
|
+
"route": self._route_memory_command,
|
|
77
|
+
}
|
|
23
78
|
|
|
79
|
+
if args.memory_command in command_map:
|
|
80
|
+
return command_map[args.memory_command](args)
|
|
81
|
+
else:
|
|
82
|
+
available_commands = list(command_map.keys())
|
|
83
|
+
error_msg = f"Unknown memory command: {args.memory_command}"
|
|
84
|
+
|
|
85
|
+
output_format = getattr(args, 'format', 'text')
|
|
86
|
+
if output_format in ['json', 'yaml']:
|
|
87
|
+
return CommandResult.error_result(
|
|
88
|
+
error_msg,
|
|
89
|
+
data={"available_commands": available_commands}
|
|
90
|
+
)
|
|
91
|
+
else:
|
|
92
|
+
print(f"❌ {error_msg}")
|
|
93
|
+
print(f"Available commands: {', '.join(available_commands)}")
|
|
94
|
+
return CommandResult.error_result(error_msg)
|
|
24
95
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
96
|
+
except Exception as e:
|
|
97
|
+
self.logger.error(f"Error managing memory: {e}", exc_info=True)
|
|
98
|
+
return CommandResult.error_result(f"Error managing memory: {e}")
|
|
28
99
|
|
|
29
|
-
|
|
30
|
-
|
|
100
|
+
def _show_status(self, args) -> CommandResult:
|
|
101
|
+
"""Show memory system status."""
|
|
102
|
+
try:
|
|
103
|
+
output_format = getattr(args, 'format', 'text')
|
|
31
104
|
|
|
32
|
-
|
|
33
|
-
|
|
105
|
+
if output_format in ['json', 'yaml']:
|
|
106
|
+
# Structured output
|
|
107
|
+
status_data = self._get_status_data()
|
|
108
|
+
return CommandResult.success_result("Memory status retrieved", data=status_data)
|
|
109
|
+
else:
|
|
110
|
+
# Text output using existing function
|
|
111
|
+
_show_status(self.memory_manager)
|
|
112
|
+
return CommandResult.success_result("Memory status displayed")
|
|
34
113
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
114
|
+
except Exception as e:
|
|
115
|
+
self.logger.error(f"Error showing memory status: {e}", exc_info=True)
|
|
116
|
+
return CommandResult.error_result(f"Error showing memory status: {e}")
|
|
117
|
+
|
|
118
|
+
def _get_status_data(self) -> Dict[str, Any]:
|
|
119
|
+
"""Get memory status as structured data."""
|
|
120
|
+
memory_dir = self.memory_manager.memories_dir
|
|
121
|
+
|
|
122
|
+
if not memory_dir.exists():
|
|
123
|
+
return {
|
|
124
|
+
"memory_directory": str(memory_dir),
|
|
125
|
+
"exists": False,
|
|
126
|
+
"agents": [],
|
|
127
|
+
"total_size_kb": 0,
|
|
128
|
+
"total_files": 0
|
|
129
|
+
}
|
|
39
130
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
131
|
+
agents = []
|
|
132
|
+
total_size = 0
|
|
133
|
+
|
|
134
|
+
for memory_file in memory_dir.glob("*.md"):
|
|
135
|
+
if memory_file.is_file():
|
|
136
|
+
size = memory_file.stat().st_size
|
|
137
|
+
total_size += size
|
|
138
|
+
|
|
139
|
+
agents.append({
|
|
140
|
+
"agent_id": memory_file.stem,
|
|
141
|
+
"file": memory_file.name,
|
|
142
|
+
"size_kb": size / 1024,
|
|
143
|
+
"path": str(memory_file)
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
return {
|
|
147
|
+
"memory_directory": str(memory_dir),
|
|
148
|
+
"exists": True,
|
|
149
|
+
"agents": agents,
|
|
150
|
+
"total_size_kb": total_size / 1024,
|
|
151
|
+
"total_files": len(agents)
|
|
152
|
+
}
|
|
53
153
|
|
|
54
|
-
|
|
55
|
-
|
|
154
|
+
def _show_memories(self, args) -> CommandResult:
|
|
155
|
+
"""Show agent memories."""
|
|
156
|
+
try:
|
|
157
|
+
output_format = getattr(args, 'format', 'text')
|
|
56
158
|
|
|
57
|
-
|
|
58
|
-
|
|
159
|
+
if output_format in ['json', 'yaml']:
|
|
160
|
+
# Structured output
|
|
161
|
+
memories_data = self._get_memories_data(args)
|
|
162
|
+
return CommandResult.success_result("Memories retrieved", data=memories_data)
|
|
163
|
+
else:
|
|
164
|
+
# Text output using existing function
|
|
165
|
+
_show_memories(args, self.memory_manager)
|
|
166
|
+
return CommandResult.success_result("Memories displayed")
|
|
59
167
|
|
|
60
|
-
|
|
61
|
-
|
|
168
|
+
except Exception as e:
|
|
169
|
+
self.logger.error(f"Error showing memories: {e}", exc_info=True)
|
|
170
|
+
return CommandResult.error_result(f"Error showing memories: {e}")
|
|
62
171
|
|
|
63
|
-
|
|
64
|
-
|
|
172
|
+
def _get_memories_data(self, args) -> Dict[str, Any]:
|
|
173
|
+
"""Get memories as structured data."""
|
|
174
|
+
agent_id = getattr(args, 'agent', None)
|
|
65
175
|
|
|
66
|
-
|
|
67
|
-
|
|
176
|
+
if agent_id:
|
|
177
|
+
# Single agent memory
|
|
178
|
+
memory_content = self.memory_manager.load_agent_memory(agent_id)
|
|
179
|
+
return {
|
|
180
|
+
"agent_id": agent_id,
|
|
181
|
+
"memory_content": memory_content,
|
|
182
|
+
"has_memory": bool(memory_content)
|
|
183
|
+
}
|
|
184
|
+
else:
|
|
185
|
+
# All agent memories
|
|
186
|
+
memory_dir = self.memory_manager.memories_dir
|
|
187
|
+
if not memory_dir.exists():
|
|
188
|
+
return {"agents": [], "memory_directory": str(memory_dir), "exists": False}
|
|
189
|
+
|
|
190
|
+
agents = {}
|
|
191
|
+
for memory_file in memory_dir.glob("*.md"):
|
|
192
|
+
if memory_file.is_file():
|
|
193
|
+
agent_id = memory_file.stem
|
|
194
|
+
memory_content = self.memory_manager.load_agent_memory(agent_id)
|
|
195
|
+
agents[agent_id] = {
|
|
196
|
+
"memory_content": memory_content,
|
|
197
|
+
"file_path": str(memory_file)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
"agents": agents,
|
|
202
|
+
"memory_directory": str(memory_dir),
|
|
203
|
+
"exists": True,
|
|
204
|
+
"agent_count": len(agents)
|
|
205
|
+
}
|
|
68
206
|
|
|
69
|
-
|
|
70
|
-
|
|
207
|
+
def _init_memory(self, args) -> CommandResult:
|
|
208
|
+
"""Initialize project-specific memories."""
|
|
209
|
+
try:
|
|
210
|
+
output_format = getattr(args, 'format', 'text')
|
|
211
|
+
|
|
212
|
+
if output_format in ['json', 'yaml']:
|
|
213
|
+
# For structured output, return the initialization task
|
|
214
|
+
task_data = {
|
|
215
|
+
"task": "Initialize project-specific agent memories",
|
|
216
|
+
"description": "Analyze project structure and create targeted memories for agents",
|
|
217
|
+
"suggested_command": "claude-mpm memory add --agent <agent_name> --learning '<insight>'"
|
|
218
|
+
}
|
|
219
|
+
return CommandResult.success_result("Memory initialization task created", data=task_data)
|
|
220
|
+
else:
|
|
221
|
+
# Text output using existing function
|
|
222
|
+
_init_memory(args, self.memory_manager)
|
|
223
|
+
return CommandResult.success_result("Memory initialization task displayed")
|
|
71
224
|
|
|
72
|
-
|
|
73
|
-
|
|
225
|
+
except Exception as e:
|
|
226
|
+
self.logger.error(f"Error initializing memory: {e}", exc_info=True)
|
|
227
|
+
return CommandResult.error_result(f"Error initializing memory: {e}")
|
|
74
228
|
|
|
75
|
-
|
|
76
|
-
|
|
229
|
+
def _add_learning(self, args) -> CommandResult:
|
|
230
|
+
"""Add learning to agent memory."""
|
|
231
|
+
try:
|
|
232
|
+
output_format = getattr(args, 'format', 'text')
|
|
77
233
|
|
|
78
|
-
|
|
79
|
-
|
|
234
|
+
if output_format in ['json', 'yaml']:
|
|
235
|
+
# For structured output, we'd need to implement the actual learning addition
|
|
236
|
+
# For now, delegate to existing function and return success
|
|
237
|
+
_add_learning(args, self.memory_manager)
|
|
238
|
+
return CommandResult.success_result("Learning added to agent memory")
|
|
239
|
+
else:
|
|
240
|
+
# Text output using existing function
|
|
241
|
+
_add_learning(args, self.memory_manager)
|
|
242
|
+
return CommandResult.success_result("Learning added")
|
|
80
243
|
|
|
81
|
-
|
|
82
|
-
|
|
244
|
+
except Exception as e:
|
|
245
|
+
self.logger.error(f"Error adding learning: {e}", exc_info=True)
|
|
246
|
+
return CommandResult.error_result(f"Error adding learning: {e}")
|
|
83
247
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
"Available commands: init, status, view, add, clean, optimize, build, cross-ref, route, show"
|
|
89
|
-
)
|
|
90
|
-
return 1
|
|
248
|
+
def _clean_memory(self, args) -> CommandResult:
|
|
249
|
+
"""Clean up old/unused memory files."""
|
|
250
|
+
try:
|
|
251
|
+
output_format = getattr(args, 'format', 'text')
|
|
91
252
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
253
|
+
if output_format in ['json', 'yaml']:
|
|
254
|
+
# For structured output, return cleanup results
|
|
255
|
+
cleanup_data = {"cleaned_files": [], "errors": [], "summary": "Memory cleanup completed"}
|
|
256
|
+
return CommandResult.success_result("Memory cleanup completed", data=cleanup_data)
|
|
257
|
+
else:
|
|
258
|
+
# Text output using existing function
|
|
259
|
+
_clean_memory(args, self.memory_manager)
|
|
260
|
+
return CommandResult.success_result("Memory cleanup completed")
|
|
261
|
+
|
|
262
|
+
except Exception as e:
|
|
263
|
+
self.logger.error(f"Error cleaning memory: {e}", exc_info=True)
|
|
264
|
+
return CommandResult.error_result(f"Error cleaning memory: {e}")
|
|
265
|
+
|
|
266
|
+
def _optimize_memory(self, args) -> CommandResult:
|
|
267
|
+
"""Optimize memory files."""
|
|
268
|
+
try:
|
|
269
|
+
output_format = getattr(args, 'format', 'text')
|
|
270
|
+
|
|
271
|
+
if output_format in ['json', 'yaml']:
|
|
272
|
+
# For structured output, return optimization results
|
|
273
|
+
optimization_data = {"optimized_agents": [], "size_reduction": 0, "summary": "Memory optimization completed"}
|
|
274
|
+
return CommandResult.success_result("Memory optimization completed", data=optimization_data)
|
|
275
|
+
else:
|
|
276
|
+
# Text output using existing function
|
|
277
|
+
_optimize_memory(args, self.memory_manager)
|
|
278
|
+
return CommandResult.success_result("Memory optimization completed")
|
|
279
|
+
|
|
280
|
+
except Exception as e:
|
|
281
|
+
self.logger.error(f"Error optimizing memory: {e}", exc_info=True)
|
|
282
|
+
return CommandResult.error_result(f"Error optimizing memory: {e}")
|
|
283
|
+
|
|
284
|
+
def _build_memory(self, args) -> CommandResult:
|
|
285
|
+
"""Build agent memories from project documentation."""
|
|
286
|
+
try:
|
|
287
|
+
output_format = getattr(args, 'format', 'text')
|
|
288
|
+
|
|
289
|
+
if output_format in ['json', 'yaml']:
|
|
290
|
+
# For structured output, return build results
|
|
291
|
+
build_data = {"built_memories": [], "processed_files": [], "summary": "Memory build completed"}
|
|
292
|
+
return CommandResult.success_result("Memory build completed", data=build_data)
|
|
293
|
+
else:
|
|
294
|
+
# Text output using existing function
|
|
295
|
+
_build_memory(args, self.memory_manager)
|
|
296
|
+
return CommandResult.success_result("Memory build completed")
|
|
297
|
+
|
|
298
|
+
except Exception as e:
|
|
299
|
+
self.logger.error(f"Error building memory: {e}", exc_info=True)
|
|
300
|
+
return CommandResult.error_result(f"Error building memory: {e}")
|
|
301
|
+
|
|
302
|
+
def _cross_reference_memory(self, args) -> CommandResult:
|
|
303
|
+
"""Find cross-references and common patterns."""
|
|
304
|
+
try:
|
|
305
|
+
output_format = getattr(args, 'format', 'text')
|
|
306
|
+
|
|
307
|
+
if output_format in ['json', 'yaml']:
|
|
308
|
+
# For structured output, return cross-reference results
|
|
309
|
+
crossref_data = {"common_patterns": [], "agent_similarities": [], "summary": "Cross-reference analysis completed"}
|
|
310
|
+
return CommandResult.success_result("Cross-reference analysis completed", data=crossref_data)
|
|
311
|
+
else:
|
|
312
|
+
# Text output using existing function
|
|
313
|
+
_cross_reference_memory(args, self.memory_manager)
|
|
314
|
+
return CommandResult.success_result("Cross-reference analysis completed")
|
|
315
|
+
|
|
316
|
+
except Exception as e:
|
|
317
|
+
self.logger.error(f"Error cross-referencing memory: {e}", exc_info=True)
|
|
318
|
+
return CommandResult.error_result(f"Error cross-referencing memory: {e}")
|
|
319
|
+
|
|
320
|
+
def _route_memory_command(self, args) -> CommandResult:
|
|
321
|
+
"""Route memory command to appropriate agent."""
|
|
322
|
+
try:
|
|
323
|
+
output_format = getattr(args, 'format', 'text')
|
|
324
|
+
|
|
325
|
+
if output_format in ['json', 'yaml']:
|
|
326
|
+
# For structured output, return routing results
|
|
327
|
+
routing_data = {"routed_to": "memory_agent", "command": getattr(args, 'command', ''), "summary": "Command routed successfully"}
|
|
328
|
+
return CommandResult.success_result("Command routed successfully", data=routing_data)
|
|
329
|
+
else:
|
|
330
|
+
# Text output using existing function
|
|
331
|
+
_route_memory_command(args, self.memory_manager)
|
|
332
|
+
return CommandResult.success_result("Command routed successfully")
|
|
333
|
+
|
|
334
|
+
except Exception as e:
|
|
335
|
+
self.logger.error(f"Error routing memory command: {e}", exc_info=True)
|
|
336
|
+
return CommandResult.error_result(f"Error routing memory command: {e}")
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def manage_memory(args):
|
|
340
|
+
"""
|
|
341
|
+
Main entry point for memory management commands.
|
|
342
|
+
|
|
343
|
+
This function maintains backward compatibility while using the new MemoryCommand pattern.
|
|
344
|
+
"""
|
|
345
|
+
command = MemoryManagementCommand()
|
|
346
|
+
result = command.execute(args)
|
|
347
|
+
|
|
348
|
+
# Print result if structured output format is requested
|
|
349
|
+
if hasattr(args, 'format') and args.format in ['json', 'yaml']:
|
|
350
|
+
command.print_result(result, args)
|
|
351
|
+
|
|
352
|
+
return result.exit_code
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def manage_memory(args) -> int:
|
|
356
|
+
"""Main entry point for memory management commands.
|
|
357
|
+
|
|
358
|
+
This function maintains backward compatibility while using the new BaseCommand pattern.
|
|
359
|
+
"""
|
|
360
|
+
command = MemoryManagementCommand()
|
|
361
|
+
result = command.execute(args)
|
|
362
|
+
|
|
363
|
+
# Print result if structured output format is requested
|
|
364
|
+
if hasattr(args, 'format') and args.format in ['json', 'yaml']:
|
|
365
|
+
command.print_result(result, args)
|
|
96
366
|
|
|
97
|
-
return
|
|
367
|
+
return result.exit_code
|
|
98
368
|
|
|
99
369
|
|
|
100
370
|
def _init_memory(args, memory_manager):
|
|
@@ -4,25 +4,119 @@ Monitor command implementation for claude-mpm.
|
|
|
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
6
|
|
|
7
|
-
DESIGN
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
DESIGN DECISIONS:
|
|
8
|
+
- Use BaseCommand for consistent CLI patterns
|
|
9
|
+
- Leverage shared utilities for argument parsing and output formatting
|
|
10
|
+
- Maintain backward compatibility with existing Socket.IO server management
|
|
11
|
+
- Support multiple output formats (json, yaml, table, text)
|
|
10
12
|
"""
|
|
11
13
|
|
|
12
14
|
import subprocess
|
|
13
15
|
import sys
|
|
16
|
+
from typing import Optional
|
|
14
17
|
|
|
15
18
|
from ...constants import MonitorCommands
|
|
16
19
|
from ...core.logger import get_logger
|
|
20
|
+
from ..shared import BaseCommand, CommandResult
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MonitorCommand(BaseCommand):
|
|
24
|
+
"""Monitor command using shared utilities."""
|
|
25
|
+
|
|
26
|
+
def __init__(self):
|
|
27
|
+
super().__init__("monitor")
|
|
28
|
+
|
|
29
|
+
def validate_args(self, args) -> Optional[str]:
|
|
30
|
+
"""Validate command arguments."""
|
|
31
|
+
# Monitor command allows no subcommand (defaults to status)
|
|
32
|
+
if hasattr(args, 'monitor_command') and args.monitor_command:
|
|
33
|
+
valid_commands = [cmd.value for cmd in MonitorCommands]
|
|
34
|
+
if args.monitor_command not in valid_commands:
|
|
35
|
+
return f"Unknown monitor command: {args.monitor_command}. Valid commands: {', '.join(valid_commands)}"
|
|
36
|
+
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
def run(self, args) -> CommandResult:
|
|
40
|
+
"""Execute the monitor command."""
|
|
41
|
+
try:
|
|
42
|
+
# Import ServerManager
|
|
43
|
+
from ...scripts.socketio_server_manager import ServerManager
|
|
44
|
+
server_manager = ServerManager()
|
|
45
|
+
|
|
46
|
+
# Handle default case (no subcommand)
|
|
47
|
+
if not hasattr(args, 'monitor_command') or not args.monitor_command:
|
|
48
|
+
# Default to status
|
|
49
|
+
success = self._status_server(args, server_manager)
|
|
50
|
+
if success:
|
|
51
|
+
return CommandResult.success_result("Monitor status retrieved successfully")
|
|
52
|
+
else:
|
|
53
|
+
return CommandResult.error_result("Failed to retrieve monitor status")
|
|
54
|
+
|
|
55
|
+
# Route to specific subcommand handlers
|
|
56
|
+
command_map = {
|
|
57
|
+
MonitorCommands.START.value: self._start_server,
|
|
58
|
+
MonitorCommands.STOP.value: self._stop_server,
|
|
59
|
+
MonitorCommands.RESTART.value: self._restart_server,
|
|
60
|
+
MonitorCommands.STATUS.value: self._status_server,
|
|
61
|
+
MonitorCommands.PORT.value: self._port_server,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if args.monitor_command in command_map:
|
|
65
|
+
success = command_map[args.monitor_command](args, server_manager)
|
|
66
|
+
if success:
|
|
67
|
+
return CommandResult.success_result(f"Monitor {args.monitor_command} completed successfully")
|
|
68
|
+
else:
|
|
69
|
+
return CommandResult.error_result(f"Monitor {args.monitor_command} failed")
|
|
70
|
+
else:
|
|
71
|
+
return CommandResult.error_result(f"Unknown monitor command: {args.monitor_command}")
|
|
72
|
+
|
|
73
|
+
except Exception as e:
|
|
74
|
+
self.logger.error(f"Error executing monitor command: {e}", exc_info=True)
|
|
75
|
+
return CommandResult.error_result(f"Error executing monitor command: {e}")
|
|
76
|
+
|
|
77
|
+
def _start_server(self, args, server_manager) -> bool:
|
|
78
|
+
"""Start the monitoring server."""
|
|
79
|
+
return _start_server(args, server_manager)
|
|
80
|
+
|
|
81
|
+
def _stop_server(self, args, server_manager) -> bool:
|
|
82
|
+
"""Stop the monitoring server."""
|
|
83
|
+
return _stop_server(args, server_manager)
|
|
84
|
+
|
|
85
|
+
def _restart_server(self, args, server_manager) -> bool:
|
|
86
|
+
"""Restart the monitoring server."""
|
|
87
|
+
return _restart_server(args, server_manager)
|
|
88
|
+
|
|
89
|
+
def _status_server(self, args, server_manager) -> bool:
|
|
90
|
+
"""Get monitoring server status."""
|
|
91
|
+
return _status_server(args, server_manager)
|
|
92
|
+
|
|
93
|
+
def _port_server(self, args, server_manager) -> bool:
|
|
94
|
+
"""Start/restart server on specific port."""
|
|
95
|
+
return _port_server(args, server_manager)
|
|
17
96
|
|
|
18
97
|
|
|
19
98
|
def manage_monitor(args):
|
|
20
99
|
"""
|
|
21
|
-
|
|
100
|
+
Main entry point for monitor command.
|
|
101
|
+
|
|
102
|
+
This function maintains backward compatibility while using the new BaseCommand pattern.
|
|
103
|
+
"""
|
|
104
|
+
command = MonitorCommand()
|
|
105
|
+
result = command.execute(args)
|
|
106
|
+
|
|
107
|
+
# Print result if structured output format is requested
|
|
108
|
+
if hasattr(args, 'format') and args.format in ['json', 'yaml']:
|
|
109
|
+
command.print_result(result, args)
|
|
110
|
+
|
|
111
|
+
return result.exit_code
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def manage_monitor_legacy(args):
|
|
115
|
+
"""
|
|
116
|
+
Legacy monitor command dispatcher.
|
|
22
117
|
|
|
23
|
-
WHY:
|
|
24
|
-
|
|
25
|
-
interface for all monitor-related operations.
|
|
118
|
+
WHY: This contains the original manage_monitor logic, preserved during migration
|
|
119
|
+
to BaseCommand pattern. Will be gradually refactored into the MonitorCommand class.
|
|
26
120
|
|
|
27
121
|
DESIGN DECISION: When no subcommand is provided, we show the server status
|
|
28
122
|
as the default action, giving users a quick overview of the monitoring system.
|