claude-mpm 3.1.1__py3-none-any.whl → 3.1.3__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/__main__.py +27 -3
 - claude_mpm/agents/INSTRUCTIONS.md +17 -2
 - claude_mpm/agents/templates/test-integration-agent.md +34 -0
 - claude_mpm/cli/README.md +109 -0
 - claude_mpm/cli/__init__.py +172 -0
 - claude_mpm/cli/commands/__init__.py +20 -0
 - claude_mpm/cli/commands/agents.py +202 -0
 - claude_mpm/cli/commands/info.py +94 -0
 - claude_mpm/cli/commands/run.py +95 -0
 - claude_mpm/cli/commands/tickets.py +70 -0
 - claude_mpm/cli/commands/ui.py +79 -0
 - claude_mpm/cli/parser.py +337 -0
 - claude_mpm/cli/utils.py +190 -0
 - claude_mpm/cli_enhancements.py +19 -0
 - claude_mpm/core/agent_registry.py +4 -4
 - claude_mpm/core/factories.py +1 -1
 - claude_mpm/core/service_registry.py +1 -1
 - claude_mpm/core/simple_runner.py +17 -27
 - claude_mpm/hooks/claude_hooks/hook_handler.py +53 -4
 - claude_mpm/models/__init__.py +106 -0
 - claude_mpm/models/agent_definition.py +196 -0
 - claude_mpm/models/common.py +41 -0
 - claude_mpm/models/lifecycle.py +97 -0
 - claude_mpm/models/modification.py +126 -0
 - claude_mpm/models/persistence.py +57 -0
 - claude_mpm/models/registry.py +91 -0
 - claude_mpm/security/__init__.py +8 -0
 - claude_mpm/security/bash_validator.py +393 -0
 - claude_mpm/services/agent_lifecycle_manager.py +206 -94
 - claude_mpm/services/agent_modification_tracker.py +27 -100
 - claude_mpm/services/agent_persistence_service.py +74 -0
 - claude_mpm/services/agent_registry.py +43 -82
 - claude_mpm/services/agent_versioning.py +37 -0
 - claude_mpm/services/{ticketing_service_original.py → legacy_ticketing_service.py} +16 -9
 - claude_mpm/services/ticket_manager.py +5 -4
 - claude_mpm/services/{ticket_manager_di.py → ticket_manager_dependency_injection.py} +39 -12
 - claude_mpm/services/version_control/semantic_versioning.py +10 -9
 - claude_mpm/utils/path_operations.py +20 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.3.dist-info}/METADATA +9 -1
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.3.dist-info}/RECORD +45 -25
 - claude_mpm/cli_main.py +0 -13
 - claude_mpm/utils/import_migration_example.py +0 -80
 - /claude_mpm/{cli.py → cli_old.py} +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.3.dist-info}/WHEEL +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.3.dist-info}/entry_points.txt +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.3.dist-info}/licenses/LICENSE +0 -0
 - {claude_mpm-3.1.1.dist-info → claude_mpm-3.1.3.dist-info}/top_level.txt +0 -0
 
| 
         @@ -27,95 +27,46 @@ Created for ISS-0118: Agent Registry and Hierarchical Discovery System 
     | 
|
| 
       27 
27 
     | 
    
         
             
            import asyncio
         
     | 
| 
       28 
28 
     | 
    
         
             
            import logging
         
     | 
| 
       29 
29 
     | 
    
         
             
            import time
         
     | 
| 
       30 
     | 
    
         
            -
            from dataclasses import dataclass, field
         
     | 
| 
       31 
30 
     | 
    
         
             
            from datetime import datetime, timedelta
         
     | 
| 
       32 
     | 
    
         
            -
            from enum import Enum
         
     | 
| 
       33 
31 
     | 
    
         
             
            from pathlib import Path
         
     | 
| 
       34 
32 
     | 
    
         
             
            from typing import Dict, List, Optional, Set, Any, Tuple, Union
         
     | 
| 
       35 
33 
     | 
    
         | 
| 
       36 
34 
     | 
    
         
             
            from claude_mpm.services.shared_prompt_cache import SharedPromptCache
         
     | 
| 
       37 
     | 
    
         
            -
            from claude_mpm.services.agent_registry import AgentRegistry 
     | 
| 
       38 
     | 
    
         
            -
            from claude_mpm.services.agent_modification_tracker import  
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 35 
     | 
    
         
            +
            from claude_mpm.services.agent_registry import AgentRegistry
         
     | 
| 
      
 36 
     | 
    
         
            +
            from claude_mpm.services.agent_modification_tracker import AgentModificationTracker
         
     | 
| 
      
 37 
     | 
    
         
            +
            from claude_mpm.services.agent_persistence_service import AgentPersistenceService
         
     | 
| 
      
 38 
     | 
    
         
            +
            from claude_mpm.services.agent_management_service import AgentManager
         
     | 
| 
      
 39 
     | 
    
         
            +
            from claude_mpm.models.agent_definition import AgentDefinition, AgentType
         
     | 
| 
      
 40 
     | 
    
         
            +
            from claude_mpm.models.lifecycle import (
         
     | 
| 
      
 41 
     | 
    
         
            +
                LifecycleOperation,
         
     | 
| 
      
 42 
     | 
    
         
            +
                LifecycleState,
         
     | 
| 
      
 43 
     | 
    
         
            +
                AgentLifecycleRecord,
         
     | 
| 
      
 44 
     | 
    
         
            +
                LifecycleOperationResult
         
     | 
| 
      
 45 
     | 
    
         
            +
            )
         
     | 
| 
      
 46 
     | 
    
         
            +
            from claude_mpm.models.modification import (
         
     | 
| 
      
 47 
     | 
    
         
            +
                AgentModification,
         
     | 
| 
      
 48 
     | 
    
         
            +
                ModificationType,
         
     | 
| 
       42 
49 
     | 
    
         
             
                ModificationTier
         
     | 
| 
       43 
50 
     | 
    
         
             
            )
         
     | 
| 
       44 
     | 
    
         
            -
            from claude_mpm. 
     | 
| 
       45 
     | 
    
         
            -
                AgentPersistenceService,
         
     | 
| 
       46 
     | 
    
         
            -
                PersistenceRecord,
         
     | 
| 
      
 51 
     | 
    
         
            +
            from claude_mpm.models.persistence import (
         
     | 
| 
       47 
52 
     | 
    
         
             
                PersistenceStrategy,
         
     | 
| 
      
 53 
     | 
    
         
            +
                PersistenceRecord,
         
     | 
| 
       48 
54 
     | 
    
         
             
                PersistenceOperation
         
     | 
| 
       49 
55 
     | 
    
         
             
            )
         
     | 
| 
      
 56 
     | 
    
         
            +
            from claude_mpm.models.registry import AgentRegistryMetadata
         
     | 
| 
       50 
57 
     | 
    
         
             
            from claude_mpm.core.base_service import BaseService
         
     | 
| 
       51 
58 
     | 
    
         
             
            from claude_mpm.utils.path_operations import path_ops
         
     | 
| 
       52 
59 
     | 
    
         
             
            from claude_mpm.utils.config_manager import ConfigurationManager
         
     | 
| 
       53 
60 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                 
     | 
| 
       58 
     | 
    
         
            -
                 
     | 
| 
       59 
     | 
    
         
            -
                 
     | 
