claude-mpm 3.7.8__py3-none-any.whl → 3.9.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/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +0 -106
- claude_mpm/agents/INSTRUCTIONS.md +0 -96
- claude_mpm/agents/MEMORY.md +94 -0
- claude_mpm/agents/WORKFLOW.md +86 -0
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +1 -1
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/ops.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +3 -8
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +2 -2
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +2 -2
- claude_mpm/cli/commands/__init__.py +2 -1
- claude_mpm/cli/commands/agents.py +8 -3
- claude_mpm/cli/commands/tickets.py +596 -19
- claude_mpm/cli/parser.py +217 -5
- claude_mpm/config/__init__.py +30 -39
- claude_mpm/config/socketio_config.py +8 -5
- claude_mpm/constants.py +13 -0
- claude_mpm/core/__init__.py +8 -18
- claude_mpm/core/cache.py +596 -0
- claude_mpm/core/claude_runner.py +166 -622
- claude_mpm/core/config.py +7 -3
- claude_mpm/core/constants.py +339 -0
- claude_mpm/core/container.py +548 -38
- claude_mpm/core/exceptions.py +392 -0
- claude_mpm/core/framework_loader.py +249 -93
- claude_mpm/core/interactive_session.py +479 -0
- claude_mpm/core/interfaces.py +424 -0
- claude_mpm/core/lazy.py +467 -0
- claude_mpm/core/logging_config.py +444 -0
- claude_mpm/core/oneshot_session.py +465 -0
- claude_mpm/core/optimized_agent_loader.py +485 -0
- claude_mpm/core/optimized_startup.py +490 -0
- claude_mpm/core/service_registry.py +52 -26
- claude_mpm/core/socketio_pool.py +162 -5
- claude_mpm/core/types.py +292 -0
- claude_mpm/core/typing_utils.py +477 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +213 -99
- claude_mpm/init.py +2 -1
- claude_mpm/services/__init__.py +78 -14
- claude_mpm/services/agent/__init__.py +24 -0
- claude_mpm/services/agent/deployment.py +2548 -0
- claude_mpm/services/agent/management.py +598 -0
- claude_mpm/services/agent/registry.py +813 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +728 -308
- claude_mpm/services/agents/memory/agent_memory_manager.py +160 -4
- claude_mpm/services/async_session_logger.py +8 -3
- claude_mpm/services/communication/__init__.py +21 -0
- claude_mpm/services/communication/socketio.py +1933 -0
- claude_mpm/services/communication/websocket.py +479 -0
- claude_mpm/services/core/__init__.py +123 -0
- claude_mpm/services/core/base.py +247 -0
- claude_mpm/services/core/interfaces.py +951 -0
- claude_mpm/services/framework_claude_md_generator/__init__.py +10 -3
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +14 -11
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +23 -23
- claude_mpm/services/framework_claude_md_generator.py +3 -2
- claude_mpm/services/health_monitor.py +4 -3
- claude_mpm/services/hook_service.py +64 -4
- claude_mpm/services/infrastructure/__init__.py +21 -0
- claude_mpm/services/infrastructure/logging.py +202 -0
- claude_mpm/services/infrastructure/monitoring.py +893 -0
- claude_mpm/services/memory/indexed_memory.py +648 -0
- claude_mpm/services/project/__init__.py +21 -0
- claude_mpm/services/project/analyzer.py +864 -0
- claude_mpm/services/project/registry.py +608 -0
- claude_mpm/services/project_analyzer.py +95 -2
- claude_mpm/services/recovery_manager.py +15 -9
- claude_mpm/services/response_tracker.py +3 -5
- claude_mpm/services/socketio/__init__.py +25 -0
- claude_mpm/services/socketio/handlers/__init__.py +25 -0
- claude_mpm/services/socketio/handlers/base.py +121 -0
- claude_mpm/services/socketio/handlers/connection.py +198 -0
- claude_mpm/services/socketio/handlers/file.py +213 -0
- claude_mpm/services/socketio/handlers/git.py +723 -0
- claude_mpm/services/socketio/handlers/memory.py +27 -0
- claude_mpm/services/socketio/handlers/project.py +25 -0
- claude_mpm/services/socketio/handlers/registry.py +145 -0
- claude_mpm/services/socketio_client_manager.py +12 -7
- claude_mpm/services/socketio_server.py +156 -30
- claude_mpm/services/ticket_manager.py +172 -9
- claude_mpm/services/ticket_manager_di.py +1 -1
- claude_mpm/services/version_control/semantic_versioning.py +80 -7
- claude_mpm/services/version_control/version_parser.py +528 -0
- claude_mpm/utils/error_handler.py +1 -1
- claude_mpm/validation/agent_validator.py +27 -14
- claude_mpm/validation/frontmatter_validator.py +231 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/METADATA +38 -128
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/RECORD +100 -59
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/WHEEL +0 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-3.7.8.dist-info → claude_mpm-3.9.0.dist-info}/top_level.txt +0 -0
    
        claude_mpm/core/container.py
    CHANGED
    
    | @@ -18,6 +18,7 @@ from enum import Enum | |
| 18 18 | 
             
            from typing import Any, Callable, Dict, List, Optional, Set, Type, TypeVar, Union
         | 
| 19 19 |  | 
| 20 20 | 
             
            from .logger import get_logger
         | 
| 21 | 
            +
            from claude_mpm.services.core.interfaces import IServiceContainer
         | 
| 21 22 |  | 
| 22 23 | 
             
            logger = get_logger(__name__)
         | 
| 23 24 |  | 
| @@ -28,7 +29,7 @@ class ServiceLifetime(Enum): | |
| 28 29 | 
             
                """Service lifetime options."""
         | 
| 29 30 | 
             
                SINGLETON = "singleton"  # One instance per container
         | 
| 30 31 | 
             
                TRANSIENT = "transient"  # New instance per request
         | 
| 31 | 
            -
                SCOPED = "scoped"       # One instance per scope | 
| 32 | 
            +
                SCOPED = "scoped"       # One instance per scope
         | 
| 32 33 |  | 
| 33 34 |  | 
| 34 35 | 
             
            class ServiceRegistration:
         | 
| @@ -88,21 +89,123 @@ class ServiceNotFoundError(Exception): | |
| 88 89 | 
             
                pass
         | 
| 89 90 |  | 
| 90 91 |  | 
| 91 | 
            -
            class  | 
| 92 | 
            +
            class ServiceScope:
         | 
