claude-mpm 3.9.7__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/agents/templates/ticketing.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/__init__.py +28 -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 +138 -0
- claude_mpm/services/mcp_gateway/config/__init__.py +17 -0
- claude_mpm/services/mcp_gateway/config/config_loader.py +232 -0
- claude_mpm/services/mcp_gateway/config/config_schema.py +234 -0
- claude_mpm/services/mcp_gateway/config/configuration.py +371 -0
- claude_mpm/services/mcp_gateway/core/__init__.py +51 -0
- claude_mpm/services/mcp_gateway/core/base.py +315 -0
- claude_mpm/services/mcp_gateway/core/exceptions.py +239 -0
- claude_mpm/services/mcp_gateway/core/interfaces.py +476 -0
- claude_mpm/services/mcp_gateway/main.py +326 -0
- claude_mpm/services/mcp_gateway/registry/__init__.py +12 -0
- 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 +15 -0
- 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 +22 -0
- 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.7.dist-info → claude_mpm-3.9.9.dist-info}/METADATA +4 -1
- {claude_mpm-3.9.7.dist-info → claude_mpm-3.9.9.dist-info}/RECORD +49 -26
- 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.7.dist-info → claude_mpm-3.9.9.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.7.dist-info → claude_mpm-3.9.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.9.7.dist-info → claude_mpm-3.9.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.9.7.dist-info → claude_mpm-3.9.9.dist-info}/top_level.txt +0 -0
| @@ -0,0 +1,293 @@ | |
| 1 | 
            +
            #!/usr/bin/env python3
         | 
| 2 | 
            +
            """
         | 
| 3 | 
            +
            File utilities for Claude MPM.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            This module provides safe file operations with atomic writes,
         | 
| 6 | 
            +
            error handling, and directory management.
         | 
| 7 | 
            +
            """
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            import json
         | 
| 10 | 
            +
            import os
         | 
| 11 | 
            +
            import shutil
         | 
| 12 | 
            +
            import tempfile
         | 
| 13 | 
            +
            from pathlib import Path
         | 
| 14 | 
            +
            from typing import Any, Dict, Optional, Union
         | 
| 15 | 
            +
             | 
| 16 | 
            +
             | 
| 17 | 
            +
            class FileOperationError(Exception):
         | 
| 18 | 
            +
                """Exception raised for file operation errors."""
         | 
| 19 | 
            +
                pass
         | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 22 | 
            +
            def ensure_directory(path: Union[str, Path]) -> Path:
         | 
| 23 | 
            +
                """
         | 
| 24 | 
            +
                Ensure a directory exists, creating it if necessary.
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                Args:
         | 
| 27 | 
            +
                    path: Directory path to ensure exists
         | 
| 28 | 
            +
                    
         | 
| 29 | 
            +
                Returns:
         | 
| 30 | 
            +
                    Path object for the directory
         | 
| 31 | 
            +
                    
         | 
| 32 | 
            +
                Raises:
         | 
| 33 | 
            +
                    FileOperationError: If directory cannot be created
         | 
| 34 | 
            +
                """
         | 
| 35 | 
            +
                path = Path(path)
         | 
| 36 | 
            +
                try:
         | 
| 37 | 
            +
                    path.mkdir(parents=True, exist_ok=True)
         | 
| 38 | 
            +
                    return path
         | 
| 39 | 
            +
                except Exception as e:
         | 
| 40 | 
            +
                    raise FileOperationError(f"Failed to create directory {path}: {e}")
         | 
| 41 | 
            +
             | 
| 42 | 
            +
             | 
| 43 | 
            +
            def safe_read_file(path: Union[str, Path], encoding: str = 'utf-8') -> str:
         | 
| 44 | 
            +
                """
         | 
| 45 | 
            +
                Safely read a file with error handling.
         | 
| 46 | 
            +
                
         | 
| 47 | 
            +
                Args:
         | 
| 48 | 
            +
                    path: File path to read
         | 
| 49 | 
            +
                    encoding: Text encoding to use
         | 
| 50 | 
            +
                    
         | 
| 51 | 
            +
                Returns:
         | 
| 52 | 
            +
                    File contents as string
         | 
| 53 | 
            +
                    
         | 
| 54 | 
            +
                Raises:
         | 
| 55 | 
            +
                    FileOperationError: If file cannot be read
         | 
| 56 | 
            +
                """
         | 
| 57 | 
            +
                path = Path(path)
         | 
| 58 | 
            +
                try:
         | 
| 59 | 
            +
                    return path.read_text(encoding=encoding)
         | 
| 60 | 
            +
                except Exception as e:
         | 
