claude-mpm 3.1.2__py3-none-any.whl → 3.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/__init__.py +3 -3
 - claude_mpm/agents/INSTRUCTIONS.md +80 -2
 - claude_mpm/agents/backups/INSTRUCTIONS.md +238 -0
 - claude_mpm/agents/base_agent.json +1 -1
 - claude_mpm/agents/templates/pm.json +25 -0
 - claude_mpm/agents/templates/research.json +2 -1
 - claude_mpm/cli/__init__.py +6 -1
 - claude_mpm/cli/commands/__init__.py +3 -1
 - claude_mpm/cli/commands/memory.py +232 -0
 - claude_mpm/cli/commands/run.py +496 -8
 - claude_mpm/cli/parser.py +91 -1
 - claude_mpm/config/socketio_config.py +256 -0
 - claude_mpm/constants.py +9 -0
 - claude_mpm/core/__init__.py +2 -2
 - claude_mpm/core/claude_runner.py +919 -0
 - claude_mpm/core/config.py +21 -1
 - claude_mpm/core/hook_manager.py +196 -0
 - claude_mpm/core/pm_hook_interceptor.py +205 -0
 - claude_mpm/core/simple_runner.py +296 -16
 - claude_mpm/core/socketio_pool.py +582 -0
 - claude_mpm/core/websocket_handler.py +233 -0
 - claude_mpm/deployment_paths.py +261 -0
 - claude_mpm/hooks/builtin/memory_hooks_example.py +67 -0
 - claude_mpm/hooks/claude_hooks/hook_handler.py +669 -632
 - claude_mpm/hooks/claude_hooks/hook_wrapper.sh +9 -4
 - claude_mpm/hooks/memory_integration_hook.py +312 -0
 - claude_mpm/orchestration/__init__.py +1 -1
 - claude_mpm/scripts/claude-mpm-socketio +32 -0
 - claude_mpm/scripts/claude_mpm_monitor.html +567 -0
 - claude_mpm/scripts/install_socketio_server.py +407 -0
 - claude_mpm/scripts/launch_monitor.py +132 -0
 - claude_mpm/scripts/manage_version.py +479 -0
 - claude_mpm/scripts/socketio_daemon.py +181 -0
 - claude_mpm/scripts/socketio_server_manager.py +428 -0
 - claude_mpm/services/__init__.py +5 -0
 - claude_mpm/services/agent_memory_manager.py +684 -0
 - claude_mpm/services/hook_service.py +362 -0
 - claude_mpm/services/socketio_client_manager.py +474 -0
 - claude_mpm/services/socketio_server.py +698 -0
 - claude_mpm/services/standalone_socketio_server.py +631 -0
 - claude_mpm/services/websocket_server.py +376 -0
 - claude_mpm/utils/dependency_manager.py +211 -0
 - claude_mpm/web/open_dashboard.py +34 -0
 - {claude_mpm-3.1.2.dist-info → claude_mpm-3.2.1.dist-info}/METADATA +20 -1
 - {claude_mpm-3.1.2.dist-info → claude_mpm-3.2.1.dist-info}/RECORD +50 -24
 - claude_mpm-3.2.1.dist-info/entry_points.txt +7 -0
 - claude_mpm/cli_old.py +0 -728
 - claude_mpm-3.1.2.dist-info/entry_points.txt +0 -4
 - /claude_mpm/{cli_enhancements.py → experimental/cli_enhancements.py} +0 -0
 - {claude_mpm-3.1.2.dist-info → claude_mpm-3.2.1.dist-info}/WHEEL +0 -0
 - {claude_mpm-3.1.2.dist-info → claude_mpm-3.2.1.dist-info}/licenses/LICENSE +0 -0
 - {claude_mpm-3.1.2.dist-info → claude_mpm-3.2.1.dist-info}/top_level.txt +0 -0
 
| 
         @@ -0,0 +1,256 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            """Socket.IO server configuration for different deployment scenarios.
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            This module provides configuration management for Socket.IO servers
         
     | 
| 
      
 4 
     | 
    
         
            +
            across different deployment environments and installation methods.
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            WHY configuration management:
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Enables different settings for development vs production
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Supports multiple deployment scenarios (local, PyPI, Docker, etc.)
         
     | 
| 
      
 9 
     | 
    
         
            +
            - Provides environment-specific defaults
         
     | 
| 
      
 10 
     | 
    
         
            +
            - Allows runtime configuration overrides
         
     | 
| 
      
 11 
     | 
    
         
            +
            """
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            import os
         
     | 