| 
       60 
     | 
    
         
            -
                 
     | 
| 
       61 
     | 
    
         
            -
                 
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
                VALIDATE = "validate"
         
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
            class LifecycleState(Enum):
         
     | 
| 
       67 
     | 
    
         
            -
                """Agent lifecycle states."""
         
     | 
| 
       68 
     | 
    
         
            -
                ACTIVE = "active"
         
     | 
| 
       69 
     | 
    
         
            -
                MODIFIED = "modified"
         
     | 
| 
       70 
     | 
    
         
            -
                DELETED = "deleted"
         
     | 
| 
       71 
     | 
    
         
            -
                CONFLICTED = "conflicted"
         
     | 
| 
       72 
     | 
    
         
            -
                MIGRATING = "migrating"
         
     | 
| 
       73 
     | 
    
         
            -
                VALIDATING = "validating"
         
     | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
       75 
     | 
    
         
            -
             
     | 
| 
       76 
     | 
    
         
            -
            @dataclass
         
     | 
| 
       77 
     | 
    
         
            -
            class AgentLifecycleRecord:
         
     | 
| 
       78 
     | 
    
         
            -
                """Complete lifecycle record for an agent."""
         
     | 
| 
       79 
     | 
    
         
            -
                
         
     | 
| 
       80 
     | 
    
         
            -
                agent_name: str
         
     | 
| 
       81 
     | 
    
         
            -
                current_state: LifecycleState
         
     | 
| 
       82 
     | 
    
         
            -
                tier: ModificationTier
         
     | 
| 
       83 
     | 
    
         
            -
                file_path: str
         
     | 
| 
       84 
     | 
    
         
            -
                created_at: float
         
     | 
| 
       85 
     | 
    
         
            -
                last_modified: float
         
     | 
| 
       86 
     | 
    
         
            -
                version: str
         
     | 
| 
       87 
     | 
    
         
            -
                modifications: List[str] = field(default_factory=list)  # Modification IDs
         
     | 
| 
       88 
     | 
    
         
            -
                persistence_operations: List[str] = field(default_factory=list)  # Operation IDs
         
     | 
| 
       89 
     | 
    
         
            -
                backup_paths: List[str] = field(default_factory=list)
         
     | 
| 
       90 
     | 
    
         
            -
                validation_status: str = "valid"
         
     | 
| 
       91 
     | 
    
         
            -
                validation_errors: List[str] = field(default_factory=list)
         
     | 
| 
       92 
     | 
    
         
            -
                metadata: Dict[str, Any] = field(default_factory=dict)
         
     | 
| 
       93 
     | 
    
         
            -
                
         
     | 
| 
       94 
     | 
    
         
            -
                @property
         
     | 
| 
       95 
     | 
    
         
            -
                def age_days(self) -> float:
         
     | 
| 
       96 
     | 
    
         
            -
                    """Get age in days."""
         
     | 
| 
       97 
     | 
    
         
            -
                    return (time.time() - self.created_at) / (24 * 3600)
         
     | 
| 
       98 
     | 
    
         
            -
                
         
     | 
| 
       99 
     | 
    
         
            -
                @property
         
     | 
| 
       100 
     | 
    
         
            -
                def last_modified_datetime(self) -> datetime:
         
     | 
| 
       101 
     | 
    
         
            -
                    """Get last modified as datetime."""
         
     | 
| 
       102 
     | 
    
         
            -
                    return datetime.fromtimestamp(self.last_modified)
         
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
            @dataclass
         
     | 
| 
       106 
     | 
    
         
            -
            class LifecycleOperationResult:
         
     | 
| 
       107 
     | 
    
         
            -
                """Result of a lifecycle operation."""
         
     | 
| 
       108 
     | 
    
         
            -
                
         
     | 
| 
       109 
     | 
    
         
            -
                operation: LifecycleOperation
         
     | 
| 
       110 
     | 
    
         
            -
                agent_name: str
         
     | 
| 
       111 
     | 
    
         
            -
                success: bool
         
     | 
| 
       112 
     | 
    
         
            -
                duration_ms: float
         
     | 
| 
       113 
     | 
    
         
            -
                error_message: Optional[str] = None
         
     | 
| 
       114 
     | 
    
         
            -
                modification_id: Optional[str] = None
         
     | 
| 
       115 
     | 
    
         
            -
                persistence_id: Optional[str] = None
         
     | 
| 
       116 
     | 
    
         
            -
                cache_invalidated: bool = False
         
     | 
| 
       117 
     | 
    
         
            -
                registry_updated: bool = False
         
     | 
| 
       118 
     | 
    
         
            -
                metadata: Dict[str, Any] = field(default_factory=dict)
         
     | 
| 
      
 61 
     | 
    
         
            +
            # Backward compatibility imports
         
     | 
| 
      
 62 
     | 
    
         
            +
            # These allow existing code to import from this module
         
     | 
| 
      
 63 
     | 
    
         
            +
            __all__ = [
         
     | 
| 
      
 64 
     | 
    
         
            +
                'LifecycleOperation',
         
     | 
| 
      
 65 
     | 
    
         
            +
                'LifecycleState', 
         
     | 
| 
      
 66 
     | 
    
         
            +
                'AgentLifecycleRecord',
         
     | 
| 
      
 67 
     | 
    
         
            +
                'LifecycleOperationResult',
         
     | 
| 
      
 68 
     | 
    
         
            +
                'AgentLifecycleManager'
         
     | 
| 
      
 69 
     | 
    
         
            +
            ]
         
     | 
| 
       119 
70 
     | 
    
         | 
| 
       120 
71 
     | 
    
         | 
| 
       121 
72 
     | 
    
         
             
            class AgentLifecycleManager(BaseService):
         
     | 
| 
         @@ -149,6 +100,7 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       149 
100 
     | 
    
         
             
                    self.agent_registry: Optional[AgentRegistry] = None
         
     | 
| 
       150 
101 
     | 
    
         
             
                    self.modification_tracker: Optional[AgentModificationTracker] = None
         
     | 
| 
       151 
102 
     | 
    
         
             
                    self.persistence_service: Optional[AgentPersistenceService] = None
         
     | 
| 
      
 103 
     | 
    
         
            +
                    self.agent_manager: Optional[AgentManager] = None
         
     | 
| 
       152 
104 
     | 
    
         | 
| 
       153 
105 
     | 
    
         
             
                    # Lifecycle tracking
         
     | 
| 
       154 
106 
     | 
    
         
             
                    self.agent_records: Dict[str, AgentLifecycleRecord] = {}
         
     | 
| 
         @@ -246,6 +198,9 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       246 
198 
     | 
    
         
             
                        self.persistence_service = AgentPersistenceService()
         
     | 
| 
       247 
199 
     | 
    
         
             
                        await self.persistence_service.start()
         
     | 
| 
       248 
200 
     | 
    
         | 
| 
      
 201 
     | 
    
         
            +
                        # Initialize AgentManager
         
     | 
| 
      
 202 
     | 
    
         
            +
                        self.agent_manager = AgentManager()
         
     | 
| 
      
 203 
     | 
    
         
            +
                        
         
     | 
| 
       249 
204 
     | 
    
         
             
                        self.logger.info("Core services initialized successfully")
         
     | 
| 
       250 
205 
     | 
    
         | 
