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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/WORKFLOW.md +2 -14
- claude_mpm/cli/commands/configure.py +2 -29
- claude_mpm/cli/commands/doctor.py +2 -2
- claude_mpm/cli/commands/mpm_init.py +3 -3
- claude_mpm/cli/parsers/configure_parser.py +4 -15
- claude_mpm/core/framework/__init__.py +38 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +356 -0
- claude_mpm/core/framework/formatters/content_formatter.py +283 -0
- claude_mpm/core/framework/formatters/context_generator.py +180 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +202 -0
- claude_mpm/core/framework/loaders/file_loader.py +213 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +151 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +208 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +222 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +238 -0
- claude_mpm/core/framework_loader.py +277 -1798
- claude_mpm/hooks/__init__.py +9 -1
- claude_mpm/hooks/kuzu_memory_hook.py +352 -0
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/services/agents/memory/content_manager.py +5 -2
- claude_mpm/services/agents/memory/memory_file_service.py +1 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +1 -0
- claude_mpm/services/core/path_resolver.py +1 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +1 -0
- claude_mpm/services/mcp_config_manager.py +67 -4
- claude_mpm/services/mcp_gateway/core/process_pool.py +281 -0
- claude_mpm/services/mcp_gateway/core/startup_verification.py +2 -2
- claude_mpm/services/mcp_gateway/main.py +3 -13
- claude_mpm/services/mcp_gateway/server/stdio_server.py +4 -10
- claude_mpm/services/mcp_gateway/tools/__init__.py +13 -2
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +36 -6
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +542 -0
- claude_mpm/services/shared/__init__.py +2 -1
- claude_mpm/services/shared/service_factory.py +8 -5
- claude_mpm/services/unified/__init__.py +65 -0
- claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +473 -0
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +643 -0
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +804 -0
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +661 -0
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +696 -0
- claude_mpm/services/unified/config_strategies/__init__.py +190 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +689 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +748 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +999 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +871 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +802 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1105 -0
- claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
- claude_mpm/services/unified/deployment_strategies/base.py +557 -0
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +486 -0
- claude_mpm/services/unified/deployment_strategies/local.py +594 -0
- claude_mpm/services/unified/deployment_strategies/utils.py +672 -0
- claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
- claude_mpm/services/unified/interfaces.py +499 -0
- claude_mpm/services/unified/migration.py +532 -0
- claude_mpm/services/unified/strategies.py +551 -0
- claude_mpm/services/unified/unified_analyzer.py +534 -0
- claude_mpm/services/unified/unified_config.py +688 -0
- claude_mpm/services/unified/unified_deployment.py +470 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/METADATA +15 -15
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/RECORD +71 -32
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.3.22.dist-info → claude_mpm-4.4.3.dist-info}/licenses/LICENSE +0 -0
- {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)
|