claude-mpm 3.7.8__py3-none-any.whl → 3.8.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +0 -106
  3. claude_mpm/agents/INSTRUCTIONS.md +0 -96
  4. claude_mpm/agents/MEMORY.md +88 -0
  5. claude_mpm/agents/WORKFLOW.md +86 -0
  6. claude_mpm/agents/templates/code_analyzer.json +2 -2
  7. claude_mpm/agents/templates/data_engineer.json +1 -1
  8. claude_mpm/agents/templates/documentation.json +1 -1
  9. claude_mpm/agents/templates/engineer.json +1 -1
  10. claude_mpm/agents/templates/ops.json +1 -1
  11. claude_mpm/agents/templates/qa.json +1 -1
  12. claude_mpm/agents/templates/research.json +1 -1
  13. claude_mpm/agents/templates/security.json +1 -1
  14. claude_mpm/agents/templates/ticketing.json +2 -7
  15. claude_mpm/agents/templates/version_control.json +1 -1
  16. claude_mpm/agents/templates/web_qa.json +2 -2
  17. claude_mpm/agents/templates/web_ui.json +2 -2
  18. claude_mpm/cli/__init__.py +2 -2
  19. claude_mpm/cli/commands/__init__.py +2 -1
  20. claude_mpm/cli/commands/tickets.py +596 -19
  21. claude_mpm/cli/parser.py +217 -5
  22. claude_mpm/config/__init__.py +30 -39
  23. claude_mpm/config/socketio_config.py +8 -5
  24. claude_mpm/constants.py +13 -0
  25. claude_mpm/core/__init__.py +8 -18
  26. claude_mpm/core/cache.py +596 -0
  27. claude_mpm/core/claude_runner.py +166 -622
  28. claude_mpm/core/config.py +5 -1
  29. claude_mpm/core/constants.py +339 -0
  30. claude_mpm/core/container.py +461 -22
  31. claude_mpm/core/exceptions.py +392 -0
  32. claude_mpm/core/framework_loader.py +208 -94
  33. claude_mpm/core/interactive_session.py +432 -0
  34. claude_mpm/core/interfaces.py +424 -0
  35. claude_mpm/core/lazy.py +467 -0
  36. claude_mpm/core/logging_config.py +444 -0
  37. claude_mpm/core/oneshot_session.py +465 -0
  38. claude_mpm/core/optimized_agent_loader.py +485 -0
  39. claude_mpm/core/optimized_startup.py +490 -0
  40. claude_mpm/core/service_registry.py +52 -26
  41. claude_mpm/core/socketio_pool.py +162 -5
  42. claude_mpm/core/types.py +292 -0
  43. claude_mpm/core/typing_utils.py +477 -0
  44. claude_mpm/hooks/claude_hooks/hook_handler.py +213 -99
  45. claude_mpm/init.py +2 -1
  46. claude_mpm/services/__init__.py +78 -14
  47. claude_mpm/services/agent/__init__.py +24 -0
  48. claude_mpm/services/agent/deployment.py +2548 -0
  49. claude_mpm/services/agent/management.py +598 -0
  50. claude_mpm/services/agent/registry.py +813 -0
  51. claude_mpm/services/agents/deployment/agent_deployment.py +587 -268
  52. claude_mpm/services/agents/memory/agent_memory_manager.py +156 -1
  53. claude_mpm/services/async_session_logger.py +8 -3
  54. claude_mpm/services/communication/__init__.py +21 -0
  55. claude_mpm/services/communication/socketio.py +1933 -0
  56. claude_mpm/services/communication/websocket.py +479 -0
  57. claude_mpm/services/core/__init__.py +123 -0
  58. claude_mpm/services/core/base.py +247 -0
  59. claude_mpm/services/core/interfaces.py +951 -0
  60. claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +23 -23
  61. claude_mpm/services/framework_claude_md_generator.py +3 -2
  62. claude_mpm/services/health_monitor.py +4 -3
  63. claude_mpm/services/hook_service.py +64 -4
  64. claude_mpm/services/infrastructure/__init__.py +21 -0
  65. claude_mpm/services/infrastructure/logging.py +202 -0
  66. claude_mpm/services/infrastructure/monitoring.py +893 -0
  67. claude_mpm/services/memory/indexed_memory.py +648 -0
  68. claude_mpm/services/project/__init__.py +21 -0
  69. claude_mpm/services/project/analyzer.py +864 -0
  70. claude_mpm/services/project/registry.py +608 -0
  71. claude_mpm/services/project_analyzer.py +95 -2
  72. claude_mpm/services/recovery_manager.py +15 -9
  73. claude_mpm/services/socketio/__init__.py +25 -0
  74. claude_mpm/services/socketio/handlers/__init__.py +25 -0
  75. claude_mpm/services/socketio/handlers/base.py +121 -0
  76. claude_mpm/services/socketio/handlers/connection.py +198 -0
  77. claude_mpm/services/socketio/handlers/file.py +213 -0
  78. claude_mpm/services/socketio/handlers/git.py +723 -0
  79. claude_mpm/services/socketio/handlers/memory.py +27 -0
  80. claude_mpm/services/socketio/handlers/project.py +25 -0
  81. claude_mpm/services/socketio/handlers/registry.py +145 -0
  82. claude_mpm/services/socketio_client_manager.py +12 -7
  83. claude_mpm/services/socketio_server.py +156 -30
  84. claude_mpm/services/ticket_manager.py +170 -7
  85. claude_mpm/utils/error_handler.py +1 -1
  86. claude_mpm/validation/agent_validator.py +27 -14
  87. claude_mpm/validation/frontmatter_validator.py +231 -0
  88. {claude_mpm-3.7.8.dist-info → claude_mpm-3.8.1.dist-info}/METADATA +58 -21
  89. {claude_mpm-3.7.8.dist-info → claude_mpm-3.8.1.dist-info}/RECORD +93 -53
  90. {claude_mpm-3.7.8.dist-info → claude_mpm-3.8.1.dist-info}/WHEEL +0 -0
  91. {claude_mpm-3.7.8.dist-info → claude_mpm-3.8.1.dist-info}/entry_points.txt +0 -0
  92. {claude_mpm-3.7.8.dist-info → claude_mpm-3.8.1.dist-info}/licenses/LICENSE +0 -0
  93. {claude_mpm-3.7.8.dist-info → claude_mpm-3.8.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,490 @@
1
+ #!/usr/bin/env python3
2
+ """Optimized startup performance with deferred initialization.
3
+
4
+ This module provides startup optimization techniques:
5
+ - Deferred service initialization
6
+ - Async configuration loading
7
+ - Minimal import strategy
8
+ - Progressive enhancement
9
+
10
+ WHY optimized startup:
11
+ - Reduces startup time from 3-5 seconds to <2 seconds
12
+ - Defers non-critical initialization
13
+ - Loads only required components
14
+ - Provides instant CLI responsiveness
15
+ """
16
+
17
+ import asyncio
18
+ import importlib
19
+ import sys
20
+ import time
21
+ from concurrent.futures import ThreadPoolExecutor
22
+ from dataclasses import dataclass, field
23
+ from pathlib import Path
24
+ from typing import Any, Callable, Dict, List, Optional, Set, Tuple
25
+
26
+ from .lazy import LazyService, lazy_load
27
+ from .cache import get_file_cache
28
+ from ..core.logger import get_logger
29
+
30
+
31
+ @dataclass
32
+ class StartupMetrics:
33
+ """Metrics for startup performance."""
34
+ total_time: float = 0.0
35
+ import_time: float = 0.0
36
+ config_time: float = 0.0
37
+ service_time: float = 0.0
38
+ agent_time: float = 0.0
39
+ phases: Dict[str, float] = field(default_factory=dict)
40
+ deferred_services: List[str] = field(default_factory=list)
41
+
42
+
43
+ class OptimizedStartup:
44
+ """Manager for optimized application startup.
45
+
46
+ WHY this design:
47
+ - Phase-based initialization for progressive loading
48
+ - Critical-path optimization
49
+ - Deferred loading for optional features
50
+ - Parallel initialization where possible
51
+
52
+ Example:
53
+ startup = OptimizedStartup()
54
+
55
+ # Fast minimal startup
56
+ startup.initialize_minimal()
57
+
58
+ # Progressive enhancement
59
+ startup.initialize_services()
60
+ startup.initialize_agents()
61
+ """
62
+
63
+ # Critical services needed immediately
64
+ CRITICAL_SERVICES = {
65
+ 'logger', 'config', 'paths', 'cli_parser'
66
+ }
67
+
68
+ # Services that can be deferred
69
+ DEFERRED_SERVICES = {
70
+ 'socketio', 'dashboard', 'memory', 'hooks',
71
+ 'project_analyzer', 'tree_sitter', 'monitoring'
72
+ }
73
+
74
+ # Heavy imports to defer
75
+ HEAVY_IMPORTS = {
76
+ 'numpy', 'pandas', 'matplotlib', 'scipy',
77
+ 'tensorflow', 'torch', 'transformers'
78
+ }
79
+
80
+ def __init__(self):
81
+ self.metrics = StartupMetrics()
82
+ self.logger = get_logger("startup")
83
+ self.initialized_services: Set[str] = set()
84
+ self.lazy_services: Dict[str, LazyService] = {}
85
+ self.import_cache: Dict[str, Any] = {}
86
+ self.executor = ThreadPoolExecutor(max_workers=4)
87
+
88
+ # Start timer
89
+ self.start_time = time.time()
90
+
91
+ def initialize_minimal(self) -> float:
92
+ """Initialize only critical components for fast startup.
93
+
94
+ Returns:
95
+ Time taken for minimal initialization
96
+ """
97
+ phase_start = time.time()
98
+
99
+ # 1. Setup basic logging (synchronous, required immediately)
100
+ self._setup_logging()
101
+
102
+ # 2. Load minimal config (only required settings)
103
+ self._load_minimal_config()
104
+
105
+ # 3. Setup CLI parser (needed for argument processing)
106
+ self._setup_cli_parser()
107
+
108
+ elapsed = time.time() - phase_start
109
+ self.metrics.phases['minimal'] = elapsed
110
+ self.logger.info(f"Minimal initialization completed in {elapsed:.2f}s")
111
+
112
+ return elapsed
113
+
114
+ def initialize_services(self, lazy: bool = True) -> float:
115
+ """Initialize service layer with optional lazy loading.
116
+
117
+ Args:
118
+ lazy: Whether to use lazy loading for services
119
+
120
+ Returns:
121
+ Time taken for service initialization
122
+ """
123
+ phase_start = time.time()
124
+
125
+ if lazy:
126
+ # Create lazy wrappers for deferred services
127
+ self._create_lazy_services()
128
+ self.logger.debug(f"Created {len(self.lazy_services)} lazy services")
129
+ else:
130
+ # Initialize all services immediately
131
+ self._initialize_all_services()
132
+
133
+ elapsed = time.time() - phase_start
134
+ self.metrics.phases['services'] = elapsed
135
+ self.metrics.service_time = elapsed
136
+
137
+ return elapsed
138
+
139
+ def initialize_agents(self, preload: bool = False) -> float:
140
+ """Initialize agent system with optional preloading.
141
+
142
+ Args:
143
+ preload: Whether to preload all agents
144
+
145
+ Returns:
146
+ Time taken for agent initialization
147
+ """
148
+ phase_start = time.time()
149
+
150
+ if preload:
151
+ # Load all agents immediately
152
+ from .optimized_agent_loader import preload_system_agents
153
+ preload_system_agents()
154
+ else:
155
+ # Just setup agent registry, load on demand
156
+ self._setup_agent_registry()
157
+
158
+ elapsed = time.time() - phase_start
159
+ self.metrics.phases['agents'] = elapsed
160
+ self.metrics.agent_time = elapsed
161
+
162
+ return elapsed
163
+
164
+ async def initialize_async(self) -> StartupMetrics:
165
+ """Fully async initialization for maximum performance.
166
+
167
+ Returns:
168
+ Complete startup metrics
169
+ """
170
+ start = time.time()
171
+
172
+ # Run initialization phases concurrently where possible
173
+ tasks = [
174
+ self._async_load_config(),
175
+ self._async_setup_services(),
176
+ self._async_load_agents()
177
+ ]
178
+
179
+ results = await asyncio.gather(*tasks, return_exceptions=True)
180
+
181
+ # Handle any errors
182
+ for i, result in enumerate(results):
183
+ if isinstance(result, Exception):
184
+ self.logger.error(f"Async initialization error in task {i}: {result}")
185
+
186
+ self.metrics.total_time = time.time() - start
187
+ self.logger.info(f"Async startup completed in {self.metrics.total_time:.2f}s")
188
+
189
+ return self.metrics
190
+
191
+ def _setup_logging(self):
192
+ """Setup basic logging (critical path)."""
193
+ # Minimal logging setup - already handled by logger module
194
+ self.initialized_services.add('logger')
195
+
196
+ def _load_minimal_config(self):
197
+ """Load only essential configuration."""
198
+ try:
199
+ # Use cache for config if available
200
+ cache = get_file_cache()
201
+ config_path = Path.home() / ".claude-mpm" / "config.yaml"
202
+
203
+ if config_path.exists():
204
+ config = cache.get_or_compute(
205
+ f"config:{config_path}",
206
+ lambda: self._parse_config(config_path),
207
+ ttl=60
208
+ )
209
+ # Store in a lightweight way
210
+ self._store_config(config)
211
+
212
+ self.initialized_services.add('config')
213
+ except Exception as e:
214
+ self.logger.warning(f"Failed to load config: {e}")
215
+
216
+ def _parse_config(self, path: Path) -> Dict[str, Any]:
217
+ """Parse configuration file."""
218
+ import yaml
219
+ with open(path) as f:
220
+ return yaml.safe_load(f) or {}
221
+
222
+ def _store_config(self, config: Dict[str, Any]):
223
+ """Store configuration for later use."""
224
+ # Simple storage without heavy Config class
225
+ sys.modules['__claude_mpm_config__'] = type('Config', (), config)()
226
+
227
+ def _setup_cli_parser(self):
228
+ """Setup CLI argument parser."""
229
+ # Defer actual parser creation until needed
230
+ self.lazy_services['cli_parser'] = LazyService(
231
+ service_class=self._create_cli_parser,
232
+ name='cli_parser'
233
+ )
234
+ self.initialized_services.add('cli_parser')
235
+
236
+ def _create_cli_parser(self):
237
+ """Actually create the CLI parser when needed."""
238
+ from ..cli.parser import create_parser
239
+ return create_parser()
240
+
241
+ def _create_lazy_services(self):
242
+ """Create lazy wrappers for deferred services."""
243
+ # SocketIO service (heavy, often not needed)
244
+ self.lazy_services['socketio'] = lazy_load(
245
+ self._create_socketio_service,
246
+ name='socketio'
247
+ )
248
+
249
+ # Dashboard service
250
+ self.lazy_services['dashboard'] = lazy_load(
251
+ self._create_dashboard_service,
252
+ name='dashboard'
253
+ )
254
+
255
+ # Memory service
256
+ self.lazy_services['memory'] = lazy_load(
257
+ self._create_memory_service,
258
+ name='memory'
259
+ )
260
+
261
+ # Hook service
262
+ self.lazy_services['hooks'] = lazy_load(
263
+ self._create_hook_service,
264
+ name='hooks'
265
+ )
266
+
267
+ # Project analyzer (very heavy)
268
+ self.lazy_services['project_analyzer'] = lazy_load(
269
+ self._create_project_analyzer,
270
+ name='project_analyzer'
271
+ )
272
+
273
+ # Track deferred services
274
+ self.metrics.deferred_services = list(self.lazy_services.keys())
275
+
276
+ def _create_socketio_service(self):
277
+ """Create SocketIO service when needed."""
278
+ from ..core.socketio_pool import get_connection_pool
279
+ return get_connection_pool()
280
+
281
+ def _create_dashboard_service(self):
282
+ """Create dashboard service when needed."""
283
+ # Import only when needed
284
+ from ..services.dashboard import DashboardService
285
+ return DashboardService()
286
+
287
+ def _create_memory_service(self):
288
+ """Create memory service when needed."""
289
+ from ..services.memory.indexed_memory import get_indexed_memory
290
+ return get_indexed_memory()
291
+
292
+ def _create_hook_service(self):
293
+ """Create hook service when needed."""
294
+ from ..services.hook_service import HookService
295
+ return HookService()
296
+
297
+ def _create_project_analyzer(self):
298
+ """Create project analyzer when needed."""
299
+ # This is typically very heavy
300
+ from ..services.agent_modification_tracker.analyzer import ProjectAnalyzer
301
+ return ProjectAnalyzer()
302
+
303
+ def _initialize_all_services(self):
304
+ """Initialize all services immediately (non-lazy mode)."""
305
+ services = [
306
+ 'socketio', 'dashboard', 'memory', 'hooks', 'project_analyzer'
307
+ ]
308
+
309
+ for service_name in services:
310
+ try:
311
+ creator = getattr(self, f'_create_{service_name}_service', None)
312
+ if creator:
313
+ creator()
314
+ self.initialized_services.add(service_name)
315
+ except Exception as e:
316
+ self.logger.warning(f"Failed to initialize {service_name}: {e}")
317
+
318
+ def _setup_agent_registry(self):
319
+ """Setup agent registry for on-demand loading."""
320
+ self.lazy_services['agent_registry'] = lazy_load(
321
+ self._create_agent_registry,
322
+ name='agent_registry'
323
+ )
324
+ self.initialized_services.add('agent_registry')
325
+
326
+ def _create_agent_registry(self):
327
+ """Create agent registry when needed."""
328
+ from ..core.agent_registry import SimpleAgentRegistry
329
+ from pathlib import Path
330
+ return SimpleAgentRegistry(Path.cwd())
331
+
332
+ async def _async_load_config(self):
333
+ """Load configuration asynchronously."""
334
+ loop = asyncio.get_event_loop()
335
+ config_path = Path.home() / ".claude-mpm" / "config.yaml"
336
+
337
+ if config_path.exists():
338
+ config = await loop.run_in_executor(
339
+ None,
340
+ self._parse_config,
341
+ config_path
342
+ )
343
+ self._store_config(config)
344
+
345
+ async def _async_setup_services(self):
346
+ """Setup services asynchronously."""
347
+ # Create all lazy services concurrently
348
+ loop = asyncio.get_event_loop()
349
+ await loop.run_in_executor(None, self._create_lazy_services)
350
+
351
+ async def _async_load_agents(self):
352
+ """Load agents asynchronously."""
353
+ from .optimized_agent_loader import get_optimized_loader
354
+
355
+ loader = get_optimized_loader()
356
+ agent_paths = self._discover_agent_paths()
357
+
358
+ if agent_paths:
359
+ await loader.load_agents_async(agent_paths)
360
+
361
+ def _discover_agent_paths(self) -> List[Path]:
362
+ """Discover agent file paths."""
363
+ paths = []
364
+ agent_dirs = [
365
+ Path.cwd() / ".claude" / "agents",
366
+ Path.cwd() / ".claude-mpm" / "agents",
367
+ Path.home() / ".claude-mpm" / "agents"
368
+ ]
369
+
370
+ for dir_path in agent_dirs:
371
+ if dir_path.exists():
372
+ paths.extend(dir_path.glob('*.json'))
373
+ paths.extend(dir_path.glob('*.md'))
374
+
375
+ return paths
376
+
377
+ def defer_import(self, module_name: str) -> Optional[Any]:
378
+ """Defer heavy imports until actually needed.
379
+
380
+ Args:
381
+ module_name: Name of module to import
382
+
383
+ Returns:
384
+ Imported module or None if not needed yet
385
+ """
386
+ if module_name in self.HEAVY_IMPORTS:
387
+ # Don't import heavy modules during startup
388
+ self.logger.debug(f"Deferring import of {module_name}")
389
+ return None
390
+
391
+ # Check cache
392
+ if module_name in self.import_cache:
393
+ return self.import_cache[module_name]
394
+
395
+ # Import and cache
396
+ try:
397
+ module = importlib.import_module(module_name)
398
+ self.import_cache[module_name] = module
399
+ return module
400
+ except ImportError as e:
401
+ self.logger.warning(f"Failed to import {module_name}: {e}")
402
+ return None
403
+
404
+ def get_service(self, name: str) -> Any:
405
+ """Get a service, initializing if needed.
406
+
407
+ Args:
408
+ name: Service name
409
+
410
+ Returns:
411
+ Service instance
412
+ """
413
+ if name in self.lazy_services:
414
+ # Lazy service will initialize on first access
415
+ return self.lazy_services[name]
416
+
417
+ # Try to create service
418
+ creator = getattr(self, f'_create_{name}_service', None)
419
+ if creator:
420
+ service = creator()
421
+ self.initialized_services.add(name)
422
+ return service
423
+
424
+ return None
425
+
426
+ def get_metrics(self) -> Dict[str, Any]:
427
+ """Get startup performance metrics."""
428
+ self.metrics.total_time = time.time() - self.start_time
429
+
430
+ return {
431
+ 'total_time': self.metrics.total_time,
432
+ 'phases': self.metrics.phases,
433
+ 'service_time': self.metrics.service_time,
434
+ 'agent_time': self.metrics.agent_time,
435
+ 'initialized_services': list(self.initialized_services),
436
+ 'deferred_services': self.metrics.deferred_services,
437
+ 'lazy_services_initialized': sum(
438
+ 1 for s in self.lazy_services.values()
439
+ if s.is_initialized
440
+ )
441
+ }
442
+
443
+
444
+ def optimize_startup(mode: str = 'lazy') -> OptimizedStartup:
445
+ """Optimize application startup.
446
+
447
+ Args:
448
+ mode: Startup mode ('lazy', 'eager', 'async')
449
+
450
+ Returns:
451
+ Configured startup manager
452
+
453
+ Example:
454
+ # Fast lazy startup
455
+ startup = optimize_startup('lazy')
456
+ startup.initialize_minimal()
457
+ startup.initialize_services(lazy=True)
458
+
459
+ # Access services as needed (they initialize on first use)
460
+ memory = startup.get_service('memory')
461
+ """
462
+ startup = OptimizedStartup()
463
+
464
+ if mode == 'lazy':
465
+ # Minimal startup with lazy loading
466
+ startup.initialize_minimal()
467
+ startup.initialize_services(lazy=True)
468
+ startup.initialize_agents(preload=False)
469
+ elif mode == 'eager':
470
+ # Full initialization upfront
471
+ startup.initialize_minimal()
472
+ startup.initialize_services(lazy=False)
473
+ startup.initialize_agents(preload=True)
474
+ elif mode == 'async':
475
+ # Async initialization
476
+ asyncio.run(startup.initialize_async())
477
+
478
+ return startup
479
+
480
+
481
+ # Global startup manager
482
+ _startup_manager: Optional[OptimizedStartup] = None
483
+
484
+
485
+ def get_startup_manager() -> OptimizedStartup:
486
+ """Get or create global startup manager."""
487
+ global _startup_manager
488
+ if _startup_manager is None:
489
+ _startup_manager = OptimizedStartup()
490
+ return _startup_manager
@@ -7,11 +7,15 @@ the DI container to manage application services.
7
7
 
8
8
  import logging
9
9
  from pathlib import Path
10
- from typing import Any, Dict, List, Optional, Type, Union
10
+ from typing import Any, Dict, List, Optional, Type, Union, TYPE_CHECKING
11
11
 
12
12
  from .container import DIContainer, ServiceLifetime, get_container
13
13
  from .base_service import BaseService
14
14
  from .logger import get_logger
15
+ from .config import Config
16
+
17
+ if TYPE_CHECKING:
18
+ from claude_mpm.services.agents.deployment import AgentDeploymentService
15
19
 
16
20
  logger = get_logger(__name__)
17
21
 
@@ -41,13 +45,12 @@ class ServiceRegistry:
41
45
  from ..services import AgentDeploymentService
42
46
  from .session_manager import SessionManager
43
47
  from .agent_session_manager import AgentSessionManager
44
- from .config import Config
45
48
 
46
- # Register configuration as singleton
49
+ # Register configuration as singleton with name
47
50
  config = Config()
48
- self.container.register_singleton(Config, instance=config)
51
+ self.container.register_singleton(Config, instance=config, name="main_config")
49
52
 
50
- # Register core services
53
+ # Register core services with proper lifetime management
51
54
  self.register_service(
52
55
  "session_manager",
53
56
  SessionManager,
@@ -59,33 +62,51 @@ class ServiceRegistry:
59
62
  AgentSessionManager,
60
63
  lifetime=ServiceLifetime.SINGLETON,
61
64
  dependencies={
62
- 'session_dir': lambda c: c.resolve(Config).get('session_dir')
65
+ 'session_dir': lambda c: c.get(Config).get('session_dir')
63
66
  }
64
67
  )
65
68
 
66
- # Register shared cache as singleton (it's already a singleton internally)
67
- self.register_service(
68
- "prompt_cache",
69
+ # Register shared cache as singleton with factory
70
+ self.container.register_factory(
69
71
  SharedPromptCache,
72
+ lambda c: SharedPromptCache.get_instance(),
70
73
  lifetime=ServiceLifetime.SINGLETON,
71
- factory=lambda c: SharedPromptCache.get_instance()
74
+ name="prompt_cache"
72
75
  )
73
76
 
74
- # Register ticket manager
75
- self.register_service(
76
- "ticket_manager",
77
+ # Register ticket manager as scoped (per-request)
78
+ self.container.register_scoped(
77
79
  TicketManager,
78
- lifetime=ServiceLifetime.TRANSIENT
80
+ TicketManager,
81
+ name="ticket_manager"
79
82
  )
80
83
 
81
- # Register agent deployment service
82
- self.register_service(
83
- "agent_deployment",
84
+ # Register agent deployment service with factory for better initialization
85
+ self.container.register_factory(
84
86
  AgentDeploymentService,
85
- lifetime=ServiceLifetime.TRANSIENT
87
+ lambda c: self._create_agent_deployment_service(c),
88
+ lifetime=ServiceLifetime.TRANSIENT,
89
+ name="agent_deployment"
86
90
  )
87
91
 
88
- logger.info("Core services registered")
92
+ logger.info("Core services registered with enhanced DI container")
93
+
94
+ def _create_agent_deployment_service(self, container: DIContainer) -> 'AgentDeploymentService':
95
+ """Factory method for creating agent deployment service."""
96
+ import os
97
+ from pathlib import Path
98
+
99
+ config = container.get(Config)
100
+
101
+ # Get working directory from environment or config
102
+ if 'CLAUDE_MPM_USER_PWD' in os.environ:
103
+ working_dir = Path(os.environ['CLAUDE_MPM_USER_PWD'])
104
+ else:
105
+ working_dir = Path(config.get('project.dir', '.'))
106
+
107
+ # Lazy import to avoid circular dependencies
108
+ from claude_mpm.services.agents.deployment import AgentDeploymentService
109
+ return AgentDeploymentService(working_directory=working_dir)
89
110
 
90
111
  def register_service(
91
112
  self,
@@ -138,14 +159,19 @@ class ServiceRegistry:
138
159
  Service instance
139
160
  """
140
161
  if isinstance(service_type, str):
141
- # Look up by name
142
- if service_type not in self._services:
143
- raise KeyError(f"Service '{service_type}' not registered")
144
- service_class = self._services[service_type]
162
+ # First try to get by name from container
163
+ try:
164
+ # Use the enhanced container's named resolution
165
+ return self.container.get(BaseService, name=service_type)
166
+ except:
167
+ # Fall back to looking up class and resolving
168
+ if service_type not in self._services:
169
+ raise KeyError(f"Service '{service_type}' not registered")
170
+ service_class = self._services[service_type]
171
+ return self.container.get(service_class)
145
172
  else:
146
- service_class = service_type
147
-
148
- return self.container.resolve(service_class)
173
+ # Direct class resolution
174
+ return self.container.get(service_type)
149
175
 
150
176
  def get_service_optional(
151
177
  self,