| 
       251 
206 
     | 
    
         
             
                    except Exception as e:
         
     | 
| 
         @@ -319,9 +274,9 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       319 
274 
     | 
    
         
             
                        if not self.agent_registry:
         
     | 
| 
       320 
275 
     | 
    
         
             
                            return
         
     | 
| 
       321 
276 
     | 
    
         | 
| 
       322 
     | 
    
         
            -
                        # Discover all agents via registry
         
     | 
| 
       323 
     | 
    
         
            -
                         
     | 
| 
       324 
     | 
    
         
            -
                        all_agents =  
     | 
| 
      
 277 
     | 
    
         
            +
                        # Discover all agents via registry (sync methods)
         
     | 
| 
      
 278 
     | 
    
         
            +
                        self.agent_registry.discover_agents()
         
     | 
| 
      
 279 
     | 
    
         
            +
                        all_agents = self.agent_registry.list_agents()
         
     | 
| 
       325 
280 
     | 
    
         | 
| 
       326 
281 
     | 
    
         
             
                        # Update lifecycle records with registry data
         
     | 
| 
       327 
282 
     | 
    
         
             
                        for agent_metadata in all_agents:
         
     | 
| 
         @@ -391,8 +346,32 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       391 
346 
     | 
    
         
             
                                    error_message="Agent already exists"
         
     | 
| 
       392 
347 
     | 
    
         
             
                                )
         
     | 
| 
       393 
348 
     | 
    
         | 
| 
       394 
     | 
    
         
            -
                            #  
     | 
| 
       395 
     | 
    
         
            -
                             
     | 
| 
      
 349 
     | 
    
         
            +
                            # Create agent definition
         
     | 
| 
      
 350 
     | 
    
         
            +
                            agent_def = await self._create_agent_definition(
         
     | 
| 
      
 351 
     | 
    
         
            +
                                agent_name, agent_content, tier, agent_type, **kwargs
         
     | 
| 
      
 352 
     | 
    
         
            +
                            )
         
     | 
| 
      
 353 
     | 
    
         
            +
                            
         
     | 
| 
      
 354 
     | 
    
         
            +
                            # Determine location based on tier
         
     | 
| 
      
 355 
     | 
    
         
            +
                            location = "project" if tier == ModificationTier.PROJECT else "framework"
         
     | 
| 
      
 356 
     | 
    
         
            +
                            
         
     | 
| 
      
 357 
     | 
    
         
            +
                            # Create agent using AgentManager (sync call in executor)
         
     | 
| 
      
 358 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 359 
     | 
    
         
            +
                                if self.agent_manager:
         
     | 
| 
      
 360 
     | 
    
         
            +
                                    file_path = await self._run_sync_in_executor(
         
     | 
| 
      
 361 
     | 
    
         
            +
                                        self.agent_manager.create_agent,
         
     | 
| 
      
 362 
     | 
    
         
            +
                                        agent_name, agent_def, location
         
     | 
| 
      
 363 
     | 
    
         
            +
                                    )
         
     | 
| 
      
 364 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 365 
     | 
    
         
            +
                                    # Fallback to direct file creation if AgentManager not available
         
     | 
| 
      
 366 
     | 
    
         
            +
                                    file_path = await self._determine_agent_file_path(agent_name, tier)
         
     | 
| 
      
 367 
     | 
    
         
            +
                                    path_ops.ensure_dir(file_path.parent)
         
     | 
| 
      
 368 
     | 
    
         
            +
                                    path_ops.safe_write(file_path, agent_content)
         
     | 
| 
      
 369 
     | 
    
         
            +
                            except Exception as e:
         
     | 
| 
      
 370 
     | 
    
         
            +
                                self.logger.error(f"AgentManager failed to create agent: {e}")
         
     | 
| 
      
 371 
     | 
    
         
            +
                                # Fallback to direct file creation
         
     | 
| 
      
 372 
     | 
    
         
            +
                                file_path = await self._determine_agent_file_path(agent_name, tier)
         
     | 
| 
      
 373 
     | 
    
         
            +
                                path_ops.ensure_dir(file_path.parent)
         
     | 
| 
      
 374 
     | 
    
         
            +
                                path_ops.safe_write(file_path, agent_content)
         
     | 
| 
       396 
375 
     | 
    
         | 
| 
       397 
376 
     | 
    
         
             
                            # Track modification
         
     | 
| 
       398 
377 
     | 
    
         
             
                            modification = await self.modification_tracker.track_modification(
         
     | 
| 
         @@ -404,13 +383,18 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       404 
383 
     | 
    
         
             
                                **kwargs
         
     | 
| 
       405 
384 
     | 
    
         
             
                            )
         
     | 
| 
       406 
385 
     | 
    
         | 
| 
       407 
     | 
    
         
            -
                            #  
     | 
| 
       408 
     | 
    
         
            -
                             
     | 
| 
      
 386 
     | 
    
         
            +
                            # Note: We don't use persistence_service for the actual write anymore
         
     | 
| 
      
 387 
     | 
    
         
            +
                            # since AgentManager handles that. We create a synthetic record for compatibility.
         
     | 
| 
      
 388 
     | 
    
         
            +
                            persistence_record = PersistenceRecord(
         
     | 
| 
      
 389 
     | 
    
         
            +
                                operation_id=f"create_{agent_name}_{time.time()}",
         
     | 
| 
      
 390 
     | 
    
         
            +
                                operation_type=PersistenceOperation.CREATE,
         
     | 
| 
       409 
391 
     | 
    
         
             
                                agent_name=agent_name,
         
     | 
| 
       410 
     | 
    
         
            -
                                agent_content=agent_content,
         
     | 
| 
       411 
392 
     | 
    
         
             
                                source_tier=tier,
         
     | 
| 
       412 
393 
     | 
    
         
             
                                target_tier=tier,
         
     | 
| 
       413 
     | 
    
         
            -
                                strategy=self.default_persistence_strategy
         
     | 
| 
      
 394 
     | 
    
         
            +
                                strategy=self.default_persistence_strategy,
         
     | 
| 
      
 395 
     | 
    
         
            +
                                success=True,
         
     | 
| 
      
 396 
     | 
    
         
            +
                                timestamp=time.time(),
         
     | 
| 
      
 397 
     | 
    
         
            +
                                file_path=str(file_path)
         
     | 
| 
       414 
398 
     | 
    
         
             
                            )
         
     | 
| 
       415 
399 
     | 
    
         | 
| 
       416 
400 
     | 
    
         
             
                            # Create lifecycle record
         
     | 
| 
         @@ -512,6 +496,48 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       512 
496 
     | 
    
         | 
| 
       513 
497 
     | 
    
         
             
                            record = self.agent_records[agent_name]
         
     | 
| 
       514 
498 
     | 
    
         | 
| 
      
 499 
     | 
    
         
            +
                            # Update agent using AgentManager
         
     | 
| 
      
 500 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 501 
     | 
    
         
            +
                                if self.agent_manager:
         
     | 
| 
      
 502 
     | 
    
         
            +
                                    # Read current agent to get full definition
         
     | 
| 
      
 503 
     | 
    
         
            +
                                    current_def = await self._run_sync_in_executor(
         
     | 
| 
      
 504 
     | 
    
         
            +
                                        self.agent_manager.read_agent, agent_name
         
     | 
| 
      
 505 
     | 
    
         
            +
                                    )
         
     | 