| 
      
 14 
     | 
    
         
            +
            from dataclasses import dataclass
         
     | 
| 
      
 15 
     | 
    
         
            +
            from pathlib import Path
         
     | 
| 
      
 16 
     | 
    
         
            +
            from typing import Dict, Any, List, Optional
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            @dataclass
         
     | 
| 
      
 20 
     | 
    
         
            +
            class SocketIOConfig:
         
     | 
| 
      
 21 
     | 
    
         
            +
                """Configuration for Socket.IO server instances."""
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
      
 23 
     | 
    
         
            +
                # Server settings
         
     | 
| 
      
 24 
     | 
    
         
            +
                host: str = "localhost"
         
     | 
| 
      
 25 
     | 
    
         
            +
                port: int = 8765
         
     | 
| 
      
 26 
     | 
    
         
            +
                server_id: Optional[str] = None
         
     | 
| 
      
 27 
     | 
    
         
            +
                
         
     | 
| 
      
 28 
     | 
    
         
            +
                # Connection settings
         
     | 
| 
      
 29 
     | 
    
         
            +
                cors_allowed_origins: str = "*"  # Configure properly for production
         
     | 
| 
      
 30 
     | 
    
         
            +
                ping_timeout: int = 60
         
     | 
| 
      
 31 
     | 
    
         
            +
                ping_interval: int = 25
         
     | 
| 
      
 32 
     | 
    
         
            +
                max_http_buffer_size: int = 1000000
         
     | 
| 
      
 33 
     | 
    
         
            +
                
         
     | 
| 
      
 34 
     | 
    
         
            +
                # Compatibility settings
         
     | 
| 
      
 35 
     | 
    
         
            +
                min_client_version: str = "0.7.0"
         
     | 
| 
      
 36 
     | 
    
         
            +
                max_history_size: int = 10000
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
                # Deployment settings
         
     | 
| 
      
 39 
     | 
    
         
            +
                deployment_mode: str = "auto"  # auto, standalone, embedded, client
         
     | 
| 
      
 40 
     | 
    
         
            +
                auto_start: bool = True
         
     | 
| 
      
 41 
     | 
    
         
            +
                persistent: bool = True
         
     | 
| 
      
 42 
     | 
    
         
            +
                
         
     | 
| 
      
 43 
     | 
    
         
            +
                # Logging settings
         
     | 
| 
      
 44 
     | 
    
         
            +
                log_level: str = "INFO"
         
     | 
| 
      
 45 
     | 
    
         
            +
                log_to_file: bool = False
         
     | 
| 
      
 46 
     | 
    
         
            +
                log_file_path: Optional[str] = None
         
     | 
| 
      
 47 
     | 
    
         
            +
                
         
     | 
| 
      
 48 
     | 
    
         
            +
                # Health monitoring
         
     | 
| 
      
 49 
     | 
    
         
            +
                health_check_interval: int = 30
         
     | 
| 
      
 50 
     | 
    
         
            +
                max_connection_attempts: int = 3
         
     | 
| 
      
 51 
     | 
    
         
            +
                reconnection_delay: int = 1
         
     | 
| 
      
 52 
     | 
    
         
            +
                
         
     | 
| 
      
 53 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 54 
     | 
    
         
            +
                def from_env(cls) -> 'SocketIOConfig':
         
     | 
| 
      
 55 
     | 
    
         
            +
                    """Create configuration from environment variables."""
         
     | 