| 61 | 
            +
                    raise FileOperationError(f"Failed to read file {path}: {e}")
         | 
| 62 | 
            +
             | 
| 63 | 
            +
             | 
| 64 | 
            +
            def safe_write_file(
         | 
| 65 | 
            +
                path: Union[str, Path], 
         | 
| 66 | 
            +
                content: str, 
         | 
| 67 | 
            +
                encoding: str = 'utf-8',
         | 
| 68 | 
            +
                create_dirs: bool = True
         | 
| 69 | 
            +
            ) -> None:
         | 
| 70 | 
            +
                """
         | 
| 71 | 
            +
                Safely write content to a file with directory creation.
         | 
| 72 | 
            +
                
         | 
| 73 | 
            +
                Args:
         | 
| 74 | 
            +
                    path: File path to write
         | 
| 75 | 
            +
                    content: Content to write
         | 
| 76 | 
            +
                    encoding: Text encoding to use
         | 
| 77 | 
            +
                    create_dirs: Whether to create parent directories
         | 
| 78 | 
            +
                    
         | 
| 79 | 
            +
                Raises:
         | 
| 80 | 
            +
                    FileOperationError: If file cannot be written
         | 
| 81 | 
            +
                """
         | 
| 82 | 
            +
                path = Path(path)
         | 
| 83 | 
            +
                try:
         | 
| 84 | 
            +
                    if create_dirs:
         | 
| 85 | 
            +
                        ensure_directory(path.parent)
         | 
| 86 | 
            +
                    path.write_text(content, encoding=encoding)
         | 
| 87 | 
            +
                except Exception as e:
         | 
| 88 | 
            +
                    raise FileOperationError(f"Failed to write file {path}: {e}")
         | 
| 89 | 
            +
             | 
| 90 | 
            +
             | 
| 91 | 
            +
            def atomic_write(
         | 
| 92 | 
            +
                path: Union[str, Path], 
         | 
| 93 | 
            +
                content: str, 
         | 
| 94 | 
            +
                encoding: str = 'utf-8',
         | 
| 95 | 
            +
                create_dirs: bool = True
         | 
| 96 | 
            +
            ) -> None:
         | 
| 97 | 
            +
                """
         | 
| 98 | 
            +
                Atomically write content to a file using a temporary file.
         | 
| 99 | 
            +
                
         | 
| 100 | 
            +
                This prevents corruption if the write operation is interrupted.
         | 
| 101 | 
            +
                
         | 
| 102 | 
            +
                Args:
         | 
| 103 | 
            +
                    path: File path to write
         | 
| 104 | 
            +
                    content: Content to write
         | 
| 105 | 
            +
                    encoding: Text encoding to use
         | 
| 106 | 
            +
                    create_dirs: Whether to create parent directories
         | 
| 107 | 
            +
                    
         | 
| 108 | 
            +
                Raises:
         | 
| 109 | 
            +
                    FileOperationError: If file cannot be written atomically
         | 
| 110 | 
            +
                """
         | 
| 111 | 
            +
                path = Path(path)
         | 
| 112 | 
            +
                try:
         | 
| 113 | 
            +
                    if create_dirs:
         | 
| 114 | 
            +
                        ensure_directory(path.parent)
         | 
| 115 | 
            +
                        
         | 
| 116 | 
            +
                    # Write to temporary file first
         | 
| 117 | 
            +
                    with tempfile.NamedTemporaryFile(
         | 
| 118 | 
            +
                        mode='w',
         | 
| 119 | 
            +
                        encoding=encoding,
         | 
| 120 | 
            +
                        dir=path.parent,
         | 
| 121 | 
            +
                        delete=False,
         | 
| 122 | 
            +
                        suffix='.tmp'
         | 
| 123 | 
            +
                    ) as temp_file:
         | 
| 124 | 
            +
                        temp_file.write(content)
         | 
| 125 | 
            +
                        temp_path = temp_file.name
         | 
| 126 | 
            +
                        
         | 
| 127 | 
            +
                    # Atomically move temporary file to target
         | 
| 128 | 
            +
                    shutil.move(temp_path, path)
         | 
| 129 | 
            +
                    
         | 
| 130 | 
            +
                except Exception as e:
         | 
| 131 | 
            +
                    # Clean up temporary file if it exists
         | 
| 132 | 
            +
                    try:
         | 
| 133 | 
            +
                        if 'temp_path' in locals():
         | 
| 134 | 
            +
                            os.unlink(temp_path)
         | 
| 135 | 
            +
                    except:
         | 
| 136 | 
            +
                        pass
         | 
| 137 | 
            +
                    raise FileOperationError(f"Failed to atomically write file {path}: {e}")
         | 
