claude-mpm 3.5.4__py3-none-any.whl → 3.6.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/.claude-mpm/logs/hooks_20250728.log +10 -0
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +96 -23
- claude_mpm/agents/BASE_PM.md +273 -0
- claude_mpm/agents/INSTRUCTIONS.md +114 -102
- claude_mpm/agents/agent-template.yaml +83 -0
- claude_mpm/agents/agent_loader.py +36 -1
- claude_mpm/agents/async_agent_loader.py +421 -0
- claude_mpm/agents/templates/code_analyzer.json +81 -0
- claude_mpm/agents/templates/data_engineer.json +18 -3
- claude_mpm/agents/templates/documentation.json +18 -3
- claude_mpm/agents/templates/engineer.json +19 -4
- claude_mpm/agents/templates/ops.json +18 -3
- claude_mpm/agents/templates/qa.json +20 -4
- claude_mpm/agents/templates/research.json +20 -4
- claude_mpm/agents/templates/security.json +18 -3
- claude_mpm/agents/templates/version_control.json +16 -3
- claude_mpm/cli/README.md +108 -0
- claude_mpm/cli/__init__.py +5 -1
- claude_mpm/cli/commands/__init__.py +5 -1
- claude_mpm/cli/commands/agents.py +233 -6
- claude_mpm/cli/commands/aggregate.py +462 -0
- claude_mpm/cli/commands/config.py +277 -0
- claude_mpm/cli/commands/run.py +228 -47
- claude_mpm/cli/parser.py +176 -1
- claude_mpm/cli/utils.py +9 -1
- claude_mpm/cli_module/refactoring_guide.md +253 -0
- claude_mpm/config/async_logging_config.yaml +145 -0
- claude_mpm/constants.py +19 -0
- claude_mpm/core/.claude-mpm/logs/hooks_20250730.log +34 -0
- claude_mpm/core/claude_runner.py +413 -76
- claude_mpm/core/config.py +161 -4
- claude_mpm/core/config_paths.py +0 -1
- claude_mpm/core/factories.py +9 -3
- claude_mpm/core/framework_loader.py +81 -0
- claude_mpm/dashboard/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/README.md +121 -0
- claude_mpm/dashboard/static/js/dashboard.js.backup +1973 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/README.md +36 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/engineer_agent.md +39 -0
- claude_mpm/dashboard/templates/.claude-mpm/memories/version_control_agent.md +38 -0
- claude_mpm/hooks/README.md +96 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +391 -9
- claude_mpm/init.py +123 -18
- claude_mpm/models/agent_session.py +511 -0
- claude_mpm/schemas/agent_schema.json +435 -0
- claude_mpm/scripts/__init__.py +15 -0
- claude_mpm/scripts/start_activity_logging.py +86 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +326 -24
- claude_mpm/services/agents/deployment/async_agent_deployment.py +461 -0
- claude_mpm/services/agents/management/agent_management_service.py +2 -1
- claude_mpm/services/event_aggregator.py +547 -0
- claude_mpm/services/framework_claude_md_generator/README.md +92 -0
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +2 -2
- claude_mpm/services/version_control/VERSION +1 -0
- claude_mpm/utils/agent_dependency_loader.py +655 -0
- claude_mpm/utils/console.py +11 -0
- claude_mpm/utils/dependency_cache.py +376 -0
- claude_mpm/utils/dependency_strategies.py +343 -0
- claude_mpm/utils/environment_context.py +310 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/METADATA +87 -1
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/RECORD +67 -37
- claude_mpm/agents/templates/pm.json +0 -122
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/WHEEL +0 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.5.4.dist-info → claude_mpm-3.6.0.dist-info}/top_level.txt +0 -0
    
        claude_mpm/init.py
    CHANGED
    
    | @@ -8,6 +8,7 @@ import shutil | |
| 8 8 | 
             
            from pathlib import Path
         | 
| 9 9 | 
             
            from typing import Optional, Dict, Any
         | 
| 10 10 | 
             
            import json
         | 
| 11 | 
            +
            import yaml
         | 
| 11 12 |  | 
| 12 13 | 
             
            from claude_mpm.core.logger import get_logger
         | 
| 13 14 |  | 
| @@ -48,9 +49,15 @@ class ProjectInitializer: | |
| 48 49 | 
             
                        for directory in directories:
         | 
| 49 50 | 
             
                            directory.mkdir(parents=True, exist_ok=True)
         | 
| 50 51 |  | 
| 51 | 
            -
                        #  | 
| 52 | 
            -
                         | 
| 53 | 
            -
                         | 
| 52 | 
            +
                        # Check for migration from old settings.json to new configuration.yaml
         | 
| 53 | 
            +
                        old_config_file = self.user_dir / "config" / "settings.json"
         | 