| 
      
 56 
     | 
    
         
            +
                    return cls(
         
     | 
| 
      
 57 
     | 
    
         
            +
                        host=os.getenv('CLAUDE_MPM_SOCKETIO_HOST', 'localhost'),
         
     | 
| 
      
 58 
     | 
    
         
            +
                        port=int(os.getenv('CLAUDE_MPM_SOCKETIO_PORT', '8765')),
         
     | 
| 
      
 59 
     | 
    
         
            +
                        server_id=os.getenv('CLAUDE_MPM_SOCKETIO_SERVER_ID'),
         
     | 
| 
      
 60 
     | 
    
         
            +
                        cors_allowed_origins=os.getenv('CLAUDE_MPM_SOCKETIO_CORS', '*'),
         
     | 
| 
      
 61 
     | 
    
         
            +
                        ping_timeout=int(os.getenv('CLAUDE_MPM_SOCKETIO_PING_TIMEOUT', '60')),
         
     | 
| 
      
 62 
     | 
    
         
            +
                        ping_interval=int(os.getenv('CLAUDE_MPM_SOCKETIO_PING_INTERVAL', '25')),
         
     | 
| 
      
 63 
     | 
    
         
            +
                        deployment_mode=os.getenv('CLAUDE_MPM_SOCKETIO_MODE', 'auto'),
         
     | 
| 
      
 64 
     | 
    
         
            +
                        auto_start=os.getenv('CLAUDE_MPM_SOCKETIO_AUTO_START', 'true').lower() == 'true',
         
     | 
| 
      
 65 
     | 
    
         
            +
                        persistent=os.getenv('CLAUDE_MPM_SOCKETIO_PERSISTENT', 'true').lower() == 'true',
         
     | 
| 
      
 66 
     | 
    
         
            +
                        log_level=os.getenv('CLAUDE_MPM_SOCKETIO_LOG_LEVEL', 'INFO'),
         
     | 
| 
      
 67 
     | 
    
         
            +
                        max_history_size=int(os.getenv('CLAUDE_MPM_SOCKETIO_HISTORY_SIZE', '10000'))
         
     | 
| 
      
 68 
     | 
    
         
            +
                    )
         
     | 
| 
      
 69 
     | 
    
         
            +
                
         
     | 
| 
      
 70 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 71 
     | 
    
         
            +
                def for_development(cls) -> 'SocketIOConfig':
         
     | 
| 
      
 72 
     | 
    
         
            +
                    """Configuration optimized for development."""
         
     | 
| 
      
 73 
     | 
    
         
            +
                    return cls(
         
     | 
| 
      
 74 
     | 
    
         
            +
                        host="localhost",
         
     | 
| 
      
 75 
     | 
    
         
            +
                        port=8765,
         
     | 
| 
      
 76 
     | 
    
         
            +
                        deployment_mode="auto",
         
     | 
| 
      
 77 
     | 
    
         
            +
                        log_level="DEBUG",
         
     | 
| 
      
 78 
     | 
    
         
            +
                        ping_timeout=30,
         
     | 
| 
      
 79 
     | 
    
         
            +
                        ping_interval=10,
         
     | 
| 
      
 80 
     | 
    
         
            +
                        max_history_size=5000
         
     | 
| 
      
 81 
     | 
    
         
            +
                    )
         
     | 
| 
      
 82 
     | 
    
         
            +
                
         
     | 
| 
      
 83 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 84 
     | 
    
         
            +
                def for_production(cls) -> 'SocketIOConfig':
         
     | 
| 
      
 85 
     | 
    
         
            +
                    """Configuration optimized for production."""
         
     | 
| 
      
 86 
     | 
    
         
            +
                    return cls(
         
     | 
| 
      
 87 
     | 
    
         
            +
                        host="0.0.0.0",  # Bind to all interfaces in production
         
     | 
| 
      
 88 
     | 
    
         
            +
                        port=8765,
         
     | 
| 
      
 89 
     | 
    
         
            +
                        cors_allowed_origins="https://your-domain.com",  # Restrict CORS
         
     | 
| 
      
 90 
     | 
    
         
            +
                        deployment_mode="standalone",
         
     | 
| 
      
 91 
     | 
    
         
            +
                        persistent=True,
         
     | 
| 
      
 92 
     | 
    
         
            +
                        log_level="INFO",
         
     | 
| 
      
 93 
     | 
    
         
            +
                        log_to_file=True,
         
     | 
| 
      
 94 
     | 
    
         
            +
                        log_file_path="/var/log/claude-mpm-socketio.log",
         
     | 
| 
      
 95 
     | 
    
         
            +
                        ping_timeout=120,
         
     | 
| 
      
 96 
     | 
    
         
            +
                        ping_interval=30,
         
     | 
| 
      
 97 
     | 
    
         
            +
                        max_history_size=20000
         
     | 
| 
      
 98 
     | 
    
         
            +
                    )
         
     | 
| 
      
 99 
     | 
    
         
            +
                
         
     | 