| 138 | 
            +
             | 
| 139 | 
            +
             | 
| 140 | 
            +
            def get_file_info(path: Union[str, Path]) -> Optional[Dict[str, Any]]:
         | 
| 141 | 
            +
                """
         | 
| 142 | 
            +
                Get file metadata safely.
         | 
| 143 | 
            +
                
         | 
| 144 | 
            +
                Args:
         | 
| 145 | 
            +
                    path: File path to examine
         | 
| 146 | 
            +
                    
         | 
| 147 | 
            +
                Returns:
         | 
| 148 | 
            +
                    Dictionary with file information or None if file doesn't exist
         | 
| 149 | 
            +
                """
         | 
| 150 | 
            +
                path = Path(path)
         | 
| 151 | 
            +
                try:
         | 
| 152 | 
            +
                    if not path.exists():
         | 
| 153 | 
            +
                        return None
         | 
| 154 | 
            +
                        
         | 
| 155 | 
            +
                    stat = path.stat()
         | 
| 156 | 
            +
                    return {
         | 
| 157 | 
            +
                        "path": str(path),
         | 
| 158 | 
            +
                        "size": stat.st_size,
         | 
| 159 | 
            +
                        "modified": stat.st_mtime,
         | 
| 160 | 
            +
                        "created": stat.st_ctime,
         | 
| 161 | 
            +
                        "is_file": path.is_file(),
         | 
| 162 | 
            +
                        "is_dir": path.is_dir(),
         | 
| 163 | 
            +
                        "permissions": oct(stat.st_mode)[-3:]
         | 
| 164 | 
            +
                    }
         | 
| 165 | 
            +
                except Exception:
         | 
| 166 | 
            +
                    return None
         | 
| 167 | 
            +
             | 
| 168 | 
            +
             | 
| 169 | 
            +
            def safe_copy_file(
         | 
| 170 | 
            +
                src: Union[str, Path], 
         | 
| 171 | 
            +
                dst: Union[str, Path],
         | 
| 172 | 
            +
                create_dirs: bool = True
         | 
| 173 | 
            +
            ) -> None:
         | 
| 174 | 
            +
                """
         | 
| 175 | 
            +
                Safely copy a file with error handling.
         | 
| 176 | 
            +
                
         | 
| 177 | 
            +
                Args:
         | 
| 178 | 
            +
                    src: Source file path
         | 
| 179 | 
            +
                    dst: Destination file path
         | 
| 180 | 
            +
                    create_dirs: Whether to create destination directories
         | 
| 181 | 
            +
                    
         | 
| 182 | 
            +
                Raises:
         | 
| 183 | 
            +
                    FileOperationError: If file cannot be copied
         | 
| 184 | 
            +
                """
         | 
| 185 | 
            +
                src = Path(src)
         | 
| 186 | 
            +
                dst = Path(dst)
         | 
| 187 | 
            +
                
         | 
| 188 | 
            +
                try:
         | 
| 189 | 
            +
                    if not src.exists():
         | 
| 190 | 
            +
                        raise FileOperationError(f"Source file does not exist: {src}")
         | 
| 191 | 
            +
                        
         | 
| 192 | 
            +
                    if create_dirs:
         | 
| 193 | 
            +
                        ensure_directory(dst.parent)
         | 
| 194 | 
            +
                        
         | 
| 195 | 
            +
                    shutil.copy2(src, dst)
         | 
| 196 | 
            +
                    
         | 
| 197 | 
            +
                except Exception as e:
         | 
| 198 | 
            +
                    raise FileOperationError(f"Failed to copy {src} to {dst}: {e}")
         | 
| 199 | 
            +
             | 
| 200 | 
            +
             | 
| 201 | 
            +
            def safe_remove_file(path: Union[str, Path]) -> bool:
         | 
| 202 | 
            +
                """
         | 
| 203 | 
            +
                Safely remove a file.
         | 
| 204 | 
            +
                
         | 
| 205 | 
            +
                Args:
         | 
| 206 | 
            +
                    path: File path to remove
         | 
| 207 | 
            +
                    
         | 
| 208 | 
            +
                Returns:
         | 
| 209 | 
            +
                    True if file was removed, False if it didn't exist
         | 
| 210 | 
            +
                    
         | 
| 211 | 
            +
                Raises:
         | 
| 212 | 
            +
                    FileOperationError: If file cannot be removed
         | 
| 213 | 
            +
                """
         | 
| 214 | 
            +
                path = Path(path)
         | 
| 215 | 
            +
                try:
         | 
| 216 | 
            +
                    if not path.exists():
         | 
