claude-mpm 3.9.8__py3-none-any.whl → 3.9.9__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_agent.json +1 -1
- claude_mpm/cli/__init__.py +3 -1
- claude_mpm/cli/commands/__init__.py +3 -1
- claude_mpm/cli/commands/cleanup.py +21 -1
- claude_mpm/cli/commands/mcp.py +821 -0
- claude_mpm/cli/parser.py +148 -1
- claude_mpm/config/memory_guardian_config.py +325 -0
- claude_mpm/constants.py +13 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +76 -19
- claude_mpm/models/state_models.py +433 -0
- claude_mpm/services/communication/__init__.py +2 -2
- claude_mpm/services/communication/socketio.py +18 -16
- claude_mpm/services/infrastructure/__init__.py +4 -1
- claude_mpm/services/infrastructure/logging.py +3 -3
- claude_mpm/services/infrastructure/memory_guardian.py +770 -0
- claude_mpm/services/mcp_gateway/__init__.py +28 -12
- claude_mpm/services/mcp_gateway/main.py +326 -0
- claude_mpm/services/mcp_gateway/registry/__init__.py +6 -3
- claude_mpm/services/mcp_gateway/registry/service_registry.py +397 -0
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +477 -0
- claude_mpm/services/mcp_gateway/server/__init__.py +9 -3
- claude_mpm/services/mcp_gateway/server/mcp_server.py +430 -0
- claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +444 -0
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +373 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +16 -3
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +497 -0
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +729 -0
- claude_mpm/services/mcp_gateway/tools/hello_world.py +551 -0
- claude_mpm/utils/file_utils.py +293 -0
- claude_mpm/utils/platform_memory.py +524 -0
- claude_mpm/utils/subprocess_utils.py +305 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/METADATA +3 -1
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/RECORD +39 -28
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -36
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_agent.md +0 -39
- claude_mpm/agents/templates/.claude-mpm/memories/qa_agent.md +0 -38
- claude_mpm/agents/templates/.claude-mpm/memories/research_agent.md +0 -39
- claude_mpm/agents/templates/.claude-mpm/memories/version_control_agent.md +0 -38
- /claude_mpm/agents/templates/{research_memory_efficient.json → backup/research_memory_efficient.json} +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.9.8.dist-info → claude_mpm-3.9.9.dist-info}/top_level.txt +0 -0
| @@ -0,0 +1,433 @@ | |
| 1 | 
            +
            """State models for context preservation across Claude Code restarts.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This module defines data models for capturing and restoring various aspects
         | 
| 4 | 
            +
            of the Claude Code execution state to enable seamless restarts.
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Design Principles:
         | 
| 7 | 
            +
            - Comprehensive state capture (process, conversation, project, restart info)
         | 
| 8 | 
            +
            - Serialization-friendly data structures
         | 
| 9 | 
            +
            - Validation and sanitization of sensitive data
         | 
| 10 | 
            +
            - Platform-agnostic representations
         | 
| 11 | 
            +
            """
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            import os
         | 
| 14 | 
            +
            import json
         | 
| 15 | 
            +
            from dataclasses import dataclass, field, asdict
         | 
| 16 | 
            +
            from datetime import datetime
         | 
| 17 | 
            +
            from pathlib import Path
         | 
| 18 | 
            +
            from typing import Dict, Any, List, Optional, Set
         | 
| 19 | 
            +
            from enum import Enum
         | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 22 | 
            +
            class StateType(Enum):
         | 
| 23 | 
            +
                """Types of state that can be captured."""
         | 
| 24 | 
            +
                PROCESS = "process"
         | 
| 25 | 
            +
                CONVERSATION = "conversation"
         | 
| 26 | 
            +
                PROJECT = "project"
         | 
| 27 | 
            +
                RESTART = "restart"
         | 
| 28 | 
            +
                FULL = "full"
         | 
| 29 | 
            +
             | 
| 30 | 
            +
             | 
| 31 | 
            +
            @dataclass
         | 
| 32 | 
            +
            class ProcessState:
         | 
| 33 | 
            +
                """Process execution state information.
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                Captures the runtime state of the Claude Code process including
         | 
| 36 | 
            +
                environment, working directory, and command line arguments.
         | 
| 37 | 
            +
                """
         | 
| 38 | 
            +
                
         | 
| 39 | 
            +
                # Process identification
         | 
| 40 | 
            +
                pid: int
         | 
| 41 | 
            +
                parent_pid: int
         | 
| 42 | 
            +
                process_name: str
         | 
| 43 | 
            +
                
         | 
| 44 | 
            +
                # Execution context
         | 
| 45 | 
            +
                command: List[str]
         | 
| 46 | 
            +
                args: List[str]
         | 