| 
      
 506 
     | 
    
         
            +
                                    
         
     | 
| 
      
 507 
     | 
    
         
            +
                                    if current_def:
         
     | 
| 
      
 508 
     | 
    
         
            +
                                        # Update raw content
         
     | 
| 
      
 509 
     | 
    
         
            +
                                        current_def.raw_content = agent_content
         
     | 
| 
      
 510 
     | 
    
         
            +
                                        
         
     | 
| 
      
 511 
     | 
    
         
            +
                                        # Apply any metadata updates from kwargs
         
     | 
| 
      
 512 
     | 
    
         
            +
                                        if 'model_preference' in kwargs:
         
     | 
| 
      
 513 
     | 
    
         
            +
                                            current_def.metadata.model_preference = kwargs['model_preference']
         
     | 
| 
      
 514 
     | 
    
         
            +
                                        if 'tags' in kwargs:
         
     | 
| 
      
 515 
     | 
    
         
            +
                                            current_def.metadata.tags = kwargs['tags']
         
     | 
| 
      
 516 
     | 
    
         
            +
                                        if 'specializations' in kwargs:
         
     | 
| 
      
 517 
     | 
    
         
            +
                                            current_def.metadata.specializations = kwargs['specializations']
         
     | 
| 
      
 518 
     | 
    
         
            +
                                        
         
     | 
| 
      
 519 
     | 
    
         
            +
                                        # Update via AgentManager
         
     | 
| 
      
 520 
     | 
    
         
            +
                                        updated_def = await self._run_sync_in_executor(
         
     | 
| 
      
 521 
     | 
    
         
            +
                                            self.agent_manager.update_agent,
         
     | 
| 
      
 522 
     | 
    
         
            +
                                            agent_name, {"raw_content": agent_content}, True
         
     | 
| 
      
 523 
     | 
    
         
            +
                                        )
         
     | 
| 
      
 524 
     | 
    
         
            +
                                        
         
     | 
| 
      
 525 
     | 
    
         
            +
                                        if not updated_def:
         
     | 
| 
      
 526 
     | 
    
         
            +
                                            raise Exception("AgentManager update failed")
         
     | 
| 
      
 527 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 528 
     | 
    
         
            +
                                        raise Exception("Could not read current agent definition")
         
     | 
| 
      
 529 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 530 
     | 
    
         
            +
                                    # Fallback to direct file update
         
     | 
| 
      
 531 
     | 
    
         
            +
                                    file_path = Path(record.file_path)
         
     | 
| 
      
 532 
     | 
    
         
            +
                                    if path_ops.validate_exists(file_path):
         
     | 
| 
      
 533 
     | 
    
         
            +
                                        path_ops.safe_write(file_path, agent_content)
         
     | 
| 
      
 534 
     | 
    
         
            +
                            except Exception as e:
         
     | 
| 
      
 535 
     | 
    
         
            +
                                self.logger.error(f"AgentManager failed to update agent: {e}")
         
     | 
| 
      
 536 
     | 
    
         
            +
                                # Fallback to direct file update
         
     | 
| 
      
 537 
     | 
    
         
            +
                                file_path = Path(record.file_path)
         
     | 
| 
      
 538 
     | 
    
         
            +
                                if path_ops.validate_exists(file_path):
         
     | 
| 
      
 539 
     | 
    
         
            +
                                    path_ops.safe_write(file_path, agent_content)
         
     | 
| 
      
 540 
     | 
    
         
            +
                            
         
     | 
| 
       515 
541 
     | 
    
         
             
                            # Track modification
         
     | 
| 
       516 
542 
     | 
    
         
             
                            modification = await self.modification_tracker.track_modification(
         
     | 
| 
       517 
543 
     | 
    
         
             
                                agent_name=agent_name,
         
     | 
| 
         @@ -521,12 +547,17 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       521 
547 
     | 
    
         
             
                                **kwargs
         
     | 
| 
       522 
548 
     | 
    
         
             
                            )
         
     | 
| 
       523 
549 
     | 
    
         | 
| 
       524 
     | 
    
         
            -
                            #  
     | 
| 
       525 
     | 
    
         
            -
                            persistence_record =  
     | 
| 
      
 550 
     | 
    
         
            +
                            # Create synthetic persistence record for compatibility
         
     | 
| 
      
 551 
     | 
    
         
            +
                            persistence_record = PersistenceRecord(
         
     | 
| 
      
 552 
     | 
    
         
            +
                                operation_id=f"update_{agent_name}_{time.time()}",
         
     | 
| 
      
 553 
     | 
    
         
            +
                                operation_type=PersistenceOperation.UPDATE,
         
     | 
| 
       526 
554 
     | 
    
         
             
                                agent_name=agent_name,
         
     | 
| 
       527 
     | 
    
         
            -
                                agent_content=agent_content,
         
     | 
| 
       528 
555 
     | 
    
         
             
                                source_tier=record.tier,
         
     | 
| 
       529 
     | 
    
         
            -
                                 
     | 
| 
      
 556 
     | 
    
         
            +
                                target_tier=record.tier,
         
     | 
| 
      
 557 
     | 
    
         
            +
                                strategy=self.default_persistence_strategy,
         
     | 
| 
      
 558 
     | 
    
         
            +
                                success=True,
         
     | 
| 
      
 559 
     | 
    
         
            +
                                timestamp=time.time(),
         
     | 
| 
      
 560 
     | 
    
         
            +
                                file_path=record.file_path
         
     | 
| 
       530 
561 
     | 
    
         
             
                            )
         
     | 
| 
       531 
562 
     | 
    
         | 
| 
       532 
563 
     | 
    
         
             
                            # Update lifecycle record
         
     | 
| 
         @@ -631,10 +662,28 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       631 
662 
     | 
    
         
             
                                **kwargs
         
     | 
| 
       632 
663 
     | 
    
         
             
                            )
         
     | 
| 
       633 
664 
     | 
    
         | 
| 
       634 
     | 
    
         
            -
                            # Delete  
     | 
| 
       635 
     | 
    
         
            -
                             
     | 
| 
       636 
     | 
    
         
            -
                             
     | 
| 
       637 
     | 
    
         
            -
                                 
     | 
| 
      
 665 
     | 
    
         
            +
                            # Delete agent using AgentManager
         
     | 
| 
      
 666 
     | 
    
         
            +
                            deletion_success = False
         
     | 
| 
      
 667 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 668 
     | 
    
         
            +
                                if self.agent_manager:
         
     | 
| 
      
 669 
     | 
    
         
            +
                                    deletion_success = await self._run_sync_in_executor(
         
     | 
| 
      
 670 
     | 
    
         
            +
                                        self.agent_manager.delete_agent, agent_name
         
     | 
| 
      
 671 
     | 
    
         
            +
                                    )
         
     | 
| 
      
 672 
     | 
    
         
            +
                                    if not deletion_success:
         
     | 
| 
      
 673 
     | 
    
         
            +
                                        raise Exception("AgentManager delete failed")
         
     | 
| 
      
 674 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 675 
     | 
    
         
            +
                                    # Fallback to direct file deletion
         
     | 
| 
      
 676 
     | 
    
         
            +
                                    file_path = Path(record.file_path)
         
     | 
