claude-mpm 3.7.8__py3-none-any.whl → 3.9.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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +0 -106
- claude_mpm/agents/INSTRUCTIONS.md +0 -96
- claude_mpm/agents/MEMORY.md +94 -0
- claude_mpm/agents/WORKFLOW.md +86 -0
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +1 -1
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/ops.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +3 -8
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +2 -2
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +2 -2
- claude_mpm/cli/commands/__init__.py +2 -1
- claude_mpm/cli/commands/agents.py +8 -3
- claude_mpm/cli/commands/tickets.py +596 -19
- claude_mpm/cli/parser.py +217 -5
- claude_mpm/config/__init__.py +30 -39
- claude_mpm/config/socketio_config.py +8 -5
- claude_mpm/constants.py +13 -0
- claude_mpm/core/__init__.py +8 -18
- claude_mpm/core/cache.py +596 -0
- claude_mpm/core/claude_runner.py +166 -622
- claude_mpm/core/config.py +7 -3
- claude_mpm/core/constants.py +339 -0
- claude_mpm/core/container.py +548 -38
- claude_mpm/core/exceptions.py +392 -0
- claude_mpm/core/framework_loader.py +249 -93
- claude_mpm/core/interactive_session.py +479 -0
- claude_mpm/core/interfaces.py +424 -0
- claude_mpm/core/lazy.py +467 -0
- claude_mpm/core/logging_config.py +444 -0
- claude_mpm/core/oneshot_session.py +465 -0
- claude_mpm/core/optimized_agent_loader.py +485 -0
- claude_mpm/core/optimized_startup.py +490 -0
- claude_mpm/core/service_registry.py +52 -26
- claude_mpm/core/socketio_pool.py +162 -5
- claude_mpm/core/types.py +292 -0
- claude_mpm/core/typing_utils.py +477 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +213 -99
- claude_mpm/init.py +2 -1
- claude_mpm/services/__init__.py +78 -14
- claude_mpm/services/agent/__init__.py +24 -0
- claude_mpm/services/agent/deployment.py +2548 -0
- claude_mpm/services/agent/management.py +598 -0
- claude_mpm/services/agent/registry.py +813 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +728 -308
- claude_mpm/services/agents/memory/agent_memory_manager.py +160 -4
- claude_mpm/services/async_session_logger.py +8 -3
- claude_mpm/services/communication/__init__.py +21 -0
- claude_mpm/services/communication/socketio.py +1933 -0
- claude_mpm/services/communication/websocket.py +479 -0
- claude_mpm/services/core/__init__.py +123 -0
- claude_mpm/services/core/base.py +247 -0
- claude_mpm/services/core/interfaces.py +951 -0
- claude_mpm/services/framework_claude_md_generator/__init__.py +10 -3
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +14 -11
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +23 -23
- claude_mpm/services/framework_claude_md_generator.py +3 -2
- claude_mpm/services/health_monitor.py +4 -3
- claude_mpm/services/hook_service.py +64 -4
- claude_mpm/services/infrastructure/__init__.py +21 -0
- claude_mpm/services/infrastructure/logging.py +202 -0
- claude_mpm/services/infrastructure/monitoring.py +893 -0
- claude_mpm/services/memory/indexed_memory.py +648 -0
- claude_mpm/services/project/__init__.py +21 -0
- claude_mpm/services/project/analyzer.py +864 -0
- claude_mpm/services/project/registry.py +608 -0
- claude_mpm/services/project_analyzer.py +95 -2
- claude_mpm/services/recovery_manager.py +15 -9
- claude_mpm/services/response_tracker.py +3 -5
- claude_mpm/services/socketio/__init__.py +25 -0
- claude_mpm/services/socketio/handlers/__init__.py +25 -0
- claude_mpm/services/socketio/handlers/base.py +121 -0
- claude_mpm/services/socketio/handlers/connection.py +198 -0
- claude_mpm/services/socketio/handlers/file.py +213 -0
- claude_mpm/services/socketio/handlers/git.py +723 -0
- claude_mpm/services/socketio/handlers/memory.py +27 -0
- claude_mpm/services/socketio/handlers/project.py +25 -0
- claude_mpm/services/socketio/handlers/registry.py +145 -0
- claude_mpm/services/socketio_client_manager.py +12 -7
- claude_mpm/services/socketio_server.py +156 -30
- claude_mpm/services/ticket_manager.py +172 -9
- claude_mpm/services/ticket_manager_di.py +1 -1
- claude_mpm/services/version_control/semantic_versioning.py +80 -7
- claude_mpm/services/version_control/version_parser.py +528 -0
- claude_mpm/utils/error_handler.py +1 -1
- claude_mpm/validation/agent_validator.py +27 -14
- claude_mpm/validation/frontmatter_validator.py +231 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/METADATA +38 -128
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/RECORD +100 -59
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/WHEEL +0 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/top_level.txt +0 -0
| @@ -24,8 +24,14 @@ class FrameworkClaudeMdGenerator: | |
| 24 24 | 
             
                This is the main facade class that coordinates all the submodules.
         | 
| 25 25 | 
             
                """
         | 
| 26 26 |  | 
| 27 | 
            -
                def __init__(self):
         | 
| 28 | 
            -
                    """ | 