| 47 | 
            +
                working_directory: str
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
                # Environment (filtered for security)
         | 
| 50 | 
            +
                environment: Dict[str, str]
         | 
| 51 | 
            +
                
         | 
| 52 | 
            +
                # Resource usage
         | 
| 53 | 
            +
                memory_mb: float
         | 
| 54 | 
            +
                cpu_percent: float
         | 
| 55 | 
            +
                open_files: List[str]
         | 
| 56 | 
            +
                
         | 
| 57 | 
            +
                # Timing
         | 
| 58 | 
            +
                start_time: float
         | 
| 59 | 
            +
                capture_time: float
         | 
| 60 | 
            +
                
         | 
| 61 | 
            +
                def to_dict(self) -> Dict[str, Any]:
         | 
| 62 | 
            +
                    """Convert to dictionary for serialization."""
         | 
| 63 | 
            +
                    return {
         | 
| 64 | 
            +
                        'pid': self.pid,
         | 
| 65 | 
            +
                        'parent_pid': self.parent_pid,
         | 
| 66 | 
            +
                        'process_name': self.process_name,
         | 
| 67 | 
            +
                        'command': self.command,
         | 
| 68 | 
            +
                        'args': self.args,
         | 
| 69 | 
            +
                        'working_directory': self.working_directory,
         | 
| 70 | 
            +
                        'environment': self._sanitize_environment(self.environment),
         | 
| 71 | 
            +
                        'memory_mb': round(self.memory_mb, 2),
         | 
| 72 | 
            +
                        'cpu_percent': round(self.cpu_percent, 2),
         | 
| 73 | 
            +
                        'open_files': self.open_files[:100],  # Limit to prevent huge lists
         | 
| 74 | 
            +
                        'start_time': self.start_time,
         | 
| 75 | 
            +
                        'start_time_iso': datetime.fromtimestamp(self.start_time).isoformat(),
         | 
| 76 | 
            +
                        'capture_time': self.capture_time,
         | 
| 77 | 
            +
                        'capture_time_iso': datetime.fromtimestamp(self.capture_time).isoformat()
         | 
| 78 | 
            +
                    }
         | 
| 79 | 
            +
                
         | 
| 80 | 
            +
                @staticmethod
         | 
| 81 | 
            +
                def _sanitize_environment(env: Dict[str, str]) -> Dict[str, str]:
         | 
| 82 | 
            +
                    """Remove sensitive environment variables."""
         | 
| 83 | 
            +
                    sensitive_patterns = [
         | 
| 84 | 
            +
                        'TOKEN', 'KEY', 'SECRET', 'PASSWORD', 'CREDENTIAL',
         | 
| 85 | 
            +
                        'API_KEY', 'AUTH', 'PRIVATE'
         | 
| 86 | 
            +
                    ]
         | 
| 87 | 
            +
                    
         | 
| 88 | 
            +
                    sanitized = {}
         | 
| 89 | 
            +
                    for key, value in env.items():
         | 
| 90 | 
            +
                        # Check if key contains sensitive patterns
         | 
| 91 | 
            +
                        is_sensitive = any(pattern in key.upper() for pattern in sensitive_patterns)
         | 
| 92 | 
            +
                        
         | 
| 93 | 
            +
                        if is_sensitive:
         | 
| 94 | 
            +
                            sanitized[key] = '***REDACTED***'
         | 
| 95 | 
            +
                        else:
         | 
| 96 | 
            +
                            sanitized[key] = value
         | 
| 97 | 
            +
                    
         | 
| 98 | 
            +
                    return sanitized
         | 
| 99 | 
            +
                
         | 
| 100 | 
            +
                @classmethod
         | 
| 101 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> 'ProcessState':
         | 
| 102 | 
            +
                    """Create from dictionary."""
         | 
| 103 | 
            +
                    return cls(
         | 
| 104 | 
            +
                        pid=data['pid'],
         | 
| 105 | 
            +
                        parent_pid=data['parent_pid'],
         | 
| 106 | 
            +
                        process_name=data['process_name'],
         | 
| 107 | 
            +
                        command=data['command'],
         | 
| 108 | 
            +
                        args=data['args'],
         | 
| 109 | 
            +
                        working_directory=data['working_directory'],
         | 
| 110 | 
            +
                        environment=data['environment'],
         | 
| 111 | 
            +
                        memory_mb=data['memory_mb'],
         | 
| 112 | 
            +
                        cpu_percent=data['cpu_percent'],
         | 
| 113 | 
            +
                        open_files=data['open_files'],
         | 
| 114 | 
            +
                        start_time=data['start_time'],
         | 
| 115 | 
            +
                        capture_time=data['capture_time']
         | 
| 116 | 
            +
                    )
         | 
