claude-mpm 4.4.3__py3-none-any.whl → 4.4.4__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 (118) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/agent_loader.py +3 -2
  3. claude_mpm/agents/agent_loader_integration.py +2 -1
  4. claude_mpm/agents/async_agent_loader.py +2 -2
  5. claude_mpm/agents/base_agent_loader.py +2 -2
  6. claude_mpm/agents/frontmatter_validator.py +1 -0
  7. claude_mpm/agents/system_agent_config.py +2 -1
  8. claude_mpm/cli/commands/doctor.py +44 -5
  9. claude_mpm/cli/commands/mpm_init.py +116 -62
  10. claude_mpm/cli/parsers/configure_parser.py +3 -1
  11. claude_mpm/cli/startup_logging.py +1 -3
  12. claude_mpm/config/agent_config.py +1 -1
  13. claude_mpm/config/paths.py +2 -1
  14. claude_mpm/core/agent_name_normalizer.py +1 -0
  15. claude_mpm/core/config.py +2 -1
  16. claude_mpm/core/config_aliases.py +2 -1
  17. claude_mpm/core/file_utils.py +0 -1
  18. claude_mpm/core/framework/__init__.py +6 -6
  19. claude_mpm/core/framework/formatters/__init__.py +2 -2
  20. claude_mpm/core/framework/formatters/capability_generator.py +19 -8
  21. claude_mpm/core/framework/formatters/content_formatter.py +8 -3
  22. claude_mpm/core/framework/formatters/context_generator.py +7 -3
  23. claude_mpm/core/framework/loaders/__init__.py +3 -3
  24. claude_mpm/core/framework/loaders/agent_loader.py +7 -3
  25. claude_mpm/core/framework/loaders/file_loader.py +16 -6
  26. claude_mpm/core/framework/loaders/instruction_loader.py +16 -6
  27. claude_mpm/core/framework/loaders/packaged_loader.py +36 -12
  28. claude_mpm/core/framework/processors/__init__.py +2 -2
  29. claude_mpm/core/framework/processors/memory_processor.py +14 -6
  30. claude_mpm/core/framework/processors/metadata_processor.py +5 -5
  31. claude_mpm/core/framework/processors/template_processor.py +12 -6
  32. claude_mpm/core/framework_loader.py +44 -20
  33. claude_mpm/core/log_manager.py +2 -1
  34. claude_mpm/core/tool_access_control.py +1 -0
  35. claude_mpm/core/unified_agent_registry.py +2 -1
  36. claude_mpm/core/unified_paths.py +1 -0
  37. claude_mpm/experimental/cli_enhancements.py +1 -0
  38. claude_mpm/hooks/base_hook.py +1 -0
  39. claude_mpm/hooks/instruction_reinforcement.py +1 -0
  40. claude_mpm/hooks/kuzu_memory_hook.py +20 -13
  41. claude_mpm/hooks/validation_hooks.py +1 -1
  42. claude_mpm/scripts/mpm_doctor.py +1 -0
  43. claude_mpm/services/agents/loading/agent_profile_loader.py +1 -1
  44. claude_mpm/services/agents/loading/base_agent_manager.py +1 -1
  45. claude_mpm/services/agents/loading/framework_agent_loader.py +1 -1
  46. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -0
  47. claude_mpm/services/agents/management/agent_management_service.py +1 -1
  48. claude_mpm/services/agents/memory/memory_categorization_service.py +0 -1
  49. claude_mpm/services/agents/memory/memory_file_service.py +6 -2
  50. claude_mpm/services/agents/memory/memory_format_service.py +0 -1
  51. claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
  52. claude_mpm/services/async_session_logger.py +1 -1
  53. claude_mpm/services/claude_session_logger.py +1 -0
  54. claude_mpm/services/core/path_resolver.py +1 -0
  55. claude_mpm/services/diagnostics/checks/__init__.py +2 -0
  56. claude_mpm/services/diagnostics/checks/installation_check.py +126 -25
  57. claude_mpm/services/diagnostics/checks/mcp_services_check.py +399 -0
  58. claude_mpm/services/diagnostics/diagnostic_runner.py +3 -0
  59. claude_mpm/services/diagnostics/doctor_reporter.py +259 -32
  60. claude_mpm/services/event_bus/direct_relay.py +2 -1
  61. claude_mpm/services/event_bus/event_bus.py +1 -0
  62. claude_mpm/services/event_bus/relay.py +3 -2
  63. claude_mpm/services/framework_claude_md_generator/content_assembler.py +1 -1
  64. claude_mpm/services/infrastructure/daemon_manager.py +1 -1
  65. claude_mpm/services/mcp_config_manager.py +10 -10
  66. claude_mpm/services/mcp_gateway/core/process_pool.py +62 -23
  67. claude_mpm/services/mcp_gateway/tools/__init__.py +6 -5
  68. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +3 -1
  69. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +16 -31
  70. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  71. claude_mpm/services/project/archive_manager.py +159 -96
  72. claude_mpm/services/project/documentation_manager.py +64 -45
  73. claude_mpm/services/project/enhanced_analyzer.py +132 -89
  74. claude_mpm/services/project/project_organizer.py +225 -131
  75. claude_mpm/services/response_tracker.py +1 -1
  76. claude_mpm/services/socketio/server/eventbus_integration.py +1 -1
  77. claude_mpm/services/unified/__init__.py +1 -1
  78. claude_mpm/services/unified/analyzer_strategies/__init__.py +3 -3
  79. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +97 -53
  80. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +81 -40
  81. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +277 -178
  82. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +196 -112
  83. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +83 -49
  84. claude_mpm/services/unified/config_strategies/__init__.py +111 -126
  85. claude_mpm/services/unified/config_strategies/config_schema.py +157 -111
  86. claude_mpm/services/unified/config_strategies/context_strategy.py +91 -89
  87. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +183 -173
  88. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +160 -152
  89. claude_mpm/services/unified/config_strategies/unified_config_service.py +124 -112
  90. claude_mpm/services/unified/config_strategies/validation_strategy.py +298 -259
  91. claude_mpm/services/unified/deployment_strategies/__init__.py +7 -7
  92. claude_mpm/services/unified/deployment_strategies/base.py +24 -28
  93. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +168 -88
  94. claude_mpm/services/unified/deployment_strategies/local.py +49 -34
  95. claude_mpm/services/unified/deployment_strategies/utils.py +39 -43
  96. claude_mpm/services/unified/deployment_strategies/vercel.py +30 -24
  97. claude_mpm/services/unified/interfaces.py +0 -26
  98. claude_mpm/services/unified/migration.py +17 -40
  99. claude_mpm/services/unified/strategies.py +9 -26
  100. claude_mpm/services/unified/unified_analyzer.py +48 -44
  101. claude_mpm/services/unified/unified_config.py +21 -19
  102. claude_mpm/services/unified/unified_deployment.py +21 -26
  103. claude_mpm/storage/state_storage.py +1 -0
  104. claude_mpm/utils/agent_dependency_loader.py +18 -6
  105. claude_mpm/utils/common.py +14 -12
  106. claude_mpm/utils/database_connector.py +15 -12
  107. claude_mpm/utils/error_handler.py +1 -0
  108. claude_mpm/utils/log_cleanup.py +1 -0
  109. claude_mpm/utils/path_operations.py +1 -0
  110. claude_mpm/utils/session_logging.py +1 -1
  111. claude_mpm/utils/subprocess_utils.py +1 -0
  112. claude_mpm/validation/agent_validator.py +1 -1
  113. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/METADATA +9 -3
  114. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/RECORD +118 -117
  115. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/WHEEL +0 -0
  116. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/entry_points.txt +0 -0
  117. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/licenses/LICENSE +0 -0
  118. {claude_mpm-4.4.3.dist-info → claude_mpm-4.4.4.dist-info}/top_level.txt +0 -0