| 27 | 
            +
                def __init__(self, target_filename: str = "INSTRUCTIONS.md"):
         | 
| 28 | 
            +
                    """
         | 
| 29 | 
            +
                    Initialize the generator with current framework version.
         | 
| 30 | 
            +
                    
         | 
| 31 | 
            +
                    Args:
         | 
| 32 | 
            +
                        target_filename: Target filename for deployment (default: "INSTRUCTIONS.md")
         | 
| 33 | 
            +
                                       Can be set to "CLAUDE.md" for legacy compatibility
         | 
| 34 | 
            +
                    """
         | 
| 29 35 | 
             
                    # Initialize managers
         | 
| 30 36 | 
             
                    self.version_manager = VersionManager()
         | 
| 31 37 | 
             
                    self.validator = ContentValidator()
         | 
| @@ -35,7 +41,8 @@ class FrameworkClaudeMdGenerator: | |
| 35 41 | 
             
                    # Initialize deployment manager with dependencies
         | 
| 36 42 | 
             
                    self.deployment_manager = DeploymentManager(
         | 
| 37 43 | 
             
                        self.version_manager, 
         | 
| 38 | 
            -
                        self.validator
         | 
| 44 | 
            +
                        self.validator,
         | 
| 45 | 
            +
                        target_filename=target_filename
         | 
| 39 46 | 
             
                    )
         | 
| 40 47 |  | 
| 41 48 | 
             
                    # Get framework version
         | 
| @@ -6,7 +6,7 @@ Handles deployment operations to parent directories. | |
| 6 6 |  | 
| 7 7 | 
             
            from pathlib import Path
         | 
| 8 8 | 
             
            from typing import Tuple, Optional
         | 
| 9 | 
            -
            from datetime import datetime
         | 
| 9 | 
            +
            from datetime import datetime, timezone
         | 
| 10 10 | 
             
            from .version_manager import VersionManager
         | 
| 11 11 | 
             
            from .content_validator import ContentValidator
         | 
| 12 12 |  | 
| @@ -17,16 +17,20 @@ from ...utils.framework_detection import is_framework_source_directory | |
| 17 17 | 
             
            class DeploymentManager:
         | 
| 18 18 | 
             
                """Manages deployment of framework CLAUDE.md to parent directories."""
         | 