| 117 | 
            +
             | 
| 118 | 
            +
             | 
| 119 | 
            +
            @dataclass
         | 
| 120 | 
            +
            class ConversationContext:
         | 
| 121 | 
            +
                """Represents a single conversation context."""
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                conversation_id: str
         | 
| 124 | 
            +
                title: str
         | 
| 125 | 
            +
                created_at: float
         | 
| 126 | 
            +
                updated_at: float
         | 
| 127 | 
            +
                message_count: int
         | 
| 128 | 
            +
                
         | 
| 129 | 
            +
                # Context window information
         | 
| 130 | 
            +
                total_tokens: int
         | 
| 131 | 
            +
                max_tokens: int
         | 
| 132 | 
            +
                
         | 
| 133 | 
            +
                # File references in conversation
         | 
| 134 | 
            +
                referenced_files: List[str]
         | 
| 135 | 
            +
                open_tabs: List[str]
         | 
| 136 | 
            +
                
         | 
| 137 | 
            +
                # Conversation metadata
         | 
| 138 | 
            +
                tags: List[str]
         | 
| 139 | 
            +
                is_active: bool
         | 
| 140 | 
            +
                
         | 
| 141 | 
            +
                def to_dict(self) -> Dict[str, Any]:
         | 
| 142 | 
            +
                    """Convert to dictionary."""
         | 
| 143 | 
            +
                    return asdict(self)
         | 
| 144 | 
            +
                
         | 
| 145 | 
            +
                @classmethod
         | 
| 146 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> 'ConversationContext':
         | 
| 147 | 
            +
                    """Create from dictionary."""
         | 
| 148 | 
            +
                    return cls(**data)
         | 
| 149 | 
            +
             | 
| 150 | 
            +
             | 
| 151 | 
            +
            @dataclass
         | 
| 152 | 
            +
            class ConversationState:
         | 
| 153 | 
            +
                """Claude conversation state and context.
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
                Captures the current conversation state including active conversations,
         | 
| 156 | 
            +
                context windows, and file references.
         | 
| 157 | 
            +
                """
         | 
| 158 | 
            +
                
         | 
| 159 | 
            +
                # Active conversation
         | 
| 160 | 
            +
                active_conversation_id: Optional[str]
         | 
| 161 | 
            +
                active_conversation: Optional[ConversationContext]
         | 
| 162 | 
            +
                
         | 
| 163 | 
            +
                # Recent conversations (for context)
         | 
| 164 | 
            +
                recent_conversations: List[ConversationContext]
         | 
| 165 | 
            +
                
         | 
| 166 | 
            +
                # Global context
         | 
| 167 | 
            +
                total_conversations: int
         | 
| 168 | 
            +
                total_storage_mb: float
         | 
| 169 | 
            +
                
         | 
| 170 | 
            +
                # User preferences preserved
         | 
| 171 | 
            +
                preferences: Dict[str, Any]
         | 
| 172 | 
            +
                
         | 
| 173 | 
            +
                # File state
         | 
| 174 | 
            +
                open_files: List[str]
         | 
| 175 | 
            +
                recent_files: List[str]
         | 
| 176 | 
            +
                pinned_files: List[str]
         | 
| 177 | 
            +
                
         | 
| 178 | 
            +
                def to_dict(self) -> Dict[str, Any]:
         | 
| 179 | 
            +
                    """Convert to dictionary for serialization."""
         | 
| 180 | 
            +
                    return {
         | 
| 181 | 
            +
                        'active_conversation_id': self.active_conversation_id,
         | 
| 182 | 
            +
                        'active_conversation': self.active_conversation.to_dict() if self.active_conversation else None,
         | 
| 183 | 
            +
                        'recent_conversations': [c.to_dict() for c in self.recent_conversations],
         | 
| 184 | 
            +
                        'total_conversations': self.total_conversations,
         | 
| 185 | 
            +
                        'total_storage_mb': round(self.total_storage_mb, 2),
         | 
| 186 | 
            +
                        'preferences': self.preferences,
         | 
| 187 | 
            +
                        'open_files': self.open_files,
         | 
| 188 | 
            +
                        'recent_files': self.recent_files,
         | 
| 189 | 
            +
                        'pinned_files': self.pinned_files
         | 
| 190 | 
            +
                    }
         | 
| 191 | 
            +
                
         | 
| 192 | 
            +
                @classmethod
         | 
| 193 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> 'ConversationState':
         | 
| 194 | 
            +
                    """Create from dictionary."""
         | 