| 92 93 | 
             
                """
         | 
| 93 | 
            -
                 | 
| 94 | 
            +
                Represents a service scope for scoped lifetime services.
         | 
| 94 95 |  | 
| 95 | 
            -
                 | 
| 96 | 
            +
                Scoped services live for the duration of the scope and are shared
         | 
| 97 | 
            +
                within that scope.
         | 
| 98 | 
            +
                """
         | 
| 99 | 
            +
                
         | 
| 100 | 
            +
                def __init__(self, container: 'DIContainer'):
         | 
| 101 | 
            +
                    """Initialize service scope."""
         | 
| 102 | 
            +
                    self._container = container
         | 
| 103 | 
            +
                    self._scoped_instances: Dict[Type, Any] = {}
         | 
| 104 | 
            +
                    self._disposed = False
         | 
| 105 | 
            +
                    self._lock = threading.Lock()
         | 
| 106 | 
            +
                    
         | 
| 107 | 
            +
                def get_scoped_instance(self, service_type: Type) -> Optional[Any]:
         | 
| 108 | 
            +
                    """Get scoped instance if exists."""
         | 
| 109 | 
            +
                    with self._lock:
         | 
| 110 | 
            +
                        return self._scoped_instances.get(service_type)
         | 
| 111 | 
            +
                        
         | 
| 112 | 
            +
                def set_scoped_instance(self, service_type: Type, instance: Any) -> None:
         | 
| 113 | 
            +
                    """Store scoped instance."""
         | 
| 114 | 
            +
                    with self._lock:
         | 
| 115 | 
            +
                        if not self._disposed:
         | 
| 116 | 
            +
                            self._scoped_instances[service_type] = instance
         | 
| 117 | 
            +
                            
         | 
| 118 | 
            +
                def dispose(self) -> None:
         | 
| 119 | 
            +
                    """
         | 
| 120 | 
            +
                    Dispose of the scope and all scoped instances.
         | 
| 121 | 
            +
                    
         | 
| 122 | 
            +
                    Calls dispose() on instances that implement IDisposable.
         | 
| 123 | 
            +
                    """
         | 
| 124 | 
            +
                    with self._lock:
         | 
| 125 | 
            +
                        if self._disposed:
         | 
| 126 | 
            +
                            return
         | 
| 127 | 
            +
                            
         | 
| 128 | 
            +
                        for service_type, instance in self._scoped_instances.items():
         | 
| 129 | 
            +
                            # Call dispose if available
         | 
| 130 | 
            +
                            if hasattr(instance, 'dispose'):
         | 
| 131 | 
            +
                                try:
         | 
| 132 | 
            +
                                    instance.dispose()
         | 
| 133 | 
            +
                                except Exception as e:
         | 
| 134 | 
            +
                                    logger.error(f"Error disposing scoped service {service_type}: {e}")
         | 
| 135 | 
            +
                                    
         | 
| 136 | 
            +
                        self._scoped_instances.clear()
         | 
| 137 | 
            +
                        self._disposed = True
         | 
| 138 | 
            +
                        
         | 
| 139 | 
            +
                def __enter__(self):
         | 
| 140 | 
            +
                    """Context manager entry."""
         | 
| 141 | 
            +
                    return self
         | 
| 142 | 
            +
                    
         | 
| 143 | 
            +
                def __exit__(self, exc_type, exc_val, exc_tb):
         | 
| 144 | 
            +
                    """Context manager exit - dispose scope."""
         | 
| 145 | 
            +
                    self.dispose()
         | 
| 146 | 
            +
             | 
| 147 | 
            +
             | 
| 148 | 
            +
            class DIContainer(IServiceContainer):
         | 
| 149 | 
            +
                """
         | 
| 150 | 
            +
                Enhanced Dependency Injection Container.
         | 
| 151 | 
            +
                
         | 
| 152 | 
            +
                Implements IServiceContainer interface to provide a complete
         | 
| 153 | 
            +
                dependency injection solution.
         | 
| 154 | 
            +
                
         | 
| 155 | 
            +
                Provides:
         | 
| 156 | 
            +
                - Service registration with multiple lifetime options
         | 
| 157 | 
            +
                - Automatic constructor injection
         | 
| 158 | 
            +
                - Interface to implementation mapping
         | 
| 159 | 
            +
                - Circular dependency detection
         | 
| 160 | 
            +
                - Lazy loading support
         | 
| 161 | 
            +
                - Scoped service support
         | 
| 162 | 
            +
                - Service disposal lifecycle
         | 
| 163 | 
            +
                - Named registrations
         | 
| 164 | 
            +
                - Configuration injection
         | 
| 96 165 | 
             
                """
         | 
| 97 166 |  | 
| 98 167 | 
             
                def __init__(self):
         | 
| 99 168 | 
             
                    """Initialize the DI container."""
         | 
| 100 169 | 
             
                    self._registrations: Dict[Type, ServiceRegistration] = {}
         | 
| 170 | 
            +
                    self._named_registrations: Dict[str, ServiceRegistration] = {}
         | 
| 171 | 
            +
                    self._factories: Dict[Type, Callable] = {}
         | 
| 101 172 | 
             
                    self._singletons: Dict[Type, Any] = {}
         | 
| 173 | 
            +
                    self._scopes: List[ServiceScope] = []
         | 
| 174 | 
            +
                    self._initialization_order: List[Type] = []
         | 
| 175 | 
            +
                    self._disposal_handlers: Dict[Type, Callable] = {}
         | 
| 102 176 | 
             
                    self._lock = threading.RLock()
         | 
| 103 177 | 
             
                    self._resolving: Set[Type] = set()
         | 
| 178 | 
            +
                    self._current_scope: Optional[ServiceScope] = None
         | 
| 104 179 |  | 
| 105 180 | 
             
                def register(
         | 
| 181 | 
            +
                    self,
         | 
| 182 | 
            +
                    service_type: type,
         | 
| 183 | 
            +
                    implementation: type,
         | 
| 184 | 
            +
                    singleton: bool = True
         | 
| 185 | 
            +
                ) -> None:
         | 
| 186 | 
            +
                    """
         | 
| 187 | 
            +
                    Register a service implementation (IServiceContainer interface method).
         | 
| 188 | 
            +
                    
         | 
| 189 | 
            +
                    Args:
         | 
| 190 | 
            +
                        service_type: The interface/base type to register
         | 
| 191 | 
            +
                        implementation: The concrete implementation class
         | 
| 192 | 
            +
                        singleton: Whether to use singleton lifetime (default True)
         | 
| 193 | 
            +
                        
         | 
| 194 | 
            +
                    Examples:
         | 
| 195 | 
            +
                        # Register interface with implementation
         | 
| 196 | 
            +
                        container.register(ILogger, ConsoleLogger)
         | 
| 197 | 
            +
                        
         | 
| 198 | 
            +
                        # Register as transient (new instance each time)
         | 
| 199 | 
            +
                        container.register(IService, ServiceImpl, singleton=False)
         | 
| 200 | 
            +
                    """
         | 