| 
      
 677 
     | 
    
         
            +
                                    if path_ops.validate_exists(file_path):
         
     | 
| 
      
 678 
     | 
    
         
            +
                                        path_ops.safe_delete(file_path)
         
     | 
| 
      
 679 
     | 
    
         
            +
                                        deletion_success = True
         
     | 
| 
      
 680 
     | 
    
         
            +
                            except Exception as e:
         
     | 
| 
      
 681 
     | 
    
         
            +
                                self.logger.error(f"AgentManager failed to delete agent: {e}")
         
     | 
| 
      
 682 
     | 
    
         
            +
                                # Fallback to direct file deletion
         
     | 
| 
      
 683 
     | 
    
         
            +
                                file_path = Path(record.file_path)
         
     | 
| 
      
 684 
     | 
    
         
            +
                                if path_ops.validate_exists(file_path):
         
     | 
| 
      
 685 
     | 
    
         
            +
                                    path_ops.safe_delete(file_path)
         
     | 
| 
      
 686 
     | 
    
         
            +
                                    deletion_success = True
         
     | 
| 
       638 
687 
     | 
    
         | 
| 
       639 
688 
     | 
    
         
             
                            # Update lifecycle record
         
     | 
| 
       640 
689 
     | 
    
         
             
                            record.current_state = LifecycleState.DELETED
         
     | 
| 
         @@ -749,8 +798,8 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       749 
798 
     | 
    
         
             
                        return False
         
     | 
| 
       750 
799 
     | 
    
         | 
| 
       751 
800 
     | 
    
         
             
                    try:
         
     | 
| 
       752 
     | 
    
         
            -
                        # Refresh  
     | 
| 
       753 
     | 
    
         
            -
                         
     | 
| 
      
 801 
     | 
    
         
            +
                        # Refresh registry (discover_agents is synchronous)
         
     | 
| 
      
 802 
     | 
    
         
            +
                        self.agent_registry.discover_agents()
         
     | 
| 
       754 
803 
     | 
    
         
             
                        return True
         
     | 
| 
       755 
804 
     | 
    
         | 
| 
       756 
805 
     | 
    
         
             
                    except Exception as e:
         
     | 
| 
         @@ -950,6 +999,69 @@ class AgentLifecycleManager(BaseService): 
     | 
|
| 
       950 
999 
     | 
    
         | 
| 
       951 
1000 
     | 
    
         
             
                    return stats
         
     | 
| 
       952 
1001 
     | 
    
         | 
| 
      
 1002 
     | 
    
         
            +
                async def _create_agent_definition(self, agent_name: str, agent_content: str, 
         
     | 
| 
      
 1003 
     | 
    
         
            +
                                                  tier: ModificationTier, agent_type: str, **kwargs) -> AgentDefinition:
         
     | 
| 
      
 1004 
     | 
    
         
            +
                    """
         
     | 
| 
      
 1005 
     | 
    
         
            +
                    Create an AgentDefinition from lifecycle parameters.
         
     | 
| 
      
 1006 
     | 
    
         
            +
                    
         
     | 
| 
      
 1007 
     | 
    
         
            +
                    WHY: This method bridges the gap between the lifecycle manager's parameters
         
     | 
| 
      
 1008 
     | 
    
         
            +
                    and the AgentManager's expected AgentDefinition model.
         
     | 
| 
      
 1009 
     | 
    
         
            +
                    
         
     | 
| 
      
 1010 
     | 
    
         
            +
                    DESIGN DECISION: Creating a minimal AgentDefinition here because:
         
     | 
| 
      
 1011 
     | 
    
         
            +
                    - The full markdown parsing happens in AgentManager
         
     | 
| 
      
 1012 
     | 
    
         
            +
                    - We only need to provide the essential metadata
         
     | 
| 
      
 1013 
     | 
    
         
            +
                    - This keeps the lifecycle manager focused on orchestration
         
     | 
| 
      
 1014 
     | 
    
         
            +
                    """
         
     | 
| 
      
 1015 
     | 
    
         
            +
                    # Map tier to AgentType
         
     | 
| 
      
 1016 
     | 
    
         
            +
                    type_map = {
         
     | 
| 
      
 1017 
     | 
    
         
            +
                        ModificationTier.USER: AgentType.CUSTOM,
         
     | 
| 
      
 1018 
     | 
    
         
            +
                        ModificationTier.PROJECT: AgentType.PROJECT,
         
     | 
| 
      
 1019 
     | 
    
         
            +
                        ModificationTier.SYSTEM: AgentType.SYSTEM
         
     | 
| 
      
 1020 
     | 
    
         
            +
                    }
         
     | 
| 
      
 1021 
     | 
    
         
            +
                    
         
     | 
| 
      
 1022 
     | 
    
         
            +
                    # Create metadata
         
     | 
| 
      
 1023 
     | 
    
         
            +
                    from claude_mpm.models.agent_definition import AgentMetadata, AgentPermissions
         
     | 
| 
      
 1024 
     | 
    
         
            +
                    metadata = AgentMetadata(
         
     | 
| 
      
 1025 
     | 
    
         
            +
                        type=type_map.get(tier, AgentType.CUSTOM),
         
     | 
| 
      
 1026 
     | 
    
         
            +
                        model_preference=kwargs.get('model_preference', 'claude-3-sonnet'),
         
     | 
| 
      
 1027 
     | 
    
         
            +
                        version="1.0.0",
         
     | 
| 
      
 1028 
     | 
    
         
            +
                        author=kwargs.get('author', 'claude-mpm'),
         
     | 
| 
      
 1029 
     | 
    
         
            +
                        tags=kwargs.get('tags', []),
         
     | 
| 
      
 1030 
     | 
    
         
            +
                        specializations=kwargs.get('specializations', [])
         
     | 
| 
      
 1031 
     | 
    
         
            +
                    )
         
     | 
| 
      
 1032 
     | 
    
         
            +
                    
         
     | 
| 
      
 1033 
     | 
    
         
            +
                    # Create minimal definition
         
     | 
| 
      
 1034 
     | 
    
         
            +
                    definition = AgentDefinition(
         
     | 
| 
      
 1035 
     | 
    
         
            +
                        name=agent_name,
         
     | 
| 
      
 1036 
     | 
    
         
            +
                        title=agent_name.replace('-', ' ').title(),
         
     | 
| 
      
 1037 
     | 
    
         
            +
                        file_path="",  # Will be set by AgentManager
         
     | 
| 
      
 1038 
     | 
    
         
            +
                        metadata=metadata,
         
     | 
| 
      
 1039 
     | 
    
         
            +
                        primary_role=kwargs.get('primary_role', f"{agent_name} agent"),
         
     | 
| 
      
 1040 
     | 
    
         
            +
                        when_to_use={"select": [], "do_not_select": []},
         
     | 
| 
      
 1041 
     | 
    
         
            +
                        capabilities=[],
         
     | 
| 
      
 1042 
     | 
    
         
            +
                        authority=AgentPermissions(),
         
     | 
| 
      
 1043 
     | 
    
         
            +
                        workflows=[],
         
     | 
| 
      
 1044 
     | 
    
         
            +
                        escalation_triggers=[],
         
     | 
| 
      
 1045 
     | 
    
         
            +
                        kpis=[],
         
     | 
| 
      
 1046 
     | 
    
         
            +
                        dependencies=[],
         
     | 
| 
      
 1047 
     | 
    
         
            +
                        tools_commands="",
         
     | 
| 
      
 1048 
     | 
    
         
            +
                        raw_content=agent_content
         
     | 
| 
      
 1049 
     | 
    
         
            +
                    )
         
     | 