| 195 | 
            +
                    return cls(
         | 
| 196 | 
            +
                        active_conversation_id=data.get('active_conversation_id'),
         | 
| 197 | 
            +
                        active_conversation=(
         | 
| 198 | 
            +
                            ConversationContext.from_dict(data['active_conversation'])
         | 
| 199 | 
            +
                            if data.get('active_conversation') else None
         | 
| 200 | 
            +
                        ),
         | 
| 201 | 
            +
                        recent_conversations=[
         | 
| 202 | 
            +
                            ConversationContext.from_dict(c)
         | 
| 203 | 
            +
                            for c in data.get('recent_conversations', [])
         | 
| 204 | 
            +
                        ],
         | 
| 205 | 
            +
                        total_conversations=data.get('total_conversations', 0),
         | 
| 206 | 
            +
                        total_storage_mb=data.get('total_storage_mb', 0.0),
         | 
| 207 | 
            +
                        preferences=data.get('preferences', {}),
         | 
| 208 | 
            +
                        open_files=data.get('open_files', []),
         | 
| 209 | 
            +
                        recent_files=data.get('recent_files', []),
         | 
| 210 | 
            +
                        pinned_files=data.get('pinned_files', [])
         | 
| 211 | 
            +
                    )
         | 
| 212 | 
            +
             | 
| 213 | 
            +
             | 
| 214 | 
            +
            @dataclass
         | 
| 215 | 
            +
            class ProjectState:
         | 
| 216 | 
            +
                """Project and Git repository state.
         | 
| 217 | 
            +
                
         | 
| 218 | 
            +
                Captures the current project context including Git branch,
         | 
| 219 | 
            +
                modified files, and project metadata.
         | 
| 220 | 
            +
                """
         | 
| 221 | 
            +
                
         | 
| 222 | 
            +
                # Project identification
         | 
| 223 | 
            +
                project_path: str
         | 
| 224 | 
            +
                project_name: str
         | 
| 225 | 
            +
                
         | 
| 226 | 
            +
                # Git state
         | 
| 227 | 
            +
                git_branch: Optional[str]
         | 
| 228 | 
            +
                git_commit: Optional[str]
         | 
| 229 | 
            +
                git_status: Dict[str, List[str]]  # staged, modified, untracked
         | 
| 230 | 
            +
                git_remotes: Dict[str, str]
         | 
| 231 | 
            +
                
         | 
| 232 | 
            +
                # File state
         | 
| 233 | 
            +
                modified_files: List[str]
         | 
| 234 | 
            +
                open_editors: List[str]
         | 
| 235 | 
            +
                breakpoints: Dict[str, List[int]]  # file -> line numbers
         | 
| 236 | 
            +
                
         | 
| 237 | 
            +
                # Project metadata
         | 
| 238 | 
            +
                project_type: str  # python, node, go, etc.
         | 
| 239 | 
            +
                dependencies: Dict[str, str]  # package -> version
         | 
| 240 | 
            +
                environment_vars: Dict[str, str]  # project-specific env vars
         | 
| 241 | 
            +
                
         | 
| 242 | 
            +
                # Build/test state
         | 
| 243 | 
            +
                last_build_status: Optional[str]
         | 
| 244 | 
            +
                last_test_results: Optional[Dict[str, Any]]
         | 
| 245 | 
            +
                
         | 
| 246 | 
            +
                def to_dict(self) -> Dict[str, Any]:
         | 
| 247 | 
            +
                    """Convert to dictionary for serialization."""
         | 
| 248 | 
            +
                    return {
         | 
| 249 | 
            +
                        'project_path': self.project_path,
         | 
| 250 | 
            +
                        'project_name': self.project_name,
         | 
| 251 | 
            +
                        'git_branch': self.git_branch,
         | 
| 252 | 
            +
                        'git_commit': self.git_commit,
         | 
| 253 | 
            +
                        'git_status': self.git_status,
         | 
| 254 | 
            +
                        'git_remotes': self.git_remotes,
         | 
| 255 | 
            +
                        'modified_files': self.modified_files,
         | 
| 256 | 
            +
                        'open_editors': self.open_editors,
         | 
| 257 | 
            +
                        'breakpoints': self.breakpoints,
         | 
| 258 | 
            +
                        'project_type': self.project_type,
         | 
| 259 | 
            +
                        'dependencies': self.dependencies,
         | 
| 260 | 
            +
                        'environment_vars': ProcessState._sanitize_environment(self.environment_vars),
         | 
| 261 | 
            +
                        'last_build_status': self.last_build_status,
         | 
| 262 | 
            +
                        'last_test_results': self.last_test_results
         | 
| 263 | 
            +
                    }
         | 
| 264 | 
            +
                
         | 
| 265 | 
            +
                @classmethod
         | 
| 266 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> 'ProjectState':
         | 
