claude-mpm 4.4.3__py3-none-any.whl → 4.4.5__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/agent_loader.py +3 -2
- claude_mpm/agents/agent_loader_integration.py +2 -1
- claude_mpm/agents/async_agent_loader.py +2 -2
- claude_mpm/agents/base_agent_loader.py +2 -2
- claude_mpm/agents/frontmatter_validator.py +1 -0
- claude_mpm/agents/system_agent_config.py +2 -1
- claude_mpm/cli/commands/doctor.py +44 -5
- claude_mpm/cli/commands/mpm_init.py +116 -62
- claude_mpm/cli/parsers/configure_parser.py +3 -1
- claude_mpm/cli/startup_logging.py +1 -3
- claude_mpm/config/agent_config.py +1 -1
- claude_mpm/config/paths.py +2 -1
- claude_mpm/core/agent_name_normalizer.py +1 -0
- claude_mpm/core/config.py +2 -1
- claude_mpm/core/config_aliases.py +2 -1
- claude_mpm/core/file_utils.py +0 -1
- claude_mpm/core/framework/__init__.py +6 -6
- claude_mpm/core/framework/formatters/__init__.py +2 -2
- claude_mpm/core/framework/formatters/capability_generator.py +19 -8
- claude_mpm/core/framework/formatters/content_formatter.py +8 -3
- claude_mpm/core/framework/formatters/context_generator.py +7 -3
- claude_mpm/core/framework/loaders/__init__.py +3 -3
- claude_mpm/core/framework/loaders/agent_loader.py +7 -3
- claude_mpm/core/framework/loaders/file_loader.py +16 -6
- claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
- claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
- claude_mpm/core/framework/processors/__init__.py +2 -2
- claude_mpm/core/framework/processors/memory_processor.py +14 -6
- claude_mpm/core/framework/processors/metadata_processor.py +5 -5
- claude_mpm/core/framework/processors/template_processor.py +12 -6
- claude_mpm/core/framework_loader.py +44 -20
- claude_mpm/core/log_manager.py +2 -1
- claude_mpm/core/tool_access_control.py +1 -0
- claude_mpm/core/unified_agent_registry.py +2 -1
- claude_mpm/core/unified_paths.py +1 -0
- claude_mpm/experimental/cli_enhancements.py +1 -0
- claude_mpm/hooks/base_hook.py +1 -0
- claude_mpm/hooks/instruction_reinforcement.py +1 -0
- claude_mpm/hooks/kuzu_memory_hook.py +20 -13
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/scripts/mpm_doctor.py +1 -0
- claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
- claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
- claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
- claude_mpm/services/agents/management/agent_management_service.py +1 -1
- claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
- claude_mpm/services/agents/memory/memory_file_service.py +6 -2
- claude_mpm/services/agents/memory/memory_format_service.py +0 -1
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/async_session_logger.py +1 -1
- claude_mpm/services/claude_session_logger.py +1 -0
- claude_mpm/services/core/path_resolver.py +1 -0
- claude_mpm/services/diagnostics/checks/__init__.py +2 -0
- claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +451 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
- claude_mpm/services/event_bus/direct_relay.py +2 -1
- claude_mpm/services/event_bus/event_bus.py +1 -0
- claude_mpm/services/event_bus/relay.py +3 -2
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
- claude_mpm/services/infrastructure/daemon_manager.py +1 -1
- claude_mpm/services/mcp_config_manager.py +301 -54
- claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
- claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/project/archive_manager.py +159 -96
- claude_mpm/services/project/documentation_manager.py +64 -45
- claude_mpm/services/project/enhanced_analyzer.py +132 -89
- claude_mpm/services/project/project_organizer.py +225 -131
- claude_mpm/services/response_tracker.py +1 -1
- claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
- claude_mpm/services/unified/__init__.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
- claude_mpm/services/unified/config_strategies/__init__.py +111 -126
- claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
- claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
- claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
- claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
- claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
- claude_mpm/services/unified/deployment_strategies/base.py +24 -28
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
- claude_mpm/services/unified/deployment_strategies/local.py +49 -34
- claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
- claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
- claude_mpm/services/unified/interfaces.py +0 -26
- claude_mpm/services/unified/migration.py +17 -40
- claude_mpm/services/unified/strategies.py +9 -26
- claude_mpm/services/unified/unified_analyzer.py +48 -44
- claude_mpm/services/unified/unified_config.py +21 -19
- claude_mpm/services/unified/unified_deployment.py +21 -26
- claude_mpm/storage/state_storage.py +1 -0
- claude_mpm/utils/agent_dependency_loader.py +18 -6
- claude_mpm/utils/common.py +14 -12
- claude_mpm/utils/database_connector.py +15 -12
- claude_mpm/utils/error_handler.py +1 -0
- claude_mpm/utils/log_cleanup.py +1 -0
- claude_mpm/utils/path_operations.py +1 -0
- claude_mpm/utils/session_logging.py +1 -1
- claude_mpm/utils/subprocess_utils.py +1 -0
- claude_mpm/validation/agent_validator.py +1 -1
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/METADATA +35 -15
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/RECORD +118 -117
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/WHEEL +0 -0
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.5.dist-info}/top_level.txt +0 -0
@@ -3,36 +3,39 @@ Context Strategy - Context-based lifecycle management for configurations
|
|
3
3
|
Part of Phase 3 Configuration Consolidation
|
4
4
|
"""
|
5
5
|
|
6
|
+
import threading
|
7
|
+
import weakref
|
6
8
|
from abc import ABC, abstractmethod
|
7
|
-
from
|
9
|
+
from collections import OrderedDict
|
10
|
+
from contextlib import contextmanager
|
8
11
|
from dataclasses import dataclass, field
|
12
|
+
from datetime import datetime, timedelta
|
9
13
|
from enum import Enum
|
10
14
|
from pathlib import Path
|
11
|
-
import
|
12
|
-
from datetime import datetime, timedelta
|
13
|
-
from contextlib import contextmanager
|
14
|
-
import weakref
|
15
|
-
from collections import OrderedDict
|
15
|
+
from typing import Any, Callable, Dict, List, Optional, Set, Union
|
16
16
|
|
17
17
|
from claude_mpm.core.logging_utils import get_logger
|
18
|
-
|
18
|
+
|
19
|
+
from .unified_config_service import IConfigStrategy
|
19
20
|
|
20
21
|
|
21
22
|
class ContextScope(Enum):
|
22
23
|
"""Configuration context scopes"""
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
24
|
+
|
25
|
+
GLOBAL = "global" # Application-wide
|
26
|
+
SESSION = "session" # User session
|
27
|
+
PROJECT = "project" # Project-specific
|
28
|
+
AGENT = "agent" # Agent-specific
|
29
|
+
SERVICE = "service" # Service-specific
|
30
|
+
TRANSACTION = "transaction" # Transaction-specific
|
31
|
+
REQUEST = "request" # Request-specific
|
32
|
+
THREAD = "thread" # Thread-local
|
33
|
+
TEMPORARY = "temporary" # Temporary context
|
32
34
|
|
33
35
|
|
34
36
|
class ContextLifecycle(Enum):
|
35
37
|
"""Context lifecycle states"""
|
38
|
+
|
36
39
|
CREATED = "created"
|
37
40
|
INITIALIZING = "initializing"
|
38
41
|
ACTIVE = "active"
|
@@ -44,6 +47,7 @@ class ContextLifecycle(Enum):
|
|
44
47
|
@dataclass
|
45
48
|
class ContextMetadata:
|
46
49
|
"""Metadata for context tracking"""
|
50
|
+
|
47
51
|
id: str
|
48
52
|
scope: ContextScope
|
49
53
|
lifecycle: ContextLifecycle
|
@@ -59,6 +63,7 @@ class ContextMetadata:
|
|
59
63
|
@dataclass
|
60
64
|
class ContextConfig:
|
61
65
|
"""Configuration within a context"""
|
66
|
+
|
62
67
|
context_id: str
|
63
68
|
data: Dict[str, Any]
|
64
69
|
overrides: Dict[str, Any] = field(default_factory=dict)
|
@@ -79,17 +84,14 @@ class BaseContextManager(ABC):
|
|
79
84
|
@abstractmethod
|
80
85
|
def create_context(self, scope: ContextScope, **kwargs) -> str:
|
81
86
|
"""Create a new context"""
|
82
|
-
pass
|
83
87
|
|
84
88
|
@abstractmethod
|
85
89
|
def get_context(self, context_id: str) -> Optional[ContextMetadata]:
|
86
90
|
"""Get context metadata"""
|
87
|
-
pass
|
88
91
|
|
89
92
|
@abstractmethod
|
90
93
|
def close_context(self, context_id: str):
|
91
94
|
"""Close a context"""
|
92
|
-
pass
|
93
95
|
|
94
96
|
|
95
97
|
class HierarchicalContextManager(BaseContextManager):
|
@@ -105,7 +107,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
105
107
|
scope: ContextScope,
|
106
108
|
parent_id: Optional[str] = None,
|
107
109
|
ttl: Optional[timedelta] = None,
|
108
|
-
**kwargs
|
110
|
+
**kwargs,
|
109
111
|
) -> str:
|
110
112
|
"""Create a new hierarchical context"""
|
111
113
|
with self._lock:
|
@@ -113,7 +115,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
113
115
|
context_id = self._generate_context_id(scope)
|
114
116
|
|
115
117
|
# Use current context as parent if not specified
|
116
|
-
if parent_id is None and hasattr(self.context_stack,
|
118
|
+
if parent_id is None and hasattr(self.context_stack, "stack"):
|
117
119
|
if self.context_stack.stack:
|
118
120
|
parent_id = self.context_stack.stack[-1]
|
119
121
|
|
@@ -127,7 +129,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
127
129
|
parent_id=parent_id,
|
128
130
|
ttl=ttl,
|
129
131
|
expires_at=datetime.now() + ttl if ttl else None,
|
130
|
-
attributes=kwargs
|
132
|
+
attributes=kwargs,
|
131
133
|
)
|
132
134
|
|
133
135
|
# Store context
|
@@ -142,10 +144,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
142
144
|
self.context_hierarchy[parent_id].append(context_id)
|
143
145
|
|
144
146
|
# Initialize context config
|
145
|
-
self.configs[context_id] = ContextConfig(
|
146
|
-
context_id=context_id,
|
147
|
-
data={}
|
148
|
-
)
|
147
|
+
self.configs[context_id] = ContextConfig(context_id=context_id, data={})
|
149
148
|
|
150
149
|
# Set lifecycle to active
|
151
150
|
metadata.lifecycle = ContextLifecycle.ACTIVE
|
@@ -216,6 +215,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
216
215
|
def _generate_context_id(self, scope: ContextScope) -> str:
|
217
216
|
"""Generate unique context ID"""
|
218
217
|
import uuid
|
218
|
+
|
219
219
|
return f"{scope.value}_{uuid.uuid4().hex[:8]}"
|
220
220
|
|
221
221
|
@contextmanager
|
@@ -224,7 +224,7 @@ class HierarchicalContextManager(BaseContextManager):
|
|
224
224
|
context_id = self.create_context(scope, **kwargs)
|
225
225
|
|
226
226
|
# Push to thread-local stack
|
227
|
-
if not hasattr(self.context_stack,
|
227
|
+
if not hasattr(self.context_stack, "stack"):
|
228
228
|
self.context_stack.stack = []
|
229
229
|
self.context_stack.stack.append(context_id)
|
230
230
|
|
@@ -248,10 +248,7 @@ class ScopedConfigManager:
|
|
248
248
|
self._lock = threading.RLock()
|
249
249
|
|
250
250
|
def get_config(
|
251
|
-
self,
|
252
|
-
context_id: str,
|
253
|
-
key: Optional[str] = None,
|
254
|
-
inherit: bool = True
|
251
|
+
self, context_id: str, key: Optional[str] = None, inherit: bool = True
|
255
252
|
) -> Any:
|
256
253
|
"""Get configuration value from context"""
|
257
254
|
with self._lock:
|
@@ -275,7 +272,7 @@ class ScopedConfigManager:
|
|
275
272
|
key: str,
|
276
273
|
value: Any,
|
277
274
|
override: bool = False,
|
278
|
-
lock: bool = False
|
275
|
+
lock: bool = False,
|
279
276
|
):
|
280
277
|
"""Set configuration value in context"""
|
281
278
|
with self._lock:
|
@@ -330,7 +327,11 @@ class ScopedConfigManager:
|
|
330
327
|
result = base.copy()
|
331
328
|
|
332
329
|
for key, value in override.items():
|
333
|
-
if
|
330
|
+
if (
|
331
|
+
key in result
|
332
|
+
and isinstance(result[key], dict)
|
333
|
+
and isinstance(value, dict)
|
334
|
+
):
|
334
335
|
result[key] = self._deep_merge(result[key], value)
|
335
336
|
else:
|
336
337
|
result[key] = value
|
@@ -339,7 +340,7 @@ class ScopedConfigManager:
|
|
339
340
|
|
340
341
|
def _get_nested_value(self, config: Dict, key: str) -> Any:
|
341
342
|
"""Get nested value using dot notation"""
|
342
|
-
parts = key.split(
|
343
|
+
parts = key.split(".")
|
343
344
|
current = config
|
344
345
|
|
345
346
|
for part in parts:
|
@@ -352,7 +353,7 @@ class ScopedConfigManager:
|
|
352
353
|
|
353
354
|
def _set_nested_value(self, config: Dict, key: str, value: Any):
|
354
355
|
"""Set nested value using dot notation"""
|
355
|
-
parts = key.split(
|
356
|
+
parts = key.split(".")
|
356
357
|
current = config
|
357
358
|
|
358
359
|
for part in parts[:-1]:
|
@@ -377,8 +378,9 @@ class ScopedConfigManager:
|
|
377
378
|
|
378
379
|
# Trigger pattern watchers
|
379
380
|
for pattern, watchers in config.watchers.items():
|
380
|
-
if
|
381
|
+
if "*" in pattern or "?" in pattern:
|
381
382
|
import fnmatch
|
383
|
+
|
382
384
|
if fnmatch.fnmatch(key, pattern):
|
383
385
|
for watcher in watchers:
|
384
386
|
try:
|
@@ -396,11 +398,11 @@ class IsolatedContextManager:
|
|
396
398
|
self._lock = threading.RLock()
|
397
399
|
|
398
400
|
def create_isolated_context(
|
399
|
-
self,
|
400
|
-
base_config: Optional[Dict[str, Any]] = None
|
401
|
+
self, base_config: Optional[Dict[str, Any]] = None
|
401
402
|
) -> str:
|
402
403
|
"""Create an isolated context with no inheritance"""
|
403
404
|
import uuid
|
405
|
+
|
404
406
|
context_id = f"isolated_{uuid.uuid4().hex[:8]}"
|
405
407
|
|
406
408
|
with self._lock:
|
@@ -434,11 +436,13 @@ class ThreadLocalContextManager:
|
|
434
436
|
def __init__(self):
|
435
437
|
self.logger = get_logger(self.__class__.__name__)
|
436
438
|
self.thread_contexts = threading.local()
|
437
|
-
self._global_registry: weakref.WeakValueDictionary =
|
439
|
+
self._global_registry: weakref.WeakValueDictionary = (
|
440
|
+
weakref.WeakValueDictionary()
|
441
|
+
)
|
438
442
|
|
439
443
|
def get_thread_context(self) -> Optional[Dict[str, Any]]:
|
440
444
|
"""Get current thread's context"""
|
441
|
-
if hasattr(self.thread_contexts,
|
445
|
+
if hasattr(self.thread_contexts, "config"):
|
442
446
|
return self.thread_contexts.config
|
443
447
|
return None
|
444
448
|
|
@@ -449,8 +453,8 @@ class ThreadLocalContextManager:
|
|
449
453
|
|
450
454
|
def clear_thread_context(self):
|
451
455
|
"""Clear current thread's context"""
|
452
|
-
if hasattr(self.thread_contexts,
|
453
|
-
delattr(self.thread_contexts,
|
456
|
+
if hasattr(self.thread_contexts, "config"):
|
457
|
+
delattr(self.thread_contexts, "config")
|
454
458
|
|
455
459
|
@contextmanager
|
456
460
|
def thread_context(self, config: Dict[str, Any]):
|
@@ -507,8 +511,7 @@ class CachingContextManager:
|
|
507
511
|
"""Invalidate all cached values for context"""
|
508
512
|
with self._lock:
|
509
513
|
keys_to_remove = [
|
510
|
-
k for k in self.cache.keys()
|
511
|
-
if k.startswith(f"{context_id}:")
|
514
|
+
k for k in self.cache.keys() if k.startswith(f"{context_id}:")
|
512
515
|
]
|
513
516
|
|
514
517
|
for key in keys_to_remove:
|
@@ -519,12 +522,16 @@ class CachingContextManager:
|
|
519
522
|
total_requests = self.hit_count + self.miss_count
|
520
523
|
|
521
524
|
return {
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
525
|
+
"size": len(self.cache),
|
526
|
+
"max_size": self.max_size,
|
527
|
+
"hit_count": self.hit_count,
|
528
|
+
"miss_count": self.miss_count,
|
529
|
+
"hit_rate": (
|
530
|
+
(self.hit_count / total_requests * 100) if total_requests > 0 else 0
|
531
|
+
),
|
532
|
+
"utilization": (
|
533
|
+
(len(self.cache) / self.max_size * 100) if self.max_size > 0 else 0
|
534
|
+
),
|
528
535
|
}
|
529
536
|
|
530
537
|
|
@@ -548,14 +555,13 @@ class ContextStrategy(IConfigStrategy):
|
|
548
555
|
|
549
556
|
def load(self, source: Any, **kwargs) -> Dict[str, Any]:
|
550
557
|
"""Load configuration into context"""
|
551
|
-
context_scope = kwargs.get(
|
552
|
-
context_id = kwargs.get(
|
558
|
+
context_scope = kwargs.get("context_scope", ContextScope.TEMPORARY)
|
559
|
+
context_id = kwargs.get("context_id")
|
553
560
|
|
554
561
|
if not context_id:
|
555
562
|
# Create new context
|
556
563
|
context_id = self.hierarchy_manager.create_context(
|
557
|
-
context_scope,
|
558
|
-
ttl=kwargs.get('ttl')
|
564
|
+
context_scope, ttl=kwargs.get("ttl")
|
559
565
|
)
|
560
566
|
|
561
567
|
# Load config into context
|
@@ -577,9 +583,7 @@ class ContextStrategy(IConfigStrategy):
|
|
577
583
|
if context:
|
578
584
|
# Apply context-specific overrides
|
579
585
|
overrides = self.scoped_manager.get_config(
|
580
|
-
context,
|
581
|
-
'transformations.overrides',
|
582
|
-
inherit=True
|
586
|
+
context, "transformations.overrides", inherit=True
|
583
587
|
)
|
584
588
|
|
585
589
|
if overrides:
|
@@ -592,31 +596,31 @@ class ContextStrategy(IConfigStrategy):
|
|
592
596
|
scope: ContextScope = ContextScope.TEMPORARY,
|
593
597
|
parent: Optional[str] = None,
|
594
598
|
isolated: bool = False,
|
595
|
-
**kwargs
|
599
|
+
**kwargs,
|
596
600
|
) -> str:
|
597
601
|
"""Create a new configuration context"""
|
598
602
|
if isolated:
|
599
603
|
return self.isolated_manager.create_isolated_context(
|
600
|
-
kwargs.get(
|
601
|
-
)
|
602
|
-
else:
|
603
|
-
return self.hierarchy_manager.create_context(
|
604
|
-
scope,
|
605
|
-
parent_id=parent,
|
606
|
-
**kwargs
|
604
|
+
kwargs.get("base_config")
|
607
605
|
)
|
606
|
+
return self.hierarchy_manager.create_context(
|
607
|
+
scope, parent_id=parent, **kwargs
|
608
|
+
)
|
608
609
|
|
609
610
|
def get_current_context(self) -> Optional[str]:
|
610
611
|
"""Get current active context"""
|
611
612
|
# Check thread-local stack
|
612
|
-
if hasattr(self.hierarchy_manager.context_stack,
|
613
|
+
if hasattr(self.hierarchy_manager.context_stack, "stack"):
|
613
614
|
stack = self.hierarchy_manager.context_stack.stack
|
614
615
|
if stack:
|
615
616
|
return stack[-1]
|
616
617
|
|
617
618
|
# Check for global context
|
618
619
|
for ctx_id, metadata in self.hierarchy_manager.contexts.items():
|
619
|
-
if
|
620
|
+
if (
|
621
|
+
metadata.scope == ContextScope.GLOBAL
|
622
|
+
and metadata.lifecycle == ContextLifecycle.ACTIVE
|
623
|
+
):
|
620
624
|
return ctx_id
|
621
625
|
|
622
626
|
return None
|
@@ -624,7 +628,7 @@ class ContextStrategy(IConfigStrategy):
|
|
624
628
|
def with_context(self, context_id: str, operation: Callable) -> Any:
|
625
629
|
"""Execute operation within specified context"""
|
626
630
|
# Push context
|
627
|
-
if not hasattr(self.hierarchy_manager.context_stack,
|
631
|
+
if not hasattr(self.hierarchy_manager.context_stack, "stack"):
|
628
632
|
self.hierarchy_manager.context_stack.stack = []
|
629
633
|
|
630
634
|
self.hierarchy_manager.context_stack.stack.append(context_id)
|
@@ -646,7 +650,7 @@ class ContextStrategy(IConfigStrategy):
|
|
646
650
|
self,
|
647
651
|
key: Optional[str] = None,
|
648
652
|
context: Optional[str] = None,
|
649
|
-
default: Any = None
|
653
|
+
default: Any = None,
|
650
654
|
) -> Any:
|
651
655
|
"""Get configuration value from context"""
|
652
656
|
context_id = context or self.get_current_context()
|
@@ -669,13 +673,7 @@ class ContextStrategy(IConfigStrategy):
|
|
669
673
|
|
670
674
|
return value if value is not None else default
|
671
675
|
|
672
|
-
def set_config(
|
673
|
-
self,
|
674
|
-
key: str,
|
675
|
-
value: Any,
|
676
|
-
context: Optional[str] = None,
|
677
|
-
**kwargs
|
678
|
-
):
|
676
|
+
def set_config(self, key: str, value: Any, context: Optional[str] = None, **kwargs):
|
679
677
|
"""Set configuration value in context"""
|
680
678
|
context_id = context or self.get_current_context()
|
681
679
|
|
@@ -694,7 +692,7 @@ class ContextStrategy(IConfigStrategy):
|
|
694
692
|
self.cache_manager.invalidate_context(context_id)
|
695
693
|
|
696
694
|
# Close context
|
697
|
-
if context_id.startswith(
|
695
|
+
if context_id.startswith("isolated_"):
|
698
696
|
self.isolated_manager.close_isolated_context(context_id)
|
699
697
|
else:
|
700
698
|
self.hierarchy_manager.close_context(context_id)
|
@@ -704,7 +702,11 @@ class ContextStrategy(IConfigStrategy):
|
|
704
702
|
result = config.copy()
|
705
703
|
|
706
704
|
for key, value in overrides.items():
|
707
|
-
if
|
705
|
+
if (
|
706
|
+
key in result
|
707
|
+
and isinstance(result[key], dict)
|
708
|
+
and isinstance(value, dict)
|
709
|
+
):
|
708
710
|
result[key] = self._apply_overrides(result[key], value)
|
709
711
|
else:
|
710
712
|
result[key] = value
|
@@ -714,11 +716,11 @@ class ContextStrategy(IConfigStrategy):
|
|
714
716
|
def get_statistics(self) -> Dict[str, Any]:
|
715
717
|
"""Get context strategy statistics"""
|
716
718
|
return {
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
719
|
+
"active_contexts": len(self.hierarchy_manager.contexts),
|
720
|
+
"isolated_contexts": len(self.isolated_manager.isolated_contexts),
|
721
|
+
"cache_stats": self.cache_manager.get_statistics(),
|
722
|
+
"contexts_by_scope": self._count_by_scope(),
|
723
|
+
"contexts_by_lifecycle": self._count_by_lifecycle(),
|
722
724
|
}
|
723
725
|
|
724
726
|
def _count_by_scope(self) -> Dict[str, int]:
|
@@ -740,9 +742,9 @@ class ContextStrategy(IConfigStrategy):
|
|
740
742
|
|
741
743
|
# Export main components
|
742
744
|
__all__ = [
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
]
|
745
|
+
"ContextLifecycle",
|
746
|
+
"ContextScope",
|
747
|
+
"ContextStrategy",
|
748
|
+
"HierarchicalContextManager",
|
749
|
+
"ScopedConfigManager",
|
750
|
+
]
|