| 
      
 1050 
     | 
    
         
            +
                    
         
     | 
| 
      
 1051 
     | 
    
         
            +
                    return definition
         
     | 
| 
      
 1052 
     | 
    
         
            +
                
         
     | 
| 
      
 1053 
     | 
    
         
            +
                async def _run_sync_in_executor(self, func, *args, **kwargs):
         
     | 
| 
      
 1054 
     | 
    
         
            +
                    """
         
     | 
| 
      
 1055 
     | 
    
         
            +
                    Run a synchronous function in an executor to avoid blocking.
         
     | 
| 
      
 1056 
     | 
    
         
            +
                    
         
     | 
| 
      
 1057 
     | 
    
         
            +
                    WHY: AgentManager has synchronous methods but AgentLifecycleManager is async.
         
     | 
| 
      
 1058 
     | 
    
         
            +
                    This allows us to call sync methods without blocking the event loop.
         
     | 
| 
      
 1059 
     | 
    
         
            +
                    
         
     | 
| 
      
 1060 
     | 
    
         
            +
                    PERFORMANCE: Uses the default executor which manages a thread pool efficiently.
         
     | 
| 
      
 1061 
     | 
    
         
            +
                    """
         
     | 
| 
      
 1062 
     | 
    
         
            +
                    loop = asyncio.get_event_loop()
         
     | 
| 
      
 1063 
     | 
    
         
            +
                    return await loop.run_in_executor(None, func, *args, **kwargs)
         
     | 
| 
      
 1064 
     | 
    
         
            +
                
         
     | 
| 
       953 
1065 
     | 
    
         
             
                async def restore_agent(self, agent_name: str, backup_path: Optional[str] = None) -> LifecycleOperationResult:
         
     | 
| 
       954 
1066 
     | 
    
         
             
                    """Restore agent from backup."""
         
     | 
| 
       955 
1067 
     | 
    
         
             
                    start_time = time.time()
         
     | 
| 
         @@ -28,9 +28,8 @@ import os 
     | 
|
| 
       28 
28 
     | 
    
         
             
            import shutil
         
     | 
| 
       29 
29 
     | 
    
         
             
            import time
         
     | 
| 
       30 
30 
     | 
    
         
             
            import uuid
         
     | 
| 
       31 
     | 
    
         
            -
            from dataclasses import  
     | 
| 
      
 31 
     | 
    
         
            +
            from dataclasses import asdict
         
     | 
| 
       32 
32 
     | 
    
         
             
            from datetime import datetime
         
     | 
| 
       33 
     | 
    
         
            -
            from enum import Enum
         
     | 
| 
       34 
33 
     | 
    
         
             
            from pathlib import Path
         
     | 
| 
       35 
34 
     | 
    
         
             
            from typing import Dict, List, Optional, Any, Callable, Tuple, Set
         
     | 
| 
       36 
35 
     | 
    
         | 
| 
         @@ -40,105 +39,25 @@ from watchdog.events import FileSystemEventHandler, FileSystemEvent 
     | 
|
| 
       40 
39 
     | 
    
         
             
            from claude_mpm.core.base_service import BaseService
         
     | 
| 
       41 
40 
     | 
    
         
             
            from claude_mpm.services.shared_prompt_cache import SharedPromptCache
         
     | 
| 
       42 
41 
     | 
    
         
             
            from claude_mpm.services.agent_registry import AgentRegistry
         
     | 
| 
      
 42 
     | 
    
         
            +
            from claude_mpm.models.modification import (
         
     | 
| 
      
 43 
     | 
    
         
            +
                ModificationType,
         
     | 
| 
      
 44 
     | 
    
         
            +
                ModificationTier,
         
     | 
| 
      
 45 
     | 
    
         
            +
                AgentModification,
         
     | 
| 
      
 46 
     | 
    
         
            +
                ModificationHistory
         
     | 
| 
      
 47 
     | 
    
         
            +
            )
         
     | 
| 
       43 
48 
     | 
    
         
             
            from claude_mpm.utils.path_operations import path_ops
         
     | 
| 
       44 
49 
     | 
    
         
             
            from claude_mpm.utils.config_manager import ConfigurationManager
         
     | 
| 
       45 
50 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
            #  
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
     | 
    
         
            -
             
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                 
     | 
| 
       53 
     | 
    
         
            -
                 
     | 
| 
       54 
     | 
    
         
            -
                 
     | 
| 
       55 
     | 
    
         
            -
             
     | 
| 
       56 
     | 
    
         
            -
                MOVE = "move"
         
     | 
| 
       57 
     | 
    
         
            -
                RESTORE = "restore"
         
     | 
| 
       58 
     | 
    
         
            -
             
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
       60 
     | 
    
         
            -
            class ModificationTier(Enum):
         
     | 
| 
       61 
     | 
    
         
            -
                """Agent hierarchy tiers for modification tracking."""
         
     | 
| 
       62 
     | 
    
         
            -
                PROJECT = "project"
         
     | 
| 
       63 
     | 
    
         
            -
                USER = "user"
         
     | 
| 
       64 
     | 
    
         
            -
                SYSTEM = "system"
         
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
            @dataclass
         
     | 
| 
       68 
     | 
    
         
            -
            class AgentModification:
         
     | 
| 
       69 
     | 
    
         
            -
                """Agent modification record with comprehensive metadata."""
         
     | 
| 
       70 
     | 
    
         
            -
                
         
     | 
| 
       71 
     | 
    
         
            -
                modification_id: str
         
     | 
| 
       72 
     | 
    
         
            -
                agent_name: str
         
     | 
| 
       73 
     | 
    
         
            -
                modification_type: ModificationType
         
     | 
| 
       74 
     | 
    
         
            -
                tier: ModificationTier
         
     | 
| 
       75 
     | 
    
         
            -
                file_path: str
         
     | 
| 
       76 
     | 
    
         
            -
                timestamp: float
         
     | 
| 
       77 
     | 
    
         
            -
                user_id: Optional[str] = None
         
     | 
| 
       78 
     | 
    
         
            -
                modification_details: Dict[str, Any] = field(default_factory=dict)
         
     | 
| 
       79 
     | 
    
         
            -
                file_hash_before: Optional[str] = None
         
     | 
| 
       80 
     | 
    
         
            -
                file_hash_after: Optional[str] = None
         
     | 
| 
       81 
     | 
    
         
            -
                file_size_before: Optional[int] = None
         
     | 
| 
       82 
     | 
    
         
            -
                file_size_after: Optional[int] = None
         
     | 
| 
       83 
     | 
    
         
            -
                backup_path: Optional[str] = None
         
     | 
| 
       84 
     | 
    
         
            -
                validation_status: str = "pending"
         
     | 
| 
       85 
     | 
    
         
            -
                validation_errors: List[str] = field(default_factory=list)
         
     | 
| 
       86 
     | 
    
         
            -
                related_modifications: List[str] = field(default_factory=list)
         
     | 
| 
       87 
     | 
    
         
            -
                metadata: Dict[str, Any] = field(default_factory=dict)
         
     | 