| 267 | 
            +
                    """Create from dictionary."""
         | 
| 268 | 
            +
                    return cls(
         | 
| 269 | 
            +
                        project_path=data['project_path'],
         | 
| 270 | 
            +
                        project_name=data['project_name'],
         | 
| 271 | 
            +
                        git_branch=data.get('git_branch'),
         | 
| 272 | 
            +
                        git_commit=data.get('git_commit'),
         | 
| 273 | 
            +
                        git_status=data.get('git_status', {}),
         | 
| 274 | 
            +
                        git_remotes=data.get('git_remotes', {}),
         | 
| 275 | 
            +
                        modified_files=data.get('modified_files', []),
         | 
| 276 | 
            +
                        open_editors=data.get('open_editors', []),
         | 
| 277 | 
            +
                        breakpoints=data.get('breakpoints', {}),
         | 
| 278 | 
            +
                        project_type=data.get('project_type', 'unknown'),
         | 
| 279 | 
            +
                        dependencies=data.get('dependencies', {}),
         | 
| 280 | 
            +
                        environment_vars=data.get('environment_vars', {}),
         | 
| 281 | 
            +
                        last_build_status=data.get('last_build_status'),
         | 
| 282 | 
            +
                        last_test_results=data.get('last_test_results')
         | 
| 283 | 
            +
                    )
         | 
| 284 | 
            +
             | 
| 285 | 
            +
             | 
| 286 | 
            +
            @dataclass
         | 
| 287 | 
            +
            class RestartState:
         | 
| 288 | 
            +
                """Information about the restart event.
         | 
| 289 | 
            +
                
         | 
| 290 | 
            +
                Captures why and when a restart occurred, along with relevant
         | 
| 291 | 
            +
                metrics at the time of restart.
         | 
| 292 | 
            +
                """
         | 
| 293 | 
            +
                
         | 
| 294 | 
            +
                # Restart identification
         | 
| 295 | 
            +
                restart_id: str
         | 
| 296 | 
            +
                restart_count: int
         | 
| 297 | 
            +
                
         | 
| 298 | 
            +
                # Timing
         | 
| 299 | 
            +
                timestamp: float
         | 
| 300 | 
            +
                previous_uptime: float
         | 
| 301 | 
            +
                
         | 
| 302 | 
            +
                # Reason and context
         | 
| 303 | 
            +
                reason: str
         | 
| 304 | 
            +
                trigger: str  # manual, memory, crash, scheduled
         | 
| 305 | 
            +
                
         | 
| 306 | 
            +
                # Metrics at restart
         | 
| 307 | 
            +
                memory_mb: float
         | 
| 308 | 
            +
                memory_limit_mb: float
         | 
| 309 | 
            +
                cpu_percent: float
         | 
| 310 | 
            +
                
         | 
| 311 | 
            +
                # Error information (if applicable)
         | 
| 312 | 
            +
                error_type: Optional[str]
         | 
| 313 | 
            +
                error_message: Optional[str]
         | 
| 314 | 
            +
                error_traceback: Optional[str]
         | 
| 315 | 
            +
                
         | 
| 316 | 
            +
                # Recovery information
         | 
| 317 | 
            +
                recovery_attempted: bool
         | 
| 318 | 
            +
                recovery_successful: bool
         | 
| 319 | 
            +
                data_preserved: List[str]  # Types of data preserved
         | 
| 320 | 
            +
                
         | 
| 321 | 
            +
                def to_dict(self) -> Dict[str, Any]:
         | 
| 322 | 
            +
                    """Convert to dictionary for serialization."""
         | 
| 323 | 
            +
                    return {
         | 
| 324 | 
            +
                        'restart_id': self.restart_id,
         | 
| 325 | 
            +
                        'restart_count': self.restart_count,
         | 
| 326 | 
            +
                        'timestamp': self.timestamp,
         | 
| 327 | 
            +
                        'timestamp_iso': datetime.fromtimestamp(self.timestamp).isoformat(),
         | 
| 328 | 
            +
                        'previous_uptime': self.previous_uptime,
         | 
| 329 | 
            +
                        'reason': self.reason,
         | 
| 330 | 
            +
                        'trigger': self.trigger,
         | 
| 331 | 
            +
                        'memory_mb': round(self.memory_mb, 2),
         | 
| 332 | 
            +
                        'memory_limit_mb': round(self.memory_limit_mb, 2),
         | 
| 333 | 
            +
                        'cpu_percent': round(self.cpu_percent, 2),
         | 
| 334 | 
            +
                        'error_type': self.error_type,
         | 
| 335 | 
            +
                        'error_message': self.error_message,
         | 
| 336 | 
            +
                        'error_traceback': self.error_traceback,
         | 
| 337 | 
            +
                        'recovery_attempted': self.recovery_attempted,
         | 
| 338 | 
            +
                        'recovery_successful': self.recovery_successful,
         | 
| 339 | 
            +
                        'data_preserved': self.data_preserved
         | 
| 340 | 
            +
                    }
         | 