| 
      
 100 
     | 
    
         
            +
                @classmethod
         
     | 
| 
      
 101 
     | 
    
         
            +
                def for_docker(cls) -> 'SocketIOConfig':
         
     | 
| 
      
 102 
     | 
    
         
            +
                    """Configuration optimized for Docker deployment."""
         
     | 
| 
      
 103 
     | 
    
         
            +
                    return cls(
         
     | 
| 
      
 104 
     | 
    
         
            +
                        host="0.0.0.0",
         
     | 
| 
      
 105 
     | 
    
         
            +
                        port=8765,
         
     | 
| 
      
 106 
     | 
    
         
            +
                        deployment_mode="standalone",
         
     | 
| 
      
 107 
     | 
    
         
            +
                        persistent=True,
         
     | 
| 
      
 108 
     | 
    
         
            +
                        log_level="INFO",
         
     | 
| 
      
 109 
     | 
    
         
            +
                        ping_timeout=90,
         
     | 
| 
      
 110 
     | 
    
         
            +
                        ping_interval=25,
         
     | 
| 
      
 111 
     | 
    
         
            +
                        max_history_size=15000
         
     | 
| 
      
 112 
     | 
    
         
            +
                    )
         
     | 
| 
      
 113 
     | 
    
         
            +
                
         
     | 
| 
      
 114 
     | 
    
         
            +
                def to_dict(self) -> Dict[str, Any]:
         
     | 
| 
      
 115 
     | 
    
         
            +
                    """Convert configuration to dictionary."""
         
     | 
| 
      
 116 
     | 
    
         
            +
                    return {
         
     | 
| 
      
 117 
     | 
    
         
            +
                        'host': self.host,
         
     | 
| 
      
 118 
     | 
    
         
            +
                        'port': self.port,
         
     | 
| 
      
 119 
     | 
    
         
            +
                        'server_id': self.server_id,
         
     | 
| 
      
 120 
     | 
    
         
            +
                        'cors_allowed_origins': self.cors_allowed_origins,
         
     | 
| 
      
 121 
     | 
    
         
            +
                        'ping_timeout': self.ping_timeout,
         
     | 
| 
      
 122 
     | 
    
         
            +
                        'ping_interval': self.ping_interval,
         
     | 
| 
      
 123 
     | 
    
         
            +
                        'max_http_buffer_size': self.max_http_buffer_size,
         
     | 
| 
      
 124 
     | 
    
         
            +
                        'min_client_version': self.min_client_version,
         
     | 
| 
      
 125 
     | 
    
         
            +
                        'max_history_size': self.max_history_size,
         
     | 
| 
      
 126 
     | 
    
         
            +
                        'deployment_mode': self.deployment_mode,
         
     | 
| 
      
 127 
     | 
    
         
            +
                        'auto_start': self.auto_start,
         
     | 
| 
      
 128 
     | 
    
         
            +
                        'persistent': self.persistent,
         
     | 
| 
      
 129 
     | 
    
         
            +
                        'log_level': self.log_level,
         
     | 
| 
      
 130 
     | 
    
         
            +
                        'log_to_file': self.log_to_file,
         
     | 
| 
      
 131 
     | 
    
         
            +
                        'log_file_path': self.log_file_path,
         
     | 
| 
      
 132 
     | 
    
         
            +
                        'health_check_interval': self.health_check_interval,
         
     | 
| 
      
 133 
     | 
    
         
            +
                        'max_connection_attempts': self.max_connection_attempts,
         
     | 
| 
      
 134 
     | 
    
         
            +
                        'reconnection_delay': self.reconnection_delay
         
     | 
| 
      
 135 
     | 
    
         
            +
                    }
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
            class ConfigManager:
         
     | 
| 
      
 139 
     | 
    
         
            +
                """Manages Socket.IO configuration across different environments."""
         
     | 
| 
      
 140 
     | 
    
         
            +
                
         
     | 
| 
      
 141 
     | 
    
         
            +
                def __init__(self):
         
     | 
| 
      
 142 
     | 
    
         
            +
                    self.config_file_name = "socketio_config.json"
         
     | 