| 54 | 
            +
                        config_file = self.user_dir / "config" / "configuration.yaml"
         | 
| 55 | 
            +
                        
         | 
| 56 | 
            +
                        # Migrate if old file exists but new doesn't
         | 
| 57 | 
            +
                        if old_config_file.exists() and not config_file.exists():
         | 
| 58 | 
            +
                            self._migrate_json_to_yaml(old_config_file, config_file)
         | 
| 59 | 
            +
                        elif not config_file.exists():
         | 
| 60 | 
            +
                            # Create default configuration if it doesn't exist
         | 
| 54 61 | 
             
                            self._create_default_config(config_file)
         | 
| 55 62 |  | 
| 56 63 | 
             
                        # Copy agent templates if they don't exist
         | 
| @@ -68,8 +75,7 @@ class ProjectInitializer: | |
| 68 75 |  | 
| 69 76 | 
             
                    Creates:
         | 
| 70 77 | 
             
                    - .claude-mpm/
         | 
| 71 | 
            -
                      - agents/
         | 
| 72 | 
            -
                        - project-specific/
         | 
| 78 | 
            +
                      - agents/     (for project agent JSON files)
         | 
| 73 79 | 
             
                      - config/
         | 
| 74 80 | 
             
                      - responses/
         | 
| 75 81 | 
             
                      - logs/
         | 
| @@ -80,20 +86,33 @@ class ProjectInitializer: | |
| 80 86 | 
             
                            project_root = project_path
         | 
| 81 87 | 
             
                            self.project_dir = project_path / ".claude-mpm"
         | 
| 82 88 | 
             
                        else:
         | 
| 83 | 
            -
                            #  | 
| 84 | 
            -
                            #  | 
| 85 | 
            -
                             | 
| 89 | 
            +
                            # Check for the user's original working directory from launch script
         | 
| 90 | 
            +
                            # The launch script sets CLAUDE_MPM_USER_PWD before changing to framework directory
         | 
| 91 | 
            +
                            user_pwd = os.environ.get('CLAUDE_MPM_USER_PWD')
         | 
| 92 | 
            +
                            
         | 
| 93 | 
            +
                            if user_pwd:
         | 
| 94 | 
            +
                                # Use the original user working directory
         | 
| 95 | 
            +
                                project_root = Path(user_pwd)
         | 
| 96 | 
            +
                                self.logger.debug(f"Using user working directory from CLAUDE_MPM_USER_PWD: {project_root}")
         | 
| 97 | 
            +
                            else:
         | 
| 98 | 
            +
                                # Fallback to current working directory (backward compatibility)
         | 
| 99 | 
            +
                                project_root = Path.cwd()
         | 
| 100 | 
            +
                                self.logger.debug(f"CLAUDE_MPM_USER_PWD not set, using cwd: {project_root}")
         | 
| 101 | 
            +
                            
         | 
| 86 102 | 
             
                            self.project_dir = project_root / ".claude-mpm"
         | 
| 87 103 |  | 
| 88 104 | 
             
                        # Check if directory already exists
         | 
| 89 105 | 
             
                        directory_existed = self.project_dir.exists()
         | 
| 90 106 |  | 
| 107 | 
            +
                        # Migrate existing agents from project-specific subdirectory if needed
         | 
| 108 | 
            +
                        self._migrate_project_agents()
         | 
| 109 | 
            +
                        
         | 
| 91 110 | 
             
                        # Create project directory
         | 
| 92 111 | 
             
                        self.project_dir.mkdir(exist_ok=True)
         | 
| 93 112 |  | 
| 94 113 | 
             
                        # Create subdirectories
         | 