| 341 | 
            +
                
         | 
| 342 | 
            +
                @classmethod
         | 
| 343 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> 'RestartState':
         | 
| 344 | 
            +
                    """Create from dictionary."""
         | 
| 345 | 
            +
                    return cls(
         | 
| 346 | 
            +
                        restart_id=data['restart_id'],
         | 
| 347 | 
            +
                        restart_count=data['restart_count'],
         | 
| 348 | 
            +
                        timestamp=data['timestamp'],
         | 
| 349 | 
            +
                        previous_uptime=data['previous_uptime'],
         | 
| 350 | 
            +
                        reason=data['reason'],
         | 
| 351 | 
            +
                        trigger=data['trigger'],
         | 
| 352 | 
            +
                        memory_mb=data['memory_mb'],
         | 
| 353 | 
            +
                        memory_limit_mb=data['memory_limit_mb'],
         | 
| 354 | 
            +
                        cpu_percent=data['cpu_percent'],
         | 
| 355 | 
            +
                        error_type=data.get('error_type'),
         | 
| 356 | 
            +
                        error_message=data.get('error_message'),
         | 
| 357 | 
            +
                        error_traceback=data.get('error_traceback'),
         | 
| 358 | 
            +
                        recovery_attempted=data.get('recovery_attempted', False),
         | 
| 359 | 
            +
                        recovery_successful=data.get('recovery_successful', False),
         | 
| 360 | 
            +
                        data_preserved=data.get('data_preserved', [])
         | 
| 361 | 
            +
                    )
         | 
| 362 | 
            +
             | 
| 363 | 
            +
             | 
| 364 | 
            +
            @dataclass
         | 
| 365 | 
            +
            class CompleteState:
         | 
| 366 | 
            +
                """Complete state snapshot combining all state components.
         | 
| 367 | 
            +
                
         | 
| 368 | 
            +
                This is the main state object that gets serialized and restored
         | 
| 369 | 
            +
                across Claude Code restarts.
         | 
| 370 | 
            +
                """
         | 
| 371 | 
            +
                
         | 
| 372 | 
            +
                # State components
         | 
| 373 | 
            +
                process_state: ProcessState
         | 
| 374 | 
            +
                conversation_state: ConversationState
         | 
| 375 | 
            +
                project_state: ProjectState
         | 
| 376 | 
            +
                restart_state: RestartState
         | 
| 377 | 
            +
                
         | 
| 378 | 
            +
                # Metadata
         | 
| 379 | 
            +
                state_version: str = "1.0.0"
         | 
| 380 | 
            +
                state_id: str = field(default_factory=lambda: datetime.now().strftime("%Y%m%d_%H%M%S"))
         | 
| 381 | 
            +
                created_at: float = field(default_factory=lambda: datetime.now().timestamp())
         | 
| 382 | 
            +
                
         | 
| 383 | 
            +
                def to_dict(self) -> Dict[str, Any]:
         | 
| 384 | 
            +
                    """Convert to dictionary for serialization."""
         | 
| 385 | 
            +
                    return {
         | 
| 386 | 
            +
                        'state_version': self.state_version,
         | 
| 387 | 
            +
                        'state_id': self.state_id,
         | 
| 388 | 
            +
                        'created_at': self.created_at,
         | 
| 389 | 
            +
                        'created_at_iso': datetime.fromtimestamp(self.created_at).isoformat(),
         | 
| 390 | 
            +
                        'process': self.process_state.to_dict(),
         | 
| 391 | 
            +
                        'conversation': self.conversation_state.to_dict(),
         | 
| 392 | 
            +
                        'project': self.project_state.to_dict(),
         | 
| 393 | 
            +
                        'restart': self.restart_state.to_dict()
         | 
| 394 | 
            +
                    }
         | 
| 395 | 
            +
                
         | 
| 396 | 
            +
                @classmethod
         | 
| 397 | 
            +
                def from_dict(cls, data: Dict[str, Any]) -> 'CompleteState':
         | 
| 398 | 
            +
                    """Create from dictionary."""
         | 