| 
      
 143 
     | 
    
         
            +
                    self.config_search_paths = [
         
     | 
| 
      
 144 
     | 
    
         
            +
                        Path.cwd() / self.config_file_name,  # Current directory
         
     | 
| 
      
 145 
     | 
    
         
            +
                        Path.home() / ".claude-mpm" / self.config_file_name,  # User home
         
     | 
| 
      
 146 
     | 
    
         
            +
                        Path("/etc/claude-mpm") / self.config_file_name,  # System config
         
     | 
| 
      
 147 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 148 
     | 
    
         
            +
                
         
     | 
| 
      
 149 
     | 
    
         
            +
                def detect_environment(self) -> str:
         
     | 
| 
      
 150 
     | 
    
         
            +
                    """Detect the current deployment environment."""
         
     | 
| 
      
 151 
     | 
    
         
            +
                    # Check for Docker
         
     | 
| 
      
 152 
     | 
    
         
            +
                    if os.path.exists('/.dockerenv') or os.getenv('DOCKER_CONTAINER'):
         
     | 
| 
      
 153 
     | 
    
         
            +
                        return "docker"
         
     | 
| 
      
 154 
     | 
    
         
            +
                    
         
     | 
| 
      
 155 
     | 
    
         
            +
                    # Check for production indicators
         
     | 
| 
      
 156 
     | 
    
         
            +
                    if os.getenv('ENVIRONMENT') == 'production' or os.getenv('NODE_ENV') == 'production':
         
     | 
| 
      
 157 
     | 
    
         
            +
                        return "production"
         
     | 
| 
      
 158 
     | 
    
         
            +
                    
         
     | 
| 
      
 159 
     | 
    
         
            +
                    # Check if running from installed package
         
     | 
| 
      
 160 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 161 
     | 
    
         
            +
                        import claude_mpm
         
     | 
| 
      
 162 
     | 
    
         
            +
                        pkg_path = Path(claude_mpm.__file__).parent
         
     | 
| 
      
 163 
     | 
    
         
            +
                        if 'site-packages' in str(pkg_path) or 'dist-packages' in str(pkg_path):
         
     | 
| 
      
 164 
     | 
    
         
            +
                            return "installed"
         
     | 
| 
      
 165 
     | 
    
         
            +
                    except ImportError:
         
     | 
| 
      
 166 
     | 
    
         
            +
                        pass
         
     | 
| 
      
 167 
     | 
    
         
            +
                    
         
     | 
| 
      
 168 
     | 
    
         
            +
                    # Default to development
         
     | 
| 
      
 169 
     | 
    
         
            +
                    return "development"
         
     | 
| 
      
 170 
     | 
    
         
            +
                
         
     | 
| 
      
 171 
     | 
    
         
            +
                def get_config(self, environment: str = None) -> SocketIOConfig:
         
     | 
| 
      
 172 
     | 
    
         
            +
                    """Get configuration for the specified environment."""
         
     | 
| 
      
 173 
     | 
    
         
            +
                    if environment is None:
         
     | 
| 
      
 174 
     | 
    
         
            +
                        environment = self.detect_environment()
         
     | 
| 
      
 175 
     | 
    
         
            +
                    
         
     | 
| 
      
 176 
     | 
    
         
            +
                    # Start with environment-specific defaults
         
     | 
| 
      
 177 
     | 
    
         
            +
                    if environment == "production":
         
     | 
| 
      
 178 
     | 
    
         
            +
                        config = SocketIOConfig.for_production()
         
     | 
| 
      
 179 
     | 
    
         
            +
                    elif environment == "docker":
         
     | 
| 
      
 180 
     | 
    
         
            +
                        config = SocketIOConfig.for_docker()
         
     | 
| 
      
 181 
     | 
    
         
            +
                    elif environment == "development":
         
     | 
| 
      
 182 
     | 
    
         
            +
                        config = SocketIOConfig.for_development()
         
     | 
| 
      
 183 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 184 
     | 
    
         
            +
                        config = SocketIOConfig()
         
     | 
| 
      
 185 
     | 
    
         
            +
                    
         
     | 
| 
      
 186 
     | 
    
         
            +
                    # Override with environment variables
         
     | 
| 
      
 187 
     | 
    
         
            +
                    env_config = SocketIOConfig.from_env()
         
     | 
| 
      
 188 
     | 
    
         
            +
                    for field in config.__dataclass_fields__:
         
     | 
| 
      
 189 
     | 
    
         
            +
                        env_value = getattr(env_config, field)
         
     | 
| 
      
 190 
     | 
    
         
            +
                        if env_value != getattr(SocketIOConfig(), field):  # Only if different from default
         
     | 
| 
      
 191 
     | 
    
         
            +
                            setattr(config, field, env_value)
         
     | 
| 
      
 192 
     | 
    
         
            +
                    
         
     | 
| 
      
 193 
     | 
    
         
            +
                    # Override with config file if available
         
     | 
| 
      
 194 
     | 
    
         
            +
                    config_file_data = self._load_config_file()
         
     | 
| 
      
 195 
     | 
    
         
            +
                    if config_file_data:
         
     | 
| 
      
 196 
     | 
    
         
            +
                        for key, value in config_file_data.items():
         
     | 
| 
      
 197 
     | 
    
         
            +
                            if hasattr(config, key):
         
     | 
| 
      
 198 
     | 
    
         
            +
                                setattr(config, key, value)
         
     | 
| 
      
 199 
     | 
    
         
            +
                    
         
     | 
| 
      
 200 
     | 
    
         
            +
                    return config
         
     | 
| 
      
 201 
     | 
    
         
            +
                
         
     | 
| 
      
 202 
     | 
    
         
            +
                def _load_config_file(self) -> Optional[Dict[str, Any]]:
         
     | 
| 
      
 203 
     | 
    
         
            +
                    """Load configuration from file if available."""
         
     | 
| 
      
 204 
     | 
    
         
            +
                    import json
         
     | 
| 
      
 205 
     | 
    
         
            +
                    
         
     | 
| 
      
 206 
     | 
    
         
            +
                    for config_path in self.config_search_paths:
         
     | 
| 
      
 207 
     | 
    
         
            +
                        if config_path.exists():
         
     | 
| 
      
 208 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 209 
     | 
    
         
            +
                                with open(config_path, 'r') as f:
         
     | 
| 
      
 210 
     | 
    
         
            +
                                    return json.load(f)
         
     | 
| 
      
 211 
     | 
    
         
            +
                            except Exception as e:
         
     | 
| 
      
 212 
     | 
    
         
            +
                                print(f"Warning: Failed to load config from {config_path}: {e}")
         
     | 
| 
      
 213 
     | 
    
         
            +
                    
         
     | 
| 
      
 214 
     | 
    
         
            +
                    return None
         
     | 
| 
      
 215 
     | 
    
         
            +
                
         
     | 
| 
      
 216 
     | 
    
         
            +
                def save_config(self, config: SocketIOConfig, path: str = None) -> bool:
         
     | 
| 
      
 217 
     | 
    
         
            +
                    """Save configuration to file."""
         
     | 
| 
      
 218 
     | 
    
         
            +
                    import json
         
     | 
| 
      
 219 
     | 
    
         
            +
                    
         
     | 
| 
      
 220 
     | 
    
         
            +
                    if path is None:
         
     | 
| 
      
 221 
     | 
    
         
            +
                        # Use user config directory
         
     | 
| 
      
 222 
     | 
    
         
            +
                        config_dir = Path.home() / ".claude-mpm"
         
     | 
| 
      
 223 
     | 
    
         
            +
                        config_dir.mkdir(exist_ok=True)
         
     | 
| 
      
 224 
     | 
    
         
            +
                        path = config_dir / self.config_file_name
         
     | 
| 
      
 225 
     | 
    
         
            +
                    
         
     | 
| 
      
 226 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 227 
     | 
    
         
            +
                        with open(path, 'w') as f:
         
     | 
| 
      
 228 
     | 
    
         
            +
                            json.dump(config.to_dict(), f, indent=2)
         
     | 
| 
      
 229 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 230 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 231 
     | 
    
         
            +
                        print(f"Error saving config to {path}: {e}")
         
     | 
| 
      
 232 
     | 
    
         
            +
                        return False
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
            # Global configuration manager instance
         
     | 
| 
      
 236 
     | 
    
         
            +
            _config_manager = ConfigManager()
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
             
     | 
| 
      
 239 
     | 
    
         
            +
            def get_config(environment: str = None) -> SocketIOConfig:
         
     | 
| 
      
 240 
     | 
    
         
            +
                """Get Socket.IO configuration for the current or specified environment."""
         
     | 
| 
      
 241 
     | 
    
         
            +
                return _config_manager.get_config(environment)
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
            def get_server_ports(config: SocketIOConfig) -> List[int]:
         
     | 
| 
      
 245 
     | 
    
         
            +
                """Get list of ports to try for server discovery."""
         
     | 
| 
      
 246 
     | 
    
         
            +
                base_port = config.port
         
     | 
| 
      
 247 
     | 
    
         
            +
                return [base_port, base_port + 1, base_port + 2, base_port + 3, base_port + 4]
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
             
     | 
| 
      
 250 
     | 
    
         
            +
            def get_discovery_hosts(config: SocketIOConfig) -> List[str]:
         
     | 
| 
      
 251 
     | 
    
         
            +
                """Get list of hosts to try for server discovery."""
         
     | 
| 
      
 252 
     | 
    
         
            +
                if config.host == "0.0.0.0":
         
     | 
| 
      
 253 
     | 
    
         
            +
                    # If server binds to all interfaces, try localhost and 127.0.0.1 for discovery
         
     | 
| 
      
 254 
     | 
    
         
            +
                    return ["localhost", "127.0.0.1"]
         
     | 
| 
      
 255 
     | 
    
         
            +
                else:
         
     | 
| 
      
 256 
     | 
    
         
            +
                    return [config.host, "localhost", "127.0.0.1"]
         
     | 
    
        claude_mpm/constants.py
    CHANGED
    
    | 
         @@ -27,6 +27,7 @@ class CLICommands(str, Enum): 
     | 
|
| 
       27 
27 
     | 
    
         
             
                INFO = "info"
         
     | 
| 
       28 
28 
     | 
    
         
             
                AGENTS = "agents"
         
     | 
| 
       29 
29 
     | 
    
         
             
                UI = "ui"
         
     | 
| 
      
 30 
     | 
    
         
            +
                MEMORY = "memory"
         
     | 
| 
       30 
31 
     | 
    
         | 
| 
       31 
32 
     | 
    
         
             
                def with_prefix(self, prefix: CLIPrefix = CLIPrefix.MPM) -> str:
         
     | 
| 
       32 
33 
     | 
    
         
             
                    """Get command with prefix."""
         
     | 
| 
         @@ -55,6 +56,14 @@ class AgentCommands(str, Enum): 
     | 
|
| 
       55 
56 
     | 
    
         
             
                CLEAN = "clean"
         
     | 
| 
       56 
57 
     | 
    
         | 
| 
       57 
58 
     | 
    
         | 
| 
      
 59 
     | 
    
         
            +
            class MemoryCommands(str, Enum):
         
     | 
| 
      
 60 
     | 
    
         
            +
                """Memory subcommand constants."""
         
     | 
| 
      
 61 
     | 
    
         
            +
                STATUS = "status"
         
     | 
| 
      
 62 
     | 
    
         
            +
                VIEW = "view"
         
     | 
| 
      
 63 
     | 
    
         
            +
                ADD = "add"
         
     | 
| 
      
 64 
     | 
    
         
            +
                CLEAN = "clean"
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
       58 
67 
     | 
    
         
             
            class CLIFlags(str, Enum):
         
     | 
| 
       59 
68 
     | 
    
         
             
                """CLI flag constants (without prefix)."""
         
     | 
| 
       60 
69 
     | 
    
         
             
                # Logging flags
         
     | 
    
        claude_mpm/core/__init__.py
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            """Core components for Claude MPM."""
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            from . 
     | 
| 
      
 3 
     | 
    
         
            +
            from .claude_runner import ClaudeRunner
         
     | 
| 
       4 
4 
     | 
    
         
             
            from .mixins import LoggerMixin
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            # Import config components if needed
         
     | 
| 
         @@ -24,7 +24,7 @@ except ImportError: 
     | 
|
| 
       24 
24 
     | 
    
         
             
                pass
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
            __all__ = [
         
     | 
| 
       27 
     | 
    
         
            -
                " 
     | 
| 
      
 27 
     | 
    
         
            +
                "ClaudeRunner",
         
     | 
| 
       28 
28 
     | 
    
         
             
                "LoggerMixin",
         
     | 
| 
       29 
29 
     | 
    
         
             
                "Config",
         
     | 
| 
       30 
30 
     | 
    
         
             
                "ConfigAliases",
         
     |