| 95 114 | 
             
                        directories = [
         | 
| 96 | 
            -
                            self.project_dir / "agents"  | 
| 115 | 
            +
                            self.project_dir / "agents",  # Direct agents directory for project agents
         | 
| 97 116 | 
             
                            self.project_dir / "config",
         | 
| 98 117 | 
             
                            self.project_dir / "responses",
         | 
| 99 118 | 
             
                            self.project_dir / "logs",
         | 
| @@ -122,6 +141,12 @@ class ProjectInitializer: | |
| 122 141 | 
             
                        else:
         | 
| 123 142 | 
             
                            print(f"✓ Initialized .claude-mpm/ in {project_root}")
         | 
| 124 143 |  | 
| 144 | 
            +
                        # Check if migration happened
         | 
| 145 | 
            +
                        agents_dir = self.project_dir / "agents"
         | 
| 146 | 
            +
                        if agents_dir.exists() and any(agents_dir.glob("*.json")):
         | 
| 147 | 
            +
                            agent_count = len(list(agents_dir.glob("*.json")))
         | 
| 148 | 
            +
                            print(f"✓ Found {agent_count} project agent(s) in .claude-mpm/agents/")
         | 
| 149 | 
            +
                        
         | 
| 125 150 | 
             
                        return True
         | 
| 126 151 |  | 
| 127 152 | 
             
                    except Exception as e:
         | 
| @@ -129,6 +154,54 @@ class ProjectInitializer: | |
| 129 154 | 
             
                        print(f"✗ Failed to create .claude-mpm/ directory: {e}")
         | 
| 130 155 | 
             
                        return False
         | 
| 131 156 |  | 
| 157 | 
            +
                def _migrate_project_agents(self):
         | 
| 158 | 
            +
                    """Migrate agents from old subdirectory structure to direct agents directory.
         | 
| 159 | 
            +
                    
         | 
| 160 | 
            +
                    WHY: We're simplifying the directory structure to match the deployment expectations.
         | 
| 161 | 
            +
                    The old structure had a subdirectory but the deployment now looks for agents 
         | 
| 162 | 
            +
                    directly in .claude-mpm/agents/.
         | 
| 163 | 
            +
                    """
         | 
| 164 | 
            +
                    if not self.project_dir:
         | 
| 165 | 
            +
                        return
         | 
| 166 | 
            +
                    
         | 
| 167 | 
            +
                    old_agents_dir = self.project_dir / "agents" / "project-specific"
         | 
| 168 | 
            +
                    new_agents_dir = self.project_dir / "agents"
         | 
| 169 | 
            +
                    
         | 
| 170 | 
            +
                    # Check if old directory exists with JSON files
         | 
| 171 | 
            +
                    if old_agents_dir.exists() and old_agents_dir.is_dir():
         | 
| 172 | 
            +
                        json_files = list(old_agents_dir.glob("*.json"))
         | 
| 173 | 
            +
                        if json_files:
         | 
| 174 | 
            +
                            self.logger.info(f"Migrating {len(json_files)} agents from old subdirectory")
         | 
| 175 | 
            +
                            
         | 
| 176 | 
            +
                            # Ensure new agents directory exists
         | 
| 177 | 
            +
                            new_agents_dir.mkdir(parents=True, exist_ok=True)
         | 
| 178 | 
            +
                            
         | 
| 179 | 
            +
                            # Move each JSON file
         | 
| 180 | 
            +
                            migrated_count = 0
         | 
| 181 | 
            +
                            for json_file in json_files:
         | 
| 182 | 
            +
                                try:
         | 
| 183 | 
            +
                                    target_file = new_agents_dir / json_file.name
         | 
| 184 | 
            +
                                    if not target_file.exists():
         | 
| 185 | 
            +
                                        # Move the file
         | 
| 186 | 
            +
                                        shutil.move(str(json_file), str(target_file))
         | 
| 187 | 
            +
                                        migrated_count += 1
         | 
| 188 | 
            +
                                        self.logger.debug(f"Migrated {json_file.name} to agents directory")
         | 
| 189 | 
            +
                                    else:
         | 
| 190 | 
            +
                                        self.logger.debug(f"Skipping {json_file.name} - already exists in target")
         | 
| 191 | 
            +
                                except Exception as e:
         | 
| 192 | 
            +
                                    self.logger.error(f"Failed to migrate {json_file.name}: {e}")
         | 
| 193 | 
            +
                            
         | 
| 194 | 
            +
                            if migrated_count > 0:
         | 
| 195 | 
            +
                                print(f"✓ Migrated {migrated_count} agent(s) from old location to agents/")
         | 
| 196 | 
            +
                            
         | 
| 197 | 
            +
                            # Remove old directory if empty
         | 
| 198 | 
            +
                            try:
         | 
| 199 | 
            +
                                if not any(old_agents_dir.iterdir()):
         | 
| 200 | 
            +
                                    old_agents_dir.rmdir()
         | 
| 201 | 
            +
                                    self.logger.debug("Removed empty old subdirectory")
         | 
| 202 | 
            +
                            except Exception as e:
         | 
| 203 | 
            +
                                self.logger.debug(f"Could not remove old directory: {e}")
         | 
| 204 | 
            +
                
         | 
| 132 205 | 
             
                def _find_project_root(self) -> Optional[Path]:
         | 
| 133 206 | 
             
                    """Find project root by looking for .git or other project markers."""
         | 
| 134 207 | 
             
                    current = Path.cwd()
         | 
| @@ -142,8 +215,36 @@ class ProjectInitializer: | |
| 142 215 | 
             
                        current = current.parent
         | 
| 143 216 | 
             
                    return None
         | 
| 144 217 |  | 
| 218 | 
            +
                def _migrate_json_to_yaml(self, old_file: Path, new_file: Path):
         | 
| 219 | 
            +
                    """Migrate configuration from JSON to YAML format.
         | 
| 220 | 
            +
                    
         | 
| 221 | 
            +
                    Args:
         | 
| 222 | 
            +
                        old_file: Path to existing settings.json
         | 
| 223 | 
            +
                        new_file: Path to new configuration.yaml
         | 
| 224 | 
            +
                    """
         | 
| 225 | 
            +
                    try:
         | 
| 226 | 
            +
                        # Read existing JSON configuration
         | 
| 227 | 
            +
                        with open(old_file, 'r') as f:
         | 
| 228 | 
            +
                            config = json.load(f)
         | 
| 229 | 
            +
                        
         | 
| 230 | 
            +
                        # Write as YAML
         | 
| 231 | 
            +
                        with open(new_file, 'w') as f:
         | 
| 232 | 
            +
                            yaml.dump(config, f, default_flow_style=False, sort_keys=False)
         | 
| 233 | 
            +
                        
         | 
| 234 | 
            +
                        self.logger.info(f"Migrated configuration from {old_file.name} to {new_file.name}")
         | 
| 235 | 
            +
                        
         | 
| 236 | 
            +
                        # Optionally rename old file to .backup
         | 
| 237 | 
            +
                        backup_file = old_file.with_suffix('.json.backup')
         | 
| 238 | 
            +
                        old_file.rename(backup_file)
         | 
| 239 | 
            +
                        self.logger.info(f"Renamed old configuration to {backup_file.name}")
         | 
| 240 | 
            +
                        
         | 
| 241 | 
            +
                    except Exception as e:
         | 
| 242 | 
            +
                        self.logger.error(f"Failed to migrate configuration: {e}")
         | 
| 243 | 
            +
                        # Fall back to creating default config
         | 
| 244 | 
            +
                        self._create_default_config(new_file)
         | 
| 245 | 
            +
                
         | 
| 145 246 | 
             
                def _create_default_config(self, config_file: Path):
         | 
| 146 | 
            -
                    """Create default user configuration."""
         | 
| 247 | 
            +
                    """Create default user configuration in YAML format."""
         | 
| 147 248 | 
             
                    default_config = {
         | 
| 148 249 | 
             
                        "version": "1.0",
         | 
| 149 250 | 
             
                        "hooks": {
         | 
| @@ -166,7 +267,7 @@ class ProjectInitializer: | |
| 166 267 | 
             
                    }
         | 
| 167 268 |  | 
| 168 269 | 
             
                    with open(config_file, 'w') as f:
         | 
| 169 | 
            -
                         | 
| 270 | 
            +
                        yaml.dump(default_config, f, default_flow_style=False, sort_keys=False)
         | 
| 170 271 |  | 
| 171 272 | 
             
                def _create_project_config(self, config_file: Path):
         | 
| 172 273 | 
             
                    """Create default project configuration."""
         | 
| @@ -237,19 +338,23 @@ class ProjectInitializer: | |
| 237 338 |  | 
| 238 339 | 
             
                    Shows clear information about where directories are being created.
         | 
| 239 340 | 
             
                    """
         | 
| 240 | 
            -
                    #  | 
| 241 | 
            -
                     | 
| 242 | 
            -
                     | 
| 341 | 
            +
                    # Determine actual working directory
         | 
| 342 | 
            +
                    user_pwd = os.environ.get('CLAUDE_MPM_USER_PWD')
         | 
| 343 | 
            +
                    if user_pwd:
         | 
| 344 | 
            +
                        actual_wd = Path(user_pwd)
         | 
| 345 | 
            +
                        self.logger.info(f"User working directory (from CLAUDE_MPM_USER_PWD): {actual_wd}")
         | 
| 346 | 
            +
                    else:
         | 
| 347 | 
            +
                        actual_wd = Path.cwd()
         | 
| 348 | 
            +
                        self.logger.info(f"Working directory: {actual_wd}")
         | 
| 243 349 |  | 
| 244 | 
            -
                     | 
| 245 | 
            -
                    self.logger.info(f"Working directory: {cwd}")
         | 
| 350 | 
            +
                    framework_path = Path(__file__).parent.parent.parent
         | 
| 246 351 | 
             
                    self.logger.info(f"Framework path: {framework_path}")
         | 
| 247 352 |  | 
| 248 353 | 
             
                    # Initialize user directory (in home)
         | 
| 249 354 | 
             
                    user_ok = self.initialize_user_directory()
         | 
| 250 355 |  | 
| 251 | 
            -
                    # Initialize project directory (in  | 
| 252 | 
            -
                    self.logger.info(f"Checking for .claude-mpm/ in { | 
| 356 | 
            +
                    # Initialize project directory (in user's actual working directory)
         | 
| 357 | 
            +
                    self.logger.info(f"Checking for .claude-mpm/ in {actual_wd}")
         | 
| 253 358 | 
             
                    project_ok = self.initialize_project_directory()
         | 
| 254 359 |  | 
| 255 360 | 
             
                    return user_ok and project_ok
         |