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
@@ -22,7 +22,6 @@ Features:
|
|
22
22
|
- Version control and rollback capabilities
|
23
23
|
"""
|
24
24
|
|
25
|
-
import asyncio
|
26
25
|
import json
|
27
26
|
from pathlib import Path
|
28
27
|
from typing import Any, Dict, List, Optional, Union
|
@@ -121,7 +120,7 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
121
120
|
return True
|
122
121
|
|
123
122
|
except Exception as e:
|
124
|
-
self._logger.error(f"Failed to initialize: {
|
123
|
+
self._logger.error(f"Failed to initialize: {e!s}")
|
125
124
|
return False
|
126
125
|
|
127
126
|
async def shutdown(self) -> None:
|
@@ -266,16 +265,18 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
266
265
|
success=True,
|
267
266
|
config=config_with_defaults,
|
268
267
|
validation_errors=[],
|
269
|
-
applied_defaults=self._get_applied_defaults(
|
268
|
+
applied_defaults=self._get_applied_defaults(
|
269
|
+
config, config_with_defaults
|
270
|
+
),
|
270
271
|
source=str(source),
|
271
272
|
)
|
272
273
|
|
273
274
|
except Exception as e:
|
274
|
-
self._logger.error(f"Failed to load configuration: {
|
275
|
+
self._logger.error(f"Failed to load configuration: {e!s}")
|
275
276
|
self._metrics["validation_errors"] += 1
|
276
277
|
return ConfigurationResult(
|
277
278
|
success=False,
|
278
|
-
validation_errors=[f"Load failed: {
|
279
|
+
validation_errors=[f"Load failed: {e!s}"],
|
279
280
|
)
|
280
281
|
|
281
282
|
def save_config(
|
@@ -352,10 +353,10 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
352
353
|
)
|
353
354
|
|
354
355
|
except Exception as e:
|
355
|
-
self._logger.error(f"Failed to save configuration: {
|
356
|
+
self._logger.error(f"Failed to save configuration: {e!s}")
|
356
357
|
return ConfigurationResult(
|
357
358
|
success=False,
|
358
|
-
validation_errors=[f"Save failed: {
|
359
|
+
validation_errors=[f"Save failed: {e!s}"],
|
359
360
|
)
|
360
361
|
|
361
362
|
def validate_config(self, config: Dict[str, Any]) -> List[str]:
|
@@ -414,13 +415,12 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
414
415
|
# Implement merge based on strategy
|
415
416
|
if strategy == "deep":
|
416
417
|
return self._deep_merge(*configs)
|
417
|
-
|
418
|
+
if strategy == "shallow":
|
418
419
|
return self._shallow_merge(*configs)
|
419
|
-
|
420
|
+
if strategy == "override":
|
420
421
|
return self._override_merge(*configs)
|
421
|
-
|
422
|
-
|
423
|
-
return self._deep_merge(*configs)
|
422
|
+
self._logger.warning(f"Unknown merge strategy: {strategy}, using deep")
|
423
|
+
return self._deep_merge(*configs)
|
424
424
|
|
425
425
|
def get_config_value(
|
426
426
|
self, key: str, default: Any = None, config: Optional[Dict[str, Any]] = None
|
@@ -595,9 +595,9 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
595
595
|
# Infer from filename
|
596
596
|
if "project" in path.name.lower():
|
597
597
|
return "project"
|
598
|
-
|
598
|
+
if "agent" in path.name.lower():
|
599
599
|
return "agent"
|
600
|
-
|
600
|
+
if "env" in path.name.lower():
|
601
601
|
return "environment"
|
602
602
|
|
603
603
|
return "generic"
|
@@ -639,9 +639,7 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
639
639
|
applied[key] = value
|
640
640
|
return applied
|
641
641
|
|
642
|
-
def _add_to_version_history(
|
643
|
-
self, config_id: str, config: Dict[str, Any]
|
644
|
-
) -> None:
|
642
|
+
def _add_to_version_history(self, config_id: str, config: Dict[str, Any]) -> None:
|
645
643
|
"""Add configuration to version history."""
|
646
644
|
if config_id not in self._config_versions:
|
647
645
|
self._config_versions[config_id] = []
|
@@ -663,7 +661,11 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
663
661
|
|
664
662
|
for config in configs:
|
665
663
|
for key, value in config.items():
|
666
|
-
if
|
664
|
+
if (
|
665
|
+
key in result
|
666
|
+
and isinstance(result[key], dict)
|
667
|
+
and isinstance(value, dict)
|
668
|
+
):
|
667
669
|
result[key] = self._deep_merge(result[key], value)
|
668
670
|
else:
|
669
671
|
result[key] = value
|
@@ -685,4 +687,4 @@ class UnifiedConfigManager(IConfigurationService, IUnifiedService):
|
|
685
687
|
"""Get current timestamp."""
|
686
688
|
from datetime import datetime
|
687
689
|
|
688
|
-
return datetime.now().isoformat()
|
690
|
+
return datetime.now().isoformat()
|
@@ -21,7 +21,6 @@ Features:
|
|
21
21
|
- Metrics and monitoring integration
|
22
22
|
"""
|
23
23
|
|
24
|
-
import asyncio
|
25
24
|
from pathlib import Path
|
26
25
|
from typing import Any, Dict, List, Optional, Union
|
27
26
|
|
@@ -114,7 +113,7 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
114
113
|
return True
|
115
114
|
|
116
115
|
except Exception as e:
|
117
|
-
self._logger.error(f"Failed to initialize: {
|
116
|
+
self._logger.error(f"Failed to initialize: {e!s}")
|
118
117
|
return False
|
119
118
|
|
120
119
|
async def shutdown(self) -> None:
|
@@ -215,7 +214,9 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
215
214
|
strategy = self._registry.select_strategy(DeploymentStrategy, context)
|
216
215
|
|
217
216
|
if not strategy:
|
218
|
-
errors.append(
|
217
|
+
errors.append(
|
218
|
+
f"No strategy available for deployment type: {deployment_type}"
|
219
|
+
)
|
219
220
|
else:
|
220
221
|
# Delegate validation to strategy
|
221
222
|
strategy_errors = strategy.validate_input(config)
|
@@ -314,20 +315,19 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
314
315
|
metadata=result,
|
315
316
|
rollback_info=rollback_info,
|
316
317
|
)
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
)
|
318
|
+
self._metrics["failed_deployments"] += 1
|
319
|
+
return DeploymentResult(
|
320
|
+
success=False,
|
321
|
+
message=result.get("error", "Deployment failed"),
|
322
|
+
metadata=result,
|
323
|
+
)
|
324
324
|
|
325
325
|
except Exception as e:
|
326
|
-
self._logger.error(f"Deployment error: {
|
326
|
+
self._logger.error(f"Deployment error: {e!s}")
|
327
327
|
self._metrics["failed_deployments"] += 1
|
328
328
|
return DeploymentResult(
|
329
329
|
success=False,
|
330
|
-
message=f"Deployment failed: {
|
330
|
+
message=f"Deployment failed: {e!s}",
|
331
331
|
)
|
332
332
|
|
333
333
|
def rollback(
|
@@ -355,9 +355,7 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
355
355
|
try:
|
356
356
|
# Get the strategy used for deployment
|
357
357
|
strategy_name = deployment["strategy"]
|
358
|
-
strategy = self._registry.get_strategy(
|
359
|
-
DeploymentStrategy, strategy_name
|
360
|
-
)
|
358
|
+
strategy = self._registry.get_strategy(DeploymentStrategy, strategy_name)
|
361
359
|
|
362
360
|
if not strategy:
|
363
361
|
return DeploymentResult(
|
@@ -380,17 +378,16 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
380
378
|
success=True,
|
381
379
|
message=f"Successfully rolled back deployment {deployment_id}",
|
382
380
|
)
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
)
|
381
|
+
return DeploymentResult(
|
382
|
+
success=False,
|
383
|
+
message="Rollback failed",
|
384
|
+
)
|
388
385
|
|
389
386
|
except Exception as e:
|
390
|
-
self._logger.error(f"Rollback error: {
|
387
|
+
self._logger.error(f"Rollback error: {e!s}")
|
391
388
|
return DeploymentResult(
|
392
389
|
success=False,
|
393
|
-
message=f"Rollback failed: {
|
390
|
+
message=f"Rollback failed: {e!s}",
|
394
391
|
)
|
395
392
|
|
396
393
|
def list_deployments(
|
@@ -409,9 +406,7 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
409
406
|
|
410
407
|
if target:
|
411
408
|
target_str = str(target)
|
412
|
-
deployments = [
|
413
|
-
d for d in deployments if d["target"] == target_str
|
414
|
-
]
|
409
|
+
deployments = [d for d in deployments if d["target"] == target_str]
|
415
410
|
|
416
411
|
return deployments
|
417
412
|
|
@@ -467,4 +462,4 @@ class UnifiedDeploymentService(IDeploymentService, IUnifiedService):
|
|
467
462
|
"""Get current timestamp."""
|
468
463
|
from datetime import datetime
|
469
464
|
|
470
|
-
return datetime.now().isoformat()
|
465
|
+
return datetime.now().isoformat()
|
@@ -149,7 +149,9 @@ class AgentDependencyLoader:
|
|
149
149
|
|
150
150
|
# Check if this is an optional package that already failed
|
151
151
|
if package_name in self.optional_failed:
|
152
|
-
logger.debug(
|
152
|
+
logger.debug(
|
153
|
+
f"Skipping optional package {package_name} (previously failed)"
|
154
|
+
)
|
153
155
|
return True, "optional-skipped"
|
154
156
|
|
155
157
|
# Try to import and check version
|
@@ -174,14 +176,18 @@ class AgentDependencyLoader:
|
|
174
176
|
for alternative in self.OPTIONAL_DB_PACKAGES[package_name]:
|
175
177
|
try:
|
176
178
|
alt_version = importlib.metadata.version(alternative)
|
177
|
-
logger.info(
|
179
|
+
logger.info(
|
180
|
+
f"Using {alternative} as alternative to {package_name}"
|
181
|
+
)
|
178
182
|
self.checked_packages.add(package_name)
|
179
183
|
return True, f"{alternative}:{alt_version}"
|
180
184
|
except importlib.metadata.PackageNotFoundError:
|
181
185
|
continue
|
182
186
|
# If no alternatives work, mark as optional failure
|
183
187
|
self.optional_failed[package_name] = "No alternatives available"
|
184
|
-
logger.warning(
|
188
|
+
logger.warning(
|
189
|
+
f"Optional package {package_name} not found, marking as optional"
|
190
|
+
)
|
185
191
|
return True, "optional-not-found"
|
186
192
|
return False, None
|
187
193
|
|
@@ -202,14 +208,20 @@ class AgentDependencyLoader:
|
|
202
208
|
if package_name in self.OPTIONAL_DB_PACKAGES:
|
203
209
|
for alternative in self.OPTIONAL_DB_PACKAGES[package_name]:
|
204
210
|
try:
|
205
|
-
alt_version = pkg_resources.get_distribution(
|
206
|
-
|
211
|
+
alt_version = pkg_resources.get_distribution(
|
212
|
+
alternative
|
213
|
+
).version
|
214
|
+
logger.info(
|
215
|
+
f"Using {alternative} as alternative to {package_name}"
|
216
|
+
)
|
207
217
|
self.checked_packages.add(package_name)
|
208
218
|
return True, f"{alternative}:{alt_version}"
|
209
219
|
except pkg_resources.DistributionNotFound:
|
210
220
|
continue
|
211
221
|
self.optional_failed[package_name] = "No alternatives available"
|
212
|
-
logger.warning(
|
222
|
+
logger.warning(
|
223
|
+
f"Optional package {package_name} not found, marking as optional"
|
224
|
+
)
|
213
225
|
return True, "optional-not-found"
|
214
226
|
return False, None
|
215
227
|
|
claude_mpm/utils/common.py
CHANGED
@@ -46,7 +46,7 @@ def load_json_safe(
|
|
46
46
|
file_path = Path(file_path)
|
47
47
|
|
48
48
|
try:
|
49
|
-
with open(file_path,
|
49
|
+
with open(file_path, encoding=encoding) as f:
|
50
50
|
return json.load(f)
|
51
51
|
except FileNotFoundError:
|
52
52
|
logger.debug(f"JSON file not found: {file_path}")
|
@@ -112,7 +112,7 @@ def load_yaml_safe(
|
|
112
112
|
file_path = Path(file_path)
|
113
113
|
|
114
114
|
try:
|
115
|
-
with open(file_path,
|
115
|
+
with open(file_path, encoding=encoding) as f:
|
116
116
|
return yaml.safe_load(f) or default or {}
|
117
117
|
except FileNotFoundError:
|
118
118
|
logger.debug(f"YAML file not found: {file_path}")
|
@@ -191,11 +191,10 @@ def ensure_path_exists(
|
|
191
191
|
path.parent.mkdir(parents=True, exist_ok=True)
|
192
192
|
# Don't create the file itself, just ensure parent exists
|
193
193
|
return path.parent.exists()
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
return False
|
194
|
+
if create_parents:
|
195
|
+
path.mkdir(parents=True, exist_ok=True)
|
196
|
+
return True
|
197
|
+
return False
|
199
198
|
except Exception as e:
|
200
199
|
logger.error(f"Error ensuring path exists {path}: {e}")
|
201
200
|
return False
|
@@ -304,8 +303,7 @@ def find_files(
|
|
304
303
|
|
305
304
|
if recursive:
|
306
305
|
return list(directory.rglob(pattern))
|
307
|
-
|
308
|
-
return list(directory.glob(pattern))
|
306
|
+
return list(directory.glob(pattern))
|
309
307
|
except Exception as e:
|
310
308
|
logger.error(f"Error finding files in {directory}: {e}")
|
311
309
|
return []
|
@@ -357,7 +355,7 @@ def run_command_safe(
|
|
357
355
|
env=env,
|
358
356
|
)
|
359
357
|
return result
|
360
|
-
except subprocess.TimeoutExpired
|
358
|
+
except subprocess.TimeoutExpired:
|
361
359
|
logger.error(f"Command timed out: {command}")
|
362
360
|
raise
|
363
361
|
except subprocess.CalledProcessError as e:
|
@@ -436,7 +434,9 @@ def get_env_int(key: str, default: int = 0) -> int:
|
|
436
434
|
return default
|
437
435
|
|
438
436
|
|
439
|
-
def get_env_list(
|
437
|
+
def get_env_list(
|
438
|
+
key: str, separator: str = ",", default: Optional[List[str]] = None
|
439
|
+
) -> List[str]:
|
440
440
|
"""
|
441
441
|
Get list from environment variable.
|
442
442
|
|
@@ -476,6 +476,7 @@ def safe_import(module_name: str, fallback: Any = None) -> Any:
|
|
476
476
|
"""
|
477
477
|
try:
|
478
478
|
import importlib
|
479
|
+
|
479
480
|
return importlib.import_module(module_name)
|
480
481
|
except ImportError as e:
|
481
482
|
logger.debug(f"Could not import {module_name}: {e}")
|
@@ -524,6 +525,7 @@ def deprecated(replacement: str = None):
|
|
524
525
|
Returns:
|
525
526
|
Decorated function
|
526
527
|
"""
|
528
|
+
|
527
529
|
def decorator(func):
|
528
530
|
def wrapper(*args, **kwargs):
|
529
531
|
import warnings
|
@@ -539,4 +541,4 @@ def deprecated(replacement: str = None):
|
|
539
541
|
wrapper.__doc__ = func.__doc__
|
540
542
|
return wrapper
|
541
543
|
|
542
|
-
return decorator
|
544
|
+
return decorator
|
@@ -10,7 +10,6 @@ DESIGN DECISION: We prioritize pure Python implementations over native ones
|
|
10
10
|
for better cross-platform compatibility, even if they might be slightly slower.
|
11
11
|
"""
|
12
12
|
|
13
|
-
import logging
|
14
13
|
from typing import Any, Dict, Optional, Tuple
|
15
14
|
|
16
15
|
from ..core.logger import get_logger
|
@@ -92,12 +91,14 @@ class DatabaseConnector:
|
|
92
91
|
"""
|
93
92
|
try:
|
94
93
|
import importlib
|
94
|
+
|
95
95
|
return importlib.import_module(module_name)
|
96
96
|
except ImportError:
|
97
97
|
return None
|
98
98
|
|
99
|
-
def get_mysql_connection_string(
|
100
|
-
|
99
|
+
def get_mysql_connection_string(
|
100
|
+
self, host: str, database: str, user: str, password: str, port: int = 3306
|
101
|
+
) -> Optional[str]:
|
101
102
|
"""
|
102
103
|
Get a SQLAlchemy connection string for MySQL with automatic driver selection.
|
103
104
|
|
@@ -125,15 +126,16 @@ class DatabaseConnector:
|
|
125
126
|
# Format connection string based on driver
|
126
127
|
if package_name == "pymysql":
|
127
128
|
return f"mysql+pymysql://{user}:{password}@{host}:{port}/{database}"
|
128
|
-
|
129
|
+
if package_name == "mysqlclient":
|
129
130
|
return f"mysql+mysqldb://{user}:{password}@{host}:{port}/{database}"
|
130
|
-
|
131
|
+
if package_name == "mysql-connector-python":
|
131
132
|
return f"mysql+mysqlconnector://{user}:{password}@{host}:{port}/{database}"
|
132
133
|
|
133
134
|
return None
|
134
135
|
|
135
|
-
def get_postgresql_connection_string(
|
136
|
-
|
136
|
+
def get_postgresql_connection_string(
|
137
|
+
self, host: str, database: str, user: str, password: str, port: int = 5432
|
138
|
+
) -> Optional[str]:
|
137
139
|
"""
|
138
140
|
Get a SQLAlchemy connection string for PostgreSQL with automatic driver selection.
|
139
141
|
|
@@ -158,13 +160,14 @@ class DatabaseConnector:
|
|
158
160
|
# Format connection string based on driver
|
159
161
|
if package_name in ["psycopg2-binary", "psycopg2"]:
|
160
162
|
return f"postgresql+psycopg2://{user}:{password}@{host}:{port}/{database}"
|
161
|
-
|
163
|
+
if package_name == "pg8000":
|
162
164
|
return f"postgresql+pg8000://{user}:{password}@{host}:{port}/{database}"
|
163
165
|
|
164
166
|
return None
|
165
167
|
|
166
|
-
def get_oracle_connection_string(
|
167
|
-
|
168
|
+
def get_oracle_connection_string(
|
169
|
+
self, host: str, database: str, user: str, password: str, port: int = 1521
|
170
|
+
) -> Optional[str]:
|
168
171
|
"""
|
169
172
|
Get a SQLAlchemy connection string for Oracle with automatic driver selection.
|
170
173
|
|
@@ -189,7 +192,7 @@ class DatabaseConnector:
|
|
189
192
|
# Format connection string based on driver
|
190
193
|
if package_name == "cx_Oracle":
|
191
194
|
return f"oracle+cx_oracle://{user}:{password}@{host}:{port}/{database}"
|
192
|
-
|
195
|
+
if package_name == "oracledb":
|
193
196
|
return f"oracle+oracledb://{user}:{password}@{host}:{port}/{database}"
|
194
197
|
|
195
198
|
return None
|
@@ -295,4 +298,4 @@ def test_database_connectivity() -> None:
|
|
295
298
|
|
296
299
|
if __name__ == "__main__":
|
297
300
|
# Run connectivity test when module is executed directly
|
298
|
-
test_database_connectivity()
|
301
|
+
test_database_connectivity()
|
claude_mpm/utils/log_cleanup.py
CHANGED
@@ -9,9 +9,9 @@ Convenience functions for session-based response logging.
|
|
9
9
|
import os
|
10
10
|
from typing import Any, Dict, Optional
|
11
11
|
|
12
|
+
from claude_mpm.core.logging_utils import get_logger
|
12
13
|
from claude_mpm.services.claude_session_logger import get_session_logger
|
13
14
|
|
14
|
-
from claude_mpm.core.logging_utils import get_logger
|
15
15
|
logger = get_logger(__name__)
|
16
16
|
|
17
17
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: claude-mpm
|
3
|
-
Version: 4.4.
|
3
|
+
Version: 4.4.5
|
4
4
|
Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
|
5
5
|
Author-email: Bob Matsuoka <bob@matsuoka.com>
|
6
6
|
Maintainer: Claude MPM Team
|
@@ -41,11 +41,6 @@ Requires-Dist: python-frontmatter>=1.0.0
|
|
41
41
|
Requires-Dist: mistune>=3.0.0
|
42
42
|
Requires-Dist: tree-sitter>=0.21.0
|
43
43
|
Requires-Dist: ijson>=3.2.0
|
44
|
-
Requires-Dist: kuzu-memory>=1.1.1
|
45
|
-
Requires-Dist: mcp>=0.1.0
|
46
|
-
Requires-Dist: mcp-vector-search>=0.1.0
|
47
|
-
Requires-Dist: mcp-browser>=0.1.0
|
48
|
-
Requires-Dist: mcp-ticketer>=0.1.0
|
49
44
|
Requires-Dist: toml>=0.10.2
|
50
45
|
Requires-Dist: packaging>=21.0
|
51
46
|
Requires-Dist: pydantic>=2.0.0
|
@@ -54,6 +49,12 @@ Requires-Dist: rich>=13.0.0
|
|
54
49
|
Requires-Dist: pyee>=13.0.0
|
55
50
|
Requires-Dist: importlib-resources>=5.0; python_version < "3.9"
|
56
51
|
Requires-Dist: pathspec>=0.11.0
|
52
|
+
Provides-Extra: mcp
|
53
|
+
Requires-Dist: mcp>=0.1.0; extra == "mcp"
|
54
|
+
Requires-Dist: mcp-vector-search>=0.1.0; extra == "mcp"
|
55
|
+
Requires-Dist: mcp-browser>=0.1.0; extra == "mcp"
|
56
|
+
Requires-Dist: mcp-ticketer>=0.1.0; extra == "mcp"
|
57
|
+
Requires-Dist: kuzu-memory>=1.1.1; extra == "mcp"
|
57
58
|
Provides-Extra: dev
|
58
59
|
Requires-Dist: pytest>=7.0; extra == "dev"
|
59
60
|
Requires-Dist: pytest-asyncio; extra == "dev"
|
@@ -157,7 +158,7 @@ A powerful orchestration framework for Claude Code that enables multi-agent work
|
|
157
158
|
- 🧠 **Persistent Knowledge System**: Project-specific kuzu-memory integration for intelligent context retention
|
158
159
|
- 🔄 **Session Management**: Resume previous sessions with `--resume`
|
159
160
|
- 📊 **Real-Time Monitoring**: Live dashboard with `--monitor` flag
|
160
|
-
- 🔌 **
|
161
|
+
- 🔌 **Optional MCP Services**: mcp-vector-search and kuzu-memory with automatic fallback installation
|
161
162
|
- 📁 **Multi-Project Support**: Per-session working directories with persistent knowledge graphs
|
162
163
|
- 🔍 **Git Integration**: View diffs and track changes across projects
|
163
164
|
- 🎯 **Smart Task Orchestration**: PM agent intelligently routes work to specialists
|
@@ -167,22 +168,32 @@ A powerful orchestration framework for Claude Code that enables multi-agent work
|
|
167
168
|
## Quick Installation
|
168
169
|
|
169
170
|
```bash
|
171
|
+
# Basic installation
|
170
172
|
pip install claude-mpm
|
173
|
+
|
174
|
+
# Install with optional MCP services (recommended)
|
175
|
+
pip install "claude-mpm[mcp]"
|
171
176
|
```
|
172
177
|
|
173
178
|
Or with pipx (recommended for isolated installation):
|
174
179
|
```bash
|
175
|
-
#
|
176
|
-
pipx install "claude-mpm[monitor]"
|
177
|
-
|
178
|
-
# Basic installation without monitor
|
180
|
+
# Basic installation
|
179
181
|
pipx install claude-mpm
|
180
182
|
|
183
|
+
# Install with optional MCP services (recommended)
|
184
|
+
pipx install "claude-mpm[mcp]"
|
185
|
+
|
186
|
+
# Install with all features
|
187
|
+
pipx install "claude-mpm[mcp,monitor]"
|
188
|
+
|
181
189
|
# Configure MCP for pipx users:
|
182
190
|
claude-mpm mcp-pipx-config
|
183
191
|
```
|
184
192
|
|
185
|
-
**💡
|
193
|
+
**💡 Optional Dependencies**:
|
194
|
+
- `[mcp]` - Include MCP services (mcp-vector-search, kuzu-memory) as dependencies
|
195
|
+
- `[monitor]` - Full monitoring dashboard with Socket.IO and async web server components
|
196
|
+
- Without optional dependencies, services auto-install on first use via pipx
|
186
197
|
|
187
198
|
**🎉 Pipx Support Now Fully Functional!** Recent improvements ensure complete compatibility:
|
188
199
|
- ✅ Socket.IO daemon script path resolution (fixed)
|
@@ -204,9 +215,18 @@ claude-mpm run --monitor
|
|
204
215
|
# Use MCP Gateway for external tool integration
|
205
216
|
claude-mpm mcp
|
206
217
|
|
207
|
-
# Run health diagnostics
|
218
|
+
# Run comprehensive health diagnostics
|
208
219
|
claude-mpm doctor
|
209
220
|
|
221
|
+
# Generate detailed diagnostic report with MCP service analysis
|
222
|
+
claude-mpm doctor --verbose --output-file doctor-report.md
|
223
|
+
|
224
|
+
# Run specific diagnostic checks including MCP services
|
225
|
+
claude-mpm doctor --checks installation configuration agents mcp
|
226
|
+
|
227
|
+
# Check MCP service status specifically
|
228
|
+
claude-mpm doctor --checks mcp --verbose
|
229
|
+
|
210
230
|
# Manage memory for large conversation histories
|
211
231
|
claude-mpm cleanup-memory
|
212
232
|
```
|
@@ -219,7 +239,7 @@ See [QUICKSTART.md](QUICKSTART.md) for complete usage examples.
|
|
219
239
|
Following Phase 3 architectural simplification in v4.4.1, Claude MPM features:
|
220
240
|
|
221
241
|
- **Streamlined Rich Interface**: Removed complex TUI system (~2,500 lines) for cleaner user experience
|
222
|
-
- **
|
242
|
+
- **Optional MCP Services**: mcp-vector-search and kuzu-memory with automatic fallback installation
|
223
243
|
- **Persistent Knowledge System**: Project-specific kuzu-memory databases with intelligent prompt enrichment
|
224
244
|
- **Service-Oriented Architecture**: Simplified five specialized service domains
|
225
245
|
- **Interface-Based Contracts**: All services implement explicit interfaces
|
@@ -316,7 +336,7 @@ See [docs/MEMORY.md](docs/MEMORY.md) and [docs/developer/11-dashboard/README.md]
|
|
316
336
|
#### 🚀 For Operations
|
317
337
|
- **[🚀 Deployment](docs/DEPLOYMENT.md)** - Release management & versioning
|
318
338
|
- **[📊 Monitoring](docs/MONITOR.md)** - Real-time dashboard & metrics
|
319
|
-
- **[🐛 Troubleshooting](docs/TROUBLESHOOTING.md)** -
|
339
|
+
- **[🐛 Troubleshooting](docs/TROUBLESHOOTING.md)** - Enhanced `doctor` command with detailed reports and auto-fix capabilities
|
320
340
|
|
321
341
|
### 🎯 Documentation Features
|
322
342
|
- **Single Entry Point**: [docs/README.md](docs/README.md) is your navigation hub
|