@@ -3,20 +3,20 @@ Configuration Schema - Declarative configuration with automatic validation
3
3
  Part of Phase 3 Configuration Consolidation
4
4
  """
5
5
 
6
- from typing import Any, Dict, List, Optional, Union, Type, Callable, Generic, TypeVar
7
- from dataclasses import dataclass, field, asdict
8
- from enum import Enum
9
- from datetime import datetime
10
6
  import json
11
- from pathlib import Path
7
+ from dataclasses import dataclass, field
8
+ from datetime import datetime
9
+ from enum import Enum
10
+ from typing import Any, Callable, Dict, Generic, List, Optional, TypeVar, Union
12
11
 
13
12
  from claude_mpm.core.logging_utils import get_logger
14
13
 
15
- T = TypeVar('T')
14
+ T = TypeVar("T")
16
15
 
17
16
 
18
17
  class SchemaType(Enum):
19
18
  """Supported schema types"""
19
+
20
20
  STRING = "string"
21
21
  INTEGER = "integer"
22
22
  NUMBER = "number"
@@ -29,6 +29,7 @@ class SchemaType(Enum):
29
29
 
30
30
  class SchemaFormat(Enum):
31
31
  """Supported format constraints"""
32
+
32
33
  DATE = "date"
33
34
  DATETIME = "datetime"
34
35
  TIME = "time"
@@ -48,6 +49,7 @@ class SchemaFormat(Enum):
48
49
  @dataclass
49
50
  class SchemaProperty:
50
51
  """Schema property definition"""
52
+
51
53
  type: Union[SchemaType, List[SchemaType]]
52
54
  description: Optional[str] = None
53
55
  default: Any = None
@@ -72,19 +74,19 @@ class SchemaProperty:
72
74
  min_items: Optional[int] = None
73
75
  max_items: Optional[int] = None
74
76
  unique_items: bool = False
75
- items: Optional['SchemaProperty'] = None
77
+ items: Optional["SchemaProperty"] = None
76
78
 
77
79
  # Object constraints
78
- properties: Optional[Dict[str, 'SchemaProperty']] = None
79
- additional_properties: Union[bool, 'SchemaProperty'] = True
80
+ properties: Optional[Dict[str, "SchemaProperty"]] = None
81
+ additional_properties: Union[bool, "SchemaProperty"] = True
80
82
  required_properties: Optional[List[str]] = None
81
83
 
82
84
  # Advanced
83
- dependencies: Optional[Dict[str, Union[List[str], 'SchemaProperty']]] = None
84
- one_of: Optional[List['SchemaProperty']] = None
85
- any_of: Optional[List['SchemaProperty']] = None
86
- all_of: Optional[List['SchemaProperty']] = None
87
- not_schema: Optional['SchemaProperty'] = None
85
+ dependencies: Optional[Dict[str, Union[List[str], "SchemaProperty"]]] = None
86
+ one_of: Optional[List["SchemaProperty"]] = None
87
+ any_of: Optional[List["SchemaProperty"]] = None
88
+ all_of: Optional[List["SchemaProperty"]] = None
89
+ not_schema: Optional["SchemaProperty"] = None
88
90
 
89
91
  # Custom validation
90
92
  validator: Optional[Callable[[Any], bool]] = None
@@ -100,6 +102,7 @@ class SchemaProperty:
100
102
  @dataclass
101
103
  class ConfigSchema:
102
104
  """Complete configuration schema"""
105
+
103
106
  title: str
104
107
  description: Optional[str] = None
105
108
  version: str = "1.0.0"
@@ -119,15 +122,15 @@ class ConfigSchema:
119
122
  pattern_properties: Optional[Dict[str, SchemaProperty]] = None
120
123
 
121
124
  # Conditional schemas
122
- if_schema: Optional['ConfigSchema'] = None
123
- then_schema: Optional['ConfigSchema'] = None
124
- else_schema: Optional['ConfigSchema'] = None
125
+ if_schema: Optional["ConfigSchema"] = None
126
+ then_schema: Optional["ConfigSchema"] = None
127
+ else_schema: Optional["ConfigSchema"] = None
125
128
 
126
129
  # Composition
127
- all_of: Optional[List['ConfigSchema']] = None
128
- any_of: Optional[List['ConfigSchema']] = None
129
- one_of: Optional[List['ConfigSchema']] = None
130
- not_schema: Optional['ConfigSchema'] = None
130
+ all_of: Optional[List["ConfigSchema"]] = None
131
+ any_of: Optional[List["ConfigSchema"]] = None
132
+ one_of: Optional[List["ConfigSchema"]] = None
133
+ not_schema: Optional["ConfigSchema"] = None
131
134
 
132
135
  # Custom handlers
133
136
  pre_validators: List[Callable] = field(default_factory=list)
@@ -142,22 +145,19 @@ class SchemaBuilder:
142
145
  self.schema = ConfigSchema(title=title)
143
146
  self.logger = get_logger(self.__class__.__name__)
144
147
 
145
- def description(self, desc: str) -> 'SchemaBuilder':
148
+ def description(self, desc: str) -> "SchemaBuilder":
146
149
  """Set schema description"""
147
150
  self.schema.description = desc
148
151
  return self
149
152
 
150
- def version(self, ver: str) -> 'SchemaBuilder':
153
+ def version(self, ver: str) -> "SchemaBuilder":
151
154
  """Set schema version"""
152
155
  self.schema.version = ver
153
156
  return self
154
157
 
155
158
  def property(
156
- self,
157
- name: str,
158
- type: Union[SchemaType, str],
159
- **kwargs
160
- ) -> 'SchemaBuilder':
159
+ self, name: str, type: Union[SchemaType, str], **kwargs
160
+ ) -> "SchemaBuilder":
161
161
  """Add a property to the schema"""
162
162
  if isinstance(type, str):
163
163
  type = SchemaType(type)
@@ -165,55 +165,64 @@ class SchemaBuilder:
165
165
  prop = SchemaProperty(type=type, **kwargs)
166
166
  self.schema.properties[name] = prop
167
167
 
168
- if kwargs.get('required', False):
168
+ if kwargs.get("required", False):
169
169
  if name not in self.schema.required:
170
170
  self.schema.required.append(name)
171
171
 
172
172
  return self
173
173
 
174
- def string(self, name: str, **kwargs) -> 'SchemaBuilder':
174
+ def string(self, name: str, **kwargs) -> "SchemaBuilder":
175
175
  """Add string property"""
176
176
  return self.property(name, SchemaType.STRING, **kwargs)
177
177
 
178
- def integer(self, name: str, **kwargs) -> 'SchemaBuilder':
178
+ def integer(self, name: str, **kwargs) -> "SchemaBuilder":
179
179
  """Add integer property"""
180
180
  return self.property(name, SchemaType.INTEGER, **kwargs)
181
181
 
182
- def number(self, name: str, **kwargs) -> 'SchemaBuilder':
182
+ def number(self, name: str, **kwargs) -> "SchemaBuilder":
183
183
  """Add number property"""
184
184
  return self.property(name, SchemaType.NUMBER, **kwargs)
185
185
 
186
- def boolean(self, name: str, **kwargs) -> 'SchemaBuilder':
186
+ def boolean(self, name: str, **kwargs) -> "SchemaBuilder":
187
187
  """Add boolean property"""
188
188
  return self.property(name, SchemaType.BOOLEAN, **kwargs)
189
189
 
190
- def array(self, name: str, items: Optional[SchemaProperty] = None, **kwargs) -> 'SchemaBuilder':
190
+ def array(
191
+ self, name: str, items: Optional[SchemaProperty] = None, **kwargs
192
+ ) -> "SchemaBuilder":
191
193
  """Add array property"""
192
194
  return self.property(name, SchemaType.ARRAY, items=items, **kwargs)
193
195
 
194
- def object(self, name: str, properties: Optional[Dict[str, SchemaProperty]] = None, **kwargs) -> 'SchemaBuilder':
196
+ def object(
197
+ self,
198
+ name: str,
199
+ properties: Optional[Dict[str, SchemaProperty]] = None,
200
+ **kwargs,
201
+ ) -> "SchemaBuilder":
195
202
  """Add object property"""
196
203
  return self.property(name, SchemaType.OBJECT, properties=properties, **kwargs)
197
204
 
198
- def enum(self, name: str, values: List[Any], **kwargs) -> 'SchemaBuilder':
205
+ def enum(self, name: str, values: List[Any], **kwargs) -> "SchemaBuilder":
199
206
  """Add enum property"""
200
207
  return self.property(name, SchemaType.STRING, enum=values, **kwargs)
201
208
 
202
- def required_fields(self, *fields: str) -> 'SchemaBuilder':
209
+ def required_fields(self, *fields: str) -> "SchemaBuilder":
203
210
  """Mark fields as required"""
204
211
  for field in fields:
205
212
  if field not in self.schema.required:
206
213
  self.schema.required.append(field)
207
214
  return self
208
215
 
209
- def default(self, name: str, value: Any) -> 'SchemaBuilder':
216
+ def default(self, name: str, value: Any) -> "SchemaBuilder":
210
217
  """Set default value for property"""
211
218
  if name in self.schema.properties:
212
219
  self.schema.properties[name].default = value
213
220
  self.schema.defaults[name] = value
214
221
  return self
215
222
 
216
- def dependency(self, field: str, depends_on: Union[str, List[str]]) -> 'SchemaBuilder':
223
+ def dependency(
224
+ self, field: str, depends_on: Union[str, List[str]]
225
+ ) -> "SchemaBuilder":
217
226
  """Add field dependency"""
218
227
  if self.schema.dependencies is None:
219
228
  self.schema.dependencies = {}
@@ -224,12 +233,12 @@ class SchemaBuilder:
224
233
  self.schema.dependencies[field] = depends_on
225
234
  return self
226
235
 
227
- def validator(self, func: Callable) -> 'SchemaBuilder':
236
+ def validator(self, func: Callable) -> "SchemaBuilder":
228
237
  """Add custom validator"""
229
238
  self.schema.post_validators.append(func)
230
239
  return self
231
240
 
232
- def transformer(self, func: Callable) -> 'SchemaBuilder':
241
+ def transformer(self, func: Callable) -> "SchemaBuilder":
233
242
  """Add transformer function"""
234
243
  self.schema.transformers.append(func)
235
244
  return self
@@ -319,7 +328,9 @@ class SchemaValidator:
319
328
  if prop.validator and not prop.validator(value):
320
329
  self.errors.append(f"{path}: custom validation failed")
321
330
 
322
- def _check_type(self, value: Any, expected: Union[SchemaType, List[SchemaType]]) -> bool:
331
+ def _check_type(
332
+ self, value: Any, expected: Union[SchemaType, List[SchemaType]]
333
+ ) -> bool:
323
334
  """Check if value matches expected type"""
324
335
  if isinstance(expected, list):
325
336
  return any(self._check_type(value, t) for t in expected)
@@ -332,13 +343,15 @@ class SchemaValidator:
332
343
  SchemaType.ARRAY: list,
333
344
  SchemaType.OBJECT: dict,
334
345
  SchemaType.NULL: type(None),
335
- SchemaType.ANY: object
346
+ SchemaType.ANY: object,
336
347
  }
337
348
 
338
349
  expected_type = type_map.get(expected, object)
339
350
  return isinstance(value, expected_type)
340
351
 
341
- def _validate_numeric(self, value: Union[int, float], prop: SchemaProperty, path: str):
352
+ def _validate_numeric(
353
+ self, value: Union[int, float], prop: SchemaProperty, path: str
354
+ ):
342
355
  """Validate numeric constraints"""
343
356
  if prop.minimum is not None and value < prop.minimum:
344
357
  self.errors.append(f"{path}: value {value} is below minimum {prop.minimum}")
@@ -347,21 +360,30 @@ class SchemaValidator:
347
360
  self.errors.append(f"{path}: value {value} exceeds maximum {prop.maximum}")
348
361
 
349
362
  if prop.exclusive_minimum is not None and value <= prop.exclusive_minimum:
350
- self.errors.append(f"{path}: value {value} must be greater than {prop.exclusive_minimum}")
363
+ self.errors.append(
364
+ f"{path}: value {value} must be greater than {prop.exclusive_minimum}"
365
+ )
351
366
 
352
367
  if prop.exclusive_maximum is not None and value >= prop.exclusive_maximum:
353
- self.errors.append(f"{path}: value {value} must be less than {prop.exclusive_maximum}")
368
+ self.errors.append(
369
+ f"{path}: value {value} must be less than {prop.exclusive_maximum}"
370
+ )
354
371
 
355
372
  def _validate_string(self, value: str, prop: SchemaProperty, path: str):
356
373
  """Validate string constraints"""
357
374
  if prop.min_length is not None and len(value) < prop.min_length:
358
- self.errors.append(f"{path}: length {len(value)} is below minimum {prop.min_length}")
375
+ self.errors.append(
376
+ f"{path}: length {len(value)} is below minimum {prop.min_length}"
377
+ )
359
378
 
360
379
  if prop.max_length is not None and len(value) > prop.max_length:
361
- self.errors.append(f"{path}: length {len(value)} exceeds maximum {prop.max_length}")
380
+ self.errors.append(
381
+ f"{path}: length {len(value)} exceeds maximum {prop.max_length}"
382
+ )
362
383
 
363
384
  if prop.pattern:
364
385
  import re
386
+
365
387
  if not re.match(prop.pattern, value):
366
388
  self.errors.append(f"{path}: does not match pattern {prop.pattern}")
367
389
 
@@ -372,15 +394,23 @@ class SchemaValidator:
372
394
  def _validate_array(self, value: List, prop: SchemaProperty, path: str):
373
395
  """Validate array constraints"""
374
396
  if prop.min_items is not None and len(value) < prop.min_items:
375
- self.errors.append(f"{path}: array length {len(value)} is below minimum {prop.min_items}")
397
+ self.errors.append(
398
+ f"{path}: array length {len(value)} is below minimum {prop.min_items}"
399
+ )
376
400
 
377
401
  if prop.max_items is not None and len(value) > prop.max_items:
378
- self.errors.append(f"{path}: array length {len(value)} exceeds maximum {prop.max_items}")
402
+ self.errors.append(
403
+ f"{path}: array length {len(value)} exceeds maximum {prop.max_items}"
404
+ )
379
405
 
380
406
  if prop.unique_items:
381
407
  seen = set()
382
408
  for item in value:
383
- item_key = str(item) if not isinstance(item, (dict, list)) else json.dumps(item, sort_keys=True)
409
+ item_key = (
410
+ str(item)
411
+ if not isinstance(item, (dict, list))
412
+ else json.dumps(item, sort_keys=True)
413
+ )
384
414
  if item_key in seen:
385
415
  self.errors.append(f"{path}: duplicate items not allowed")
386
416
  break
@@ -406,7 +436,9 @@ class SchemaValidator:
406
436
  if prop.properties:
407
437
  extra = set(value.keys()) - set(prop.properties.keys())
408
438
  if extra:
409
- self.errors.append(f"{path}: additional properties not allowed: {extra}")
439
+ self.errors.append(
440
+ f"{path}: additional properties not allowed: {extra}"
441
+ )
410
442
 
411
443
  def _validate_dependencies(self, config: Dict, dependencies: Dict):
412
444
  """Validate field dependencies"""
@@ -415,20 +447,24 @@ class SchemaValidator:
415
447
  if isinstance(deps, list):
416
448
  for dep in deps:
417
449
  if dep not in config:
418
- self.errors.append(f"Field '{field}' requires '{dep}' to be present")
450
+ self.errors.append(
451
+ f"Field '{field}' requires '{dep}' to be present"
452
+ )
419
453
 
420
454
  def _validate_format(self, value: str, format: SchemaFormat) -> bool:
421
455
  """Validate string format"""
422
456
  validators = {
423
- SchemaFormat.EMAIL: lambda v: '@' in v and '.' in v.split('@')[1],
424
- SchemaFormat.DATE: lambda v: self._try_parse_date(v, '%Y-%m-%d'),
425
- SchemaFormat.DATETIME: lambda v: self._try_parse_date(v, '%Y-%m-%dT%H:%M:%S'),
457
+ SchemaFormat.EMAIL: lambda v: "@" in v and "." in v.split("@")[1],
458
+ SchemaFormat.DATE: lambda v: self._try_parse_date(v, "%Y-%m-%d"),
459
+ SchemaFormat.DATETIME: lambda v: self._try_parse_date(
460
+ v, "%Y-%m-%dT%H:%M:%S"
461
+ ),
426
462
  SchemaFormat.UUID: lambda v: self._validate_uuid(v),
427
463
  SchemaFormat.IPV4: lambda v: self._validate_ipv4(v),
428
464
  SchemaFormat.IPV6: lambda v: self._validate_ipv6(v),
429
- SchemaFormat.URI: lambda v: '://' in v,
465
+ SchemaFormat.URI: lambda v: "://" in v,
430
466
  SchemaFormat.PATH: lambda v: True, # Any string is valid path
431
- SchemaFormat.SEMVER: lambda v: self._validate_semver(v)
467
+ SchemaFormat.SEMVER: lambda v: self._validate_semver(v),
432
468
  }
433
469
 
434
470
  validator = validators.get(format)
@@ -445,6 +481,7 @@ class SchemaValidator:
445
481
  def _validate_uuid(self, value: str) -> bool:
446
482
  """Validate UUID format"""
447
483
  import uuid
484
+
448
485
  try:
449
486
  uuid.UUID(value)
450
487
  return True
@@ -454,6 +491,7 @@ class SchemaValidator:
454
491
  def _validate_ipv4(self, value: str) -> bool:
455
492
  """Validate IPv4 address"""
456
493
  import ipaddress
494
+
457
495
  try:
458
496
  ipaddress.IPv4Address(value)
459
497
  return True
@@ -463,6 +501,7 @@ class SchemaValidator:
463
501
  def _validate_ipv6(self, value: str) -> bool:
464
502
  """Validate IPv6 address"""
465
503
  import ipaddress
504
+
466
505
  try:
467
506
  ipaddress.IPv6Address(value)
468
507
  return True
@@ -472,7 +511,8 @@ class SchemaValidator:
472
511
  def _validate_semver(self, value: str) -> bool:
473
512
  """Validate semantic version"""
474
513
  import re
475
- pattern = r'^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$'
514
+
515
+ pattern = r"^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
476
516
  return bool(re.match(pattern, value))
477
517
 
478
518
 
@@ -521,10 +561,7 @@ class ConfigMigration:
521
561
  self.migrations: Dict[tuple, Callable] = {}
522
562
 
523
563
  def register_migration(
524
- self,
525
- from_version: str,
526
- to_version: str,
527
- migration_func: Callable[[Dict], Dict]
564
+ self, from_version: str, to_version: str, migration_func: Callable[[Dict], Dict]
528
565
  ):
529
566
  """Register a migration function"""
530
567
  key = (from_version, to_version)
@@ -532,10 +569,7 @@ class ConfigMigration:
532
569
  self.logger.info(f"Registered migration: {from_version} -> {to_version}")
533
570
 
534
571
  def migrate(
535
- self,
536
- config: Dict[str, Any],
537
- from_version: str,
538
- to_version: str
572
+ self, config: Dict[str, Any], from_version: str, to_version: str
539
573
  ) -> Dict[str, Any]:
540
574
  """Migrate configuration between versions"""
541
575
  key = (from_version, to_version)
@@ -560,13 +594,15 @@ class ConfigMigration:
560
594
 
561
595
  return current
562
596
 
563
- def _find_migration_path(self, from_version: str, to_version: str) -> Optional[List[str]]:
597
+ def _find_migration_path(
598
+ self, from_version: str, to_version: str
599
+ ) -> Optional[List[str]]:
564
600
  """Find migration path between versions using BFS"""
565
601
  from collections import deque
566
602
 
567
603
  # Build graph of migrations
568
604
  graph = {}
569
- for (from_v, to_v) in self.migrations.keys():
605
+ for from_v, to_v in self.migrations.keys():
570
606
  if from_v not in graph:
571
607
  graph[from_v] = []
572
608
  graph[from_v].append(to_v)
@@ -633,57 +669,67 @@ class TypedConfig(Generic[T]):
633
669
  # Predefined common schemas
634
670
  def create_database_schema() -> ConfigSchema:
635
671
  """Create common database configuration schema"""
636
- return (SchemaBuilder("Database Configuration")
637
- .string("host", required=True, default="localhost")
638
- .integer("port", required=True, minimum=1, maximum=65535, default=5432)
639
- .string("database", required=True)
640
- .string("username", required=True)
641
- .string("password", write_only=True)
642
- .integer("pool_size", minimum=1, maximum=100, default=10)
643
- .integer("timeout", minimum=1, default=30)
644
- .boolean("ssl", default=False)
645
- .build())
672
+ return (
673
+ SchemaBuilder("Database Configuration")
674
+ .string("host", required=True, default="localhost")
675
+ .integer("port", required=True, minimum=1, maximum=65535, default=5432)
676
+ .string("database", required=True)
677
+ .string("username", required=True)
678
+ .string("password", write_only=True)
679
+ .integer("pool_size", minimum=1, maximum=100, default=10)
680
+ .integer("timeout", minimum=1, default=30)
681
+ .boolean("ssl", default=False)
682
+ .build()
683
+ )
646
684
 
647
685
 
648
686
  def create_api_schema() -> ConfigSchema:
649
687
  """Create common API configuration schema"""
650
- return (SchemaBuilder("API Configuration")
651
- .string("base_url", required=True, format=SchemaFormat.URI)
652
- .string("api_key", required=True, write_only=True)
653
- .integer("timeout", minimum=1, default=30)
654
- .integer("retry_count", minimum=0, maximum=10, default=3)
655
- .number("retry_delay", minimum=0, default=1.0)
656
- .array("allowed_methods", default=["GET", "POST", "PUT", "DELETE"])
657
- .object("headers", default={})
658
- .boolean("verify_ssl", default=True)
659
- .build())
688
+ return (
689
+ SchemaBuilder("API Configuration")
690
+ .string("base_url", required=True, format=SchemaFormat.URI)
691
+ .string("api_key", required=True, write_only=True)
692
+ .integer("timeout", minimum=1, default=30)
693
+ .integer("retry_count", minimum=0, maximum=10, default=3)
694
+ .number("retry_delay", minimum=0, default=1.0)
695
+ .array("allowed_methods", default=["GET", "POST", "PUT", "DELETE"])
696
+ .object("headers", default={})
697
+ .boolean("verify_ssl", default=True)
698
+ .build()
699
+ )
660
700
 
661
701
 
662
702
  def create_logging_schema() -> ConfigSchema:
663
703
  """Create common logging configuration schema"""
664
- return (SchemaBuilder("Logging Configuration")
665
- .enum("level", ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default="INFO")
666
- .string("format", default="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
667
- .string("file", format=SchemaFormat.PATH)
668
- .integer("max_size", minimum=1, default=10485760) # 10MB
669
- .integer("backup_count", minimum=0, default=5)
670
- .boolean("console", default=True)
671
- .boolean("file_enabled", default=False)
672
- .build())
704
+ return (
705
+ SchemaBuilder("Logging Configuration")
706
+ .enum(
707
+ "level", ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], default="INFO"
708
+ )
709
+ .string(
710
+ "format", default="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
711
+ )
712
+ .string("file", format=SchemaFormat.PATH)
713
+ .integer("max_size", minimum=1, default=10485760) # 10MB
714
+ .integer("backup_count", minimum=0, default=5)
715
+ .boolean("console", default=True)
716
+ .boolean("file_enabled", default=False)
717
+ .build()
718
+ )
673
719
 
674
720
 
675
721
  # Export main components
676
722
  __all__ = [
677
- 'ConfigSchema',
678
- 'SchemaProperty',
679
- 'SchemaBuilder',
680
- 'SchemaValidator',
681
- 'SchemaRegistry',
682
- 'ConfigMigration',
683
- 'TypedConfig',
684
- 'SchemaType',
685
- 'SchemaFormat',
686
- 'create_database_schema',
687
- 'create_api_schema',
688
- 'create_logging_schema'
689
- ]
723
+ "ConfigMigration",
724
+ "ConfigSchema",
725
+ "SchemaBuilder",
726
+ "SchemaFormat",
727
+ "SchemaProperty",
728
+ "SchemaRegistry",
729
+ "SchemaType",
730
+ "SchemaValidator",
731
+ "TypedConfig",
732
+ "create_api_schema",
733
+ "create_database_schema",
734
+ "create_logging_schema",
735
+ ]