claude-mpm 4.14.9__py3-none-any.whl → 4.15.0__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/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/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.0.dist-info}/METADATA +1 -1
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.0.dist-info}/RECORD +43 -43
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.0.dist-info}/WHEEL +0 -0
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.14.9.dist-info → claude_mpm-4.15.0.dist-info}/top_level.txt +0 -0
claude_mpm/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
4.
|
|
1
|
+
4.15.0
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
],
|
|
16
16
|
"author": "Claude MPM Team",
|
|
17
17
|
"created_at": "2025-08-15T00:00:00.000000Z",
|
|
18
|
-
"updated_at": "2025-10-
|
|
18
|
+
"updated_at": "2025-10-26T00:00:00.000000Z",
|
|
19
19
|
"color": "purple"
|
|
20
20
|
},
|
|
21
21
|
"capabilities": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
]
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
|
-
"instructions": "# Project Organizer Agent\n\n**Inherits from**: BASE_OPS_AGENT.md\n**Focus**: Intelligent project structure management and organization\n\n## Core Expertise\n\nLearn existing patterns, enforce consistent structure, suggest optimal file placement, and maintain organization documentation.\n\n## Organization Standard Management\n\n**CRITICAL**: Always ensure organization standards are documented and accessible.\n\n### Standard Documentation Protocol\n\n1. **Verify Organization Standard Exists**\n - Check if `docs/reference/PROJECT_ORGANIZATION.md` exists\n - If missing, create it with current organization rules\n - If exists, verify it's up to date with current patterns\n\n2. **Update CLAUDE.md Linking**\n - Verify CLAUDE.md links to PROJECT_ORGANIZATION.md\n - Add link in \"Project Structure Requirements\" section if missing\n - Format: `See [docs/reference/PROJECT_ORGANIZATION.md](docs/reference/PROJECT_ORGANIZATION.md)`\n\n3. **Keep Standard Current**\n - Update standard when new patterns are established\n - Document framework-specific rules as discovered\n - Add version and timestamp to changes\n\n### Organization Standard Location\n- **Primary**: `docs/reference/PROJECT_ORGANIZATION.md`\n- **Reference from**: CLAUDE.md, /mpm-organize command docs\n- **Format**: Markdown with comprehensive rules, examples, and tables\n\n## Pattern Detection Protocol\n\n### 1. Structure Analysis\n- Scan directory hierarchy and patterns\n- Identify naming conventions (camelCase, kebab-case, snake_case)\n- Map file type locations\n- Detect framework-specific conventions\n- Identify organization type (feature/type/domain-based)\n\n### 2. Pattern Categories\n- **By Feature**: `/features/auth/`, `/features/dashboard/`\n- **By Type**: `/controllers/`, `/models/`, `/views/`\n- **By Domain**: `/user/`, `/product/`, `/order/`\n- **Mixed**: Combination approaches\n- **Test Organization**: Colocated vs separate\n\n## File Placement Logic\n\n### Decision Process\n1. Consult PROJECT_ORGANIZATION.md for official rules\n2. Analyze file purpose and type\n3. Apply learned project patterns\n4. Consider framework requirements\n5. Provide clear reasoning\n\n### Framework Handling\n- **Next.js**: Respect pages/app, public, API routes\n- **Django**: Maintain app structure, migrations, templates\n- **Rails**: Follow MVC, assets pipeline, migrations\n- **React**: Component organization, hooks, utils\n\n## Organization Enforcement\n\n### Validation Steps\n1. Check files against PROJECT_ORGANIZATION.md rules\n2. Flag convention violations\n3. Generate safe move operations\n4. Use `git mv` for version control\n5. Update import paths\n6. Update organization standard if needed\n\n### Batch Reorganization\n```bash\n# Analyze violations\nfind . -type f | while read file; do\n expected=$(determine_location \"$file\")\n [ \"$file\" != \"$expected\" ] && echo \"Move: $file -> $expected\"\ndone\n\n# Execute with backup\ntar -czf backup_$(date +%Y%m%d).tar.gz .\n# Run moves with git mv\n```\n\n## Documentation Maintenance\n\n### PROJECT_ORGANIZATION.md Requirements\n- Comprehensive directory structure\n- File placement rules by type and purpose\n- Naming conventions for all file types\n- Framework-specific organization rules\n- Migration procedures\n- Version history\n\n### CLAUDE.md Updates\n- Keep organization quick reference current\n- Link to PROJECT_ORGANIZATION.md prominently\n- Update when major structure changes occur\n\n## Organizer-Specific Todo Patterns\n\n**Analysis**:\n- `[Organizer] Detect project organization patterns`\n- `[Organizer] Identify framework conventions`\n- `[Organizer] Verify organization standard exists`\n\n**Placement**:\n- `[Organizer] Suggest location for API service`\n- `[Organizer] Plan feature module structure`\n\n**Enforcement**:\n- `[Organizer] Validate file organization`\n- `[Organizer] Generate reorganization plan`\n\n**Documentation**:\n- `[Organizer] Update PROJECT_ORGANIZATION.md`\n- `[Organizer] Update CLAUDE.md organization links`\n- `[Organizer] Document naming conventions`\n\n## Safety Measures\n\n- Create backups before reorganization\n- Preserve git history with git mv\n- Update imports after moves\n- Test build after changes\n- Respect .gitignore patterns\n- Document all organization changes\n\n## Success Criteria\n\n- Accurately detect patterns (90%+)\n- Correctly suggest locations\n- Maintain up-to-date documentation (PROJECT_ORGANIZATION.md)\n- Ensure CLAUDE.md links are current\n- Adapt to user corrections\n- Provide clear reasoning",
|
|
50
|
+
"instructions": "# Project Organizer Agent\n\n**Inherits from**: BASE_OPS_AGENT.md\n**Focus**: Intelligent project structure management and organization\n\n## Core Expertise\n\nLearn existing patterns, enforce consistent structure, suggest optimal file placement, and maintain organization documentation.\n\n## Organization Standard Management\n\n**CRITICAL**: Always ensure organization standards are documented and accessible.\n\n### Standard Documentation Protocol\n\n1. **Verify Organization Standard Exists**\n - Check if `docs/reference/PROJECT_ORGANIZATION.md` exists\n - If missing, create it with current organization rules\n - If exists, verify it's up to date with current patterns\n\n2. **Update CLAUDE.md Linking**\n - Verify CLAUDE.md links to PROJECT_ORGANIZATION.md\n - Add link in \"Project Structure Requirements\" section if missing\n - Format: `See [docs/reference/PROJECT_ORGANIZATION.md](docs/reference/PROJECT_ORGANIZATION.md)`\n\n3. **Keep Standard Current**\n - Update standard when new patterns are established\n - Document framework-specific rules as discovered\n - Add version and timestamp to changes\n\n### Organization Standard Location\n- **Primary**: `docs/reference/PROJECT_ORGANIZATION.md`\n- **Reference from**: CLAUDE.md, /mpm-organize command docs\n- **Format**: Markdown with comprehensive rules, examples, and tables\n\n## Project-Specific Organization Standards\n\n**PRIORITY**: Always check for project-specific organization standards before applying defaults.\n\n### Standard Detection and Application Protocol\n\n1. **Check for PROJECT_ORGANIZATION.md** (in order of precedence):\n - First: Project root (`./PROJECT_ORGANIZATION.md`)\n - Second: Documentation directory (`docs/reference/PROJECT_ORGANIZATION.md`)\n - Third: Docs root (`docs/PROJECT_ORGANIZATION.md`)\n\n2. **If PROJECT_ORGANIZATION.md exists**:\n - Read and parse the organizational standards defined within\n - Apply project-specific conventions for:\n * Directory structure and naming patterns\n * File organization principles (feature/type/domain-based)\n * Documentation placement rules\n * Code organization guidelines\n * Framework-specific organizational rules\n * Naming conventions (camelCase, kebab-case, snake_case, etc.)\n * Test organization (colocated vs separate)\n * Any custom organizational policies\n - Use these standards as the PRIMARY guide for all organization decisions\n - Project-specific standards ALWAYS take precedence over default patterns\n - When making organization decisions, explicitly reference which rule from PROJECT_ORGANIZATION.md is being applied\n\n3. **If PROJECT_ORGANIZATION.md does not exist**:\n - Fall back to pattern detection and framework defaults (see below)\n - Suggest creating PROJECT_ORGANIZATION.md to document discovered patterns\n - Use detected patterns for current organization decisions\n\n## Pattern Detection Protocol\n\n### 1. Structure Analysis\n- Scan directory hierarchy and patterns\n- Identify naming conventions (camelCase, kebab-case, snake_case)\n- Map file type locations\n- Detect framework-specific conventions\n- Identify organization type (feature/type/domain-based)\n\n### 2. Pattern Categories\n- **By Feature**: `/features/auth/`, `/features/dashboard/`\n- **By Type**: `/controllers/`, `/models/`, `/views/`\n- **By Domain**: `/user/`, `/product/`, `/order/`\n- **Mixed**: Combination approaches\n- **Test Organization**: Colocated vs separate\n\n## File Placement Logic\n\n### Decision Process\n1. Consult PROJECT_ORGANIZATION.md for official rules\n2. Analyze file purpose and type\n3. Apply learned project patterns\n4. Consider framework requirements\n5. Provide clear reasoning\n\n### Framework Handling\n- **Next.js**: Respect pages/app, public, API routes\n- **Django**: Maintain app structure, migrations, templates\n- **Rails**: Follow MVC, assets pipeline, migrations\n- **React**: Component organization, hooks, utils\n\n## Organization Enforcement\n\n### Validation Steps\n1. Check files against PROJECT_ORGANIZATION.md rules\n2. Flag convention violations\n3. Generate safe move operations\n4. Use `git mv` for version control\n5. Update import paths\n6. Update organization standard if needed\n\n### Batch Reorganization\n```bash\n# Analyze violations\nfind . -type f | while read file; do\n expected=$(determine_location \"$file\")\n [ \"$file\" != \"$expected\" ] && echo \"Move: $file -> $expected\"\ndone\n\n# Execute with backup\ntar -czf backup_$(date +%Y%m%d).tar.gz .\n# Run moves with git mv\n```\n\n## Documentation Maintenance\n\n### PROJECT_ORGANIZATION.md Requirements\n- Comprehensive directory structure\n- File placement rules by type and purpose\n- Naming conventions for all file types\n- Framework-specific organization rules\n- Migration procedures\n- Version history\n\n### CLAUDE.md Updates\n- Keep organization quick reference current\n- Link to PROJECT_ORGANIZATION.md prominently\n- Update when major structure changes occur\n\n## Organizer-Specific Todo Patterns\n\n**Analysis**:\n- `[Organizer] Detect project organization patterns`\n- `[Organizer] Identify framework conventions`\n- `[Organizer] Verify organization standard exists`\n\n**Placement**:\n- `[Organizer] Suggest location for API service`\n- `[Organizer] Plan feature module structure`\n\n**Enforcement**:\n- `[Organizer] Validate file organization`\n- `[Organizer] Generate reorganization plan`\n\n**Documentation**:\n- `[Organizer] Update PROJECT_ORGANIZATION.md`\n- `[Organizer] Update CLAUDE.md organization links`\n- `[Organizer] Document naming conventions`\n\n## Safety Measures\n\n- Create backups before reorganization\n- Preserve git history with git mv\n- Update imports after moves\n- Test build after changes\n- Respect .gitignore patterns\n- Document all organization changes\n\n## Success Criteria\n\n- Accurately detect patterns (90%+)\n- Correctly suggest locations\n- Maintain up-to-date documentation (PROJECT_ORGANIZATION.md)\n- Ensure CLAUDE.md links are current\n- Adapt to user corrections\n- Provide clear reasoning",
|
|
51
51
|
"knowledge": {
|
|
52
52
|
"domain_expertise": [
|
|
53
53
|
"Project structure patterns",
|
|
@@ -130,4 +130,4 @@
|
|
|
130
130
|
"success_rate": 0.9
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
}
|
|
133
|
+
}
|
|
@@ -26,12 +26,10 @@ try:
|
|
|
26
26
|
except ImportError:
|
|
27
27
|
RICH_AVAILABLE = False
|
|
28
28
|
|
|
29
|
+
from ...core.enums import OperationResult
|
|
29
30
|
from ...services.agents.auto_config_manager import AutoConfigManagerService
|
|
30
31
|
from ...services.agents.observers import NullObserver
|
|
31
|
-
from ...services.core.models.agent_config import
|
|
32
|
-
ConfigurationResult,
|
|
33
|
-
ConfigurationStatus,
|
|
34
|
-
)
|
|
32
|
+
from ...services.core.models.agent_config import ConfigurationResult
|
|
35
33
|
from ..shared import BaseCommand, CommandResult
|
|
36
34
|
|
|
37
35
|
|
|
@@ -419,7 +417,7 @@ class AutoConfigureCommand(BaseCommand):
|
|
|
419
417
|
return self._display_result_plain(result)
|
|
420
418
|
|
|
421
419
|
# Display summary
|
|
422
|
-
if result.status ==
|
|
420
|
+
if result.status == OperationResult.SUCCESS:
|
|
423
421
|
panel = Panel(
|
|
424
422
|
f"✅ Auto-configuration completed successfully!\n\n"
|
|
425
423
|
f"Deployed {len(result.deployed_agents)} agent(s)",
|
|
@@ -436,7 +434,7 @@ class AutoConfigureCommand(BaseCommand):
|
|
|
436
434
|
|
|
437
435
|
return CommandResult.success_result()
|
|
438
436
|
|
|
439
|
-
if result.status ==
|
|
437
|
+
if result.status == OperationResult.WARNING:
|
|
440
438
|
panel = Panel(
|
|
441
439
|
f"⚠️ Auto-configuration partially completed\n\n"
|
|
442
440
|
f"Deployed: {len(result.deployed_agents)}\n"
|
|
@@ -465,7 +463,7 @@ class AutoConfigureCommand(BaseCommand):
|
|
|
465
463
|
|
|
466
464
|
def _display_result_plain(self, result: ConfigurationResult) -> CommandResult:
|
|
467
465
|
"""Display result in plain text (fallback)."""
|
|
468
|
-
if result.status ==
|
|
466
|
+
if result.status == OperationResult.SUCCESS:
|
|
469
467
|
print("\n✅ Auto-configuration completed successfully!")
|
|
470
468
|
print(f"Deployed {len(result.deployed_agents)} agent(s)")
|
|
471
469
|
|
|
@@ -476,7 +474,7 @@ class AutoConfigureCommand(BaseCommand):
|
|
|
476
474
|
|
|
477
475
|
return CommandResult.success_result()
|
|
478
476
|
|
|
479
|
-
if result.status ==
|
|
477
|
+
if result.status == OperationResult.WARNING:
|
|
480
478
|
print("\n⚠️ Auto-configuration partially completed")
|
|
481
479
|
print(f"Deployed: {len(result.deployed_agents)}")
|
|
482
480
|
print(f"Failed: {len(result.failed_agents)}")
|
|
@@ -565,7 +563,7 @@ class AutoConfigureCommand(BaseCommand):
|
|
|
565
563
|
|
|
566
564
|
print(json.dumps(output, indent=2))
|
|
567
565
|
|
|
568
|
-
if result.status ==
|
|
566
|
+
if result.status == OperationResult.SUCCESS:
|
|
569
567
|
return CommandResult.success_result(data=output)
|
|
570
568
|
return CommandResult.error_result(
|
|
571
569
|
"Configuration failed or partial", exit_code=1, data=output
|
|
@@ -23,8 +23,9 @@ from rich.panel import Panel
|
|
|
23
23
|
from rich.table import Table
|
|
24
24
|
from rich.text import Text
|
|
25
25
|
|
|
26
|
+
from claude_mpm.core.enums import ServiceState
|
|
27
|
+
|
|
26
28
|
from ...services.local_ops import (
|
|
27
|
-
ProcessStatus,
|
|
28
29
|
StartConfig,
|
|
29
30
|
UnifiedLocalOpsManager,
|
|
30
31
|
)
|
|
@@ -298,7 +299,7 @@ class LocalDeployCommand(BaseCommand):
|
|
|
298
299
|
try:
|
|
299
300
|
status_filter_str = getattr(args, "status", None)
|
|
300
301
|
status_filter = (
|
|
301
|
-
|
|
302
|
+
ServiceState(status_filter_str) if status_filter_str else None
|
|
302
303
|
)
|
|
303
304
|
|
|
304
305
|
deployments = self.manager.list_deployments(status_filter=status_filter)
|
|
@@ -157,7 +157,7 @@ class MPMInitCommand:
|
|
|
157
157
|
pre_check_result = self._run_pre_initialization_checks(
|
|
158
158
|
organize_files, skip_archive, has_existing
|
|
159
159
|
)
|
|
160
|
-
if pre_check_result.get("status") ==
|
|
160
|
+
if pre_check_result.get("status") == OperationResult.ERROR:
|
|
161
161
|
return pre_check_result
|
|
162
162
|
|
|
163
163
|
# Build the delegation prompt
|
|
@@ -200,7 +200,7 @@ class MPMInitCommand:
|
|
|
200
200
|
progress.update(task, description=complete_desc)
|
|
201
201
|
|
|
202
202
|
# Post-processing for update mode
|
|
203
|
-
if update_mode and result.get("status") ==
|
|
203
|
+
if update_mode and result.get("status") == OperationResult.SUCCESS:
|
|
204
204
|
self._handle_update_post_processing()
|
|
205
205
|
|
|
206
206
|
return result
|
|
@@ -1685,7 +1685,7 @@ Keep it concise (<1000 words) but actionable.
|
|
|
1685
1685
|
|
|
1686
1686
|
def _display_results(self, result: Dict, verbose: bool):
|
|
1687
1687
|
"""Display initialization results."""
|
|
1688
|
-
if result["status"] ==
|
|
1688
|
+
if result["status"] == OperationResult.SUCCESS:
|
|
1689
1689
|
console.print("\n[green]✅ Project Initialization Complete![/green]\n")
|
|
1690
1690
|
|
|
1691
1691
|
# Display files created
|
|
@@ -1885,7 +1885,7 @@ def mpm_init(
|
|
|
1885
1885
|
)
|
|
1886
1886
|
|
|
1887
1887
|
# Exit with appropriate code
|
|
1888
|
-
if result["status"] ==
|
|
1888
|
+
if result["status"] == OperationResult.SUCCESS:
|
|
1889
1889
|
sys.exit(0)
|
|
1890
1890
|
else:
|
|
1891
1891
|
sys.exit(1)
|
|
@@ -8,6 +8,8 @@ from pathlib import Path
|
|
|
8
8
|
|
|
9
9
|
from rich.console import Console
|
|
10
10
|
|
|
11
|
+
from claude_mpm.core.enums import OperationResult
|
|
12
|
+
|
|
11
13
|
console = Console()
|
|
12
14
|
|
|
13
15
|
|
|
@@ -51,7 +53,10 @@ def manage_mpm_init(args):
|
|
|
51
53
|
)
|
|
52
54
|
|
|
53
55
|
# Return appropriate exit code
|
|
54
|
-
if result.get("status") in (
|
|
56
|
+
if result.get("status") in (
|
|
57
|
+
OperationResult.SUCCESS,
|
|
58
|
+
OperationResult.CONTEXT_READY,
|
|
59
|
+
):
|
|
55
60
|
return 0
|
|
56
61
|
return 1
|
|
57
62
|
|
|
@@ -102,9 +107,9 @@ def manage_mpm_init(args):
|
|
|
102
107
|
result = command.initialize_project(**init_params)
|
|
103
108
|
|
|
104
109
|
# Return appropriate exit code
|
|
105
|
-
if result.get("status") ==
|
|
110
|
+
if result.get("status") == OperationResult.SUCCESS:
|
|
106
111
|
return 0
|
|
107
|
-
if result.get("status") ==
|
|
112
|
+
if result.get("status") == OperationResult.CANCELLED:
|
|
108
113
|
return 130 # User cancelled
|
|
109
114
|
return 1 # Error
|
|
110
115
|
|
claude_mpm/core/base_service.py
CHANGED
|
@@ -31,6 +31,7 @@ from pathlib import Path
|
|
|
31
31
|
from typing import Any, Dict, List, Optional
|
|
32
32
|
|
|
33
33
|
from .config import Config
|
|
34
|
+
from .enums import HealthStatus
|
|
34
35
|
from .mixins import LoggerMixin
|
|
35
36
|
|
|
36
37
|
|
|
@@ -38,7 +39,7 @@ from .mixins import LoggerMixin
|
|
|
38
39
|
class ServiceHealth:
|
|
39
40
|
"""Service health status information."""
|
|
40
41
|
|
|
41
|
-
status:
|
|
42
|
+
status: HealthStatus # Type-safe health status using enum
|
|
42
43
|
message: str
|
|
43
44
|
timestamp: str
|
|
44
45
|
metrics: Dict[str, Any] = field(default_factory=dict)
|
|
@@ -142,7 +143,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
142
143
|
|
|
143
144
|
# Health and metrics
|
|
144
145
|
self._health = ServiceHealth(
|
|
145
|
-
status=
|
|
146
|
+
status=HealthStatus.UNKNOWN,
|
|
146
147
|
message="Service not started",
|
|
147
148
|
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
148
149
|
)
|
|
@@ -235,7 +236,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
235
236
|
except Exception as e:
|
|
236
237
|
self.logger.error(f"Failed to start service {self.name}: {e}")
|
|
237
238
|
self._health = ServiceHealth(
|
|
238
|
-
status=
|
|
239
|
+
status=HealthStatus.UNHEALTHY,
|
|
239
240
|
message=f"Startup failed: {e!s}",
|
|
240
241
|
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
241
242
|
checks={"startup": False},
|
|
@@ -272,7 +273,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
272
273
|
|
|
273
274
|
# Update health status
|
|
274
275
|
self._health = ServiceHealth(
|
|
275
|
-
status=
|
|
276
|
+
status=HealthStatus.HEALTHY,
|
|
276
277
|
message="Service started successfully",
|
|
277
278
|
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
278
279
|
checks={"startup": True},
|
|
@@ -336,7 +337,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
336
337
|
|
|
337
338
|
# Update health status
|
|
338
339
|
self._health = ServiceHealth(
|
|
339
|
-
status=
|
|
340
|
+
status=HealthStatus.UNKNOWN,
|
|
340
341
|
message="Service stopped",
|
|
341
342
|
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
342
343
|
checks={"running": False},
|
|
@@ -372,16 +373,16 @@ class BaseService(LoggerMixin, ABC):
|
|
|
372
373
|
|
|
373
374
|
# Determine overall status
|
|
374
375
|
if not checks["running"]:
|
|
375
|
-
status =
|
|
376
|
+
status = HealthStatus.UNHEALTHY
|
|
376
377
|
message = "Service is not running"
|
|
377
378
|
elif all(checks.values()):
|
|
378
|
-
status =
|
|
379
|
+
status = HealthStatus.HEALTHY
|
|
379
380
|
message = "All health checks passed"
|
|
380
381
|
elif any(checks.values()):
|
|
381
|
-
status =
|
|
382
|
+
status = HealthStatus.DEGRADED
|
|
382
383
|
message = "Some health checks failed"
|
|
383
384
|
else:
|
|
384
|
-
status =
|
|
385
|
+
status = HealthStatus.UNHEALTHY
|
|
385
386
|
message = "Multiple health checks failed"
|
|
386
387
|
|
|
387
388
|
# Update health status
|
|
@@ -402,7 +403,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
402
403
|
except Exception as e:
|
|
403
404
|
self.logger.error(f"Health check failed for {self.name}: {e}")
|
|
404
405
|
self._health = ServiceHealth(
|
|
405
|
-
status=
|
|
406
|
+
status=HealthStatus.UNHEALTHY,
|
|
406
407
|
message=f"Health check error: {e!s}",
|
|
407
408
|
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
408
409
|
checks={"health_check_error": True},
|
|
@@ -593,7 +594,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
593
594
|
)
|
|
594
595
|
else:
|
|
595
596
|
return ServiceHealth(
|
|
596
|
-
status=
|
|
597
|
+
status=HealthStatus.DEGRADED,
|
|
597
598
|
message="Service circuit breaker is open",
|
|
598
599
|
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
599
600
|
checks={"circuit_breaker": False},
|
|
@@ -604,7 +605,7 @@ class BaseService(LoggerMixin, ABC):
|
|
|
604
605
|
health = await self.health_check()
|
|
605
606
|
|
|
606
607
|
# Update circuit breaker
|
|
607
|
-
if health.status in
|
|
608
|
+
if health.status in (HealthStatus.HEALTHY, HealthStatus.DEGRADED):
|
|
608
609
|
self._record_circuit_success()
|
|
609
610
|
else:
|
|
610
611
|
self._record_circuit_failure()
|
claude_mpm/core/enums.py
CHANGED
|
@@ -70,6 +70,9 @@ class OperationResult(StrEnum):
|
|
|
70
70
|
PARTIAL = "partial"
|
|
71
71
|
"""Operation completed partially."""
|
|
72
72
|
|
|
73
|
+
WARNING = "warning"
|
|
74
|
+
"""Operation completed with warnings (partial success with issues)."""
|
|
75
|
+
|
|
73
76
|
ROLLBACK = "rollback"
|
|
74
77
|
"""Operation rolled back due to failure or cancellation."""
|
|
75
78
|
|
|
@@ -121,12 +124,26 @@ class ServiceState(StrEnum):
|
|
|
121
124
|
Service lifecycle states for all Claude MPM services.
|
|
122
125
|
|
|
123
126
|
Replaces 150+ occurrences of service state strings.
|
|
124
|
-
Used in: Hook services, MCP servers, monitoring, health checks.
|
|
127
|
+
Used in: Hook services, MCP servers, monitoring, health checks, process management.
|
|
125
128
|
|
|
126
129
|
Migration Priority: HIGH (Week 1)
|
|
127
130
|
Coverage: ~7% of all magic strings
|
|
131
|
+
|
|
132
|
+
Notes:
|
|
133
|
+
- Consolidated with ProcessStatus enum (Phase 3A Batch 24)
|
|
134
|
+
- Process states are semantically equivalent to service states
|
|
135
|
+
- CRASHED processes map to ERROR state
|
|
128
136
|
"""
|
|
129
137
|
|
|
138
|
+
UNINITIALIZED = "uninitialized"
|
|
139
|
+
"""Service has not been initialized yet."""
|
|
140
|
+
|
|
141
|
+
INITIALIZING = "initializing"
|
|
142
|
+
"""Service is in the process of initializing."""
|
|
143
|
+
|
|
144
|
+
INITIALIZED = "initialized"
|
|
145
|
+
"""Service has been initialized but not started."""
|
|
146
|
+
|
|
130
147
|
STOPPED = "stopped"
|
|
131
148
|
"""Service is completely stopped."""
|
|
132
149
|
|
|
@@ -154,6 +171,24 @@ class ServiceState(StrEnum):
|
|
|
154
171
|
IDLE = "idle"
|
|
155
172
|
"""Service is running but not actively processing."""
|
|
156
173
|
|
|
174
|
+
def is_active(self) -> bool:
|
|
175
|
+
"""
|
|
176
|
+
Check if state represents an active service/process.
|
|
177
|
+
|
|
178
|
+
Returns:
|
|
179
|
+
True if state is STARTING or RUNNING
|
|
180
|
+
"""
|
|
181
|
+
return self in (ServiceState.STARTING, ServiceState.RUNNING)
|
|
182
|
+
|
|
183
|
+
def is_terminal(self) -> bool:
|
|
184
|
+
"""
|
|
185
|
+
Check if state represents a terminal/stopped state.
|
|
186
|
+
|
|
187
|
+
Returns:
|
|
188
|
+
True if state is STOPPED or ERROR
|
|
189
|
+
"""
|
|
190
|
+
return self in (ServiceState.STOPPED, ServiceState.ERROR)
|
|
191
|
+
|
|
157
192
|
|
|
158
193
|
class ValidationSeverity(StrEnum):
|
|
159
194
|
"""
|
|
@@ -23,15 +23,14 @@ from typing import Any, Dict, List, Optional
|
|
|
23
23
|
import yaml
|
|
24
24
|
|
|
25
25
|
from ...core.base_service import BaseService
|
|
26
|
+
from ...core.enums import OperationResult, ValidationSeverity
|
|
26
27
|
from ..core.interfaces.agent import IAgentRegistry, IAutoConfigManager
|
|
27
28
|
from ..core.models.agent_config import (
|
|
28
29
|
AgentRecommendation,
|
|
29
30
|
ConfigurationPreview,
|
|
30
31
|
ConfigurationResult,
|
|
31
|
-
ConfigurationStatus,
|
|
32
32
|
ValidationIssue,
|
|
33
33
|
ValidationResult,
|
|
34
|
-
ValidationSeverity,
|
|
35
34
|
)
|
|
36
35
|
from ..core.models.toolchain import ToolchainAnalysis
|
|
37
36
|
from .observers import IDeploymentObserver, NullObserver
|
|
@@ -216,7 +215,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
216
215
|
|
|
217
216
|
if not recommendations:
|
|
218
217
|
return ConfigurationResult(
|
|
219
|
-
status=
|
|
218
|
+
status=OperationResult.SUCCESS,
|
|
220
219
|
message="No agents recommended for this project configuration",
|
|
221
220
|
recommendations=recommendations,
|
|
222
221
|
metadata={
|
|
@@ -241,7 +240,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
241
240
|
f"Validation failed with {validation_result.error_count} errors"
|
|
242
241
|
)
|
|
243
242
|
return ConfigurationResult(
|
|
244
|
-
status=
|
|
243
|
+
status=OperationResult.ERROR,
|
|
245
244
|
validation_errors=[
|
|
246
245
|
issue.message for issue in validation_result.errors
|
|
247
246
|
],
|
|
@@ -260,7 +259,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
260
259
|
if dry_run:
|
|
261
260
|
self.logger.info("Dry-run mode: skipping deployment")
|
|
262
261
|
return ConfigurationResult(
|
|
263
|
-
status=
|
|
262
|
+
status=OperationResult.SUCCESS,
|
|
264
263
|
validation_warnings=[
|
|
265
264
|
issue.message for issue in validation_result.warnings
|
|
266
265
|
],
|
|
@@ -280,7 +279,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
280
279
|
if not confirmed:
|
|
281
280
|
self.logger.info("User cancelled auto-configuration")
|
|
282
281
|
return ConfigurationResult(
|
|
283
|
-
status=
|
|
282
|
+
status=OperationResult.CANCELLED,
|
|
284
283
|
recommendations=recommendations,
|
|
285
284
|
message="Auto-configuration cancelled by user",
|
|
286
285
|
metadata={
|
|
@@ -318,9 +317,9 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
318
317
|
|
|
319
318
|
return ConfigurationResult(
|
|
320
319
|
status=(
|
|
321
|
-
|
|
320
|
+
OperationResult.WARNING
|
|
322
321
|
if deployed_agents
|
|
323
|
-
else
|
|
322
|
+
else OperationResult.FAILED
|
|
324
323
|
),
|
|
325
324
|
deployed_agents=deployed_agents,
|
|
326
325
|
failed_agents=failed_agents,
|
|
@@ -347,7 +346,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
347
346
|
)
|
|
348
347
|
|
|
349
348
|
return ConfigurationResult(
|
|
350
|
-
status=
|
|
349
|
+
status=OperationResult.SUCCESS,
|
|
351
350
|
deployed_agents=deployed_agents,
|
|
352
351
|
validation_warnings=[
|
|
353
352
|
issue.message for issue in validation_result.warnings
|
|
@@ -365,7 +364,7 @@ class AutoConfigManagerService(BaseService, IAutoConfigManager):
|
|
|
365
364
|
observer.on_error("auto-configuration", str(e), e)
|
|
366
365
|
|
|
367
366
|
return ConfigurationResult(
|
|
368
|
-
status=
|
|
367
|
+
status=OperationResult.FAILED,
|
|
369
368
|
message=f"Auto-configuration failed: {e}",
|
|
370
369
|
metadata={
|
|
371
370
|
"duration_ms": (time.time() - start_time) * 1000,
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
import time
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
|
+
from claude_mpm.core.enums import OperationResult
|
|
6
7
|
from claude_mpm.services.agents.deployment.processors import (
|
|
7
8
|
AgentDeploymentContext,
|
|
8
9
|
AgentDeploymentResult,
|
|
9
10
|
AgentProcessor,
|
|
10
11
|
)
|
|
11
12
|
|
|
12
|
-
from .base_step import BaseDeploymentStep, StepResult
|
|
13
|
+
from .base_step import BaseDeploymentStep, StepResult
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
class AgentProcessingStep(BaseDeploymentStep):
|
|
@@ -37,7 +38,7 @@ class AgentProcessingStep(BaseDeploymentStep):
|
|
|
37
38
|
if not context.template_files:
|
|
38
39
|
self.logger.warning("No template files to process")
|
|
39
40
|
return StepResult(
|
|
40
|
-
status=
|
|
41
|
+
status=OperationResult.SKIPPED,
|
|
41
42
|
message="No template files found to process",
|
|
42
43
|
execution_time=time.time() - start_time,
|
|
43
44
|
)
|
|
@@ -103,13 +104,13 @@ class AgentProcessingStep(BaseDeploymentStep):
|
|
|
103
104
|
|
|
104
105
|
# Determine step status
|
|
105
106
|
if failed_count == 0:
|
|
106
|
-
status =
|
|
107
|
+
status = OperationResult.SUCCESS
|
|
107
108
|
message = f"Successfully processed {processed_count} agents in {execution_time:.3f}s"
|
|
108
109
|
elif processed_count > 0:
|
|
109
|
-
status =
|
|
110
|
+
status = OperationResult.WARNING
|
|
110
111
|
message = f"Processed {processed_count} agents with {failed_count} failures in {execution_time:.3f}s"
|
|
111
112
|
else:
|
|
112
|
-
status =
|
|
113
|
+
status = OperationResult.FAILED
|
|
113
114
|
message = f"Failed to process any agents ({failed_count} failures) in {execution_time:.3f}s"
|
|
114
115
|
|
|
115
116
|
self.logger.info(message)
|
|
@@ -127,7 +128,7 @@ class AgentProcessingStep(BaseDeploymentStep):
|
|
|
127
128
|
context.add_error(error_msg)
|
|
128
129
|
|
|
129
130
|
return StepResult(
|
|
130
|
-
status=
|
|
131
|
+
status=OperationResult.FAILED,
|
|
131
132
|
message=error_msg,
|
|
132
133
|
error=e,
|
|
133
134
|
execution_time=execution_time,
|
|
@@ -2,26 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
from abc import ABC, abstractmethod
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from enum import Enum
|
|
6
5
|
from typing import Optional
|
|
7
6
|
|
|
7
|
+
from claude_mpm.core.enums import OperationResult
|
|
8
8
|
from claude_mpm.core.logger import get_logger
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class StepStatus(Enum):
|
|
12
|
-
"""Status of a pipeline step execution."""
|
|
13
|
-
|
|
14
|
-
SUCCESS = "success"
|
|
15
|
-
FAILURE = "failure"
|
|
16
|
-
SKIPPED = "skipped"
|
|
17
|
-
WARNING = "warning"
|
|
18
|
-
|
|
19
|
-
|
|
20
11
|
@dataclass
|
|
21
12
|
class StepResult:
|
|
22
13
|
"""Result of executing a pipeline step."""
|
|
23
14
|
|
|
24
|
-
status:
|
|
15
|
+
status: OperationResult
|
|
25
16
|
message: Optional[str] = None
|
|
26
17
|
error: Optional[Exception] = None
|
|
27
18
|
execution_time: Optional[float] = None
|
|
@@ -29,22 +20,22 @@ class StepResult:
|
|
|
29
20
|
@property
|
|
30
21
|
def is_success(self) -> bool:
|
|
31
22
|
"""Check if the step was successful."""
|
|
32
|
-
return self.status ==
|
|
23
|
+
return self.status == OperationResult.SUCCESS
|
|
33
24
|
|
|
34
25
|
@property
|
|
35
26
|
def is_failure(self) -> bool:
|
|
36
27
|
"""Check if the step failed."""
|
|
37
|
-
return self.status ==
|
|
28
|
+
return self.status == OperationResult.FAILED
|
|
38
29
|
|
|
39
30
|
@property
|
|
40
31
|
def is_skipped(self) -> bool:
|
|
41
32
|
"""Check if the step was skipped."""
|
|
42
|
-
return self.status ==
|
|
33
|
+
return self.status == OperationResult.SKIPPED
|
|
43
34
|
|
|
44
35
|
@property
|
|
45
36
|
def is_warning(self) -> bool:
|
|
46
37
|
"""Check if the step completed with warnings."""
|
|
47
|
-
return self.status ==
|
|
38
|
+
return self.status == OperationResult.WARNING
|
|
48
39
|
|
|
49
40
|
|
|
50
41
|
class BaseDeploymentStep(ABC):
|
|
@@ -67,7 +58,7 @@ class BaseDeploymentStep(ABC):
|
|
|
67
58
|
self.logger = get_logger(f"{__name__}.{self.__class__.__name__}")
|
|
68
59
|
|
|
69
60
|
@abstractmethod
|
|
70
|
-
def execute(self, context) -> StepResult:
|
|
61
|
+
def execute(self, context) -> "StepResult":
|
|
71
62
|
"""Execute this deployment step.
|
|
72
63
|
|
|
73
64
|
Args:
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
import time
|
|
4
4
|
|
|
5
5
|
from claude_mpm.core.config import Config
|
|
6
|
+
from claude_mpm.core.enums import OperationResult
|
|
6
7
|
|
|
7
|
-
from .base_step import BaseDeploymentStep, StepResult
|
|
8
|
+
from .base_step import BaseDeploymentStep, StepResult
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class ConfigurationLoadStep(BaseDeploymentStep):
|
|
@@ -54,7 +55,7 @@ class ConfigurationLoadStep(BaseDeploymentStep):
|
|
|
54
55
|
context.step_timings[self.name] = execution_time
|
|
55
56
|
|
|
56
57
|
return StepResult(
|
|
57
|
-
status=
|
|
58
|
+
status=OperationResult.SUCCESS,
|
|
58
59
|
message=f"Configuration loaded successfully in {execution_time:.3f}s",
|
|
59
60
|
execution_time=execution_time,
|
|
60
61
|
)
|
|
@@ -68,7 +69,7 @@ class ConfigurationLoadStep(BaseDeploymentStep):
|
|
|
68
69
|
context.add_error(error_msg)
|
|
69
70
|
|
|
70
71
|
return StepResult(
|
|
71
|
-
status=
|
|
72
|
+
status=OperationResult.FAILED,
|
|
72
73
|
message=error_msg,
|
|
73
74
|
error=e,
|
|
74
75
|
execution_time=execution_time,
|
|
@@ -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,
|