| 399 | 
            +
                    return cls(
         | 
| 400 | 
            +
                        state_version=data.get('state_version', '1.0.0'),
         | 
| 401 | 
            +
                        state_id=data.get('state_id'),
         | 
| 402 | 
            +
                        created_at=data.get('created_at'),
         | 
| 403 | 
            +
                        process_state=ProcessState.from_dict(data['process']),
         | 
| 404 | 
            +
                        conversation_state=ConversationState.from_dict(data['conversation']),
         | 
| 405 | 
            +
                        project_state=ProjectState.from_dict(data['project']),
         | 
| 406 | 
            +
                        restart_state=RestartState.from_dict(data['restart'])
         | 
| 407 | 
            +
                    )
         | 
| 408 | 
            +
                
         | 
| 409 | 
            +
                def validate(self) -> List[str]:
         | 
| 410 | 
            +
                    """Validate state data and return list of issues."""
         | 
| 411 | 
            +
                    issues = []
         | 
| 412 | 
            +
                    
         | 
| 413 | 
            +
                    # Check required fields
         | 
| 414 | 
            +
                    if not self.state_id:
         | 
| 415 | 
            +
                        issues.append("State ID is required")
         | 
| 416 | 
            +
                    
         | 
| 417 | 
            +
                    if not self.process_state.pid:
         | 
| 418 | 
            +
                        issues.append("Process PID is required")
         | 
| 419 | 
            +
                    
         | 
| 420 | 
            +
                    if not self.project_state.project_path:
         | 
| 421 | 
            +
                        issues.append("Project path is required")
         | 
| 422 | 
            +
                    
         | 
| 423 | 
            +
                    # Check path validity
         | 
| 424 | 
            +
                    if self.project_state.project_path:
         | 
| 425 | 
            +
                        project_path = Path(self.project_state.project_path)
         | 
| 426 | 
            +
                        if not project_path.exists():
         | 
| 427 | 
            +
                            issues.append(f"Project path does not exist: {project_path}")
         | 
| 428 | 
            +
                    
         | 
| 429 | 
            +
                    # Check state version compatibility
         | 
| 430 | 
            +
                    if self.state_version != "1.0.0":
         | 
| 431 | 
            +
                        issues.append(f"Unsupported state version: {self.state_version}")
         | 
| 432 | 
            +
                    
         | 
| 433 | 
            +
                    return issues
         | 
| @@ -13,9 +13,9 @@ Services: | |
| 13 13 | 
             
            """
         | 
| 14 14 |  | 
| 15 15 | 
             
            from .socketio import SocketIOServer
         | 
| 16 | 
            -
            from .websocket import SocketIOClientManager
         | 
| 16 | 
            +
            # from .websocket import SocketIOClientManager  # Module has import issues
         | 
| 17 17 |  | 
| 18 18 | 
             
            __all__ = [
         | 
| 19 19 | 
             
                'SocketIOServer',
         | 
| 20 | 
            -
                'SocketIOClientManager',
         | 
| 20 | 
            +
                # 'SocketIOClientManager',
         | 
| 21 21 | 
             
            ]
         | 
| @@ -31,17 +31,17 @@ except ImportError: | |
| 31 31 | 
             
                web = None
         | 
| 32 32 | 
             
                # Don't print warnings at module level
         | 
| 33 33 |  | 
| 34 | 
            -
            from  | 
| 35 | 
            -
            from  | 
| 36 | 
            -
            from .socketio.handlers import EventHandlerRegistry, FileEventHandler, GitEventHandler
         | 
| 37 | 
            -
            from  | 
| 34 | 
            +
            from claude_mpm.core.logging_config import get_logger, log_operation, log_performance_context
         | 
| 35 | 
            +
            from claude_mpm.deployment_paths import get_project_root, get_scripts_dir
         | 
| 36 | 
            +
            # from .socketio.handlers import EventHandlerRegistry, FileEventHandler, GitEventHandler  # Module not found, commenting out
         | 
| 37 | 
            +
            from claude_mpm.core.constants import (
         | 
| 38 38 | 
             
                SystemLimits,
         | 
| 39 39 | 
             
                NetworkConfig,
         | 
| 40 40 | 
             
                TimeoutConfig,
         | 
| 41 41 | 
             
                PerformanceConfig
         | 
| 42 42 | 
             
            )
         | 
| 43 | 
            -
            from  | 
| 44 | 
            -
            from  | 
| 43 | 
            +
            from claude_mpm.core.interfaces import SocketIOServiceInterface
         | 
| 44 | 
            +
            from claude_mpm.services.exceptions import SocketIOServerError as MPMConnectionError
         | 
| 45 45 |  | 
| 46 46 |  | 
| 47 47 | 
             
            class SocketIOClientProxy:
         | 
| @@ -1030,24 +1030,26 @@ class SocketIOServer(SocketIOServiceInterface): | |
| 1030 1030 | 
             
                    handlers in a modular way. Each handler focuses on a specific domain,
         | 
| 1031 1031 | 
             
                    reducing complexity and improving maintainability.
         | 
| 1032 1032 | 
             
                    """
         | 