| 201 | 
            +
                    lifetime = ServiceLifetime.SINGLETON if singleton else ServiceLifetime.TRANSIENT
         | 
| 202 | 
            +
                    self._register_internal(
         | 
| 203 | 
            +
                        service_type=service_type,
         | 
| 204 | 
            +
                        implementation=implementation,
         | 
| 205 | 
            +
                        lifetime=lifetime
         | 
| 206 | 
            +
                    )
         | 
| 207 | 
            +
                
         | 
| 208 | 
            +
                def _register_internal(
         | 
| 106 209 | 
             
                    self,
         | 
| 107 210 | 
             
                    service_type: Type[T],
         | 
| 108 211 | 
             
                    implementation: Optional[Union[Type[T], Callable[..., T]]] = None,
         | 
| @@ -112,7 +215,7 @@ class DIContainer: | |
| 112 215 | 
             
                    dependencies: Optional[Dict[str, Type]] = None
         | 
| 113 216 | 
             
                ) -> None:
         | 
| 114 217 | 
             
                    """
         | 
| 115 | 
            -
                     | 
| 218 | 
            +
                    Internal registration method with full flexibility.
         | 
| 116 219 |  | 
| 117 220 | 
             
                    Args:
         | 
| 118 221 | 
             
                        service_type: The interface/base type to register
         | 
| @@ -121,19 +224,6 @@ class DIContainer: | |
| 121 224 | 
             
                        factory: Optional factory function
         | 
| 122 225 | 
             
                        instance: Pre-created instance (for singleton)
         | 
| 123 226 | 
             
                        dependencies: Explicit dependency mapping for constructor params
         | 
| 124 | 
            -
                        
         | 
| 125 | 
            -
                    Examples:
         | 
| 126 | 
            -
                        # Register interface with implementation
         | 
| 127 | 
            -
                        container.register(ILogger, ConsoleLogger)
         | 
| 128 | 
            -
                        
         | 
| 129 | 
            -
                        # Register with factory
         | 
| 130 | 
            -
                        container.register(IDatabase, factory=lambda c: Database(c.resolve(IConfig)))
         | 
| 131 | 
            -
                        
         | 
| 132 | 
            -
                        # Register singleton instance
         | 
| 133 | 
            -
                        container.register(IConfig, instance=Config())
         | 
| 134 | 
            -
                        
         | 
| 135 | 
            -
                        # Register with explicit dependencies
         | 
| 136 | 
            -
                        container.register(IService, ServiceImpl, dependencies={'logger': ILogger})
         | 
| 137 227 | 
             
                    """
         | 
| 138 228 | 
             
                    with self._lock:
         | 
