claude-mpm 4.14.7__py3-none-any.whl → 4.14.8__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/frontmatter_validator.py +284 -253
- claude_mpm/cli/__init__.py +34 -740
- claude_mpm/cli/commands/agent_manager.py +25 -12
- claude_mpm/cli/commands/agent_state_manager.py +186 -0
- claude_mpm/cli/commands/agents.py +204 -148
- claude_mpm/cli/commands/aggregate.py +7 -3
- claude_mpm/cli/commands/analyze.py +9 -4
- claude_mpm/cli/commands/analyze_code.py +7 -2
- claude_mpm/cli/commands/config.py +47 -13
- claude_mpm/cli/commands/configure.py +159 -1801
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +165 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/memory.py +54 -20
- claude_mpm/cli/commands/mpm_init.py +35 -21
- claude_mpm/cli/executor.py +202 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +455 -0
- claude_mpm/core/enums.py +322 -0
- claude_mpm/core/instruction_reinforcement_hook.py +2 -1
- claude_mpm/core/interactive_session.py +6 -3
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/oneshot_session.py +8 -4
- claude_mpm/core/service_registry.py +5 -1
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/hooks/instruction_reinforcement.py +7 -2
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +3 -2
- claude_mpm/services/agents/memory/agent_memory_manager.py +5 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +3 -2
- claude_mpm/services/diagnostics/checks/mcp_check.py +20 -6
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +8 -7
- claude_mpm/services/memory_hook_service.py +4 -1
- claude_mpm/services/monitor/daemon_manager.py +3 -2
- claude_mpm/services/monitor/handlers/dashboard.py +2 -1
- claude_mpm/services/monitor/handlers/hooks.py +2 -1
- claude_mpm/services/monitor/management/lifecycle.py +3 -2
- claude_mpm/services/monitor/server.py +2 -1
- claude_mpm/services/session_management_service.py +3 -2
- claude_mpm/services/socketio/handlers/hook.py +3 -2
- claude_mpm/services/socketio/server/main.py +3 -1
- claude_mpm/services/subprocess_launcher_service.py +14 -5
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +6 -5
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +5 -4
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +5 -4
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +4 -3
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +4 -3
- claude_mpm/services/unified/config_strategies/validation_strategy.py +13 -9
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +10 -3
- claude_mpm/services/unified/deployment_strategies/local.py +3 -2
- claude_mpm/services/unified/deployment_strategies/utils.py +2 -1
- claude_mpm/services/unified/deployment_strategies/vercel.py +2 -1
- claude_mpm/services/unified/interfaces.py +3 -1
- claude_mpm/services/unified/unified_analyzer.py +7 -6
- claude_mpm/services/unified/unified_config.py +2 -1
- claude_mpm/services/unified/unified_deployment.py +7 -2
- claude_mpm/tools/code_tree_analyzer.py +177 -141
- claude_mpm/tools/code_tree_events.py +4 -2
- {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.8.dist-info}/METADATA +1 -1
- {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.8.dist-info}/RECORD +73 -63
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1041
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.8.dist-info}/WHEEL +0 -0
- {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.8.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.8.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.14.7.dist-info → claude_mpm-4.14.8.dist-info}/top_level.txt +0 -0
|
@@ -9,6 +9,8 @@ import json
|
|
|
9
9
|
import subprocess
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
|
+
from claude_mpm.core.enums import ServiceState
|
|
13
|
+
|
|
12
14
|
from ..models import DiagnosticResult, DiagnosticStatus
|
|
13
15
|
from .base_check import BaseDiagnosticCheck
|
|
14
16
|
|
|
@@ -226,18 +228,18 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
|
226
228
|
)
|
|
227
229
|
|
|
228
230
|
if result.returncode == 0:
|
|
229
|
-
if
|
|
231
|
+
if ServiceState.RUNNING.value in result.stdout.lower():
|
|
230
232
|
return DiagnosticResult(
|
|
231
233
|
category="MCP Server Status",
|
|
232
234
|
status=DiagnosticStatus.OK,
|
|
233
235
|
message="MCP server is running",
|
|
234
|
-
details={"running": True},
|
|
236
|
+
details={"running": True, "state": ServiceState.RUNNING},
|
|
235
237
|
)
|
|
236
238
|
return DiagnosticResult(
|
|
237
239
|
category="MCP Server Status",
|
|
238
240
|
status=DiagnosticStatus.WARNING,
|
|
239
241
|
message="MCP server not running",
|
|
240
|
-
details={"running": False},
|
|
242
|
+
details={"running": False, "state": ServiceState.STOPPED},
|
|
241
243
|
fix_command="claude-mpm mcp start",
|
|
242
244
|
fix_description="Start the MCP server",
|
|
243
245
|
)
|
|
@@ -245,7 +247,11 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
|
245
247
|
category="MCP Server Status",
|
|
246
248
|
status=DiagnosticStatus.WARNING,
|
|
247
249
|
message="Could not determine server status",
|
|
248
|
-
details={
|
|
250
|
+
details={
|
|
251
|
+
"running": "unknown",
|
|
252
|
+
"state": ServiceState.UNKNOWN,
|
|
253
|
+
"error": result.stderr,
|
|
254
|
+
},
|
|
249
255
|
)
|
|
250
256
|
|
|
251
257
|
except subprocess.TimeoutExpired:
|
|
@@ -253,14 +259,22 @@ class MCPCheck(BaseDiagnosticCheck):
|
|
|
253
259
|
category="MCP Server Status",
|
|
254
260
|
status=DiagnosticStatus.WARNING,
|
|
255
261
|
message="Server status check timed out",
|
|
256
|
-
details={
|
|
262
|
+
details={
|
|
263
|
+
"running": "unknown",
|
|
264
|
+
"state": ServiceState.UNKNOWN,
|
|
265
|
+
"error": "timeout",
|
|
266
|
+
},
|
|
257
267
|
)
|
|
258
268
|
except Exception as e:
|
|
259
269
|
return DiagnosticResult(
|
|
260
270
|
category="MCP Server Status",
|
|
261
271
|
status=DiagnosticStatus.WARNING,
|
|
262
272
|
message=f"Could not check server status: {e!s}",
|
|
263
|
-
details={
|
|
273
|
+
details={
|
|
274
|
+
"running": "unknown",
|
|
275
|
+
"state": ServiceState.UNKNOWN,
|
|
276
|
+
"error": str(e),
|
|
277
|
+
},
|
|
264
278
|
)
|
|
265
279
|
|
|
266
280
|
def _check_startup_verification(self) -> DiagnosticResult:
|
|
@@ -26,6 +26,7 @@ from typing import Any, Dict
|
|
|
26
26
|
import psutil
|
|
27
27
|
|
|
28
28
|
from claude_mpm.config.paths import paths
|
|
29
|
+
from claude_mpm.core.enums import OperationResult, ServiceState
|
|
29
30
|
from claude_mpm.core.logger import get_logger
|
|
30
31
|
from claude_mpm.services.mcp_gateway.core.interfaces import (
|
|
31
32
|
MCPToolDefinition,
|
|
@@ -168,20 +169,20 @@ class HealthCheckTool(BaseToolAdapter):
|
|
|
168
169
|
if i < len(check_results):
|
|
169
170
|
if isinstance(check_results[i], Exception):
|
|
170
171
|
results["checks"][check_name] = {
|
|
171
|
-
"status":
|
|
172
|
+
"status": OperationResult.ERROR,
|
|
172
173
|
"error": str(check_results[i]),
|
|
173
174
|
}
|
|
174
175
|
else:
|
|
175
176
|
results["checks"][check_name] = check_results[i]
|
|
176
177
|
else:
|
|
177
178
|
results["checks"][check_name] = {
|
|
178
|
-
"status":
|
|
179
|
+
"status": OperationResult.TIMEOUT,
|
|
179
180
|
"error": "Check timed out",
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
except asyncio.TimeoutError:
|
|
183
184
|
results["checks"]["timeout"] = {
|
|
184
|
-
"status":
|
|
185
|
+
"status": OperationResult.ERROR,
|
|
185
186
|
"error": f"Health checks timed out after {timeout} seconds",
|
|
186
187
|
}
|
|
187
188
|
|
|
@@ -194,7 +195,7 @@ class HealthCheckTool(BaseToolAdapter):
|
|
|
194
195
|
async def _check_system_health(self, detailed: bool) -> Dict[str, Any]:
|
|
195
196
|
"""Check system health (CPU, memory, disk, etc.)."""
|
|
196
197
|
check_result = {
|
|
197
|
-
"status":
|
|
198
|
+
"status": ServiceState.RUNNING,
|
|
198
199
|
"checks": {},
|
|
199
200
|
"warnings": [],
|
|
200
201
|
"errors": [],
|
|
@@ -270,7 +271,7 @@ class HealthCheckTool(BaseToolAdapter):
|
|
|
270
271
|
async def _check_gateway_health(self, detailed: bool) -> Dict[str, Any]:
|
|
271
272
|
"""Check MCP Gateway health."""
|
|
272
273
|
check_result = {
|
|
273
|
-
"status":
|
|
274
|
+
"status": ServiceState.RUNNING,
|
|
274
275
|
"checks": {},
|
|
275
276
|
"warnings": [],
|
|
276
277
|
"errors": [],
|
|
@@ -313,7 +314,7 @@ class HealthCheckTool(BaseToolAdapter):
|
|
|
313
314
|
async def _check_tools_health(self, detailed: bool) -> Dict[str, Any]:
|
|
314
315
|
"""Check MCP tools health."""
|
|
315
316
|
check_result = {
|
|
316
|
-
"status":
|
|
317
|
+
"status": ServiceState.RUNNING,
|
|
317
318
|
"checks": {},
|
|
318
319
|
"warnings": [],
|
|
319
320
|
"errors": [],
|
|
@@ -365,7 +366,7 @@ class HealthCheckTool(BaseToolAdapter):
|
|
|
365
366
|
async def _check_config_health(self, detailed: bool) -> Dict[str, Any]:
|
|
366
367
|
"""Check configuration health."""
|
|
367
368
|
check_result = {
|
|
368
|
-
"status":
|
|
369
|
+
"status": ServiceState.RUNNING,
|
|
369
370
|
"checks": {},
|
|
370
371
|
"warnings": [],
|
|
371
372
|
"errors": [],
|
|
@@ -11,6 +11,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
|
|
|
11
11
|
from typing import Any, Dict
|
|
12
12
|
|
|
13
13
|
from claude_mpm.core.base_service import BaseService
|
|
14
|
+
from claude_mpm.core.enums import ServiceState
|
|
14
15
|
from claude_mpm.services.core.interfaces import MemoryHookInterface
|
|
15
16
|
|
|
16
17
|
|
|
@@ -463,5 +464,7 @@ class MemoryHookService(BaseService, MemoryHookInterface):
|
|
|
463
464
|
"hook_service_available": self.hook_service is not None,
|
|
464
465
|
"memory_enabled": self.is_memory_enabled(),
|
|
465
466
|
"total_hooks": len(self.registered_hooks),
|
|
466
|
-
"status":
|
|
467
|
+
"status": (
|
|
468
|
+
ServiceState.RUNNING if self.registered_hooks else ServiceState.IDLE
|
|
469
|
+
),
|
|
467
470
|
}
|
|
@@ -31,6 +31,7 @@ import time
|
|
|
31
31
|
from pathlib import Path
|
|
32
32
|
from typing import Optional, Tuple
|
|
33
33
|
|
|
34
|
+
from ...core.enums import OperationResult
|
|
34
35
|
from ...core.logging_config import get_logger
|
|
35
36
|
|
|
36
37
|
|
|
@@ -906,7 +907,7 @@ class DaemonManager:
|
|
|
906
907
|
with self.startup_status_file.open() as f:
|
|
907
908
|
status = f.read().strip()
|
|
908
909
|
|
|
909
|
-
if status ==
|
|
910
|
+
if status == OperationResult.SUCCESS:
|
|
910
911
|
# Cleanup status file
|
|
911
912
|
Path(self.startup_status_file).unlink(missing_ok=True)
|
|
912
913
|
return True
|
|
@@ -936,7 +937,7 @@ class DaemonManager:
|
|
|
936
937
|
# Don't check if file exists - we need to write to it regardless
|
|
937
938
|
# The parent created it and is waiting for us to update it
|
|
938
939
|
with self.startup_status_file.open("w") as f:
|
|
939
|
-
f.write(
|
|
940
|
+
f.write(OperationResult.SUCCESS)
|
|
940
941
|
f.flush() # Ensure it's written immediately
|
|
941
942
|
os.fsync(f.fileno()) # Force write to disk
|
|
942
943
|
except Exception:
|
|
@@ -18,6 +18,7 @@ from typing import Dict, Set
|
|
|
18
18
|
|
|
19
19
|
import socketio
|
|
20
20
|
|
|
21
|
+
from ....core.enums import ServiceState
|
|
21
22
|
from ....core.logging_config import get_logger
|
|
22
23
|
|
|
23
24
|
|
|
@@ -128,7 +129,7 @@ class DashboardHandler:
|
|
|
128
129
|
try:
|
|
129
130
|
status = {
|
|
130
131
|
"service": "unified-monitor",
|
|
131
|
-
"status":
|
|
132
|
+
"status": ServiceState.RUNNING,
|
|
132
133
|
"clients_connected": len(self.connected_clients),
|
|
133
134
|
"uptime": asyncio.get_event_loop().time(),
|
|
134
135
|
"features": {
|
|
@@ -19,6 +19,7 @@ from typing import Dict, List
|
|
|
19
19
|
|
|
20
20
|
import socketio
|
|
21
21
|
|
|
22
|
+
from ....core.enums import ServiceState
|
|
22
23
|
from ....core.logging_config import get_logger
|
|
23
24
|
|
|
24
25
|
|
|
@@ -170,7 +171,7 @@ class HookHandler:
|
|
|
170
171
|
session_info = {
|
|
171
172
|
"session_id": session_id,
|
|
172
173
|
"start_time": asyncio.get_event_loop().time(),
|
|
173
|
-
"status":
|
|
174
|
+
"status": ServiceState.RUNNING,
|
|
174
175
|
"event_count": 0,
|
|
175
176
|
"last_activity": asyncio.get_event_loop().time(),
|
|
176
177
|
"metadata": data.get("metadata", {}),
|
|
@@ -23,6 +23,7 @@ import time
|
|
|
23
23
|
from pathlib import Path
|
|
24
24
|
from typing import Optional, Tuple
|
|
25
25
|
|
|
26
|
+
from ....core.enums import OperationResult
|
|
26
27
|
from ....core.logging_config import get_logger
|
|
27
28
|
|
|
28
29
|
|
|
@@ -388,7 +389,7 @@ class DaemonLifecycle:
|
|
|
388
389
|
with self.startup_status_file.open() as f:
|
|
389
390
|
status = f.read().strip()
|
|
390
391
|
|
|
391
|
-
if status ==
|
|
392
|
+
if status == OperationResult.SUCCESS:
|
|
392
393
|
# Child started successfully
|
|
393
394
|
self._cleanup_status_file()
|
|
394
395
|
return True
|
|
@@ -438,7 +439,7 @@ class DaemonLifecycle:
|
|
|
438
439
|
if self.startup_status_file:
|
|
439
440
|
try:
|
|
440
441
|
with self.startup_status_file.open("w") as f:
|
|
441
|
-
f.write(
|
|
442
|
+
f.write(OperationResult.SUCCESS)
|
|
442
443
|
except Exception as e:
|
|
443
444
|
self.logger.error(f"Failed to report startup success: {e}")
|
|
444
445
|
|
|
@@ -26,6 +26,7 @@ from typing import Dict, Optional
|
|
|
26
26
|
import socketio
|
|
27
27
|
from aiohttp import web
|
|
28
28
|
|
|
29
|
+
from ...core.enums import ServiceState
|
|
29
30
|
from ...core.logging_config import get_logger
|
|
30
31
|
from ...dashboard.api.simple_directory import list_directory
|
|
31
32
|
from .event_emitter import get_event_emitter
|
|
@@ -333,7 +334,7 @@ class UnifiedMonitorServer:
|
|
|
333
334
|
|
|
334
335
|
return web.json_response(
|
|
335
336
|
{
|
|
336
|
-
"status":
|
|
337
|
+
"status": ServiceState.RUNNING,
|
|
337
338
|
"service": "claude-mpm-monitor", # Important: must match what is_our_service() checks
|
|
338
339
|
"version": version,
|
|
339
340
|
"port": self.port,
|
|
@@ -17,6 +17,7 @@ from datetime import timezone
|
|
|
17
17
|
from typing import Any, Dict, List, Optional
|
|
18
18
|
|
|
19
19
|
from claude_mpm.core.base_service import BaseService
|
|
20
|
+
from claude_mpm.core.enums import OperationResult, ServiceState
|
|
20
21
|
from claude_mpm.services.core.interfaces import SessionManagementInterface
|
|
21
22
|
|
|
22
23
|
|
|
@@ -223,7 +224,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
|
223
224
|
"id": session_id,
|
|
224
225
|
"config": session_config,
|
|
225
226
|
"start_time": time.time(),
|
|
226
|
-
"status":
|
|
227
|
+
"status": ServiceState.RUNNING,
|
|
227
228
|
"type": session_config.get("type", "interactive"),
|
|
228
229
|
}
|
|
229
230
|
|
|
@@ -267,7 +268,7 @@ class SessionManagementService(BaseService, SessionManagementInterface):
|
|
|
267
268
|
return self.active_sessions[session_id].copy()
|
|
268
269
|
return {
|
|
269
270
|
"id": session_id,
|
|
270
|
-
"status":
|
|
271
|
+
"status": OperationResult.ERROR,
|
|
271
272
|
"error": "Session not found",
|
|
272
273
|
}
|
|
273
274
|
|
|
@@ -7,6 +7,7 @@ agent delegations, and other hook-based activity for the system heartbeat.
|
|
|
7
7
|
from datetime import datetime, timezone
|
|
8
8
|
from typing import Any, Dict
|
|
9
9
|
|
|
10
|
+
from ....core.enums import ServiceState
|
|
10
11
|
from .base import BaseEventHandler
|
|
11
12
|
|
|
12
13
|
|
|
@@ -108,7 +109,7 @@ class HookEventHandler(BaseEventHandler):
|
|
|
108
109
|
"session_id": session_id,
|
|
109
110
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
110
111
|
"agent": agent_type,
|
|
111
|
-
"status":
|
|
112
|
+
"status": ServiceState.RUNNING,
|
|
112
113
|
"prompt": data.get("prompt", "")[:100], # First 100 chars
|
|
113
114
|
"last_activity": datetime.now(timezone.utc).isoformat(),
|
|
114
115
|
}
|
|
@@ -159,7 +160,7 @@ class HookEventHandler(BaseEventHandler):
|
|
|
159
160
|
"session_id": session_id,
|
|
160
161
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
161
162
|
"agent": "pm", # Default to PM
|
|
162
|
-
"status":
|
|
163
|
+
"status": ServiceState.RUNNING,
|
|
163
164
|
"prompt": data.get("prompt_text", "")[:100],
|
|
164
165
|
"working_directory": data.get("working_directory", ""),
|
|
165
166
|
"last_activity": datetime.now(timezone.utc).isoformat(),
|
|
@@ -16,6 +16,8 @@ from collections import deque
|
|
|
16
16
|
from datetime import datetime, timezone
|
|
17
17
|
from typing import Any, Dict, List, Optional, Set
|
|
18
18
|
|
|
19
|
+
from ....core.enums import ServiceState
|
|
20
|
+
|
|
19
21
|
try:
|
|
20
22
|
import aiohttp
|
|
21
23
|
import socketio
|
|
@@ -384,7 +386,7 @@ class SocketIOServer(SocketIOServiceInterface):
|
|
|
384
386
|
"session_id": session_id,
|
|
385
387
|
"start_time": datetime.now(timezone.utc).isoformat(),
|
|
386
388
|
"agent": "pm", # Default to PM, will be updated if delegated
|
|
387
|
-
"status":
|
|
389
|
+
"status": ServiceState.RUNNING,
|
|
388
390
|
"launch_method": launch_method,
|
|
389
391
|
"working_dir": working_dir,
|
|
390
392
|
}
|
|
@@ -22,6 +22,7 @@ import tty
|
|
|
22
22
|
from typing import Any, Dict, List, Optional
|
|
23
23
|
|
|
24
24
|
from claude_mpm.core.base_service import BaseService
|
|
25
|
+
from claude_mpm.core.enums import OperationResult, ServiceState
|
|
25
26
|
from claude_mpm.services.core.interfaces import SubprocessLauncherInterface
|
|
26
27
|
|
|
27
28
|
|
|
@@ -62,9 +63,17 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
|
|
|
62
63
|
try:
|
|
63
64
|
env = kwargs.get("env", self.prepare_subprocess_environment())
|
|
64
65
|
self.launch_subprocess_interactive(command, env)
|
|
65
|
-
return {
|
|
66
|
+
return {
|
|
67
|
+
"status": OperationResult.SUCCESS,
|
|
68
|
+
"command": command,
|
|
69
|
+
"method": "interactive",
|
|
70
|
+
}
|
|
66
71
|
except Exception as e:
|
|
67
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
"status": OperationResult.FAILED,
|
|
74
|
+
"error": str(e),
|
|
75
|
+
"command": command,
|
|
76
|
+
}
|
|
68
77
|
|
|
69
78
|
async def launch_subprocess_async(
|
|
70
79
|
self, command: List[str], **kwargs
|
|
@@ -109,7 +118,7 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
|
|
|
109
118
|
# For now, return unknown status
|
|
110
119
|
return {
|
|
111
120
|
"process_id": process_id,
|
|
112
|
-
"status":
|
|
121
|
+
"status": OperationResult.UNKNOWN,
|
|
113
122
|
"message": "Process tracking not implemented",
|
|
114
123
|
}
|
|
115
124
|
|
|
@@ -160,7 +169,7 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
|
|
|
160
169
|
# Notify WebSocket clients
|
|
161
170
|
if self.websocket_server:
|
|
162
171
|
self.websocket_server.claude_status_changed(
|
|
163
|
-
status=
|
|
172
|
+
status=ServiceState.RUNNING,
|
|
164
173
|
pid=process.pid,
|
|
165
174
|
message="Claude subprocess started",
|
|
166
175
|
)
|
|
@@ -195,7 +204,7 @@ class SubprocessLauncherService(BaseService, SubprocessLauncherInterface):
|
|
|
195
204
|
# Notify WebSocket clients
|
|
196
205
|
if self.websocket_server:
|
|
197
206
|
self.websocket_server.claude_status_changed(
|
|
198
|
-
status=
|
|
207
|
+
status=ServiceState.STOPPED,
|
|
199
208
|
message=f"Claude subprocess exited with code {process.returncode}",
|
|
200
209
|
)
|
|
201
210
|
|
|
@@ -14,6 +14,7 @@ import re
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, Dict, List, Optional
|
|
16
16
|
|
|
17
|
+
from claude_mpm.core.enums import OperationResult
|
|
17
18
|
from claude_mpm.core.logging_utils import get_logger
|
|
18
19
|
|
|
19
20
|
from ..strategies import (
|
|
@@ -120,7 +121,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
|
|
|
120
121
|
return self._analyze_ast(target, options)
|
|
121
122
|
|
|
122
123
|
return {
|
|
123
|
-
"status":
|
|
124
|
+
"status": OperationResult.ERROR,
|
|
124
125
|
"message": f"Unsupported target type: {type(target).__name__}",
|
|
125
126
|
}
|
|
126
127
|
|
|
@@ -159,7 +160,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
|
|
|
159
160
|
metrics["maintainability_index"] = self._calculate_maintainability(metrics)
|
|
160
161
|
|
|
161
162
|
return {
|
|
162
|
-
"status":
|
|
163
|
+
"status": OperationResult.SUCCESS,
|
|
163
164
|
"type": "file",
|
|
164
165
|
"path": str(file_path),
|
|
165
166
|
"metrics": metrics,
|
|
@@ -168,7 +169,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
|
|
|
168
169
|
except Exception as e:
|
|
169
170
|
logger.error(f"Error analyzing file {file_path}: {e}")
|
|
170
171
|
return {
|
|
171
|
-
"status":
|
|
172
|
+
"status": OperationResult.ERROR,
|
|
172
173
|
"path": str(file_path),
|
|
173
174
|
"error": str(e),
|
|
174
175
|
}
|
|
@@ -178,7 +179,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
|
|
|
178
179
|
) -> Dict[str, Any]:
|
|
179
180
|
"""Analyze all code files in a directory."""
|
|
180
181
|
results = {
|
|
181
|
-
"status":
|
|
182
|
+
"status": OperationResult.SUCCESS,
|
|
182
183
|
"type": "directory",
|
|
183
184
|
"path": str(dir_path),
|
|
184
185
|
"files": [],
|
|
@@ -285,7 +286,7 @@ class CodeAnalyzerStrategy(AnalyzerStrategy):
|
|
|
285
286
|
)
|
|
286
287
|
|
|
287
288
|
return {
|
|
288
|
-
"status":
|
|
289
|
+
"status": OperationResult.SUCCESS,
|
|
289
290
|
"type": "ast",
|
|
290
291
|
"metrics": metrics,
|
|
291
292
|
}
|
|
@@ -14,6 +14,7 @@ import re
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, ClassVar, Dict, List, Optional
|
|
16
16
|
|
|
17
|
+
from claude_mpm.core.enums import OperationResult
|
|
17
18
|
from claude_mpm.core.logging_utils import get_logger
|
|
18
19
|
|
|
19
20
|
from ..strategies import (
|
|
@@ -166,7 +167,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
|
166
167
|
return self._analyze_manifest(target_path, options)
|
|
167
168
|
|
|
168
169
|
return {
|
|
169
|
-
"status":
|
|
170
|
+
"status": OperationResult.ERROR,
|
|
170
171
|
"message": f"Unsupported target type: {type(target).__name__}",
|
|
171
172
|
}
|
|
172
173
|
|
|
@@ -175,7 +176,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
|
175
176
|
) -> Dict[str, Any]:
|
|
176
177
|
"""Analyze dependencies in a project directory."""
|
|
177
178
|
results = {
|
|
178
|
-
"status":
|
|
179
|
+
"status": OperationResult.SUCCESS,
|
|
179
180
|
"type": "project",
|
|
180
181
|
"path": str(project_path),
|
|
181
182
|
"package_managers": [],
|
|
@@ -221,7 +222,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
|
221
222
|
) -> Dict[str, Any]:
|
|
222
223
|
"""Analyze a specific package manifest file."""
|
|
223
224
|
results = {
|
|
224
|
-
"status":
|
|
225
|
+
"status": OperationResult.SUCCESS,
|
|
225
226
|
"type": "manifest",
|
|
226
227
|
"path": str(manifest_path),
|
|
227
228
|
"dependencies": {},
|
|
@@ -238,7 +239,7 @@ class DependencyAnalyzerStrategy(AnalyzerStrategy):
|
|
|
238
239
|
|
|
239
240
|
if not manager:
|
|
240
241
|
return {
|
|
241
|
-
"status":
|
|
242
|
+
"status": OperationResult.ERROR,
|
|
242
243
|
"message": f"Unknown manifest file: {manifest_path.name}",
|
|
243
244
|
}
|
|
244
245
|
|
|
@@ -14,6 +14,7 @@ import re
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, ClassVar, Dict, List, Optional
|
|
16
16
|
|
|
17
|
+
from claude_mpm.core.enums import OperationResult
|
|
17
18
|
from claude_mpm.core.logging_utils import get_logger
|
|
18
19
|
|
|
19
20
|
from ..strategies import (
|
|
@@ -188,14 +189,14 @@ class PerformanceAnalyzerStrategy(AnalyzerStrategy):
|
|
|
188
189
|
return self._analyze_ast_performance(target, options)
|
|
189
190
|
|
|
190
191
|
return {
|
|
191
|
-
"status":
|
|
192
|
+
"status": OperationResult.ERROR,
|
|
192
193
|
"message": f"Unsupported target type: {type(target).__name__}",
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
def _analyze_file(self, file_path: Path, options: Dict[str, Any]) -> Dict[str, Any]:
|
|
196
197
|
"""Analyze a single file for performance issues."""
|
|
197
198
|
results = {
|
|
198
|
-
"status":
|
|
199
|
+
"status": OperationResult.SUCCESS,
|
|
199
200
|
"type": "file",
|
|
200
201
|
"path": str(file_path),
|
|
201
202
|
"issues": [],
|
|
@@ -250,7 +251,7 @@ class PerformanceAnalyzerStrategy(AnalyzerStrategy):
|
|
|
250
251
|
) -> Dict[str, Any]:
|
|
251
252
|
"""Analyze all files in a directory for performance issues."""
|
|
252
253
|
results = {
|
|
253
|
-
"status":
|
|
254
|
+
"status": OperationResult.SUCCESS,
|
|
254
255
|
"type": "directory",
|
|
255
256
|
"path": str(dir_path),
|
|
256
257
|
"files_analyzed": 0,
|
|
@@ -654,7 +655,7 @@ class PerformanceAnalyzerStrategy(AnalyzerStrategy):
|
|
|
654
655
|
) -> Dict[str, Any]:
|
|
655
656
|
"""Analyze performance of an AST node."""
|
|
656
657
|
results = {
|
|
657
|
-
"status":
|
|
658
|
+
"status": OperationResult.SUCCESS,
|
|
658
659
|
"type": "ast",
|
|
659
660
|
"complexity": {},
|
|
660
661
|
"issues": [],
|
|
@@ -14,6 +14,7 @@ import re
|
|
|
14
14
|
from pathlib import Path
|
|
15
15
|
from typing import Any, ClassVar, Dict, List, Optional
|
|
16
16
|
|
|
17
|
+
from claude_mpm.core.enums import OperationResult
|
|
17
18
|
from claude_mpm.core.logging_utils import get_logger
|
|
18
19
|
|
|
19
20
|
from ..strategies import (
|
|
@@ -198,14 +199,14 @@ class SecurityAnalyzerStrategy(AnalyzerStrategy):
|
|
|
198
199
|
return self._analyze_directory(target_path, options)
|
|
199
200
|
|
|
200
201
|
return {
|
|
201
|
-
"status":
|
|
202
|
+
"status": OperationResult.ERROR,
|
|
202
203
|
"message": f"Unsupported target type: {type(target).__name__}",
|
|
203
204
|
}
|
|
204
205
|
|
|
205
206
|
def _analyze_file(self, file_path: Path, options: Dict[str, Any]) -> Dict[str, Any]:
|
|
206
207
|
"""Analyze a single file for security issues."""
|
|
207
208
|
results = {
|
|
208
|
-
"status":
|
|
209
|
+
"status": OperationResult.SUCCESS,
|
|
209
210
|
"type": "file",
|
|
210
211
|
"path": str(file_path),
|
|
211
212
|
"vulnerabilities": [],
|
|
@@ -251,7 +252,7 @@ class SecurityAnalyzerStrategy(AnalyzerStrategy):
|
|
|
251
252
|
) -> Dict[str, Any]:
|
|
252
253
|
"""Analyze all files in a directory for security issues."""
|
|
253
254
|
results = {
|
|
254
|
-
"status":
|
|
255
|
+
"status": OperationResult.SUCCESS,
|
|
255
256
|
"type": "directory",
|
|
256
257
|
"path": str(dir_path),
|
|
257
258
|
"files_analyzed": 0,
|
|
@@ -13,6 +13,7 @@ import fnmatch
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any, ClassVar, Dict, List, Optional, Tuple
|
|
15
15
|
|
|
16
|
+
from claude_mpm.core.enums import OperationResult
|
|
16
17
|
from claude_mpm.core.logging_utils import get_logger
|
|
17
18
|
|
|
18
19
|
from ..strategies import (
|
|
@@ -174,14 +175,14 @@ class StructureAnalyzerStrategy(AnalyzerStrategy):
|
|
|
174
175
|
|
|
175
176
|
if not target_path.is_dir():
|
|
176
177
|
return {
|
|
177
|
-
"status":
|
|
178
|
+
"status": OperationResult.ERROR,
|
|
178
179
|
"message": "Target must be a directory",
|
|
179
180
|
}
|
|
180
181
|
|
|
181
182
|
return self._analyze_structure(target_path, options)
|
|
182
183
|
|
|
183
184
|
return {
|
|
184
|
-
"status":
|
|
185
|
+
"status": OperationResult.ERROR,
|
|
185
186
|
"message": f"Unsupported target type: {type(target).__name__}",
|
|
186
187
|
}
|
|
187
188
|
|
|
@@ -190,7 +191,7 @@ class StructureAnalyzerStrategy(AnalyzerStrategy):
|
|
|
190
191
|
) -> Dict[str, Any]:
|
|
191
192
|
"""Analyze the structure of a project directory."""
|
|
192
193
|
results = {
|
|
193
|
-
"status":
|
|
194
|
+
"status": OperationResult.SUCCESS,
|
|
194
195
|
"type": "structure",
|
|
195
196
|
"path": str(root_path),
|
|
196
197
|
"tree": {},
|
|
@@ -13,6 +13,7 @@ from enum import Enum
|
|
|
13
13
|
from pathlib import Path
|
|
14
14
|
from typing import Any, Callable, Dict, List, Optional, Pattern, Union
|
|
15
15
|
|
|
16
|
+
from claude_mpm.core.enums import ValidationSeverity
|
|
16
17
|
from claude_mpm.core.logging_utils import get_logger
|
|
17
18
|
|
|
18
19
|
from .unified_config_service import IConfigStrategy
|
|
@@ -45,7 +46,7 @@ class ValidationRule:
|
|
|
45
46
|
type: ValidationType
|
|
46
47
|
params: Dict[str, Any] = field(default_factory=dict)
|
|
47
48
|
message: Optional[str] = None
|
|
48
|
-
severity: str =
|
|
49
|
+
severity: str = ValidationSeverity.ERROR
|
|
49
50
|
condition: Optional[Callable] = None
|
|
50
51
|
|
|
51
52
|
|
|
@@ -73,15 +74,18 @@ class BaseValidator(ABC):
|
|
|
73
74
|
"""Perform validation"""
|
|
74
75
|
|
|
75
76
|
def _create_result(
|
|
76
|
-
self,
|
|
77
|
+
self,
|
|
78
|
+
valid: bool,
|
|
79
|
+
message: Optional[str] = None,
|
|
80
|
+
severity: str = ValidationSeverity.ERROR,
|
|
77
81
|
) -> ValidationResult:
|
|
78
82
|
"""Create validation result"""
|
|
79
83
|
result = ValidationResult(valid=valid)
|
|
80
84
|
|
|
81
85
|
if not valid and message:
|
|
82
|
-
if severity ==
|
|
86
|
+
if severity == ValidationSeverity.ERROR:
|
|
83
87
|
result.errors.append(message)
|
|
84
|
-
elif severity ==
|
|
88
|
+
elif severity == ValidationSeverity.WARNING:
|
|
85
89
|
result.warnings.append(message)
|
|
86
90
|
else:
|
|
87
91
|
result.info.append(message)
|
|
@@ -556,9 +560,9 @@ class DependencyValidator(BaseValidator):
|
|
|
556
560
|
if errors:
|
|
557
561
|
result = ValidationResult(valid=False)
|
|
558
562
|
for error in errors:
|
|
559
|
-
if rule.severity ==
|
|
563
|
+
if rule.severity == ValidationSeverity.ERROR:
|
|
560
564
|
result.errors.append(error)
|
|
561
|
-
elif rule.severity ==
|
|
565
|
+
elif rule.severity == ValidationSeverity.WARNING:
|
|
562
566
|
result.warnings.append(error)
|
|
563
567
|
else:
|
|
564
568
|
result.info.append(error)
|
|
@@ -721,7 +725,7 @@ class ConditionalValidator(BaseValidator):
|
|
|
721
725
|
type=ValidationType[rule_def.get("type", "CUSTOM").upper()],
|
|
722
726
|
params=rule_def.get("params", {}),
|
|
723
727
|
message=rule_def.get("message"),
|
|
724
|
-
severity=rule_def.get("severity",
|
|
728
|
+
severity=rule_def.get("severity", ValidationSeverity.ERROR),
|
|
725
729
|
)
|
|
726
730
|
|
|
727
731
|
# Find appropriate validator
|
|
@@ -843,9 +847,9 @@ class CrossFieldValidator(BaseValidator):
|
|
|
843
847
|
for constraint in constraints:
|
|
844
848
|
if not self._evaluate_constraint(config, constraint):
|
|
845
849
|
message = constraint.get("message", "Cross-field constraint failed")
|
|
846
|
-
if rule.severity ==
|
|
850
|
+
if rule.severity == ValidationSeverity.ERROR:
|
|
847
851
|
result.errors.append(message)
|
|
848
|
-
elif rule.severity ==
|
|
852
|
+
elif rule.severity == ValidationSeverity.WARNING:
|
|
849
853
|
result.warnings.append(message)
|
|
850
854
|
else:
|
|
851
855
|
result.info.append(message)
|