claude-mpm 4.14.9__py3-none-any.whl → 4.15.1__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/OUTPUT_STYLE.md +48 -3
- claude_mpm/agents/templates/project_organizer.json +3 -3
- claude_mpm/cli/commands/auto_configure.py +7 -9
- claude_mpm/cli/commands/local_deploy.py +3 -2
- claude_mpm/cli/commands/mpm_init.py +4 -4
- claude_mpm/cli/commands/mpm_init_handler.py +8 -3
- claude_mpm/core/base_service.py +13 -12
- claude_mpm/core/enums.py +36 -1
- claude_mpm/services/agents/auto_config_manager.py +9 -10
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +7 -6
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +5 -3
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +6 -4
- claude_mpm/services/agents/registry/modification_tracker.py +5 -2
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/interfaces/process.py +6 -6
- claude_mpm/services/core/models/__init__.py +0 -2
- claude_mpm/services/core/models/agent_config.py +12 -28
- claude_mpm/services/core/models/process.py +19 -42
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +25 -24
- claude_mpm/services/diagnostics/checks/claude_code_check.py +24 -23
- claude_mpm/services/diagnostics/checks/common_issues_check.py +25 -24
- claude_mpm/services/diagnostics/checks/configuration_check.py +24 -23
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +28 -28
- claude_mpm/services/diagnostics/checks/instructions_check.py +20 -19
- claude_mpm/services/diagnostics/checks/mcp_check.py +31 -31
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +36 -31
- claude_mpm/services/diagnostics/checks/monitor_check.py +23 -22
- claude_mpm/services/diagnostics/checks/startup_log_check.py +9 -8
- claude_mpm/services/diagnostics/diagnostic_runner.py +6 -5
- claude_mpm/services/diagnostics/doctor_reporter.py +28 -25
- claude_mpm/services/diagnostics/models.py +19 -24
- claude_mpm/services/local_ops/__init__.py +3 -3
- claude_mpm/services/local_ops/process_manager.py +12 -12
- claude_mpm/services/local_ops/state_manager.py +6 -5
- claude_mpm/services/local_ops/unified_manager.py +2 -2
- claude_mpm/services/mcp_config_manager.py +7 -2
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +18 -31
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +71 -24
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +23 -22
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +2 -2
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +2 -2
- claude_mpm/services/unified/deployment_strategies/local.py +3 -3
- claude_mpm/services/unified/deployment_strategies/utils.py +5 -5
- claude_mpm/services/unified/deployment_strategies/vercel.py +6 -6
- claude_mpm/services/unified/unified_analyzer.py +8 -5
- claude_mpm/services/unified/unified_deployment.py +2 -2
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.1.dist-info}/METADATA +1 -1
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.1.dist-info}/RECORD +59 -59
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.1.dist-info}/WHEEL +0 -0
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.1.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.1.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.1.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
import time
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
-
from .
|
|
6
|
+
from claude_mpm.core.enums import OperationResult
|
|
7
|
+
|
|
8
|
+
from .base_step import BaseDeploymentStep, StepResult
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
class TargetDirectorySetupStep(BaseDeploymentStep):
|
|
@@ -59,7 +61,7 @@ class TargetDirectorySetupStep(BaseDeploymentStep):
|
|
|
59
61
|
context.step_timings[self.name] = execution_time
|
|
60
62
|
|
|
61
63
|
return StepResult(
|
|
62
|
-
status=
|
|
64
|
+
status=OperationResult.SUCCESS,
|
|
63
65
|
message=f"Target directory set up at {context.actual_target_dir} in {execution_time:.3f}s",
|
|
64
66
|
execution_time=execution_time,
|
|
65
67
|
)
|
|
@@ -73,7 +75,7 @@ class TargetDirectorySetupStep(BaseDeploymentStep):
|
|
|
73
75
|
context.add_error(error_msg)
|
|
74
76
|
|
|
75
77
|
return StepResult(
|
|
76
|
-
status=
|
|
78
|
+
status=OperationResult.FAILED,
|
|
77
79
|
message=error_msg,
|
|
78
80
|
error=e,
|
|
79
81
|
execution_time=execution_time,
|
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import time
|
|
4
4
|
|
|
5
|
+
from claude_mpm.core.enums import OperationResult
|
|
5
6
|
from claude_mpm.services.agents.deployment.validation import DeploymentValidator
|
|
6
7
|
|
|
7
|
-
from .base_step import BaseDeploymentStep, StepResult
|
|
8
|
+
from .base_step import BaseDeploymentStep, StepResult
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class ValidationStep(BaseDeploymentStep):
|
|
@@ -49,13 +50,13 @@ class ValidationStep(BaseDeploymentStep):
|
|
|
49
50
|
|
|
50
51
|
# Determine step status
|
|
51
52
|
if not validation_result.is_valid:
|
|
52
|
-
status =
|
|
53
|
+
status = OperationResult.FAILED
|
|
53
54
|
message = f"Validation failed with {validation_result.error_count} errors in {execution_time:.3f}s"
|
|
54
55
|
elif validation_result.has_warnings:
|
|
55
|
-
status =
|
|
56
|
+
status = OperationResult.WARNING
|
|
56
57
|
message = f"Validation completed with {validation_result.warning_count} warnings in {execution_time:.3f}s"
|
|
57
58
|
else:
|
|
58
|
-
status =
|
|
59
|
+
status = OperationResult.SUCCESS
|
|
59
60
|
message = f"Validation passed successfully in {execution_time:.3f}s"
|
|
60
61
|
|
|
61
62
|
self.logger.info(message)
|
|
@@ -73,7 +74,7 @@ class ValidationStep(BaseDeploymentStep):
|
|
|
73
74
|
context.add_error(error_msg)
|
|
74
75
|
|
|
75
76
|
return StepResult(
|
|
76
|
-
status=
|
|
77
|
+
status=OperationResult.FAILED,
|
|
77
78
|
message=error_msg,
|
|
78
79
|
error=e,
|
|
79
80
|
execution_time=execution_time,
|
|
@@ -117,8 +117,10 @@ class RefactoredAgentDeploymentService(AgentDeploymentInterface):
|
|
|
117
117
|
)
|
|
118
118
|
|
|
119
119
|
# Ensure success field is present
|
|
120
|
-
if
|
|
121
|
-
results[
|
|
120
|
+
if OperationResult.SUCCESS.value not in results:
|
|
121
|
+
results[OperationResult.SUCCESS.value] = not bool(
|
|
122
|
+
results.get("errors", [])
|
|
123
|
+
)
|
|
122
124
|
|
|
123
125
|
self.logger.info(f"Deployment completed: {results.get('success', False)}")
|
|
124
126
|
return results
|
|
@@ -126,7 +128,7 @@ class RefactoredAgentDeploymentService(AgentDeploymentInterface):
|
|
|
126
128
|
except Exception as e:
|
|
127
129
|
self.logger.error(f"Deployment failed: {e}", exc_info=True)
|
|
128
130
|
return {
|
|
129
|
-
|
|
131
|
+
OperationResult.SUCCESS.value: False,
|
|
130
132
|
"error": str(e),
|
|
131
133
|
"deployed": [],
|
|
132
134
|
"updated": [],
|
|
@@ -302,7 +304,7 @@ class RefactoredAgentDeploymentService(AgentDeploymentInterface):
|
|
|
302
304
|
except Exception as e:
|
|
303
305
|
self.logger.error(f"Async deployment failed: {e}", exc_info=True)
|
|
304
306
|
return {
|
|
305
|
-
|
|
307
|
+
OperationResult.SUCCESS.value: False,
|
|
306
308
|
"error": str(e),
|
|
307
309
|
"deployed": [],
|
|
308
310
|
"updated": [],
|
|
@@ -36,6 +36,7 @@ from watchdog.events import FileSystemEvent, FileSystemEventHandler
|
|
|
36
36
|
from watchdog.observers import Observer
|
|
37
37
|
|
|
38
38
|
from claude_mpm.core.base_service import BaseService
|
|
39
|
+
from claude_mpm.core.enums import OperationResult
|
|
39
40
|
from claude_mpm.core.logging_utils import get_logger
|
|
40
41
|
from claude_mpm.core.unified_agent_registry import UnifiedAgentRegistry as AgentRegistry
|
|
41
42
|
from claude_mpm.core.unified_paths import get_path_manager
|
|
@@ -551,12 +552,14 @@ class AgentModificationTracker(BaseService):
|
|
|
551
552
|
errors.append(f"File does not exist: {modification.file_path}")
|
|
552
553
|
|
|
553
554
|
# Update validation status
|
|
554
|
-
modification.validation_status =
|
|
555
|
+
modification.validation_status = (
|
|
556
|
+
OperationResult.FAILED if errors else OperationResult.SUCCESS
|
|
557
|
+
)
|
|
555
558
|
modification.validation_errors = errors
|
|
556
559
|
|
|
557
560
|
except Exception as e:
|
|
558
561
|
self.logger.error(f"Validation error: {e}")
|
|
559
|
-
modification.validation_status =
|
|
562
|
+
modification.validation_status = OperationResult.ERROR
|
|
560
563
|
modification.validation_errors.append(str(e))
|
|
561
564
|
|
|
562
565
|
async def _invalidate_agent_cache(self, agent_name: str) -> None:
|
|
@@ -12,6 +12,7 @@ Extracted from ClaudeRunner to follow Single Responsibility Principle.
|
|
|
12
12
|
from typing import Any, Dict, List
|
|
13
13
|
|
|
14
14
|
from claude_mpm.core.base_service import BaseService
|
|
15
|
+
from claude_mpm.core.enums import OperationResult
|
|
15
16
|
from claude_mpm.services.core.interfaces import CommandHandlerInterface
|
|
16
17
|
|
|
17
18
|
|
|
@@ -169,7 +170,7 @@ class CommandHandlerService(BaseService, CommandHandlerInterface):
|
|
|
169
170
|
if command == "test":
|
|
170
171
|
success = self._handle_test_command(args)
|
|
171
172
|
return {
|
|
172
|
-
|
|
173
|
+
OperationResult.SUCCESS.value: success,
|
|
173
174
|
"command": command,
|
|
174
175
|
"args": args,
|
|
175
176
|
"message": (
|
|
@@ -179,7 +180,7 @@ class CommandHandlerService(BaseService, CommandHandlerInterface):
|
|
|
179
180
|
if command == "agents":
|
|
180
181
|
success = self._handle_agents_command(args)
|
|
181
182
|
return {
|
|
182
|
-
|
|
183
|
+
OperationResult.SUCCESS.value: success,
|
|
183
184
|
"command": command,
|
|
184
185
|
"args": args,
|
|
185
186
|
"message": (
|
|
@@ -189,14 +190,19 @@ class CommandHandlerService(BaseService, CommandHandlerInterface):
|
|
|
189
190
|
),
|
|
190
191
|
}
|
|
191
192
|
return {
|
|
192
|
-
|
|
193
|
+
OperationResult.SUCCESS.value: False,
|
|
193
194
|
"command": command,
|
|
194
195
|
"args": args,
|
|
195
|
-
|
|
196
|
+
OperationResult.ERROR.value: f"Unknown command: {command}",
|
|
196
197
|
"available_commands": self.get_available_commands(),
|
|
197
198
|
}
|
|
198
199
|
except Exception as e:
|
|
199
|
-
return {
|
|
200
|
+
return {
|
|
201
|
+
OperationResult.SUCCESS.value: False,
|
|
202
|
+
"command": command,
|
|
203
|
+
"args": args,
|
|
204
|
+
OperationResult.ERROR.value: str(e),
|
|
205
|
+
}
|
|
200
206
|
|
|
201
207
|
def get_command_help(self, command: str) -> str:
|
|
202
208
|
"""Get help text for a specific command.
|
|
@@ -32,10 +32,10 @@ USAGE:
|
|
|
32
32
|
from abc import ABC, abstractmethod
|
|
33
33
|
from typing import Dict, List, Optional
|
|
34
34
|
|
|
35
|
+
from claude_mpm.core.enums import ServiceState
|
|
35
36
|
from claude_mpm.services.core.models.process import (
|
|
36
37
|
DeploymentState,
|
|
37
38
|
ProcessInfo,
|
|
38
|
-
ProcessStatus,
|
|
39
39
|
StartConfig,
|
|
40
40
|
)
|
|
41
41
|
|
|
@@ -102,12 +102,12 @@ class IDeploymentStateManager(ABC):
|
|
|
102
102
|
"""
|
|
103
103
|
|
|
104
104
|
@abstractmethod
|
|
105
|
-
def get_deployments_by_status(self, status:
|
|
105
|
+
def get_deployments_by_status(self, status: ServiceState) -> List[DeploymentState]:
|
|
106
106
|
"""
|
|
107
107
|
Get all deployments with a specific status.
|
|
108
108
|
|
|
109
109
|
Args:
|
|
110
|
-
status:
|
|
110
|
+
status: ServiceState to filter by
|
|
111
111
|
|
|
112
112
|
Returns:
|
|
113
113
|
List of matching DeploymentState objects
|
|
@@ -168,14 +168,14 @@ class IDeploymentStateManager(ABC):
|
|
|
168
168
|
|
|
169
169
|
@abstractmethod
|
|
170
170
|
def update_deployment_status(
|
|
171
|
-
self, deployment_id: str, status:
|
|
171
|
+
self, deployment_id: str, status: ServiceState
|
|
172
172
|
) -> bool:
|
|
173
173
|
"""
|
|
174
174
|
Update the status of a deployment.
|
|
175
175
|
|
|
176
176
|
Args:
|
|
177
177
|
deployment_id: Unique deployment identifier
|
|
178
|
-
status: New
|
|
178
|
+
status: New ServiceState
|
|
179
179
|
|
|
180
180
|
Returns:
|
|
181
181
|
True if updated, False if deployment not found
|
|
@@ -290,7 +290,7 @@ class ILocalProcessManager(ABC):
|
|
|
290
290
|
|
|
291
291
|
@abstractmethod
|
|
292
292
|
def list_processes(
|
|
293
|
-
self, status_filter: Optional[
|
|
293
|
+
self, status_filter: Optional[ServiceState] = None
|
|
294
294
|
) -> List[ProcessInfo]:
|
|
295
295
|
"""
|
|
296
296
|
List all managed processes.
|
|
@@ -24,7 +24,6 @@ from .process import (
|
|
|
24
24
|
PROTECTED_PORT_RANGES,
|
|
25
25
|
DeploymentState,
|
|
26
26
|
ProcessInfo,
|
|
27
|
-
ProcessStatus,
|
|
28
27
|
StartConfig,
|
|
29
28
|
is_port_protected,
|
|
30
29
|
)
|
|
@@ -63,7 +62,6 @@ __all__ = [ # noqa: RUF022 - Grouped by category with comments for clarity
|
|
|
63
62
|
"ValidationResult",
|
|
64
63
|
"ConfigurationPreview",
|
|
65
64
|
# Process management models
|
|
66
|
-
"ProcessStatus",
|
|
67
65
|
"DeploymentState",
|
|
68
66
|
"ProcessInfo",
|
|
69
67
|
"StartConfig",
|
|
@@ -17,6 +17,8 @@ from dataclasses import dataclass, field
|
|
|
17
17
|
from enum import Enum
|
|
18
18
|
from typing import Any, Dict, List, Optional
|
|
19
19
|
|
|
20
|
+
from ....core.enums import OperationResult, ValidationSeverity
|
|
21
|
+
|
|
20
22
|
|
|
21
23
|
class AgentSpecialization(str, Enum):
|
|
22
24
|
"""Agent specialization categories.
|
|
@@ -154,20 +156,6 @@ class AgentRecommendation:
|
|
|
154
156
|
}
|
|
155
157
|
|
|
156
158
|
|
|
157
|
-
class ConfigurationStatus(str, Enum):
|
|
158
|
-
"""Status of configuration operation.
|
|
159
|
-
|
|
160
|
-
WHY: Configuration can succeed, fail, or partially succeed. This enum
|
|
161
|
-
provides a standardized way to communicate operation outcomes.
|
|
162
|
-
"""
|
|
163
|
-
|
|
164
|
-
SUCCESS = "success"
|
|
165
|
-
PARTIAL_SUCCESS = "partial_success"
|
|
166
|
-
FAILURE = "failure"
|
|
167
|
-
VALIDATION_ERROR = "validation_error"
|
|
168
|
-
USER_CANCELLED = "user_cancelled"
|
|
169
|
-
|
|
170
|
-
|
|
171
159
|
@dataclass
|
|
172
160
|
class ConfigurationResult:
|
|
173
161
|
"""Result of automated configuration operation.
|
|
@@ -179,9 +167,17 @@ class ConfigurationResult:
|
|
|
179
167
|
DESIGN DECISION: Separates successful and failed deployments to enable
|
|
180
168
|
proper error handling. Includes validation results and user-facing
|
|
181
169
|
messages for transparency.
|
|
170
|
+
|
|
171
|
+
NOTE: Uses core OperationResult enum (consolidated from ConfigurationStatus
|
|
172
|
+
in Phase 3A Batch 25). Mappings:
|
|
173
|
+
- SUCCESS → OperationResult.SUCCESS
|
|
174
|
+
- PARTIAL_SUCCESS → OperationResult.WARNING (partial success with issues)
|
|
175
|
+
- FAILURE → OperationResult.FAILED
|
|
176
|
+
- VALIDATION_ERROR → OperationResult.ERROR
|
|
177
|
+
- USER_CANCELLED → OperationResult.CANCELLED
|
|
182
178
|
"""
|
|
183
179
|
|
|
184
|
-
status:
|
|
180
|
+
status: OperationResult
|
|
185
181
|
deployed_agents: List[str] = field(default_factory=list)
|
|
186
182
|
failed_agents: List[str] = field(default_factory=list)
|
|
187
183
|
validation_warnings: List[str] = field(default_factory=list)
|
|
@@ -193,7 +189,7 @@ class ConfigurationResult:
|
|
|
193
189
|
@property
|
|
194
190
|
def is_successful(self) -> bool:
|
|
195
191
|
"""Check if configuration was completely successful."""
|
|
196
|
-
return self.status ==
|
|
192
|
+
return self.status == OperationResult.SUCCESS
|
|
197
193
|
|
|
198
194
|
@property
|
|
199
195
|
def has_failures(self) -> bool:
|
|
@@ -223,18 +219,6 @@ class ConfigurationResult:
|
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
|
|
226
|
-
class ValidationSeverity(str, Enum):
|
|
227
|
-
"""Severity level for validation issues.
|
|
228
|
-
|
|
229
|
-
WHY: Not all validation issues are equally critical. This enum enables
|
|
230
|
-
categorization of issues by severity to support appropriate handling.
|
|
231
|
-
"""
|
|
232
|
-
|
|
233
|
-
ERROR = "error" # Blocks deployment
|
|
234
|
-
WARNING = "warning" # Should be reviewed but doesn't block
|
|
235
|
-
INFO = "info" # Informational only
|
|
236
|
-
|
|
237
|
-
|
|
238
222
|
@dataclass
|
|
239
223
|
class ValidationIssue:
|
|
240
224
|
"""Represents a validation issue.
|
|
@@ -3,56 +3,27 @@ Process Management Data Models for Claude MPM Framework
|
|
|
3
3
|
========================================================
|
|
4
4
|
|
|
5
5
|
WHY: This module defines data structures for process management operations,
|
|
6
|
-
including
|
|
6
|
+
including deployment state and runtime information.
|
|
7
7
|
|
|
8
8
|
DESIGN DECISION: Uses dataclasses for immutability and type safety. Provides
|
|
9
|
-
serialization methods for state persistence.
|
|
9
|
+
serialization methods for state persistence. Process status uses ServiceState
|
|
10
|
+
enum from core.enums (consolidated in Phase 3A Batch 24).
|
|
10
11
|
|
|
11
12
|
ARCHITECTURE:
|
|
12
|
-
- ProcessStatus: Enum of process lifecycle states
|
|
13
13
|
- DeploymentState: Complete deployment information for persistence
|
|
14
14
|
- ProcessInfo: Runtime process information
|
|
15
15
|
- StartConfig: Configuration for spawning new processes
|
|
16
|
+
|
|
17
|
+
Note: ProcessStatus enum has been consolidated into ServiceState (core.enums).
|
|
16
18
|
"""
|
|
17
19
|
|
|
18
20
|
import json
|
|
19
21
|
from dataclasses import asdict, dataclass, field
|
|
20
22
|
from datetime import datetime
|
|
21
|
-
from enum import Enum
|
|
22
23
|
from pathlib import Path
|
|
23
24
|
from typing import Any, Dict, List, Optional
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
class ProcessStatus(Enum):
|
|
27
|
-
"""
|
|
28
|
-
Process lifecycle status.
|
|
29
|
-
|
|
30
|
-
WHY: Explicit status tracking enables proper state machine management
|
|
31
|
-
and prevents invalid state transitions.
|
|
32
|
-
|
|
33
|
-
States:
|
|
34
|
-
STARTING: Process is being spawned
|
|
35
|
-
RUNNING: Process is actively running
|
|
36
|
-
STOPPING: Process is shutting down
|
|
37
|
-
STOPPED: Process has stopped cleanly
|
|
38
|
-
CRASHED: Process terminated unexpectedly
|
|
39
|
-
UNKNOWN: Process state cannot be determined
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
STARTING = "starting"
|
|
43
|
-
RUNNING = "running"
|
|
44
|
-
STOPPING = "stopping"
|
|
45
|
-
STOPPED = "stopped"
|
|
46
|
-
CRASHED = "crashed"
|
|
47
|
-
UNKNOWN = "unknown"
|
|
48
|
-
|
|
49
|
-
def is_active(self) -> bool:
|
|
50
|
-
"""Check if status represents an active process."""
|
|
51
|
-
return self in (ProcessStatus.STARTING, ProcessStatus.RUNNING)
|
|
52
|
-
|
|
53
|
-
def is_terminal(self) -> bool:
|
|
54
|
-
"""Check if status represents a terminal state."""
|
|
55
|
-
return self in (ProcessStatus.STOPPED, ProcessStatus.CRASHED)
|
|
26
|
+
from claude_mpm.core.enums import ServiceState
|
|
56
27
|
|
|
57
28
|
|
|
58
29
|
@dataclass
|
|
@@ -71,7 +42,7 @@ class DeploymentState:
|
|
|
71
42
|
environment: Environment variables (beyond inherited ones)
|
|
72
43
|
port: Primary port used by the process (if applicable)
|
|
73
44
|
started_at: Timestamp when process was started
|
|
74
|
-
status: Current
|
|
45
|
+
status: Current ServiceState (process lifecycle state)
|
|
75
46
|
metadata: Additional deployment-specific information
|
|
76
47
|
"""
|
|
77
48
|
|
|
@@ -82,7 +53,7 @@ class DeploymentState:
|
|
|
82
53
|
environment: Dict[str, str] = field(default_factory=dict)
|
|
83
54
|
port: Optional[int] = None
|
|
84
55
|
started_at: datetime = field(default_factory=datetime.now)
|
|
85
|
-
status:
|
|
56
|
+
status: ServiceState = ServiceState.STARTING
|
|
86
57
|
metadata: Dict[str, Any] = field(default_factory=dict)
|
|
87
58
|
|
|
88
59
|
def to_dict(self) -> Dict[str, Any]:
|
|
@@ -114,7 +85,14 @@ class DeploymentState:
|
|
|
114
85
|
|
|
115
86
|
# Convert status string to enum
|
|
116
87
|
if isinstance(data.get("status"), str):
|
|
117
|
-
|
|
88
|
+
status_value = data["status"]
|
|
89
|
+
# Handle legacy "crashed" status -> map to ERROR
|
|
90
|
+
if status_value == "crashed":
|
|
91
|
+
data["status"] = (
|
|
92
|
+
ServiceState.ERROR
|
|
93
|
+
) # CRASHED semantically maps to ERROR state
|
|
94
|
+
else:
|
|
95
|
+
data["status"] = ServiceState(status_value)
|
|
118
96
|
|
|
119
97
|
return cls(**data)
|
|
120
98
|
|
|
@@ -153,18 +131,18 @@ class ProcessInfo:
|
|
|
153
131
|
Attributes:
|
|
154
132
|
deployment_id: Unique deployment identifier
|
|
155
133
|
process_id: OS process ID
|
|
156
|
-
status: Current
|
|
134
|
+
status: Current ServiceState (process lifecycle state)
|
|
157
135
|
port: Port the process is using
|
|
158
136
|
uptime_seconds: How long the process has been running
|
|
159
137
|
memory_mb: Current memory usage in megabytes
|
|
160
138
|
cpu_percent: Current CPU usage percentage
|
|
161
139
|
is_responding: Whether the process responds to health checks
|
|
162
|
-
error_message: Error message if status is
|
|
140
|
+
error_message: Error message if status is ERROR (crashed)
|
|
163
141
|
"""
|
|
164
142
|
|
|
165
143
|
deployment_id: str
|
|
166
144
|
process_id: int
|
|
167
|
-
status:
|
|
145
|
+
status: ServiceState
|
|
168
146
|
port: Optional[int] = None
|
|
169
147
|
uptime_seconds: float = 0.0
|
|
170
148
|
memory_mb: float = 0.0
|
|
@@ -252,7 +230,6 @@ __all__ = [
|
|
|
252
230
|
"PROTECTED_PORT_RANGES",
|
|
253
231
|
"DeploymentState",
|
|
254
232
|
"ProcessInfo",
|
|
255
|
-
"ProcessStatus",
|
|
256
233
|
"StartConfig",
|
|
257
234
|
"is_port_protected",
|
|
258
235
|
]
|
|
@@ -13,6 +13,6 @@ DESIGN DECISIONS:
|
|
|
13
13
|
|
|
14
14
|
from .diagnostic_runner import DiagnosticRunner
|
|
15
15
|
from .doctor_reporter import DoctorReporter
|
|
16
|
-
from .models import DiagnosticResult
|
|
16
|
+
from .models import DiagnosticResult
|
|
17
17
|
|
|
18
|
-
__all__ = ["DiagnosticResult", "DiagnosticRunner", "
|
|
18
|
+
__all__ = ["DiagnosticResult", "DiagnosticRunner", "DoctorReporter"]
|
|
@@ -6,7 +6,8 @@ WHY: Verify that agents are properly deployed, up-to-date, and functioning corre
|
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from
|
|
9
|
+
from ....core.enums import OperationResult, ValidationSeverity
|
|
10
|
+
from ..models import DiagnosticResult
|
|
10
11
|
from .base_check import BaseDiagnosticCheck
|
|
11
12
|
|
|
12
13
|
|
|
@@ -64,29 +65,29 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
64
65
|
available_count = details["available_count"]
|
|
65
66
|
|
|
66
67
|
if deployed_count == 0:
|
|
67
|
-
status =
|
|
68
|
+
status = ValidationSeverity.ERROR
|
|
68
69
|
message = f"No agents deployed (0/{available_count} available)"
|
|
69
70
|
fix_command = "claude-mpm agents deploy"
|
|
70
71
|
fix_description = "Deploy all available agents"
|
|
71
72
|
elif deployed_count < available_count:
|
|
72
|
-
status =
|
|
73
|
+
status = ValidationSeverity.WARNING
|
|
73
74
|
message = f"{deployed_count}/{available_count} agents deployed"
|
|
74
75
|
fix_command = "claude-mpm agents deploy"
|
|
75
76
|
fix_description = (
|
|
76
77
|
f"Deploy remaining {available_count - deployed_count} agents"
|
|
77
78
|
)
|
|
78
|
-
elif any(r.status ==
|
|
79
|
-
status =
|
|
79
|
+
elif any(r.status == ValidationSeverity.ERROR for r in sub_results):
|
|
80
|
+
status = ValidationSeverity.ERROR
|
|
80
81
|
message = "Agents have critical issues"
|
|
81
82
|
fix_command = None
|
|
82
83
|
fix_description = None
|
|
83
|
-
elif any(r.status ==
|
|
84
|
-
status =
|
|
84
|
+
elif any(r.status == ValidationSeverity.WARNING for r in sub_results):
|
|
85
|
+
status = ValidationSeverity.WARNING
|
|
85
86
|
message = "Agents have minor issues"
|
|
86
87
|
fix_command = None
|
|
87
88
|
fix_description = None
|
|
88
89
|
else:
|
|
89
|
-
status =
|
|
90
|
+
status = OperationResult.SUCCESS
|
|
90
91
|
message = f"All {deployed_count} agents properly deployed"
|
|
91
92
|
fix_command = None
|
|
92
93
|
fix_description = None
|
|
@@ -104,7 +105,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
104
105
|
except Exception as e:
|
|
105
106
|
return DiagnosticResult(
|
|
106
107
|
category=self.category,
|
|
107
|
-
status=
|
|
108
|
+
status=ValidationSeverity.ERROR,
|
|
108
109
|
message=f"Agent check failed: {e!s}",
|
|
109
110
|
details={"error": str(e)},
|
|
110
111
|
)
|
|
@@ -127,7 +128,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
127
128
|
# Neither exists, default to user directory for error message
|
|
128
129
|
return DiagnosticResult(
|
|
129
130
|
category="Deployed Agents",
|
|
130
|
-
status=
|
|
131
|
+
status=ValidationSeverity.ERROR,
|
|
131
132
|
message="No agents directory found (checked project and user)",
|
|
132
133
|
details={
|
|
133
134
|
"project_path": str(project_agents_dir),
|
|
@@ -144,7 +145,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
144
145
|
if not agent_files:
|
|
145
146
|
return DiagnosticResult(
|
|
146
147
|
category="Deployed Agents",
|
|
147
|
-
status=
|
|
148
|
+
status=ValidationSeverity.ERROR,
|
|
148
149
|
message=f"No agents deployed in {location} directory",
|
|
149
150
|
details={"path": str(agents_dir), "location": location, "count": 0},
|
|
150
151
|
fix_command="claude-mpm agents deploy",
|
|
@@ -159,7 +160,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
159
160
|
if missing_core:
|
|
160
161
|
return DiagnosticResult(
|
|
161
162
|
category="Deployed Agents",
|
|
162
|
-
status=
|
|
163
|
+
status=ValidationSeverity.WARNING,
|
|
163
164
|
message=f"Missing core agents in {location}: {', '.join(missing_core)}",
|
|
164
165
|
details={
|
|
165
166
|
"path": str(agents_dir),
|
|
@@ -174,7 +175,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
174
175
|
|
|
175
176
|
return DiagnosticResult(
|
|
176
177
|
category="Deployed Agents",
|
|
177
|
-
status=
|
|
178
|
+
status=OperationResult.SUCCESS,
|
|
178
179
|
message=f"{len(agent_files)} agents deployed ({location} level)",
|
|
179
180
|
details={
|
|
180
181
|
"path": str(agents_dir),
|
|
@@ -205,7 +206,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
205
206
|
else:
|
|
206
207
|
return DiagnosticResult(
|
|
207
208
|
category="Agent Versions",
|
|
208
|
-
status=
|
|
209
|
+
status=OperationResult.SKIPPED,
|
|
209
210
|
message="No agents to check",
|
|
210
211
|
details={},
|
|
211
212
|
)
|
|
@@ -224,7 +225,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
224
225
|
if outdated:
|
|
225
226
|
return DiagnosticResult(
|
|
226
227
|
category="Agent Versions",
|
|
227
|
-
status=
|
|
228
|
+
status=ValidationSeverity.WARNING,
|
|
228
229
|
message=f"{len(outdated)} agent(s) outdated",
|
|
229
230
|
details={"outdated": outdated, "checked": checked},
|
|
230
231
|
fix_command="claude-mpm agents update",
|
|
@@ -234,14 +235,14 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
234
235
|
if checked == 0:
|
|
235
236
|
return DiagnosticResult(
|
|
236
237
|
category="Agent Versions",
|
|
237
|
-
status=
|
|
238
|
+
status=ValidationSeverity.WARNING,
|
|
238
239
|
message="No agents to check",
|
|
239
240
|
details={"checked": 0},
|
|
240
241
|
)
|
|
241
242
|
|
|
242
243
|
return DiagnosticResult(
|
|
243
244
|
category="Agent Versions",
|
|
244
|
-
status=
|
|
245
|
+
status=OperationResult.SUCCESS,
|
|
245
246
|
message=f"All {checked} agents up-to-date",
|
|
246
247
|
details={"checked": checked},
|
|
247
248
|
)
|
|
@@ -249,7 +250,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
249
250
|
except Exception as e:
|
|
250
251
|
return DiagnosticResult(
|
|
251
252
|
category="Agent Versions",
|
|
252
|
-
status=
|
|
253
|
+
status=ValidationSeverity.WARNING,
|
|
253
254
|
message=f"Could not check versions: {e!s}",
|
|
254
255
|
details={"error": str(e)},
|
|
255
256
|
)
|
|
@@ -273,7 +274,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
273
274
|
else:
|
|
274
275
|
return DiagnosticResult(
|
|
275
276
|
category="Agent Validation",
|
|
276
|
-
status=
|
|
277
|
+
status=OperationResult.SKIPPED,
|
|
277
278
|
message="No agents to validate",
|
|
278
279
|
details={},
|
|
279
280
|
)
|
|
@@ -301,14 +302,14 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
301
302
|
if invalid:
|
|
302
303
|
return DiagnosticResult(
|
|
303
304
|
category="Agent Validation",
|
|
304
|
-
status=
|
|
305
|
+
status=ValidationSeverity.WARNING,
|
|
305
306
|
message=f"{len(invalid)} validation issue(s)",
|
|
306
307
|
details={"issues": invalid, "validated": validated},
|
|
307
308
|
)
|
|
308
309
|
|
|
309
310
|
return DiagnosticResult(
|
|
310
311
|
category="Agent Validation",
|
|
311
|
-
status=
|
|
312
|
+
status=OperationResult.SUCCESS,
|
|
312
313
|
message=f"All {validated} agents valid",
|
|
313
314
|
details={"validated": validated},
|
|
314
315
|
)
|
|
@@ -316,7 +317,7 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
316
317
|
except Exception as e:
|
|
317
318
|
return DiagnosticResult(
|
|
318
319
|
category="Agent Validation",
|
|
319
|
-
status=
|
|
320
|
+
status=ValidationSeverity.WARNING,
|
|
320
321
|
message=f"Validation failed: {e!s}",
|
|
321
322
|
details={"error": str(e)},
|
|
322
323
|
)
|
|
@@ -358,14 +359,14 @@ class AgentCheck(BaseDiagnosticCheck):
|
|
|
358
359
|
if issues:
|
|
359
360
|
return DiagnosticResult(
|
|
360
361
|
category="Common Issues",
|
|
361
|
-
status=
|
|
362
|
+
status=ValidationSeverity.WARNING,
|
|
362
363
|
message=f"{len(issues)} issue(s) found",
|
|
363
364
|
details={"issues": issues},
|
|
364
365
|
)
|
|
365
366
|
|
|
366
367
|
return DiagnosticResult(
|
|
367
368
|
category="Common Issues",
|
|
368
|
-
status=
|
|
369
|
+
status=OperationResult.SUCCESS,
|
|
369
370
|
message="No common issues detected",
|
|
370
371
|
details={},
|
|
371
372
|
)
|