| 139 229 | 
             
                        registration = ServiceRegistration(
         | 
| @@ -149,23 +239,155 @@ class DIContainer: | |
| 149 239 | 
             
                        # If instance provided, store as singleton
         | 
| 150 240 | 
             
                        if instance is not None:
         | 
| 151 241 | 
             
                            self._singletons[service_type] = instance
         | 
| 242 | 
            +
                
         | 
| 243 | 
            +
                def register_instance(self, service_type: type, instance: Any) -> None:
         | 
| 244 | 
            +
                    """
         | 
| 245 | 
            +
                    Register a service instance (IServiceContainer interface method).
         | 
| 246 | 
            +
                    
         | 
| 247 | 
            +
                    Args:
         | 
| 248 | 
            +
                        service_type: The interface/base type to register
         | 
| 249 | 
            +
                        instance: Pre-created instance to register as singleton
         | 
| 250 | 
            +
                        
         | 
| 251 | 
            +
                    Examples:
         | 
| 252 | 
            +
                        # Register a pre-created instance
         | 
| 253 | 
            +
                        config = Config()
         | 
| 254 | 
            +
                        container.register_instance(IConfig, config)
         | 
| 255 | 
            +
                    """
         | 
| 256 | 
            +
                    self._register_internal(
         | 
| 257 | 
            +
                        service_type=service_type,
         | 
| 258 | 
            +
                        instance=instance,
         | 
| 259 | 
            +
                        lifetime=ServiceLifetime.SINGLETON
         | 
| 260 | 
            +
                    )
         | 
| 261 | 
            +
                
         | 
| 262 | 
            +
                def resolve_all(self, service_type: type) -> List[Any]:
         | 
| 263 | 
            +
                    """
         | 
| 264 | 
            +
                    Resolve all implementations of a service type (IServiceContainer interface method).
         | 
| 265 | 
            +
                    
         | 
| 266 | 
            +
                    Args:
         | 
| 267 | 
            +
                        service_type: The type to resolve
         | 
| 268 | 
            +
                        
         | 
| 269 | 
            +
                    Returns:
         | 
| 270 | 
            +
                        List of all registered implementations for the service type
         | 
| 271 | 
            +
                        
         | 
| 272 | 
            +
                    Examples:
         | 
| 273 | 
            +
                        # Register multiple implementations
         | 
| 274 | 
            +
                        container.register(IPlugin, PluginA)
         | 
| 275 | 
            +
                        container.register(IPlugin, PluginB)
         | 
| 276 | 
            +
                        
         | 
| 277 | 
            +
                        # Get all implementations
         | 
| 278 | 
            +
                        plugins = container.resolve_all(IPlugin)
         | 
| 279 | 
            +
                    """
         | 
| 280 | 
            +
                    with self._lock:
         | 
| 281 | 
            +
                        # For now, return a list with the single registered implementation
         | 
| 282 | 
            +
                        # In the future, we could support multiple registrations for the same type
         | 
| 283 | 
            +
                        if service_type in self._registrations:
         | 
| 284 | 
            +
                            return [self._resolve_internal(service_type)]
         | 
| 285 | 
            +
                        return []
         | 
| 152 286 |  | 
| 153 287 | 
             
                def register_singleton(
         | 
| 154 288 | 
             
                    self,
         | 
| 155 | 
            -
                     | 
| 156 | 
            -
                    implementation: Optional[Union[Type[T], T]] = None
         | 
| 289 | 
            +
                    interface: Type[T],
         | 
| 290 | 
            +
                    implementation: Optional[Union[Type[T], T]] = None,
         | 
| 291 | 
            +
                    instance: Optional[T] = None,
         | 
| 292 | 
            +
                    name: Optional[str] = None,
         | 
| 293 | 
            +
                    dispose_handler: Optional[Callable[[T], None]] = None
         | 
| 157 294 | 
             
                ) -> None:
         | 
| 158 295 | 
             
                    """
         | 
| 159 296 | 
             
                    Register a singleton service.
         | 
| 160 297 |  | 
| 161 | 
            -
                     | 
| 298 | 
            +
                    Args:
         | 
| 299 | 
            +
                        interface: The interface/base type to register
         | 
| 300 | 
            +
                        implementation: The concrete implementation class
         | 
| 301 | 
            +
                        instance: Pre-created instance (alternative to implementation)
         | 
| 302 | 
            +
                        name: Optional name for named registration
         | 
| 303 | 
            +
                        dispose_handler: Optional handler called when disposing service
         | 
| 304 | 
            +
                    
         | 
| 305 | 
            +
                    Examples:
         | 
| 306 | 
            +
                        # Register with implementation class
         | 
| 307 | 
            +
                        container.register_singleton(ILogger, ConsoleLogger)
         | 
| 308 | 
            +
                        
         | 
| 309 | 
            +
                        # Register with instance
         | 
| 310 | 
            +
                        container.register_singleton(IConfig, instance=Config())
         | 
| 311 | 
            +
                        
         | 
| 312 | 
            +
                        # Register with disposal handler
         | 
| 313 | 
            +
                        container.register_singleton(
         | 
| 314 | 
            +
                            IDatabase,
         | 
| 315 | 
            +
                            DatabaseConnection,
         | 
| 316 | 
            +
                            dispose_handler=lambda db: db.close()
         | 
| 317 | 
            +
                        )
         | 
| 162 318 | 
             
                    """
         | 
| 163 | 
            -
                     | 
| 164 | 
            -
             | 
| 165 | 
            -
                         | 
| 319 | 
            +
                    # For named registrations, create a unique registration
         | 
| 320 | 
            +
                    if name:
         | 
| 321 | 
            +
                        # Create named registration directly
         | 
| 322 | 
            +
                        registration = ServiceRegistration(
         | 
| 323 | 
            +
                            service_type=interface,
         | 
| 324 | 
            +
                            implementation=implementation,
         | 
| 325 | 
            +
                            instance=instance,
         | 
| 326 | 
            +
                            lifetime=ServiceLifetime.SINGLETON
         | 
| 327 | 
            +
                        )
         | 
| 328 | 
            +
                        self._named_registrations[name] = registration
         | 
| 329 | 
            +
                        
         | 
| 330 | 
            +
                        # Also store the instance if provided
         | 
| 331 | 
            +
                        if instance is not None:
         | 
| 332 | 
            +
                            # Store with a composite key for retrieval
         | 
| 333 | 
            +
                            named_key = (interface, name)
         | 
| 334 | 
            +
                            if not hasattr(self, '_named_singletons'):
         | 
| 335 | 
            +
                                self._named_singletons = {}
         | 
| 336 | 
            +
                            self._named_singletons[named_key] = instance
         | 
| 166 337 | 
             
                    else:
         | 
| 167 | 
            -
                         | 
| 338 | 
            +
                        # Normal registration without name
         | 
| 339 | 
            +
                        if instance is not None:
         | 
| 340 | 
            +
                            self._register_internal(interface, instance=instance)
         | 
| 341 | 
            +
                        elif implementation is not None and not inspect.isclass(implementation):
         | 
| 342 | 
            +
                            # It's an instance passed as implementation (backward compatibility)
         | 
| 343 | 
            +
                            self._register_internal(interface, instance=implementation)
         | 
| 344 | 
            +
                        else:
         | 
| 345 | 
            +
                            self._register_internal(interface, implementation, lifetime=ServiceLifetime.SINGLETON)
         | 
| 346 | 
            +
                            
         | 
| 347 | 
            +
                    # Handle disposal handler
         | 
| 348 | 
            +
                    if dispose_handler:
         | 
| 349 | 
            +
                        if name:
         | 
| 350 | 
            +
                            # Store with composite key for named services
         | 
| 351 | 
            +
                            if not hasattr(self, '_named_disposal_handlers'):
         | 
| 352 | 
            +
                                self._named_disposal_handlers = {}
         | 
| 353 | 
            +
                            self._named_disposal_handlers[(interface, name)] = dispose_handler
         | 
| 354 | 
            +
                        else:
         | 
| 355 | 
            +
                            self._disposal_handlers[interface] = dispose_handler
         | 
| 356 | 
            +
                        
         | 
| 357 | 
            +
                    # Track initialization order for proper disposal
         | 
| 358 | 
            +
                    key = (interface, name) if name else interface
         | 
| 359 | 
            +
                    if key not in self._initialization_order:
         | 
| 360 | 
            +
                        self._initialization_order.append(key)
         | 
| 168 361 |  | 
| 362 | 
            +
                def register_scoped(
         | 
| 363 | 
            +
                    self,
         | 
| 364 | 
            +
                    interface: Type[T],
         | 
| 365 | 
            +
                    implementation: Optional[Type[T]] = None,
         | 
| 366 | 
            +
                    name: Optional[str] = None
         | 
| 367 | 
            +
                ) -> None:
         | 
| 368 | 
            +
                    """
         | 
| 369 | 
            +
                    Register a scoped service.
         | 
| 370 | 
            +
                    
         | 
| 371 | 
            +
                    Scoped services are created once per scope and shared within that scope.
         | 
| 372 | 
            +
                    
         | 
| 373 | 
            +
                    Args:
         | 
| 374 | 
            +
                        interface: The interface/base type to register
         | 
| 375 | 
            +
                        implementation: The concrete implementation
         | 
| 376 | 
            +
                        name: Optional name for named registration
         | 
| 377 | 
            +
                        
         | 
| 378 | 
            +
                    Examples:
         | 
| 379 | 
            +
                        # Register scoped service
         | 
| 380 | 
            +
                        container.register_scoped(IRequestContext, RequestContext)
         | 
| 381 | 
            +
                        
         | 
| 382 | 
            +
                        # Use in scope
         | 
| 383 | 
            +
                        with container.create_scope() as scope:
         | 
| 384 | 
            +
                            context = container.get(IRequestContext)  # Created
         | 
| 385 | 
            +
                            context2 = container.get(IRequestContext)  # Same instance
         | 
| 386 | 
            +
                    """
         | 
| 387 | 
            +
                    self._register_internal(interface, implementation, lifetime=ServiceLifetime.SCOPED)
         | 
| 388 | 
            +
                    if name:
         | 
| 389 | 
            +
                        self._named_registrations[name] = self._registrations[interface]
         | 
| 390 | 
            +
                
         | 
| 169 391 | 
             
                def register_transient(
         | 
| 170 392 | 
             
                    self,
         | 
| 171 393 | 
             
                    service_type: Type[T],
         | 
| @@ -176,24 +398,94 @@ class DIContainer: | |
| 176 398 |  | 
| 177 399 | 
             
                    Convenience method for registering transient services.
         | 
| 178 400 | 
             
                    """
         | 
| 179 | 
            -
                    self. | 
| 401 | 
            +
                    self._register_internal(service_type, implementation, lifetime=ServiceLifetime.TRANSIENT)
         | 
| 180 402 |  | 
| 181 403 | 
             
                def register_factory(
         | 
| 182 404 | 
             
                    self,
         | 
| 183 | 
            -
                     | 
| 405 | 
            +
                    interface: Type[T],
         | 
| 184 406 | 
             
                    factory: Callable[['DIContainer'], T],
         | 
| 185 | 
            -
                    lifetime: ServiceLifetime = ServiceLifetime. | 
| 407 | 
            +
                    lifetime: ServiceLifetime = ServiceLifetime.TRANSIENT,
         | 
| 408 | 
            +
                    name: Optional[str] = None
         | 
| 186 409 | 
             
                ) -> None:
         | 
| 187 410 | 
             
                    """
         | 
| 188 411 | 
             
                    Register a service with a factory function.
         | 
| 189 412 |  | 
| 190 413 | 
             
                    The factory receives the container as parameter for resolving dependencies.
         | 
| 414 | 
            +
                    
         | 
| 415 | 
            +
                    Args:
         | 
| 416 | 
            +
                        interface: The interface/base type to register
         | 
| 417 | 
            +
                        factory: Factory function that creates instances
         | 
| 418 | 
            +
                        lifetime: Service lifetime (default: TRANSIENT for factories)
         | 
| 419 | 
            +
                        name: Optional name for named registration
         | 
| 420 | 
            +
                        
         | 
| 421 | 
            +
                    Examples:
         | 
| 422 | 
            +
                        # Register with factory
         | 
| 423 | 
            +
                        container.register_factory(
         | 
| 424 | 
            +
                            IService,
         | 
| 425 | 
            +
                            lambda c: Service(c.get(ILogger), c.get(IConfig)),
         | 
| 426 | 
            +
                            lifetime=ServiceLifetime.SINGLETON
         | 
| 427 | 
            +
                        )
         | 
| 428 | 
            +
                    """
         | 
| 429 | 
            +
                    self._register_internal(interface, factory=factory, lifetime=lifetime)
         | 
| 430 | 
            +
                    self._factories[interface] = factory
         | 
| 431 | 
            +
                    if name:
         | 
| 432 | 
            +
                        self._named_registrations[name] = self._registrations[interface]
         | 
| 433 | 
            +
                    
         | 
| 434 | 
            +
                def get(self, interface: Type[T], name: Optional[str] = None) -> T:
         | 
| 435 | 
            +
                    """
         | 
| 436 | 
            +
                    Get service instance with dependency resolution.
         | 
| 437 | 
            +
                    
         | 
| 438 | 
            +
                    This is the primary method for retrieving services from the container.
         | 
| 439 | 
            +
                    It handles all lifetime management and dependency resolution.
         | 
| 440 | 
            +
                    
         | 
| 441 | 
            +
                    Args:
         | 
| 442 | 
            +
                        interface: The type to resolve
         | 
| 443 | 
            +
                        name: Optional name for named registration lookup
         | 
| 444 | 
            +
                        
         | 
| 445 | 
            +
                    Returns:
         | 
| 446 | 
            +
                        Instance of the requested service
         | 
| 447 | 
            +
                        
         | 
| 448 | 
            +
                    Raises:
         | 
| 449 | 
            +
                        ServiceNotFoundError: If service is not registered
         | 
| 450 | 
            +
                        CircularDependencyError: If circular dependencies detected
         | 
| 451 | 
            +
                        
         | 
| 452 | 
            +
                    Examples:
         | 
| 453 | 
            +
                        # Get by interface
         | 
| 454 | 
            +
                        logger = container.get(ILogger)
         | 
| 455 | 
            +
                        
         | 
| 456 | 
            +
                        # Get named service
         | 
| 457 | 
            +
                        primary_db = container.get(IDatabase, name="primary")
         | 
| 191 458 | 
             
                    """
         | 
| 192 | 
            -
                     | 
| 459 | 
            +
                    if name:
         | 
| 460 | 
            +
                        if name not in self._named_registrations:
         | 
| 461 | 
            +
                            suggestions = self._get_similar_names(name)
         | 
| 462 | 
            +
                            raise ServiceNotFoundError(
         | 
| 463 | 
            +
                                f"Named service '{name}' is not registered. "
         | 
| 464 | 
            +
                                f"Did you mean: {', '.join(suggestions)}?" if suggestions else ""
         | 
| 465 | 
            +
                            )
         | 
| 466 | 
            +
                        
         | 
| 467 | 
            +
                        # Check if we have a pre-stored instance for this named service
         | 
| 468 | 
            +
                        named_key = (interface, name)
         | 
| 469 | 
            +
                        if hasattr(self, '_named_singletons') and named_key in self._named_singletons:
         | 
| 470 | 
            +
                            return self._named_singletons[named_key]
         | 
| 471 | 
            +
                            
         | 
| 472 | 
            +
                        # Otherwise resolve from named registration
         | 
| 473 | 
            +
                        registration = self._named_registrations[name]
         | 
| 474 | 
            +
                        if registration.instance is not None:
         | 
| 475 | 
            +
                            return registration.instance
         | 
| 476 | 
            +
                        elif registration.factory:
         | 
| 477 | 
            +
                            return registration.factory(self)
         | 
| 478 | 
            +
                        else:
         | 
| 479 | 
            +
                            return self.create_instance(registration.implementation, registration.dependencies)
         | 
| 480 | 
            +
                                
         | 
| 481 | 
            +
                    return self._resolve_internal(interface)
         | 
| 193 482 |  | 
| 194 483 | 
             
                def resolve(self, service_type: Type[T]) -> T:
         | 
| 195 484 | 
             
                    """
         | 
| 196 | 
            -
                    Resolve a service from the container.
         | 
| 485 | 
            +
                    Resolve a service from the container (legacy method).
         | 
| 486 | 
            +
                    
         | 
| 487 | 
            +
                    This method is maintained for backward compatibility.
         | 
| 488 | 
            +
                    New code should use get() instead.
         | 
| 197 489 |  | 
| 198 490 | 
             
                    Args:
         | 
| 199 491 | 
             
                        service_type: The type to resolve
         | 
| @@ -205,23 +497,43 @@ class DIContainer: | |
| 205 497 | 
             
                        ServiceNotFoundError: If service is not registered
         | 
| 206 498 | 
             
                        CircularDependencyError: If circular dependencies detected
         | 
| 207 499 | 
             
                    """
         | 
| 500 | 
            +
                    return self.get(service_type)
         | 
| 501 | 
            +
                    
         | 
| 502 | 
            +
                def _resolve_internal(self, service_type: Type[T]) -> T:
         | 
| 503 | 
            +
                    """
         | 
| 504 | 
            +
                    Internal method to resolve a service.
         | 
| 505 | 
            +
                    
         | 
| 506 | 
            +
                    Handles the actual resolution logic with proper locking and lifecycle management.
         | 
| 507 | 
            +
                    """
         | 
| 208 508 | 
             
                    with self._lock:
         | 
| 209 509 | 
             
                        # Check for circular dependencies
         | 
| 210 510 | 
             
                        if service_type in self._resolving:
         | 
| 211 | 
            -
                            cycle = " -> ".join(str(t) for t in self._resolving) + f" -> {service_type}"
         | 
| 511 | 
            +
                            cycle = " -> ".join(str(t.__name__) for t in self._resolving) + f" -> {service_type.__name__}"
         | 
| 212 512 | 
             
                            raise CircularDependencyError(f"Circular dependency detected: {cycle}")
         | 
| 213 513 |  | 
| 214 514 | 
             
                        # Check if registered
         | 
| 215 515 | 
             
                        if service_type not in self._registrations:
         | 
| 216 | 
            -
                             | 
| 516 | 
            +
                            suggestions = self._get_similar_types(service_type)
         | 
| 517 | 
            +
                            error_msg = f"Service {service_type.__name__} is not registered."
         | 
| 518 | 
            +
                            if suggestions:
         | 
| 519 | 
            +
                                error_msg += f" Did you mean: {', '.join(suggestions)}?"
         | 
| 520 | 
            +
                            raise ServiceNotFoundError(error_msg)
         | 
| 217 521 |  | 
| 218 522 | 
             
                        registration = self._registrations[service_type]
         | 
| 219 523 |  | 
| 220 | 
            -
                        #  | 
| 524 | 
            +
                        # Handle different lifetimes
         | 
| 221 525 | 
             
                        if registration.lifetime == ServiceLifetime.SINGLETON:
         | 
| 526 | 
            +
                            # Return existing singleton if available
         | 
| 222 527 | 
             
                            if service_type in self._singletons:
         | 
| 223 528 | 
             
                                return self._singletons[service_type]
         | 
| 224 529 |  | 
| 530 | 
            +
                        elif registration.lifetime == ServiceLifetime.SCOPED:
         | 
| 531 | 
            +
                            # Check current scope
         | 
| 532 | 
            +
                            if self._current_scope:
         | 
| 533 | 
            +
                                instance = self._current_scope.get_scoped_instance(service_type)
         | 
| 534 | 
            +
                                if instance is not None:
         | 
| 535 | 
            +
                                    return instance
         | 
| 536 | 
            +
                                    
         | 
| 225 537 | 
             
                        # Mark as resolving
         | 
| 226 538 | 
             
                        self._resolving.add(service_type)
         | 
| 227 539 |  | 
| @@ -229,10 +541,24 @@ class DIContainer: | |
| 229 541 | 
             
                            # Create instance
         | 
| 230 542 | 
             
                            instance = registration.create_instance(self)
         | 
| 231 543 |  | 
| 232 | 
            -
                            # Store  | 
| 544 | 
            +
                            # Store based on lifetime
         | 
| 233 545 | 
             
                            if registration.lifetime == ServiceLifetime.SINGLETON:
         | 
| 234 546 | 
             
                                self._singletons[service_type] = instance
         | 
| 235 | 
            -
                                
         | 
| 547 | 
            +
                                if service_type not in self._initialization_order:
         | 
| 548 | 
            +
                                    self._initialization_order.append(service_type)
         | 
| 549 | 
            +
                                    
         | 
| 550 | 
            +
                            elif registration.lifetime == ServiceLifetime.SCOPED:
         | 
| 551 | 
            +
                                if self._current_scope:
         | 
| 552 | 
            +
                                    self._current_scope.set_scoped_instance(service_type, instance)
         | 
| 553 | 
            +
                                    
         | 
| 554 | 
            +
                            # Call initialization hook if available
         | 
| 555 | 
            +
                            if hasattr(instance, 'initialize'):
         | 
| 556 | 
            +
                                try:
         | 
| 557 | 
            +
                                    instance.initialize()
         | 
| 558 | 
            +
                                except Exception as e:
         | 
| 559 | 
            +
                                    logger.error(f"Failed to initialize service {service_type.__name__}: {e}")
         | 
| 560 | 
            +
                                    raise
         | 
| 561 | 
            +
                                    
         | 
| 236 562 | 
             
                            return instance
         | 
| 237 563 |  | 
| 238 564 | 
             
                        finally:
         | 
| @@ -278,6 +604,28 @@ class DIContainer: | |
| 278 604 | 
             
                        if param.annotation != param.empty:
         | 
| 279 605 | 
             
                            param_type = param.annotation
         | 
| 280 606 |  | 
| 607 | 
            +
                            # Handle string annotations (forward references)
         | 
| 608 | 
            +
                            if isinstance(param_type, str):
         | 
| 609 | 
            +
                                # Try to resolve forward reference
         | 
| 610 | 
            +
                                try:
         | 
| 611 | 
            +
                                    # Get the module where the class is defined
         | 
| 612 | 
            +
                                    import sys
         | 
| 613 | 
            +
                                    frame = sys._getframe(1)
         | 
| 614 | 
            +
                                    module = frame.f_globals
         | 
| 615 | 
            +
                                    if param_type in module:
         | 
| 616 | 
            +
                                        param_type = module[param_type]
         | 
| 617 | 
            +
                                    else:
         | 
| 618 | 
            +
                                        # Try looking in registrations by name
         | 
| 619 | 
            +
                                        for reg_type in self._registrations:
         | 
| 620 | 
            +
                                            if reg_type.__name__ == param_type:
         | 
| 621 | 
            +
                                                param_type = reg_type
         | 
| 622 | 
            +
                                                break
         | 
| 623 | 
            +
                                except:
         | 
| 624 | 
            +
                                    # If we can't resolve, skip this parameter
         | 
| 625 | 
            +
                                    if param.default != param.empty:
         | 
| 626 | 
            +
                                        kwargs[param_name] = param.default
         | 
| 627 | 
            +
                                    continue
         | 
| 628 | 
            +
                            
         | 
| 281 629 | 
             
                            # Handle Optional types
         | 
| 282 630 | 
             
                            if hasattr(param_type, '__origin__') and param_type.__origin__ is Union:
         | 
| 283 631 | 
             
                                # Get the non-None type from Optional
         | 
| @@ -285,7 +633,13 @@ class DIContainer: | |
| 285 633 | 
             
                                param_type = next((arg for arg in args if arg is not type(None)), None)
         | 
| 286 634 |  | 
| 287 635 | 
             
                            if param_type and param_type in self._registrations:
         | 
| 288 | 
            -
                                 | 
| 636 | 
            +
                                # Check for circular dependency
         | 
| 637 | 
            +
                                if param_type in self._resolving:
         | 
| 638 | 
            +
                                    # Circular dependency detected
         | 
| 639 | 
            +
                                    cycle = " -> ".join(str(t.__name__) for t in self._resolving) + f" -> {param_type.__name__}"
         | 
| 640 | 
            +
                                    raise CircularDependencyError(f"Circular dependency detected: {cycle}")
         | 
| 641 | 
            +
                                else:
         | 
| 642 | 
            +
                                    kwargs[param_name] = self.resolve(param_type)
         | 
| 289 643 | 
             
                            elif param.default != param.empty:
         | 
| 290 644 | 
             
                                # Use default value
         | 
| 291 645 | 
             
                                kwargs[param_name] = param.default
         | 
| @@ -301,25 +655,181 @@ class DIContainer: | |
| 301 655 | 
             
                    with self._lock:
         | 
| 302 656 | 
             
                        return self._registrations.copy()
         | 
| 303 657 |  | 
| 658 | 
            +
                def create_scope(self) -> ServiceScope:
         | 
| 659 | 
            +
                    """
         | 
| 660 | 
            +
                    Create a new service scope.
         | 
| 661 | 
            +
                    
         | 
| 662 | 
            +
                    Scoped services will be created once per scope and shared within that scope.
         | 
| 663 | 
            +
                    
         | 
| 664 | 
            +
                    Returns:
         | 
| 665 | 
            +
                        New ServiceScope instance
         | 
| 666 | 
            +
                        
         | 
| 667 | 
            +
                    Examples:
         | 
| 668 | 
            +
                        # Use scope with context manager
         | 
| 669 | 
            +
                        with container.create_scope() as scope:
         | 
| 670 | 
            +
                            # Services with SCOPED lifetime are shared within this scope
         | 
| 671 | 
            +
                            service1 = container.get(IScopedService)
         | 
| 672 | 
            +
                            service2 = container.get(IScopedService)
         | 
| 673 | 
            +
                            assert service1 is service2  # Same instance
         | 
| 674 | 
            +
                            
         | 
| 675 | 
            +
                        # Scope is disposed, scoped instances are cleaned up
         | 
| 676 | 
            +
                    """
         | 
| 677 | 
            +
                    scope = ServiceScope(self)
         | 
| 678 | 
            +
                    with self._lock:
         | 
| 679 | 
            +
                        self._scopes.append(scope)
         | 
| 680 | 
            +
                        # Set as current scope for resolution
         | 
| 681 | 
            +
                        old_scope = self._current_scope
         | 
| 682 | 
            +
                        self._current_scope = scope
         | 
| 683 | 
            +
                        
         | 
| 684 | 
            +
                    # Return a context manager that restores old scope
         | 
| 685 | 
            +
                    class ScopeContext:
         | 
| 686 | 
            +
                        def __init__(self, container, new_scope, old_scope):
         | 
| 687 | 
            +
                            self.container = container
         | 
| 688 | 
            +
                            self.new_scope = new_scope
         | 
| 689 | 
            +
                            self.old_scope = old_scope
         | 
| 690 | 
            +
                            
         | 
| 691 | 
            +
                        def __enter__(self):
         | 
| 692 | 
            +
                            return self.new_scope
         | 
| 693 | 
            +
                            
         | 
| 694 | 
            +
                        def __exit__(self, exc_type, exc_val, exc_tb):
         | 
| 695 | 
            +
                            with self.container._lock:
         | 
| 696 | 
            +
                                self.container._current_scope = self.old_scope
         | 
| 697 | 
            +
                                if self.new_scope in self.container._scopes:
         | 
| 698 | 
            +
                                    self.container._scopes.remove(self.new_scope)
         | 
| 699 | 
            +
                            self.new_scope.dispose()
         | 
| 700 | 
            +
                            
         | 
| 701 | 
            +
                    return ScopeContext(self, scope, old_scope)
         | 
| 702 | 
            +
                    
         | 
| 304 703 | 
             
                def create_child_container(self) -> 'DIContainer':
         | 
| 305 704 | 
             
                    """
         | 
| 306 705 | 
             
                    Create a child container that inherits registrations.
         | 
| 307 706 |  | 
| 308 | 
            -
                    Useful for  | 
| 707 | 
            +
                    Useful for isolated scenarios where you want separate singleton instances.
         | 
| 309 708 | 
             
                    """
         | 
| 310 709 | 
             
                    child = DIContainer()
         | 
| 311 710 | 
             
                    with self._lock:
         | 
| 312 711 | 
             
                        # Copy registrations but not singleton instances
         | 
| 313 712 | 
             
                        for service_type, registration in self._registrations.items():
         | 
| 314 713 | 
             
                            child._registrations[service_type] = registration
         | 
| 714 | 
            +
                        # Copy named registrations
         | 
| 715 | 
            +
                        child._named_registrations = self._named_registrations.copy()
         | 
| 716 | 
            +
                        # Copy factories
         | 
| 717 | 
            +
                        child._factories = self._factories.copy()
         | 
| 718 | 
            +
                        # Copy disposal handlers
         | 
| 719 | 
            +
                        child._disposal_handlers = self._disposal_handlers.copy()
         | 
| 315 720 | 
             
                    return child
         | 
| 316 721 |  | 
| 722 | 
            +
                def dispose(self) -> None:
         | 
| 723 | 
            +
                    """
         | 
| 724 | 
            +
                    Dispose of the container and all managed services.
         | 
| 725 | 
            +
                    
         | 
| 726 | 
            +
                    Calls disposal handlers for singleton services in reverse initialization order.
         | 
| 727 | 
            +
                    Also disposes any active scopes.
         | 
| 728 | 
            +
                    """
         | 
| 729 | 
            +
                    with self._lock:
         | 
| 730 | 
            +
                        # Dispose scopes first
         | 
| 731 | 
            +
                        for scope in reversed(self._scopes):
         | 
| 732 | 
            +
                            scope.dispose()
         | 
| 733 | 
            +
                        self._scopes.clear()
         | 
| 734 | 
            +
                        
         | 
| 735 | 
            +
                        # Dispose singletons in reverse initialization order
         | 
| 736 | 
            +
                        for service_type in reversed(self._initialization_order):
         | 
| 737 | 
            +
                            if service_type in self._singletons:
         | 
| 738 | 
            +
                                instance = self._singletons[service_type]
         | 
| 739 | 
            +
                                
         | 
| 740 | 
            +
                                # Call disposal handler if registered
         | 
| 741 | 
            +
                                if service_type in self._disposal_handlers:
         | 
| 742 | 
            +
                                    try:
         | 
| 743 | 
            +
                                        self._disposal_handlers[service_type](instance)
         | 
| 744 | 
            +
                                    except Exception as e:
         | 
| 745 | 
            +
                                        logger.error(f"Error in disposal handler for {service_type.__name__}: {e}")
         | 
| 746 | 
            +
                                        
         | 
| 747 | 
            +
                                # Call dispose method if available
         | 
| 748 | 
            +
                                elif hasattr(instance, 'dispose'):
         | 
| 749 | 
            +
                                    try:
         | 
| 750 | 
            +
                                        instance.dispose()
         | 
| 751 | 
            +
                                    except Exception as e:
         | 
| 752 | 
            +
                                        logger.error(f"Error disposing service {service_type.__name__}: {e}")
         | 
| 753 | 
            +
                                        
         | 
| 754 | 
            +
                        # Clear everything
         | 
| 755 | 
            +
                        self._singletons.clear()
         | 
| 756 | 
            +
                        self._initialization_order.clear()
         | 
| 757 | 
            +
                        self._current_scope = None
         | 
| 758 | 
            +
                        
         | 
| 317 759 | 
             
                def clear(self) -> None:
         | 
| 318 760 | 
             
                    """Clear all registrations and instances."""
         | 
| 761 | 
            +
                    self.dispose()
         | 
| 319 762 | 
             
                    with self._lock:
         | 
| 320 763 | 
             
                        self._registrations.clear()
         | 
| 321 | 
            -
                        self. | 
| 764 | 
            +
                        self._named_registrations.clear()
         | 
| 765 | 
            +
                        self._factories.clear()
         | 
| 766 | 
            +
                        self._disposal_handlers.clear()
         | 
| 322 767 | 
             
                        self._resolving.clear()
         | 
| 768 | 
            +
                        
         | 
| 769 | 
            +
                def _get_similar_types(self, service_type: Type) -> List[str]:
         | 
| 770 | 
            +
                    """
         | 
| 771 | 
            +
                    Get similar registered type names for better error messages.
         | 
| 772 | 
            +
                    
         | 
| 773 | 
            +
                    Uses simple string similarity to suggest possible alternatives.
         | 
| 774 | 
            +
                    """
         | 
| 775 | 
            +
                    if not self._registrations:
         | 
| 776 | 
            +
                        return []
         | 
| 777 | 
            +
                        
         | 
| 778 | 
            +
                    type_name = service_type.__name__.lower()
         | 
| 779 | 
            +
                    similar = []
         | 
| 780 | 
            +
                    
         | 
| 781 | 
            +
                    for registered_type in self._registrations.keys():
         | 
| 782 | 
            +
                        registered_name = registered_type.__name__
         | 
| 783 | 
            +
                        registered_lower = registered_name.lower()
         | 
| 784 | 
            +
                        
         | 
| 785 | 
            +
                        # Check for substring match
         | 
| 786 | 
            +
                        if type_name in registered_lower or registered_lower in type_name:
         | 
| 787 | 
            +
                            similar.append(registered_name)
         | 
| 788 | 
            +
                            continue
         | 
| 789 | 
            +
                            
         | 
| 790 | 
            +
                        # Check for common prefix
         | 
| 791 | 
            +
                        common_prefix_len = 0
         | 
| 792 | 
            +
                        for i, (a, b) in enumerate(zip(type_name, registered_lower)):
         | 
| 793 | 
            +
                            if a == b:
         | 
| 794 | 
            +
                                common_prefix_len = i + 1
         | 
| 795 | 
            +
                            else:
         | 
| 796 | 
            +
                                break
         | 
| 797 | 
            +
                                
         | 
| 798 | 
            +
                        if common_prefix_len >= min(3, len(type_name) // 2):
         | 
| 799 | 
            +
                            similar.append(registered_name)
         | 
| 800 | 
            +
                            
         | 
| 801 | 
            +
                    return similar[:3]  # Return top 3 suggestions
         | 
| 802 | 
            +
                    
         | 
| 803 | 
            +
                def _get_similar_names(self, name: str) -> List[str]:
         | 
| 804 | 
            +
                    """
         | 
| 805 | 
            +
                    Get similar registered names for better error messages.
         | 
| 806 | 
            +
                    """
         | 
| 807 | 
            +
                    if not self._named_registrations:
         | 
| 808 | 
            +
                        return []
         | 
| 809 | 
            +
                        
         | 
| 810 | 
            +
                    name_lower = name.lower()
         | 
| 811 | 
            +
                    similar = []
         | 
| 812 | 
            +
                    
         | 
| 813 | 
            +
                    for registered_name in self._named_registrations.keys():
         | 
| 814 | 
            +
                        registered_lower = registered_name.lower()
         | 
| 815 | 
            +
                        
         | 
| 816 | 
            +
                        # Check for substring match
         | 
| 817 | 
            +
                        if name_lower in registered_lower or registered_lower in name_lower:
         | 
| 818 | 
            +
                            similar.append(registered_name)
         | 
| 819 | 
            +
                            continue
         | 
| 820 | 
            +
                            
         | 
| 821 | 
            +
                        # Check for common prefix
         | 
| 822 | 
            +
                        common_prefix_len = 0
         | 
| 823 | 
            +
                        for i, (a, b) in enumerate(zip(name_lower, registered_lower)):
         | 
| 824 | 
            +
                            if a == b:
         | 
| 825 | 
            +
                                common_prefix_len = i + 1
         | 
| 826 | 
            +
                            else:
         | 
| 827 | 
            +
                                break
         | 
| 828 | 
            +
                                
         | 
| 829 | 
            +
                        if common_prefix_len >= min(3, len(name_lower) // 2):
         | 
| 830 | 
            +
                            similar.append(registered_name)
         | 
| 831 | 
            +
                            
         | 
| 832 | 
            +
                    return similar[:3]  # Return top 3 suggestions
         | 
| 323 833 |  | 
| 324 834 |  | 
| 325 835 | 
             
            # Global container instance (optional, for convenience)
         |