| 
       88 
     | 
    
         
            -
                
         
     | 
| 
       89 
     | 
    
         
            -
                @property
         
     | 
| 
       90 
     | 
    
         
            -
                def modification_datetime(self) -> datetime:
         
     | 
| 
       91 
     | 
    
         
            -
                    """Get modification timestamp as datetime."""
         
     | 
| 
       92 
     | 
    
         
            -
                    return datetime.fromtimestamp(self.timestamp)
         
     | 
| 
       93 
     | 
    
         
            -
                
         
     | 
| 
       94 
     | 
    
         
            -
                @property
         
     | 
| 
       95 
     | 
    
         
            -
                def age_seconds(self) -> float:
         
     | 
| 
       96 
     | 
    
         
            -
                    """Get age of modification in seconds."""
         
     | 
| 
       97 
     | 
    
         
            -
                    return time.time() - self.timestamp
         
     | 
| 
       98 
     | 
    
         
            -
                
         
     | 
| 
       99 
     | 
    
         
            -
                def to_dict(self) -> Dict[str, Any]:
         
     | 
| 
       100 
     | 
    
         
            -
                    """Convert to dictionary for serialization."""
         
     | 
| 
       101 
     | 
    
         
            -
                    data = asdict(self)
         
     | 
| 
       102 
     | 
    
         
            -
                    data['modification_type'] = self.modification_type.value
         
     | 
| 
       103 
     | 
    
         
            -
                    data['tier'] = self.tier.value
         
     | 
| 
       104 
     | 
    
         
            -
                    return data
         
     | 
| 
       105 
     | 
    
         
            -
                
         
     | 
| 
       106 
     | 
    
         
            -
                @classmethod
         
     | 
| 
       107 
     | 
    
         
            -
                def from_dict(cls, data: Dict[str, Any]) -> 'AgentModification':
         
     | 
| 
       108 
     | 
    
         
            -
                    """Create from dictionary."""
         
     | 
| 
       109 
     | 
    
         
            -
                    data['modification_type'] = ModificationType(data['modification_type'])
         
     | 
| 
       110 
     | 
    
         
            -
                    data['tier'] = ModificationTier(data['tier'])
         
     | 
| 
       111 
     | 
    
         
            -
                    return cls(**data)
         
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
            @dataclass
         
     | 
| 
       115 
     | 
    
         
            -
            class ModificationHistory:
         
     | 
| 
       116 
     | 
    
         
            -
                """Complete modification history for an agent."""
         
     | 
| 
       117 
     | 
    
         
            -
                
         
     | 
| 
       118 
     | 
    
         
            -
                agent_name: str
         
     | 
| 
       119 
     | 
    
         
            -
                modifications: List[AgentModification] = field(default_factory=list)
         
     | 
| 
       120 
     | 
    
         
            -
                current_version: Optional[str] = None
         
     | 
| 
       121 
     | 
    
         
            -
                total_modifications: int = 0
         
     | 
| 
       122 
     | 
    
         
            -
                first_seen: Optional[float] = None
         
     | 
| 
       123 
     | 
    
         
            -
                last_modified: Optional[float] = None
         
     | 
| 
       124 
     | 
    
         
            -
                
         
     | 
| 
       125 
     | 
    
         
            -
                def add_modification(self, modification: AgentModification) -> None:
         
     | 
| 
       126 
     | 
    
         
            -
                    """Add a modification to history."""
         
     | 
| 
       127 
     | 
    
         
            -
                    self.modifications.append(modification)
         
     | 
| 
       128 
     | 
    
         
            -
                    self.total_modifications += 1
         
     | 
| 
       129 
     | 
    
         
            -
                    self.last_modified = modification.timestamp
         
     | 
| 
       130 
     | 
    
         
            -
                    
         
     | 
| 
       131 
     | 
    
         
            -
                    if self.first_seen is None:
         
     | 
| 
       132 
     | 
    
         
            -
                        self.first_seen = modification.timestamp
         
     | 
| 
       133 
     | 
    
         
            -
                
         
     | 
| 
       134 
     | 
    
         
            -
                def get_recent_modifications(self, hours: int = 24) -> List[AgentModification]:
         
     | 
| 
       135 
     | 
    
         
            -
                    """Get modifications within specified hours."""
         
     | 
| 
       136 
     | 
    
         
            -
                    cutoff = time.time() - (hours * 3600)
         
     | 
| 
       137 
     | 
    
         
            -
                    return [mod for mod in self.modifications if mod.timestamp >= cutoff]
         
     | 
| 
       138 
     | 
    
         
            -
                
         
     | 
| 
       139 
     | 
    
         
            -
                def get_modifications_by_type(self, mod_type: ModificationType) -> List[AgentModification]:
         
     | 
| 
       140 
     | 
    
         
            -
                    """Get modifications by type."""
         
     | 
| 
       141 
     | 
    
         
            -
                    return [mod for mod in self.modifications if mod.modification_type == mod_type]
         
     | 
| 
      
 51 
     | 
    
         
            +
            # Backward compatibility exports
         
     | 
| 
      
 52 
     | 
    
         
            +
            # These allow existing code to import models from this module
         
     | 
| 
      
 53 
     | 
    
         
            +
            __all__ = [
         
     | 
| 
      
 54 
     | 
    
         
            +
                'ModificationType',
         
     | 
| 
      
 55 
     | 
    
         
            +
                'ModificationTier',
         
     | 
| 
      
 56 
     | 
    
         
            +
                'AgentModification', 
         
     | 
| 
      
 57 
     | 
    
         
            +
                'ModificationHistory',
         
     | 
| 
      
 58 
     | 
    
         
            +
                'AgentModificationTracker',
         
     | 
| 
      
 59 
     | 
    
         
            +
                'AgentFileSystemHandler'
         
     | 
| 
      
 60 
     | 
    
         
            +
            ]
         
     | 
| 
       142 
61 
     | 
    
         | 
| 
       143 
62 
     | 
    
         | 
| 
       144 
63 
     | 
    
         
             
            # ============================================================================
         
     | 
| 
         @@ -341,6 +260,14 @@ class AgentModificationTracker(BaseService): 
     | 
|
| 
       341 
260 
     | 
    
         
             
                        backup_path = await self._create_backup(file_path, modification_id)
         
     | 
| 
       342 
261 
     | 
    
         | 
| 
       343 
262 
     | 
    
         
             
                    # Create modification record
         
     | 
| 
      
 263 
     | 
    
         
            +
                    # Only include valid AgentModification fields from file_metadata
         
     | 
| 
      
 264 
     | 
    
         
            +
                    valid_metadata_fields = {'file_hash_after', 'file_size_after'}
         
     | 
| 
      
 265 
     | 
    
         
            +
                    filtered_metadata = {k: v for k, v in file_metadata.items() if k in valid_metadata_fields}
         
     | 
| 
      
 266 
     | 
    
         
            +
                    
         
     | 
| 
      
 267 
     | 
    
         
            +
                    # Add other metadata to the metadata field
         
     | 
| 
      
 268 
     | 
    
         
            +
                    extra_metadata = {k: v for k, v in file_metadata.items() if k not in valid_metadata_fields}
         
     | 
| 
      
 269 
     | 
    
         
            +
                    extra_metadata.update(kwargs)
         
     | 
