claude-mpm 4.3.22__py3-none-any.whl → 4.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/WORKFLOW.md +2 -14
  3. claude_mpm/cli/commands/configure.py +2 -29
  4. claude_mpm/cli/commands/doctor.py +2 -2
  5. claude_mpm/cli/commands/mpm_init.py +3 -3
  6. claude_mpm/cli/parsers/configure_parser.py +4 -15
  7. claude_mpm/core/framework/__init__.py +38 -0
  8. claude_mpm/core/framework/formatters/__init__.py +11 -0
  9. claude_mpm/core/framework/formatters/capability_generator.py +356 -0
  10. claude_mpm/core/framework/formatters/content_formatter.py +283 -0
  11. claude_mpm/core/framework/formatters/context_generator.py +180 -0
  12. claude_mpm/core/framework/loaders/__init__.py +13 -0
  13. claude_mpm/core/framework/loaders/agent_loader.py +202 -0
  14. claude_mpm/core/framework/loaders/file_loader.py +213 -0
  15. claude_mpm/core/framework/loaders/instruction_loader.py +151 -0
  16. claude_mpm/core/framework/loaders/packaged_loader.py +208 -0
  17. claude_mpm/core/framework/processors/__init__.py +11 -0
  18. claude_mpm/core/framework/processors/memory_processor.py +222 -0
  19. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  20. claude_mpm/core/framework/processors/template_processor.py +238 -0
  21. claude_mpm/core/framework_loader.py +277 -1798
  22. claude_mpm/hooks/__init__.py +9 -1
  23. claude_mpm/hooks/kuzu_memory_hook.py +352 -0
  24. claude_mpm/hooks/memory_integration_hook.py +1 -1
  25. claude_mpm/services/agents/memory/content_manager.py +5 -2
  26. claude_mpm/services/agents/memory/memory_file_service.py +1 -0
  27. claude_mpm/services/agents/memory/memory_limits_service.py +1 -0
  28. claude_mpm/services/core/path_resolver.py +1 -0
  29. claude_mpm/services/diagnostics/diagnostic_runner.py +1 -0
  30. claude_mpm/services/mcp_config_manager.py +67 -4
  31. claude_mpm/services/mcp_gateway/core/process_pool.py +281 -0
  32. claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
  33. claude_mpm/services/mcp_gateway/main.py +3 -13
  34. claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
  35. claude_mpm/services/mcp_gateway/tools/__init__.py +13 -2
  36. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +36 -6
  37. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +542 -0
  38. claude_mpm/services/shared/__init__.py +2 -1
  39. claude_mpm/services/shared/service_factory.py +8 -5
  40. claude_mpm/services/unified/__init__.py +65 -0
  41. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  42. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +473 -0
  43. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +643 -0
  44. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +804 -0
  45. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +661 -0
  46. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +696 -0
  47. claude_mpm/services/unified/config_strategies/__init__.py +190 -0
  48. claude_mpm/services/unified/config_strategies/config_schema.py +689 -0
  49. claude_mpm/services/unified/config_strategies/context_strategy.py +748 -0
  50. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +999 -0
  51. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +871 -0
  52. claude_mpm/services/unified/config_strategies/unified_config_service.py +802 -0
  53. claude_mpm/services/unified/config_strategies/validation_strategy.py +1105 -0
  54. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  55. claude_mpm/services/unified/deployment_strategies/base.py +557 -0
  56. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +486 -0
  57. claude_mpm/services/unified/deployment_strategies/local.py +594 -0
  58. claude_mpm/services/unified/deployment_strategies/utils.py +672 -0
  59. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  60. claude_mpm/services/unified/interfaces.py +499 -0
  61. claude_mpm/services/unified/migration.py +532 -0
  62. claude_mpm/services/unified/strategies.py +551 -0
  63. claude_mpm/services/unified/unified_analyzer.py +534 -0
  64. claude_mpm/services/unified/unified_config.py +688 -0
  65. claude_mpm/services/unified/unified_deployment.py +470 -0
  66. {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/METADATA +15 -15
  67. {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/RECORD +71 -32
  68. claude_mpm/cli/commands/configure_tui.py +0 -1927
  69. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
  70. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
  71. {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/WHEEL +0 -0
  72. {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/entry_points.txt +0 -0
  73. {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/licenses/LICENSE +0 -0
  74. {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,551 @@
1
+ """
2
+ Strategy Pattern Framework for Service Consolidation
3
+ ====================================================
4
+
5
+ This module implements the strategy pattern framework that enables pluggable behavior
6
+ in unified services. It provides base strategy classes and a plugin registry system
7
+ for dynamic strategy registration and selection.
8
+
9
+ Design Goals:
10
+ 1. Enable runtime strategy selection based on context
11
+ 2. Support plugin-based extensibility
12
+ 3. Maintain strong typing and interface contracts
13
+ 4. Allow graceful fallback to default strategies
14
+ 5. Support both sync and async operations
15
+
16
+ Architecture:
17
+ - Base strategy classes define common operations
18
+ - Concrete strategies implement specific behaviors
19
+ - Registry system manages strategy discovery and selection
20
+ - Context objects carry strategy selection criteria
21
+ """
22
+
23
+ from abc import ABC, abstractmethod
24
+ from dataclasses import dataclass, field
25
+ from enum import Enum
26
+ from pathlib import Path
27
+ from typing import Any, Callable, Dict, List, Optional, Set, Type, TypeVar, Union
28
+
29
+ from claude_mpm.core.logging_utils import get_logger
30
+
31
+ logger = get_logger(__name__)
32
+
33
+ # Type variables for generic strategies
34
+ T = TypeVar("T")
35
+ StrategyType = TypeVar("StrategyType", bound="BaseStrategy")
36
+
37
+
38
+ class StrategyPriority(Enum):
39
+ """Priority levels for strategy selection."""
40
+
41
+ CRITICAL = 100
42
+ HIGH = 75
43
+ NORMAL = 50
44
+ LOW = 25
45
+ FALLBACK = 0
46
+
47
+
48
+ @dataclass
49
+ class StrategyContext:
50
+ """
51
+ Context information for strategy selection.
52
+
53
+ Attributes:
54
+ target_type: Type of target being processed
55
+ operation: Operation being performed
56
+ parameters: Additional parameters for strategy selection
57
+ constraints: Constraints that strategies must satisfy
58
+ preferences: Preferred strategy characteristics
59
+ """
60
+
61
+ target_type: str
62
+ operation: str
63
+ parameters: Dict[str, Any] = field(default_factory=dict)
64
+ constraints: List[str] = field(default_factory=list)
65
+ preferences: Dict[str, Any] = field(default_factory=dict)
66
+
67
+
68
+ @dataclass
69
+ class StrategyMetadata:
70
+ """
71
+ Metadata for registered strategies.
72
+
73
+ Attributes:
74
+ name: Strategy identifier
75
+ description: Human-readable description
76
+ supported_types: List of supported target types
77
+ supported_operations: List of supported operations
78
+ priority: Strategy priority for selection
79
+ tags: Additional categorization tags
80
+ version: Strategy version
81
+ """
82
+
83
+ name: str
84
+ description: str = ""
85
+ supported_types: List[str] = field(default_factory=list)
86
+ supported_operations: List[str] = field(default_factory=list)
87
+ priority: StrategyPriority = StrategyPriority.NORMAL
88
+ tags: Set[str] = field(default_factory=set)
89
+ version: str = "1.0.0"
90
+
91
+
92
+ class BaseStrategy(ABC):
93
+ """
94
+ Base class for all strategies providing common functionality.
95
+
96
+ Subclasses should implement the abstract methods for specific behaviors
97
+ while inheriting common functionality like validation and logging.
98
+ """
99
+
100
+ def __init__(self, metadata: Optional[StrategyMetadata] = None):
101
+ """
102
+ Initialize base strategy.
103
+
104
+ Args:
105
+ metadata: Strategy metadata
106
+ """
107
+ self.metadata = metadata or StrategyMetadata(
108
+ name=self.__class__.__name__
109
+ )
110
+ self._logger = get_logger(f"{__name__}.{self.metadata.name}")
111
+
112
+ @abstractmethod
113
+ def can_handle(self, context: StrategyContext) -> bool:
114
+ """
115
+ Check if strategy can handle the given context.
116
+
117
+ Args:
118
+ context: Strategy context
119
+
120
+ Returns:
121
+ bool: True if strategy can handle context
122
+ """
123
+ pass
124
+
125
+ @abstractmethod
126
+ def validate_input(self, input_data: Any) -> List[str]:
127
+ """
128
+ Validate input data for strategy.
129
+
130
+ Args:
131
+ input_data: Input to validate
132
+
133
+ Returns:
134
+ List[str]: List of validation errors (empty if valid)
135
+ """
136
+ pass
137
+
138
+ def pre_execute(self, input_data: Any) -> Any:
139
+ """
140
+ Pre-processing hook before execution.
141
+
142
+ Args:
143
+ input_data: Input data
144
+
145
+ Returns:
146
+ Any: Processed input data
147
+ """
148
+ return input_data
149
+
150
+ def post_execute(self, result: Any) -> Any:
151
+ """
152
+ Post-processing hook after execution.
153
+
154
+ Args:
155
+ result: Execution result
156
+
157
+ Returns:
158
+ Any: Processed result
159
+ """
160
+ return result
161
+
162
+
163
+ class DeploymentStrategy(BaseStrategy):
164
+ """
165
+ Base strategy for deployment operations.
166
+
167
+ Concrete deployment strategies should extend this class and implement
168
+ the deploy method for specific deployment types (agent, config, resource, etc.).
169
+ """
170
+
171
+ @abstractmethod
172
+ def deploy(
173
+ self,
174
+ source: Union[str, Path],
175
+ target: Union[str, Path],
176
+ config: Optional[Dict[str, Any]] = None,
177
+ ) -> Dict[str, Any]:
178
+ """
179
+ Execute deployment strategy.
180
+
181
+ Args:
182
+ source: Deployment source
183
+ target: Deployment target
184
+ config: Deployment configuration
185
+
186
+ Returns:
187
+ Dict[str, Any]: Deployment result
188
+ """
189
+ pass
190
+
191
+ @abstractmethod
192
+ def prepare_rollback(self, deployment_info: Dict[str, Any]) -> Dict[str, Any]:
193
+ """
194
+ Prepare rollback information for deployment.
195
+
196
+ Args:
197
+ deployment_info: Current deployment information
198
+
199
+ Returns:
200
+ Dict[str, Any]: Rollback information
201
+ """
202
+ pass
203
+
204
+ @abstractmethod
205
+ def cleanup(self, target: Union[str, Path]) -> bool:
206
+ """
207
+ Clean up deployment artifacts.
208
+
209
+ Args:
210
+ target: Deployment target to clean
211
+
212
+ Returns:
213
+ bool: True if cleanup successful
214
+ """
215
+ pass
216
+
217
+
218
+ class AnalyzerStrategy(BaseStrategy):
219
+ """
220
+ Base strategy for analysis operations.
221
+
222
+ Concrete analyzer strategies should extend this class and implement
223
+ the analyze method for specific analysis types (code, complexity, dependency, etc.).
224
+ """
225
+
226
+ @abstractmethod
227
+ def analyze(
228
+ self, target: Any, options: Optional[Dict[str, Any]] = None
229
+ ) -> Dict[str, Any]:
230
+ """
231
+ Execute analysis strategy.
232
+
233
+ Args:
234
+ target: Analysis target
235
+ options: Analysis options
236
+
237
+ Returns:
238
+ Dict[str, Any]: Analysis results
239
+ """
240
+ pass
241
+
242
+ @abstractmethod
243
+ def extract_metrics(self, analysis_result: Dict[str, Any]) -> Dict[str, Any]:
244
+ """
245
+ Extract metrics from analysis results.
246
+
247
+ Args:
248
+ analysis_result: Raw analysis results
249
+
250
+ Returns:
251
+ Dict[str, Any]: Extracted metrics
252
+ """
253
+ pass
254
+
255
+ @abstractmethod
256
+ def generate_report(
257
+ self, analysis_result: Dict[str, Any], format: str = "json"
258
+ ) -> Union[str, Dict[str, Any]]:
259
+ """
260
+ Generate report from analysis results.
261
+
262
+ Args:
263
+ analysis_result: Analysis results
264
+ format: Report format (json, markdown, html)
265
+
266
+ Returns:
267
+ Union[str, Dict[str, Any]]: Generated report
268
+ """
269
+ pass
270
+
271
+
272
+ class ConfigStrategy(BaseStrategy):
273
+ """
274
+ Base strategy for configuration operations.
275
+
276
+ Concrete config strategies should extend this class and implement
277
+ the process method for specific configuration types (project, agent, environment, etc.).
278
+ """
279
+
280
+ @abstractmethod
281
+ def load(self, source: Union[str, Path, Dict[str, Any]]) -> Dict[str, Any]:
282
+ """
283
+ Load configuration using strategy.
284
+
285
+ Args:
286
+ source: Configuration source
287
+
288
+ Returns:
289
+ Dict[str, Any]: Loaded configuration
290
+ """
291
+ pass
292
+
293
+ @abstractmethod
294
+ def validate(self, config: Dict[str, Any]) -> List[str]:
295
+ """
296
+ Validate configuration using strategy schema.
297
+
298
+ Args:
299
+ config: Configuration to validate
300
+
301
+ Returns:
302
+ List[str]: Validation errors (empty if valid)
303
+ """
304
+ pass
305
+
306
+ @abstractmethod
307
+ def transform(self, config: Dict[str, Any]) -> Dict[str, Any]:
308
+ """
309
+ Transform configuration to required format.
310
+
311
+ Args:
312
+ config: Configuration to transform
313
+
314
+ Returns:
315
+ Dict[str, Any]: Transformed configuration
316
+ """
317
+ pass
318
+
319
+ @abstractmethod
320
+ def get_schema(self) -> Dict[str, Any]:
321
+ """
322
+ Get configuration schema for this strategy.
323
+
324
+ Returns:
325
+ Dict[str, Any]: Configuration schema
326
+ """
327
+ pass
328
+
329
+
330
+ class StrategyRegistry:
331
+ """
332
+ Registry for managing strategy registration and selection.
333
+
334
+ The registry provides a centralized location for registering strategies
335
+ and selecting appropriate strategies based on context.
336
+ """
337
+
338
+ def __init__(self):
339
+ """Initialize strategy registry."""
340
+ self._strategies: Dict[Type[BaseStrategy], List[BaseStrategy]] = {}
341
+ self._strategy_metadata: Dict[str, StrategyMetadata] = {}
342
+ self._logger = get_logger(f"{__name__}.StrategyRegistry")
343
+
344
+ def register(
345
+ self,
346
+ strategy_class: Type[StrategyType],
347
+ strategy: StrategyType,
348
+ override: bool = False,
349
+ ) -> None:
350
+ """
351
+ Register a strategy implementation.
352
+
353
+ Args:
354
+ strategy_class: Base strategy class type
355
+ strategy: Strategy instance
356
+ override: Whether to override existing strategy with same name
357
+
358
+ Raises:
359
+ ValueError: If strategy already registered and override is False
360
+ """
361
+ if strategy_class not in self._strategies:
362
+ self._strategies[strategy_class] = []
363
+
364
+ strategy_name = strategy.metadata.name
365
+
366
+ if strategy_name in self._strategy_metadata and not override:
367
+ raise ValueError(
368
+ f"Strategy '{strategy_name}' already registered. "
369
+ "Set override=True to replace."
370
+ )
371
+
372
+ # Remove old strategy if overriding
373
+ if override and strategy_name in self._strategy_metadata:
374
+ self._strategies[strategy_class] = [
375
+ s for s in self._strategies[strategy_class]
376
+ if s.metadata.name != strategy_name
377
+ ]
378
+
379
+ self._strategies[strategy_class].append(strategy)
380
+ self._strategy_metadata[strategy_name] = strategy.metadata
381
+
382
+ self._logger.debug(
383
+ f"Registered strategy '{strategy_name}' for {strategy_class.__name__}"
384
+ )
385
+
386
+ def unregister(self, strategy_name: str) -> bool:
387
+ """
388
+ Unregister a strategy by name.
389
+
390
+ Args:
391
+ strategy_name: Name of strategy to unregister
392
+
393
+ Returns:
394
+ bool: True if strategy was unregistered
395
+ """
396
+ if strategy_name not in self._strategy_metadata:
397
+ return False
398
+
399
+ # Remove from all strategy lists
400
+ for strategy_class in self._strategies:
401
+ self._strategies[strategy_class] = [
402
+ s for s in self._strategies[strategy_class]
403
+ if s.metadata.name != strategy_name
404
+ ]
405
+
406
+ del self._strategy_metadata[strategy_name]
407
+ self._logger.debug(f"Unregistered strategy '{strategy_name}'")
408
+ return True
409
+
410
+ def select_strategy(
411
+ self,
412
+ strategy_class: Type[StrategyType],
413
+ context: StrategyContext,
414
+ ) -> Optional[StrategyType]:
415
+ """
416
+ Select best strategy for given context.
417
+
418
+ Args:
419
+ strategy_class: Base strategy class type
420
+ context: Strategy selection context
421
+
422
+ Returns:
423
+ Optional[StrategyType]: Selected strategy or None
424
+ """
425
+ if strategy_class not in self._strategies:
426
+ self._logger.warning(
427
+ f"No strategies registered for {strategy_class.__name__}"
428
+ )
429
+ return None
430
+
431
+ candidates = []
432
+
433
+ for strategy in self._strategies[strategy_class]:
434
+ if strategy.can_handle(context):
435
+ candidates.append(strategy)
436
+
437
+ if not candidates:
438
+ self._logger.warning(
439
+ f"No suitable strategy found for context: {context}"
440
+ )
441
+ return None
442
+
443
+ # Sort by priority (highest first)
444
+ candidates.sort(
445
+ key=lambda s: s.metadata.priority.value,
446
+ reverse=True
447
+ )
448
+
449
+ selected = candidates[0]
450
+ self._logger.debug(
451
+ f"Selected strategy '{selected.metadata.name}' "
452
+ f"for {strategy_class.__name__}"
453
+ )
454
+
455
+ return selected
456
+
457
+ def get_strategy(
458
+ self,
459
+ strategy_class: Type[StrategyType],
460
+ name: str,
461
+ ) -> Optional[StrategyType]:
462
+ """
463
+ Get specific strategy by name.
464
+
465
+ Args:
466
+ strategy_class: Base strategy class type
467
+ name: Strategy name
468
+
469
+ Returns:
470
+ Optional[StrategyType]: Strategy instance or None
471
+ """
472
+ if strategy_class not in self._strategies:
473
+ return None
474
+
475
+ for strategy in self._strategies[strategy_class]:
476
+ if strategy.metadata.name == name:
477
+ return strategy
478
+
479
+ return None
480
+
481
+ def list_strategies(
482
+ self, strategy_class: Optional[Type[BaseStrategy]] = None
483
+ ) -> List[StrategyMetadata]:
484
+ """
485
+ List registered strategies.
486
+
487
+ Args:
488
+ strategy_class: Optional filter by strategy class
489
+
490
+ Returns:
491
+ List[StrategyMetadata]: List of strategy metadata
492
+ """
493
+ if strategy_class:
494
+ if strategy_class not in self._strategies:
495
+ return []
496
+ return [s.metadata for s in self._strategies[strategy_class]]
497
+
498
+ return list(self._strategy_metadata.values())
499
+
500
+ def clear(self) -> None:
501
+ """Clear all registered strategies."""
502
+ self._strategies.clear()
503
+ self._strategy_metadata.clear()
504
+ self._logger.debug("Cleared all registered strategies")
505
+
506
+
507
+ # Global strategy registry instance
508
+ _global_registry = StrategyRegistry()
509
+
510
+
511
+ def get_strategy_registry() -> StrategyRegistry:
512
+ """
513
+ Get the global strategy registry instance.
514
+
515
+ Returns:
516
+ StrategyRegistry: Global registry instance
517
+ """
518
+ return _global_registry
519
+
520
+
521
+ def register_strategy(
522
+ strategy_class: Type[BaseStrategy],
523
+ strategy: BaseStrategy,
524
+ override: bool = False,
525
+ ) -> None:
526
+ """
527
+ Register a strategy in the global registry.
528
+
529
+ Args:
530
+ strategy_class: Base strategy class type
531
+ strategy: Strategy instance
532
+ override: Whether to override existing strategy
533
+ """
534
+ _global_registry.register(strategy_class, strategy, override)
535
+
536
+
537
+ def select_strategy(
538
+ strategy_class: Type[BaseStrategy],
539
+ context: StrategyContext,
540
+ ) -> Optional[BaseStrategy]:
541
+ """
542
+ Select best strategy from global registry.
543
+
544
+ Args:
545
+ strategy_class: Base strategy class type
546
+ context: Strategy selection context
547
+
548
+ Returns:
549
+ Optional[BaseStrategy]: Selected strategy or None
550
+ """
551
+ return _global_registry.select_strategy(strategy_class, context)