| 19 19 |  | 
| 20 | 
            -
                def __init__(self, version_manager: VersionManager, validator: ContentValidator | 
| 20 | 
            +
                def __init__(self, version_manager: VersionManager, validator: ContentValidator, 
         | 
| 21 | 
            +
                             target_filename: str = "INSTRUCTIONS.md"):
         | 
| 21 22 | 
             
                    """
         | 
| 22 23 | 
             
                    Initialize deployment manager.
         | 
| 23 24 |  | 
| 24 25 | 
             
                    Args:
         | 
| 25 26 | 
             
                        version_manager: Version management instance
         | 
| 26 27 | 
             
                        validator: Content validator instance
         | 
| 28 | 
            +
                        target_filename: Target filename for deployment (default: "INSTRUCTIONS.md")
         | 
| 29 | 
            +
                                       Can be set to "CLAUDE.md" for legacy compatibility
         | 
| 27 30 | 
             
                    """
         | 
| 28 31 | 
             
                    self.version_manager = version_manager
         | 
| 29 32 | 
             
                    self.validator = validator
         | 
| 33 | 
            +
                    self.target_filename = target_filename
         | 
| 30 34 |  | 
| 31 35 | 
             
                def deploy_to_parent(self, 
         | 
| 32 36 | 
             
                                    content: str,
         | 
| @@ -53,9 +57,8 @@ class DeploymentManager: | |
| 53 57 | 
             
                    if is_framework:
         | 
| 54 58 | 
             
                        return True, f"Skipping deployment - detected framework source directory (markers: {', '.join(markers)})"
         | 
| 55 59 |  | 
| 56 | 
            -
                    # Use  | 
| 57 | 
            -
                    target_file = parent_path /  | 
| 58 | 
            -
                    # TODO: Make this configurable via parameter
         | 
| 60 | 
            +
                    # Use configured target filename
         | 
| 61 | 
            +
                    target_file = parent_path / self.target_filename
         | 
| 59 62 |  | 
| 60 63 | 
             
                    # Check if content contains template variables that need processing
         | 
| 61 64 | 
             
                    if '{{capabilities-list}}' in content:
         | 
| @@ -115,10 +118,10 @@ class DeploymentManager: | |
| 115 118 | 
             
                    Returns:
         | 
| 116 119 | 
             
                        Tuple of (needed, reason)
         | 
| 117 120 | 
             
                    """
         | 
| 118 | 
            -
                    target_file = parent_path /  | 
| 121 | 
            +
                    target_file = parent_path / self.target_filename
         | 
| 119 122 |  | 
| 120 123 | 
             
                    if not target_file.exists():
         | 
| 121 | 
            -
                        return True, " | 
| 124 | 
            +
                        return True, f"{self.target_filename} does not exist"
         | 
| 122 125 |  | 
| 123 126 | 
             
                    try:
         | 
| 124 127 | 
             
                        with open(target_file, 'r') as f:
         | 
| @@ -134,7 +137,7 @@ class DeploymentManager: | |
| 134 137 |  | 
| 135 138 | 
             
                def backup_existing(self, parent_path: Path) -> Optional[Path]:
         | 
| 136 139 | 
             
                    """
         | 
| 137 | 
            -
                    Create a backup of existing  | 
| 140 | 
            +
                    Create a backup of existing target file before deployment.
         | 
| 138 141 |  | 
| 139 142 | 
             
                    Args:
         | 
| 140 143 | 
             
                        parent_path: Path to parent directory
         | 
| @@ -142,14 +145,14 @@ class DeploymentManager: | |
| 142 145 | 
             
                    Returns:
         | 
| 143 146 | 
             
                        Path to backup file if created, None otherwise
         | 
| 144 147 | 
             
                    """
         | 
| 145 | 
            -
                    target_file = parent_path /  | 
| 148 | 
            +
                    target_file = parent_path / self.target_filename
         | 
| 146 149 |  | 
| 147 150 | 
             
                    if not target_file.exists():
         | 
| 148 151 | 
             
                        return None
         | 
| 149 152 |  | 
| 150 153 | 
             
                    # Create backup filename with timestamp
         | 
| 151 | 
            -
                    timestamp = datetime. | 
| 152 | 
            -
                    backup_file = parent_path / f" | 
| 154 | 
            +
                    timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
         | 
| 155 | 
            +
                    backup_file = parent_path / f"{self.target_filename}.backup.{timestamp}"
         | 
| 153 156 |  | 
| 154 157 | 
             
                    try:
         | 
| 155 158 | 
             
                        import shutil
         | 
| @@ -45,31 +45,31 @@ Task(description="[task description]", subagent_type="[agent-type]") | |
| 45 45 |  | 
| 46 46 | 
             
            **Valid subagent_type values (use lowercase format for Claude Code compatibility):**
         | 
| 47 47 |  | 
| 48 | 
            -
            **Required  | 
| 49 | 
            -
            - `subagent_type="research"` - For investigation and analysis
         | 
| 48 | 
            +
            **Required format (Claude Code expects these exact values from deployed agent YAML names):**
         | 
| 49 | 
            +
            - `subagent_type="research-agent"` - For investigation and analysis
         | 
| 50 50 | 
             
            - `subagent_type="engineer"` - For coding and implementation
         | 
| 51 | 
            -
            - `subagent_type="qa"` - For testing and quality assurance
         | 
| 52 | 
            -
            - `subagent_type="documentation"` - For docs and guides
         | 
| 53 | 
            -
            - `subagent_type="security"` - For security assessments
         | 
| 54 | 
            -
            - `subagent_type="ops"` - For deployment and infrastructure
         | 
| 55 | 
            -
            - `subagent_type=" | 
| 56 | 
            -
            - `subagent_type=" | 
| 51 | 
            +
            - `subagent_type="qa-agent"` - For testing and quality assurance
         | 
| 52 | 
            +
            - `subagent_type="documentation-agent"` - For docs and guides
         | 
| 53 | 
            +
            - `subagent_type="security-agent"` - For security assessments
         | 
| 54 | 
            +
            - `subagent_type="ops-agent"` - For deployment and infrastructure
         | 
| 55 | 
            +
            - `subagent_type="version-control"` - For git and version management
         | 
| 56 | 
            +
            - `subagent_type="data-engineer"` - For data processing and APIs
         | 
| 57 57 | 
             
            - `subagent_type="pm"` - For project management coordination
         | 
| 58 58 | 
             
            - `subagent_type="test_integration"` - For integration testing
         | 
| 59 59 |  | 
| 60 | 
            -
            **Note:** Claude Code's Task tool requires exact  | 
| 60 | 
            +
            **Note:** Claude Code's Task tool requires exact agent names as defined in the deployed agent YAML frontmatter. The names must match exactly - including hyphens where specified.
         | 
| 61 61 |  | 
| 62 | 
            -
            **Examples of Proper Task Tool Usage ( | 
| 63 | 
            -
            - ✅ `Task(description="Update framework documentation", subagent_type="documentation")`
         | 
| 64 | 
            -
            - ✅ `Task(description="Execute test suite validation", subagent_type="qa")`
         | 
| 65 | 
            -
            - ✅ `Task(description="Create feature branch and sync", subagent_type=" | 
| 66 | 
            -
            - ✅ `Task(description="Investigate performance patterns", subagent_type="research")`
         | 
| 62 | 
            +
            **Examples of Proper Task Tool Usage (must match deployed agent YAML names):**
         | 
| 63 | 
            +
            - ✅ `Task(description="Update framework documentation", subagent_type="documentation-agent")`
         | 
| 64 | 
            +
            - ✅ `Task(description="Execute test suite validation", subagent_type="qa-agent")`
         | 
| 65 | 
            +
            - ✅ `Task(description="Create feature branch and sync", subagent_type="version-control")`
         | 
| 66 | 
            +
            - ✅ `Task(description="Investigate performance patterns", subagent_type="research-agent")`
         | 
| 67 67 | 
             
            - ✅ `Task(description="Implement authentication system", subagent_type="engineer")`
         | 
| 68 | 
            -
            - ✅ `Task(description="Configure database and optimize queries", subagent_type=" | 
| 68 | 
            +
            - ✅ `Task(description="Configure database and optimize queries", subagent_type="data-engineer")`
         | 
| 69 69 | 
             
            - ✅ `Task(description="Coordinate project tasks", subagent_type="pm")`
         | 
| 70 | 
            -
            - ❌ `Task(description="Analyze code patterns", subagent_type=" | 
| 71 | 
            -
            - ❌ `Task(description="Update API docs", subagent_type=" | 
| 72 | 
            -
            - ❌ `Task(description="Create release tags", subagent_type=" | 
| 70 | 
            +
            - ❌ `Task(description="Analyze code patterns", subagent_type="research")` (WRONG - missing '-agent' suffix)
         | 
| 71 | 
            +
            - ❌ `Task(description="Update API docs", subagent_type="documentation")` (WRONG - missing '-agent' suffix)
         | 
| 72 | 
            +
            - ❌ `Task(description="Create release tags", subagent_type="version_control")` (WRONG - should be 'version-control')
         | 
| 73 73 |  | 
| 74 74 | 
             
            ### 🚨 MANDATORY: THREE SHORTCUT COMMANDS
         | 
| 75 75 |  | 
| @@ -98,11 +98,11 @@ Task(description="[task description]", subagent_type="[agent-type]") | |
| 98 98 | 
             
            - ☐ [Data Engineer] Validate data integrity and verify API connectivity
         | 
| 99 99 | 
             
            - ☐ [Version Control] Apply semantic version bump and create release tags
         | 
| 100 100 |  | 
| 101 | 
            -
            # Corresponding Task Tool delegations ( | 
| 102 | 
            -
            Task(description="Generate changelog and analyze version impact", subagent_type="documentation")
         | 
| 103 | 
            -
            Task(description="Execute full test suite and quality validation", subagent_type="qa")
         | 
| 104 | 
            -
            Task(description="Validate data integrity and verify API connectivity", subagent_type=" | 
| 105 | 
            -
            Task(description="Apply semantic version bump and create release tags", subagent_type=" | 
| 101 | 
            +
            # Corresponding Task Tool delegations (must match deployed agent names):
         | 
| 102 | 
            +
            Task(description="Generate changelog and analyze version impact", subagent_type="documentation-agent")
         | 
| 103 | 
            +
            Task(description="Execute full test suite and quality validation", subagent_type="qa-agent")
         | 
| 104 | 
            +
            Task(description="Validate data integrity and verify API connectivity", subagent_type="data-engineer")
         | 
| 105 | 
            +
            Task(description="Apply semantic version bump and create release tags", subagent_type="version-control")
         | 
| 106 106 |  | 
| 107 107 | 
             
            # Update TodoWrite status based on agent completions
         | 
| 108 108 | 
             
            ```
         | 
| @@ -19,6 +19,7 @@ from typing import Dict, Optional, Any, List, Tuple, Callable | |
| 19 19 | 
             
            from dataclasses import dataclass, field
         | 
| 20 20 |  | 
| 21 21 | 
             
            from claude_mpm.core.config_paths import ConfigPaths
         | 
| 22 | 
            +
            from claude_mpm.core.constants import SystemLimits
         | 
| 22 23 |  | 
| 23 24 | 
             
            logger = logging.getLogger(__name__)
         | 
| 24 25 |  | 
| @@ -450,8 +451,8 @@ class FrameworkClaudeMdGenerator: | |
| 450 451 | 
             
                    suggestions = []
         | 
| 451 452 |  | 
| 452 453 | 
             
                    # Check minimum length
         | 
| 453 | 
            -
                    if len(content) <  | 
| 454 | 
            -
                        errors.append("Content seems too short")
         | 
| 454 | 
            +
                    if len(content) < SystemLimits.MIN_CONTENT_LENGTH:
         | 
| 455 | 
            +
                        errors.append(f"Content seems too short (minimum {SystemLimits.MIN_CONTENT_LENGTH} characters)")
         | 
| 455 456 |  | 
| 456 457 | 
             
                    # Check for required sections
         | 
| 457 458 | 
             
                    required_sections = [
         | 
| @@ -27,6 +27,7 @@ from pathlib import Path | |
| 27 27 | 
             
            from typing import Any, Dict, List, Optional, Callable, Union
         | 
| 28 28 | 
             
            import json
         | 
| 29 29 | 
             
            import socket
         | 
| 30 | 
            +
            from claude_mpm.core.constants import ResourceLimits, TimeoutConfig
         | 
| 30 31 |  | 
| 31 32 | 
             
            try:
         | 
| 32 33 | 
             
                import psutil
         | 
| @@ -196,7 +197,7 @@ class ProcessResourceChecker(HealthChecker): | |
| 196 197 |  | 
| 197 198 | 
             
                        # CPU usage
         | 
| 198 199 | 
             
                        try:
         | 
| 199 | 
            -
                            cpu_percent = self.process.cpu_percent(interval= | 
| 200 | 
            +
                            cpu_percent = self.process.cpu_percent(interval=TimeoutConfig.CPU_SAMPLE_INTERVAL)
         | 
| 200 201 | 
             
                            cpu_status = HealthStatus.HEALTHY
         | 
| 201 202 | 
             
                            if cpu_percent > self.cpu_threshold:
         | 
| 202 203 | 
             
                                cpu_status = HealthStatus.WARNING if cpu_percent < self.cpu_threshold * 1.2 else HealthStatus.CRITICAL
         | 
| @@ -219,7 +220,7 @@ class ProcessResourceChecker(HealthChecker): | |
| 219 220 | 
             
                        # Memory usage
         | 
| 220 221 | 
             
                        try:
         | 
| 221 222 | 
             
                            memory_info = self.process.memory_info()
         | 
| 222 | 
            -
                            memory_mb = memory_info.rss /  | 
| 223 | 
            +
                            memory_mb = memory_info.rss / ResourceLimits.BYTES_TO_MB
         | 
| 223 224 | 
             
                            memory_status = HealthStatus.HEALTHY
         | 
| 224 225 | 
             
                            if memory_mb > self.memory_threshold_mb:
         | 
| 225 226 | 
             
                                memory_status = HealthStatus.WARNING if memory_mb < self.memory_threshold_mb * 1.2 else HealthStatus.CRITICAL
         | 
| @@ -234,7 +235,7 @@ class ProcessResourceChecker(HealthChecker): | |
| 234 235 |  | 
| 235 236 | 
             
                            metrics.append(HealthMetric(
         | 
| 236 237 | 
             
                                name="memory_vms_mb",
         | 
| 237 | 
            -
                                value=round(memory_info.vms /  | 
| 238 | 
            +
                                value=round(memory_info.vms / ResourceLimits.BYTES_TO_MB, 2),
         | 
| 238 239 | 
             
                                status=HealthStatus.HEALTHY,
         | 
| 239 240 | 
             
                                unit="MB"
         | 
| 240 241 | 
             
                            ))
         | 
| @@ -16,7 +16,7 @@ import time | |
| 16 16 | 
             
            from datetime import datetime
         | 
| 17 17 |  | 
| 18 18 | 
             
            from claude_mpm.core.config import Config
         | 
| 19 | 
            -
            from claude_mpm.core. | 
| 19 | 
            +
            from claude_mpm.core.logging_config import get_logger, log_operation
         | 
| 20 20 | 
             
            from claude_mpm.hooks.base_hook import (
         | 
| 21 21 | 
             
                BaseHook,
         | 
| 22 22 | 
             
                PreDelegationHook,
         | 
| @@ -25,9 +25,10 @@ from claude_mpm.hooks.base_hook import ( | |
| 25 25 | 
             
                HookResult,
         | 
| 26 26 | 
             
                HookType
         | 
| 27 27 | 
             
            )
         | 
| 28 | 
            +
            from claude_mpm.core.interfaces import HookServiceInterface
         | 
| 28 29 |  | 
| 29 30 |  | 
| 30 | 
            -
            class HookService:
         | 
| 31 | 
            +
            class HookService(HookServiceInterface):
         | 
| 31 32 | 
             
                """Service for managing and executing hooks in the delegation workflow.
         | 
| 32 33 |  | 
| 33 34 | 
             
                WHY: Provides a centralized place to register and execute hooks, ensuring
         | 
| @@ -47,7 +48,7 @@ class HookService: | |
| 47 48 | 
             
                        config: Optional configuration object for controlling hook behavior
         | 
| 48 49 | 
             
                    """
         | 
| 49 50 | 
             
                    self.config = config or Config()
         | 
| 50 | 
            -
                    self.logger = get_logger( | 
| 51 | 
            +
                    self.logger = get_logger(__name__)
         | 
| 51 52 |  | 
| 52 53 | 
             
                    # Separate lists for different hook types for performance
         | 
| 53 54 | 
             
                    self.pre_delegation_hooks: List[PreDelegationHook] = []
         | 
| @@ -359,4 +360,63 @@ class HookService: | |
| 359 360 | 
             
                            return True
         | 
| 360 361 |  | 
| 361 362 | 
             
                    self.logger.warning(f"Hook not found: {hook_name}")
         | 
| 362 | 
            -
                    return False
         | 
| 363 | 
            +
                    return False
         | 
| 364 | 
            +
                
         | 
| 365 | 
            +
                # ================================================================================
         | 
| 366 | 
            +
                # Interface Adapter Methods
         | 
| 367 | 
            +
                # ================================================================================
         | 
| 368 | 
            +
                # These methods are added to comply with HookServiceInterface
         | 
| 369 | 
            +
                
         | 
| 370 | 
            +
                def get_registered_hooks(self) -> Dict[str, List[Any]]:
         | 
| 371 | 
            +
                    """Get all registered hooks by type.
         | 
| 372 | 
            +
                    
         | 
| 373 | 
            +
                    WHY: This method provides interface compliance by exposing the
         | 
| 374 | 
            +
                    registered hooks for inspection and debugging purposes.
         | 
| 375 | 
            +
                    
         | 
| 376 | 
            +
                    Returns:
         | 
| 377 | 
            +
                        Dictionary mapping hook types to lists of hooks
         | 
| 378 | 
            +
                    """
         | 
| 379 | 
            +
                    return {
         | 
| 380 | 
            +
                        "pre_delegation": [
         | 
| 381 | 
            +
                            {
         | 
| 382 | 
            +
                                "name": hook.name,
         | 
| 383 | 
            +
                                "priority": hook.priority,
         | 
| 384 | 
            +
                                "enabled": hook.enabled,
         | 
| 385 | 
            +
                                "type": "pre_delegation"
         | 
| 386 | 
            +
                            }
         | 
| 387 | 
            +
                            for hook in self.pre_delegation_hooks
         | 
| 388 | 
            +
                        ],
         | 
| 389 | 
            +
                        "post_delegation": [
         | 
| 390 | 
            +
                            {
         | 
| 391 | 
            +
                                "name": hook.name,
         | 
| 392 | 
            +
                                "priority": hook.priority,
         | 
| 393 | 
            +
                                "enabled": hook.enabled,
         | 
| 394 | 
            +
                                "type": "post_delegation"
         | 
| 395 | 
            +
                            }
         | 
| 396 | 
            +
                            for hook in self.post_delegation_hooks
         | 
| 397 | 
            +
                        ]
         | 
| 398 | 
            +
                    }
         | 
| 399 | 
            +
                
         | 
| 400 | 
            +
                def clear_hooks(self, hook_type: Optional[str] = None) -> None:
         | 
| 401 | 
            +
                    """Clear registered hooks.
         | 
| 402 | 
            +
                    
         | 
| 403 | 
            +
                    WHY: This method provides interface compliance by allowing bulk
         | 
| 404 | 
            +
                    removal of hooks, useful for testing and cleanup scenarios.
         | 
| 405 | 
            +
                    
         | 
| 406 | 
            +
                    Args:
         | 
| 407 | 
            +
                        hook_type: Optional specific hook type to clear, or None for all
         | 
| 408 | 
            +
                    """
         | 
| 409 | 
            +
                    if hook_type is None or hook_type == "pre_delegation":
         | 
| 410 | 
            +
                        count = len(self.pre_delegation_hooks)
         | 
| 411 | 
            +
                        self.pre_delegation_hooks.clear()
         | 
| 412 | 
            +
                        if count > 0:
         | 
| 413 | 
            +
                            self.logger.info(f"Cleared {count} pre-delegation hooks")
         | 
| 414 | 
            +
                    
         | 
| 415 | 
            +
                    if hook_type is None or hook_type == "post_delegation":
         | 
| 416 | 
            +
                        count = len(self.post_delegation_hooks)
         | 
| 417 | 
            +
                        self.post_delegation_hooks.clear()
         | 
| 418 | 
            +
                        if count > 0:
         | 
| 419 | 
            +
                            self.logger.info(f"Cleared {count} post-delegation hooks")
         | 
| 420 | 
            +
                    
         | 
| 421 | 
            +
                    if hook_type and hook_type not in ["pre_delegation", "post_delegation"]:
         | 
| 422 | 
            +
                        self.logger.warning(f"Unknown hook type: {hook_type}")
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            """
         | 
| 2 | 
            +
            Infrastructure Services Module
         | 
| 3 | 
            +
            =============================
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            This module contains infrastructure-related services including
         | 
| 6 | 
            +
            logging, monitoring, and system health management.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            Part of TSK-0046: Service Layer Architecture Reorganization
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            Services:
         | 
| 11 | 
            +
            - LoggingService: Centralized logging with structured output
         | 
| 12 | 
            +
            - HealthMonitor: System health monitoring and alerting
         | 
| 13 | 
            +
            """
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            from .logging import LoggingService
         | 
| 16 | 
            +
            from .monitoring import HealthMonitor
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            __all__ = [
         | 
| 19 | 
            +
                'LoggingService',
         | 
| 20 | 
            +
                'HealthMonitor',
         | 
| 21 | 
            +
            ]
         | 
| @@ -0,0 +1,202 @@ | |
| 1 | 
            +
            """
         | 
| 2 | 
            +
            Logging Service for Claude MPM Framework
         | 
| 3 | 
            +
            ========================================
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            This module provides centralized logging services and utilities.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Part of TSK-0046: Service Layer Architecture Reorganization
         | 
| 8 | 
            +
            """
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            from typing import Any, Dict, Optional, List
         | 
| 11 | 
            +
            from pathlib import Path
         | 
| 12 | 
            +
            import logging
         | 
| 13 | 
            +
            import json
         | 
| 14 | 
            +
            from datetime import datetime
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            from claude_mpm.services.core import SyncBaseService, ILoggingService
         | 
| 17 | 
            +
            from claude_mpm.utils.logger import get_logger
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 20 | 
            +
            class LoggingService(SyncBaseService, ILoggingService):
         | 
| 21 | 
            +
                """
         | 
| 22 | 
            +
                Centralized logging service for the Claude MPM framework.
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
                This service provides:
         | 
| 25 | 
            +
                - Structured logging with JSON output
         | 
| 26 | 
            +
                - Log rotation and archival
         | 
| 27 | 
            +
                - Performance metrics logging
         | 
| 28 | 
            +
                - Audit trail capabilities
         | 
| 29 | 
            +
                """
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                def __init__(self, config: Optional[Dict[str, Any]] = None):
         | 
| 32 | 
            +
                    """
         | 
| 33 | 
            +
                    Initialize logging service.
         | 
| 34 | 
            +
                    
         | 
| 35 | 
            +
                    Args:
         | 
| 36 | 
            +
                        config: Logging configuration
         | 
| 37 | 
            +
                    """
         | 
| 38 | 
            +
                    super().__init__("LoggingService", config)
         | 
| 39 | 
            +
                    self.log_dir = Path(self.get_config('log_dir', '.claude-mpm/logs'))
         | 
| 40 | 
            +
                    self.log_level = self.get_config('log_level', 'INFO')
         | 
| 41 | 
            +
                    self.structured_logging = self.get_config('structured_logging', True)
         | 
| 42 | 
            +
                    self._log_handlers = []
         | 
| 43 | 
            +
                
         | 
| 44 | 
            +
                def initialize(self) -> bool:
         | 
| 45 | 
            +
                    """Initialize the logging service."""
         | 
| 46 | 
            +
                    try:
         | 
| 47 | 
            +
                        # Create log directory if it doesn't exist
         | 
| 48 | 
            +
                        self.log_dir.mkdir(parents=True, exist_ok=True)
         | 
| 49 | 
            +
                        
         | 
| 50 | 
            +
                        # Set up log rotation if configured
         | 
| 51 | 
            +
                        if self.get_config('enable_rotation', True):
         | 
| 52 | 
            +
                            self._setup_rotation()
         | 
| 53 | 
            +
                        
         | 
| 54 | 
            +
                        # Set up structured logging if enabled
         | 
| 55 | 
            +
                        if self.structured_logging:
         | 
| 56 | 
            +
                            self._setup_structured_logging()
         | 
| 57 | 
            +
                        
         | 
| 58 | 
            +
                        self._initialized = True
         | 
| 59 | 
            +
                        self.log_info("Logging service initialized successfully")
         | 
| 60 | 
            +
                        return True
         | 
| 61 | 
            +
                        
         | 
| 62 | 
            +
                    except Exception as e:
         | 
| 63 | 
            +
                        self.log_error(f"Failed to initialize logging service: {e}")
         | 
| 64 | 
            +
                        return False
         | 
| 65 | 
            +
                
         | 
| 66 | 
            +
                def shutdown(self) -> None:
         | 
| 67 | 
            +
                    """Shutdown the logging service."""
         | 
| 68 | 
            +
                    try:
         | 
| 69 | 
            +
                        # Flush all handlers
         | 
| 70 | 
            +
                        for handler in self._log_handlers:
         | 
| 71 | 
            +
                            handler.flush()
         | 
| 72 | 
            +
                            handler.close()
         | 
| 73 | 
            +
                        
         | 
| 74 | 
            +
                        self._log_handlers.clear()
         | 
| 75 | 
            +
                        self._shutdown = True
         | 
| 76 | 
            +
                        self.log_info("Logging service shutdown successfully")
         | 
| 77 | 
            +
                        
         | 
| 78 | 
            +
                    except Exception as e:
         | 
| 79 | 
            +
                        self.log_error(f"Error during logging service shutdown: {e}")
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                def log(self, level: str, message: str, **context) -> None:
         | 
| 82 | 
            +
                    """
         | 
| 83 | 
            +
                    Log a message with context.
         | 
| 84 | 
            +
                    
         | 
| 85 | 
            +
                    Args:
         | 
| 86 | 
            +
                        level: Log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
         | 
| 87 | 
            +
                        message: Log message
         | 
| 88 | 
            +
                        **context: Additional context to include
         | 
| 89 | 
            +
                    """
         | 
| 90 | 
            +
                    logger = get_logger(context.get('component', 'default'))
         | 
| 91 | 
            +
                    
         | 
| 92 | 
            +
                    if self.structured_logging:
         | 
| 93 | 
            +
                        log_entry = {
         | 
| 94 | 
            +
                            'timestamp': datetime.utcnow().isoformat(),
         | 
| 95 | 
            +
                            'level': level,
         | 
| 96 | 
            +
                            'message': message,
         | 
| 97 | 
            +
                            'context': context
         | 
| 98 | 
            +
                        }
         | 
| 99 | 
            +
                        message = json.dumps(log_entry)
         | 
| 100 | 
            +
                    
         | 
| 101 | 
            +
                    log_method = getattr(logger, level.lower(), logger.info)
         | 
| 102 | 
            +
                    log_method(message)
         | 
| 103 | 
            +
                
         | 
| 104 | 
            +
                def log_performance(self, operation: str, duration: float, **metrics) -> None:
         | 
| 105 | 
            +
                    """
         | 
| 106 | 
            +
                    Log performance metrics.
         | 
| 107 | 
            +
                    
         | 
| 108 | 
            +
                    Args:
         | 
| 109 | 
            +
                        operation: Name of the operation
         | 
| 110 | 
            +
                        duration: Duration in seconds
         | 
| 111 | 
            +
                        **metrics: Additional performance metrics
         | 
| 112 | 
            +
                    """
         | 
| 113 | 
            +
                    self.log('INFO', f"Performance: {operation}", 
         | 
| 114 | 
            +
                            operation=operation, 
         | 
| 115 | 
            +
                            duration_ms=duration * 1000,
         | 
| 116 | 
            +
                            **metrics)
         | 
| 117 | 
            +
                
         | 
| 118 | 
            +
                def log_audit(self, action: str, user: str, **details) -> None:
         | 
| 119 | 
            +
                    """
         | 
| 120 | 
            +
                    Log an audit event.
         | 
| 121 | 
            +
                    
         | 
| 122 | 
            +
                    Args:
         | 
| 123 | 
            +
                        action: Action performed
         | 
| 124 | 
            +
                        user: User who performed the action
         | 
| 125 | 
            +
                        **details: Additional audit details
         | 
| 126 | 
            +
                    """
         | 
| 127 | 
            +
                    self.log('INFO', f"Audit: {action} by {user}",
         | 
| 128 | 
            +
                            audit=True,
         | 
| 129 | 
            +
                            action=action,
         | 
| 130 | 
            +
                            user=user,
         | 
| 131 | 
            +
                            **details)
         | 
| 132 | 
            +
                
         | 
| 133 | 
            +
                def get_logs(self, level: Optional[str] = None, 
         | 
| 134 | 
            +
                             component: Optional[str] = None,
         | 
| 135 | 
            +
                             limit: int = 100) -> List[Dict[str, Any]]:
         | 
| 136 | 
            +
                    """
         | 
| 137 | 
            +
                    Retrieve recent logs.
         | 
| 138 | 
            +
                    
         | 
| 139 | 
            +
                    Args:
         | 
| 140 | 
            +
                        level: Filter by log level
         | 
| 141 | 
            +
                        component: Filter by component
         | 
| 142 | 
            +
                        limit: Maximum number of logs to return
         | 
| 143 | 
            +
                        
         | 
| 144 | 
            +
                    Returns:
         | 
| 145 | 
            +
                        List of log entries
         | 
| 146 | 
            +
                    """
         | 
| 147 | 
            +
                    # This would typically read from log files or a log aggregation service
         | 
| 148 | 
            +
                    # For now, return empty list as placeholder
         | 
| 149 | 
            +
                    return []
         | 
| 150 | 
            +
                
         | 
| 151 | 
            +
                def _setup_rotation(self) -> None:
         | 
| 152 | 
            +
                    """Set up log rotation."""
         | 
| 153 | 
            +
                    from logging.handlers import RotatingFileHandler
         | 
| 154 | 
            +
                    
         | 
| 155 | 
            +
                    max_bytes = self.get_config('max_bytes', 10 * 1024 * 1024)  # 10MB
         | 
| 156 | 
            +
                    backup_count = self.get_config('backup_count', 5)
         | 
| 157 | 
            +
                    
         | 
| 158 | 
            +
                    handler = RotatingFileHandler(
         | 
| 159 | 
            +
                        self.log_dir / 'claude_mpm.log',
         | 
| 160 | 
            +
                        maxBytes=max_bytes,
         | 
| 161 | 
            +
                        backupCount=backup_count
         | 
| 162 | 
            +
                    )
         | 
| 163 | 
            +
                    
         | 
| 164 | 
            +
                    formatter = logging.Formatter(
         | 
| 165 | 
            +
                        '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
         | 
| 166 | 
            +
                    )
         | 
| 167 | 
            +
                    handler.setFormatter(formatter)
         | 
| 168 | 
            +
                    
         | 
| 169 | 
            +
                    self._log_handlers.append(handler)
         | 
| 170 | 
            +
                    logging.getLogger().addHandler(handler)
         | 
| 171 | 
            +
                
         | 
| 172 | 
            +
                def _setup_structured_logging(self) -> None:
         | 
| 173 | 
            +
                    """Set up structured JSON logging."""
         | 
| 174 | 
            +
                    import logging.config
         | 
| 175 | 
            +
                    
         | 
| 176 | 
            +
                    config = {
         | 
| 177 | 
            +
                        'version': 1,
         | 
| 178 | 
            +
                        'disable_existing_loggers': False,
         | 
| 179 | 
            +
                        'formatters': {
         | 
| 180 | 
            +
                            'json': {
         | 
| 181 | 
            +
                                'class': 'pythonjsonlogger.jsonlogger.JsonFormatter',
         | 
| 182 | 
            +
                                'format': '%(asctime)s %(name)s %(levelname)s %(message)s'
         | 
| 183 | 
            +
                            }
         | 
| 184 | 
            +
                        },
         | 
| 185 | 
            +
                        'handlers': {
         | 
| 186 | 
            +
                            'json_file': {
         | 
| 187 | 
            +
                                'class': 'logging.FileHandler',
         | 
| 188 | 
            +
                                'filename': str(self.log_dir / 'structured.json'),
         | 
| 189 | 
            +
                                'formatter': 'json'
         | 
| 190 | 
            +
                            }
         | 
| 191 | 
            +
                        },
         | 
| 192 | 
            +
                        'root': {
         | 
| 193 | 
            +
                            'handlers': ['json_file'],
         | 
| 194 | 
            +
                            'level': self.log_level
         | 
| 195 | 
            +
                        }
         | 
| 196 | 
            +
                    }
         | 
| 197 | 
            +
                    
         | 
| 198 | 
            +
                    try:
         | 
| 199 | 
            +
                        logging.config.dictConfig(config)
         | 
| 200 | 
            +
                    except ImportError:
         | 
| 201 | 
            +
                        # If pythonjsonlogger is not available, fall back to regular logging
         | 
| 202 | 
            +
                        self.log_warning("pythonjsonlogger not available, using standard logging")
         |