| 
      
 270 
     | 
    
         
            +
                    
         
     | 
| 
       344 
271 
     | 
    
         
             
                    modification = AgentModification(
         
     | 
| 
       345 
272 
     | 
    
         
             
                        modification_id=modification_id,
         
     | 
| 
       346 
273 
     | 
    
         
             
                        agent_name=agent_name,
         
     | 
| 
         @@ -349,8 +276,8 @@ class AgentModificationTracker(BaseService): 
     | 
|
| 
       349 
276 
     | 
    
         
             
                        file_path=file_path,
         
     | 
| 
       350 
277 
     | 
    
         
             
                        timestamp=time.time(),
         
     | 
| 
       351 
278 
     | 
    
         
             
                        backup_path=backup_path,
         
     | 
| 
       352 
     | 
    
         
            -
                         
     | 
| 
       353 
     | 
    
         
            -
                        ** 
     | 
| 
      
 279 
     | 
    
         
            +
                        metadata=extra_metadata,
         
     | 
| 
      
 280 
     | 
    
         
            +
                        **filtered_metadata
         
     | 
| 
       354 
281 
     | 
    
         
             
                    )
         
     | 
| 
       355 
282 
     | 
    
         | 
| 
       356 
283 
     | 
    
         
             
                    # Validate modification if enabled
         
     | 
| 
         @@ -0,0 +1,74 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env python3
         
     | 
| 
      
 2 
     | 
    
         
            +
            """
         
     | 
| 
      
 3 
     | 
    
         
            +
            Agent Persistence Service (Stub)
         
     | 
| 
      
 4 
     | 
    
         
            +
            ================================
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            WHY: This is a stub implementation to support the AgentLifecycleManager integration.
         
     | 
| 
      
 7 
     | 
    
         
            +
            The actual persistence is now handled by AgentManager, but we maintain this interface
         
     | 
| 
      
 8 
     | 
    
         
            +
            for backward compatibility.
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            DESIGN DECISION: Creating a minimal stub because:
         
     | 
| 
      
 11 
     | 
    
         
            +
            - AgentManager handles the actual file persistence
         
     | 
| 
      
 12 
     | 
    
         
            +
            - This maintains the existing API contract
         
     | 
| 
      
 13 
     | 
    
         
            +
            - Allows for future extension if needed
         
     | 
| 
      
 14 
     | 
    
         
            +
            """
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            from typing import Optional, Any
         
     | 
| 
      
 17 
     | 
    
         
            +
            import time
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            from claude_mpm.models.persistence import (
         
     | 
| 
      
 20 
     | 
    
         
            +
                PersistenceStrategy,
         
     | 
| 
      
 21 
     | 
    
         
            +
                PersistenceOperation,
         
     | 
| 
      
 22 
     | 
    
         
            +
                PersistenceRecord
         
     | 
| 
      
 23 
     | 
    
         
            +
            )
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            # Backward compatibility exports
         
     | 
| 
      
 26 
     | 
    
         
            +
            __all__ = [
         
     | 
| 
      
 27 
     | 
    
         
            +
                'PersistenceStrategy',
         
     | 
| 
      
 28 
     | 
    
         
            +
                'PersistenceOperation',
         
     | 
| 
      
 29 
     | 
    
         
            +
                'PersistenceRecord',
         
     | 
| 
      
 30 
     | 
    
         
            +
                'AgentPersistenceService'
         
     | 
| 
      
 31 
     | 
    
         
            +
            ]
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            class AgentPersistenceService:
         
     | 
| 
      
 35 
     | 
    
         
            +
                """
         
     | 
| 
      
 36 
     | 
    
         
            +
                Stub implementation for agent persistence service.
         
     | 
| 
      
 37 
     | 
    
         
            +
                
         
     | 
| 
      
 38 
     | 
    
         
            +
                WHY: Maintains compatibility with AgentLifecycleManager while
         
     | 
| 
      
 39 
     | 
    
         
            +
                actual persistence is delegated to AgentManager.
         
     | 
| 
      
 40 
     | 
    
         
            +
                """
         
     | 
| 
      
 41 
     | 
    
         
            +
                
         
     | 
| 
      
 42 
     | 
    
         
            +
                def __init__(self):
         
     | 
| 
      
 43 
     | 
    
         
            +
                    """Initialize the persistence service."""
         
     | 
| 
      
 44 
     | 
    
         
            +
                    pass
         
     | 
| 
      
 45 
     | 
    
         
            +
                
         
     | 
| 
      
 46 
     | 
    
         
            +
                async def start(self) -> None:
         
     | 
| 
      
 47 
     | 
    
         
            +
                    """Start the persistence service."""
         
     | 
| 
      
 48 
     | 
    
         
            +
                    # No-op for stub
         
     | 
| 
      
 49 
     | 
    
         
            +
                    pass
         
     | 
| 
      
 50 
     | 
    
         
            +
                
         
     | 
| 
      
 51 
     | 
    
         
            +
                async def stop(self) -> None:
         
     | 
| 
      
 52 
     | 
    
         
            +
                    """Stop the persistence service."""
         
     | 
| 
      
 53 
     | 
    
         
            +
                    # No-op for stub
         
     | 
| 
      
 54 
     | 
    
         
            +
                    pass
         
     | 
| 
      
 55 
     | 
    
         
            +
                
         
     | 
| 
      
 56 
     | 
    
         
            +
                async def persist_agent(self, agent_name: str, agent_content: str,
         
     | 
| 
      
 57 
     | 
    
         
            +
                                       source_tier: Any, target_tier: Optional[Any] = None,
         
     | 
| 
      
 58 
     | 
    
         
            +
                                       strategy: Optional[PersistenceStrategy] = None) -> PersistenceRecord:
         
     | 
| 
      
 59 
     | 
    
         
            +
                    """
         
     | 
| 
      
 60 
     | 
    
         
            +
                    Create a persistence record (actual persistence handled by AgentManager).
         
     | 
| 
      
 61 
     | 
    
         
            +
                    
         
     | 
| 
      
 62 
     | 
    
         
            +
                    WHY: This method exists for API compatibility but doesn't perform
         
     | 
| 
      
 63 
     | 
    
         
            +
                    actual file operations since AgentManager handles that.
         
     | 
| 
      
 64 
     | 
    
         
            +
                    """
         
     | 
| 
      
 65 
     | 
    
         
            +
                    return PersistenceRecord(
         
     | 
| 
      
 66 
     | 
    
         
            +
                        operation_id=f"persist_{agent_name}_{time.time()}",
         
     | 
| 
      
 67 
     | 
    
         
            +
                        operation_type=PersistenceOperation.UPDATE,
         
     | 
| 
      
 68 
     | 
    
         
            +
                        agent_name=agent_name,
         
     | 
| 
      
 69 
     | 
    
         
            +
                        source_tier=source_tier,
         
     | 
| 
      
 70 
     | 
    
         
            +
                        target_tier=target_tier or source_tier,
         
     | 
| 
      
 71 
     | 
    
         
            +
                        strategy=strategy or PersistenceStrategy.USER_OVERRIDE,
         
     | 
| 
      
 72 
     | 
    
         
            +
                        success=True,
         
     | 
| 
      
 73 
     | 
    
         
            +
                        timestamp=time.time()
         
     | 
| 
      
 74 
     | 
    
         
            +
                    )
         
     |