| 1033 | 
            -
                    #  | 
| 1034 | 
            -
                     | 
| 1035 | 
            -
                    self.event_registry | 
| 1033 | 
            +
                    # Handler registry not available - skip handler-based registration
         | 
| 1034 | 
            +
                    # # Initialize the event handler registry
         | 
| 1035 | 
            +
                    # self.event_registry = EventHandlerRegistry(self)
         | 
| 1036 | 
            +
                    # self.event_registry.initialize()
         | 
| 1036 1037 |  | 
| 1037 | 
            -
                    # Register all events from all handlers
         | 
| 1038 | 
            -
                    self.event_registry.register_all_events()
         | 
| 1038 | 
            +
                    # # Register all events from all handlers
         | 
| 1039 | 
            +
                    # self.event_registry.register_all_events()
         | 
| 1039 1040 |  | 
| 1040 | 
            -
                    # Keep handler instances for HTTP endpoint compatibility
         | 
| 1041 | 
            -
                    self.file_handler = self.event_registry.get_handler(FileEventHandler)
         | 
| 1042 | 
            -
                    self.git_handler = self.event_registry.get_handler(GitEventHandler)
         | 
| 1041 | 
            +
                    # # Keep handler instances for HTTP endpoint compatibility
         | 
| 1042 | 
            +
                    # self.file_handler = self.event_registry.get_handler(FileEventHandler)
         | 
| 1043 | 
            +
                    # self.git_handler = self.event_registry.get_handler(GitEventHandler)
         | 
| 1043 1044 |  | 
| 1044 | 
            -
                    self.logger.info("All Socket.IO events registered via handler system")
         | 
| 1045 | 
            +
                    # self.logger.info("All Socket.IO events registered via handler system")
         | 
| 1045 1046 |  | 
| 1046 1047 | 
             
                    # Note: The actual event registration is now handled by individual
         | 
| 1047 1048 | 
             
                    # handler classes in socketio/handlers/. This dramatically reduces
         | 
| 1048 1049 | 
             
                    # the complexity of this method from 514 lines to under 20 lines.
         | 
| 1049 1050 |  | 
| 1050 | 
            -
                     | 
| 1051 | 
            +
                    # Continue with old implementation since handlers are not available
         | 
| 1052 | 
            +
                    # return  # Early return to skip old implementation
         | 
| 1051 1053 |  | 
| 1052 1054 | 
             
                    @self.sio.event
         | 
| 1053 1055 | 
             
                    async def connect(sid, environ, *args):
         | 
| @@ -10,12 +10,15 @@ Part of TSK-0046: Service Layer Architecture Reorganization | |
| 10 10 | 
             
            Services:
         | 
| 11 11 | 
             
            - LoggingService: Centralized logging with structured output
         | 
| 12 12 | 
             
            - HealthMonitor: System health monitoring and alerting
         | 
| 13 | 
            +
            - MemoryGuardian: Memory monitoring and process restart management
         | 
| 13 14 | 
             
            """
         | 
| 14 15 |  | 
| 15 16 | 
             
            from .logging import LoggingService
         | 
| 16 | 
            -
            from .monitoring import HealthMonitor
         | 
| 17 | 
            +
            from .monitoring import AdvancedHealthMonitor as HealthMonitor
         | 
| 18 | 
            +
            from .memory_guardian import MemoryGuardian
         | 
| 17 19 |  | 
| 18 20 | 
             
            __all__ = [
         | 
| 19 21 | 
             
                'LoggingService',
         | 
| 20 22 | 
             
                'HealthMonitor',
         | 
| 23 | 
            +
                'MemoryGuardian',
         | 
| 21 24 | 
             
            ]
         | 
| @@ -13,11 +13,11 @@ import logging | |
| 13 13 | 
             
            import json
         | 
| 14 14 | 
             
            from datetime import datetime
         | 
| 15 15 |  | 
| 16 | 
            -
            from claude_mpm.services.core import SyncBaseService,  | 
| 17 | 
            -
            from claude_mpm. | 
| 16 | 
            +
            from claude_mpm.services.core import SyncBaseService, IStructuredLogger
         | 
| 17 | 
            +
            from claude_mpm.core.logger import get_logger
         | 
| 18 18 |  | 
| 19 19 |  | 
| 20 | 
            -
            class LoggingService(SyncBaseService,  | 
| 20 | 
            +
            class LoggingService(SyncBaseService, IStructuredLogger):
         | 
| 21 21 | 
             
                """
         | 
| 22 22 | 
             
                Centralized logging service for the Claude MPM framework.
         | 
| 23 23 |  |