| 217 | 
            +
                        return False
         | 
| 218 | 
            +
                    path.unlink()
         | 
| 219 | 
            +
                    return True
         | 
| 220 | 
            +
                except Exception as e:
         | 
| 221 | 
            +
                    raise FileOperationError(f"Failed to remove file {path}: {e}")
         | 
| 222 | 
            +
             | 
| 223 | 
            +
             | 
| 224 | 
            +
            def read_json_file(path: Union[str, Path]) -> Any:
         | 
| 225 | 
            +
                """
         | 
| 226 | 
            +
                Read and parse a JSON file safely.
         | 
| 227 | 
            +
                
         | 
| 228 | 
            +
                Args:
         | 
| 229 | 
            +
                    path: JSON file path
         | 
| 230 | 
            +
                    
         | 
| 231 | 
            +
                Returns:
         | 
| 232 | 
            +
                    Parsed JSON data
         | 
| 233 | 
            +
                    
         | 
| 234 | 
            +
                Raises:
         | 
| 235 | 
            +
                    FileOperationError: If file cannot be read or parsed
         | 
| 236 | 
            +
                """
         | 
| 237 | 
            +
                try:
         | 
| 238 | 
            +
                    content = safe_read_file(path)
         | 
| 239 | 
            +
                    return json.loads(content)
         | 
| 240 | 
            +
                except json.JSONDecodeError as e:
         | 
| 241 | 
            +
                    raise FileOperationError(f"Invalid JSON in file {path}: {e}")
         | 
| 242 | 
            +
             | 
| 243 | 
            +
             | 
| 244 | 
            +
            def write_json_file(
         | 
| 245 | 
            +
                path: Union[str, Path], 
         | 
| 246 | 
            +
                data: Any, 
         | 
| 247 | 
            +
                indent: int = 2,
         | 
| 248 | 
            +
                atomic: bool = True
         | 
| 249 | 
            +
            ) -> None:
         | 
| 250 | 
            +
                """
         | 
| 251 | 
            +
                Write data to a JSON file safely.
         | 
| 252 | 
            +
                
         | 
| 253 | 
            +
                Args:
         | 
| 254 | 
            +
                    path: JSON file path
         | 
| 255 | 
            +
                    data: Data to serialize to JSON
         | 
| 256 | 
            +
                    indent: JSON indentation level
         | 
| 257 | 
            +
                    atomic: Whether to use atomic write
         | 
| 258 | 
            +
                    
         | 
| 259 | 
            +
                Raises:
         | 
| 260 | 
            +
                    FileOperationError: If file cannot be written
         | 
| 261 | 
            +
                """
         | 
| 262 | 
            +
                try:
         | 
| 263 | 
            +
                    content = json.dumps(data, indent=indent, ensure_ascii=False)
         | 
| 264 | 
            +
                    if atomic:
         | 
| 265 | 
            +
                        atomic_write(path, content)
         | 
| 266 | 
            +
                    else:
         | 
| 267 | 
            +
                        safe_write_file(path, content)
         | 
| 268 | 
            +
                except Exception as e:
         | 
| 269 | 
            +
                    raise FileOperationError(f"Failed to write JSON file {path}: {e}")
         | 
| 270 | 
            +
             | 
| 271 | 
            +
             | 
| 272 | 
            +
            def backup_file(path: Union[str, Path], backup_suffix: str = '.backup') -> Path:
         | 
| 273 | 
            +
                """
         | 
| 274 | 
            +
                Create a backup copy of a file.
         | 
| 275 | 
            +
                
         | 
| 276 | 
            +
                Args:
         | 
| 277 | 
            +
                    path: File path to backup
         | 
| 278 | 
            +
                    backup_suffix: Suffix to add to backup filename
         | 
| 279 | 
            +
                    
         | 
| 280 | 
            +
                Returns:
         | 
| 281 | 
            +
                    Path to the backup file
         | 
| 282 | 
            +
                    
         | 
| 283 | 
            +
                Raises:
         | 
| 284 | 
            +
                    FileOperationError: If backup cannot be created
         | 
| 285 | 
            +
                """
         | 
| 286 | 
            +
                path = Path(path)
         | 
| 287 | 
            +
                backup_path = path.with_suffix(path.suffix + backup_suffix)
         | 
| 288 | 
            +
                
         | 
| 289 | 
            +
                try:
         | 
| 290 | 
            +
                    safe_copy_file(path, backup_path)
         | 
| 291 | 
            +
                    return backup_path
         | 
| 292 | 
            +
                except Exception as e:
         | 
| 293 | 
            +
                    raise FileOperationError(f"Failed to create backup of {path}: {e}")
         |