claude-mpm 4.5.11__py3-none-any.whl → 4.5.13__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/BASE_ENGINEER.md +47 -0
- claude_mpm/agents/BASE_QA.md +60 -0
- claude_mpm/agents/frontmatter_validator.py +4 -4
- claude_mpm/agents/templates/nextjs_engineer.json +2 -2
- claude_mpm/agents/templates/qa.json +13 -3
- claude_mpm/agents/templates/react_engineer.json +2 -2
- claude_mpm/agents/templates/typescript_engineer.json +2 -2
- claude_mpm/agents/templates/web_qa.json +14 -3
- claude_mpm/cli/commands/agent_manager.py +3 -3
- claude_mpm/cli/commands/agents.py +6 -6
- claude_mpm/cli/commands/aggregate.py +4 -4
- claude_mpm/cli/commands/analyze.py +2 -2
- claude_mpm/cli/commands/analyze_code.py +1 -1
- claude_mpm/cli/commands/cleanup.py +3 -3
- claude_mpm/cli/commands/config.py +2 -2
- claude_mpm/cli/commands/configure.py +14 -14
- claude_mpm/cli/commands/dashboard.py +1 -1
- claude_mpm/cli/commands/debug.py +3 -3
- claude_mpm/cli/commands/doctor.py +1 -1
- claude_mpm/cli/commands/mcp.py +7 -7
- claude_mpm/cli/commands/mcp_command_router.py +1 -1
- claude_mpm/cli/commands/mcp_config.py +2 -2
- claude_mpm/cli/commands/mcp_external_commands.py +2 -2
- claude_mpm/cli/commands/mcp_install_commands.py +3 -3
- claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +3 -3
- claude_mpm/cli/commands/monitor.py +1 -1
- claude_mpm/cli/commands/mpm_init_handler.py +1 -1
- claude_mpm/cli/interactive/agent_wizard.py +1 -1
- claude_mpm/cli/parsers/search_parser.py +1 -1
- claude_mpm/cli/shared/argument_patterns.py +2 -2
- claude_mpm/cli/shared/base_command.py +1 -1
- claude_mpm/cli/startup_logging.py +6 -4
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/socketio_config.py +2 -2
- claude_mpm/core/agent_session_manager.py +2 -2
- claude_mpm/core/api_validator.py +3 -3
- claude_mpm/core/base_service.py +10 -1
- claude_mpm/core/cache.py +2 -2
- claude_mpm/core/config.py +4 -4
- claude_mpm/core/config_aliases.py +4 -4
- claude_mpm/core/config_constants.py +1 -1
- claude_mpm/core/error_handler.py +1 -1
- claude_mpm/core/file_utils.py +5 -5
- claude_mpm/core/framework/formatters/capability_generator.py +5 -5
- claude_mpm/core/framework/loaders/agent_loader.py +1 -1
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/framework/processors/template_processor.py +3 -3
- claude_mpm/core/framework_loader.py +2 -2
- claude_mpm/core/log_manager.py +4 -4
- claude_mpm/core/logger.py +2 -2
- claude_mpm/core/optimized_startup.py +1 -1
- claude_mpm/core/output_style_manager.py +1 -1
- claude_mpm/core/service_registry.py +2 -2
- claude_mpm/core/session_manager.py +3 -3
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/socketio_pool.py +2 -2
- claude_mpm/core/unified_agent_registry.py +2 -2
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +2 -2
- claude_mpm/dashboard/api/simple_directory.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +1 -1
- claude_mpm/hooks/claude_hooks/event_handlers.py +2 -2
- claude_mpm/hooks/claude_hooks/installer.py +9 -9
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +7 -2
- claude_mpm/hooks/claude_hooks/tool_analysis.py +2 -2
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/validation_hooks.py +1 -1
- claude_mpm/init.py +4 -4
- claude_mpm/models/agent_session.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +5 -5
- claude_mpm/services/__init__.py +2 -2
- claude_mpm/services/agent_capabilities_service.py +1 -1
- claude_mpm/services/agents/agent_builder.py +6 -4
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +1 -1
- claude_mpm/services/agents/deployment/agent_record_service.py +3 -3
- claude_mpm/services/agents/deployment/deployment_wrapper.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +2 -2
- claude_mpm/services/agents/local_template_manager.py +5 -5
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +1 -1
- claude_mpm/services/agents/registry/modification_tracker.py +19 -11
- claude_mpm/services/async_session_logger.py +1 -1
- claude_mpm/services/claude_session_logger.py +1 -1
- claude_mpm/services/cli/agent_listing_service.py +3 -3
- claude_mpm/services/cli/agent_validation_service.py +1 -1
- claude_mpm/services/cli/session_manager.py +2 -2
- claude_mpm/services/core/path_resolver.py +1 -1
- claude_mpm/services/diagnostics/checks/agent_check.py +1 -1
- claude_mpm/services/diagnostics/checks/claude_code_check.py +2 -2
- claude_mpm/services/diagnostics/checks/common_issues_check.py +3 -3
- claude_mpm/services/diagnostics/checks/configuration_check.py +2 -2
- claude_mpm/services/diagnostics/checks/installation_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_check.py +1 -1
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +9 -9
- claude_mpm/services/diagnostics/checks/monitor_check.py +1 -1
- claude_mpm/services/diagnostics/doctor_reporter.py +1 -1
- claude_mpm/services/event_aggregator.py +1 -1
- claude_mpm/services/event_bus/event_bus.py +9 -2
- claude_mpm/services/events/consumers/dead_letter.py +2 -2
- claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
- claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
- claude_mpm/services/hook_installer_service.py +7 -7
- claude_mpm/services/infrastructure/context_preservation.py +7 -7
- claude_mpm/services/infrastructure/daemon_manager.py +5 -5
- claude_mpm/services/mcp_config_manager.py +10 -10
- claude_mpm/services/mcp_gateway/auto_configure.py +5 -5
- claude_mpm/services/mcp_gateway/config/config_loader.py +2 -2
- claude_mpm/services/mcp_gateway/config/configuration.py +5 -3
- claude_mpm/services/mcp_gateway/core/process_pool.py +3 -3
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
- claude_mpm/services/mcp_gateway/core/startup_verification.py +1 -1
- claude_mpm/services/mcp_gateway/main.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +2 -1
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +1 -1
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +1 -1
- claude_mpm/services/mcp_gateway/tools/hello_world.py +1 -1
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +5 -5
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +2 -2
- claude_mpm/services/mcp_service_verifier.py +1 -1
- claude_mpm/services/memory/builder.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
- claude_mpm/services/memory/indexed_memory.py +3 -3
- claude_mpm/services/monitor/daemon.py +1 -1
- claude_mpm/services/monitor/daemon_manager.py +9 -9
- claude_mpm/services/monitor/handlers/file.py +1 -1
- claude_mpm/services/monitor/handlers/hooks.py +3 -3
- claude_mpm/services/monitor/management/lifecycle.py +7 -7
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/orphan_detection.py +11 -16
- claude_mpm/services/port_manager.py +2 -2
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/archive_manager.py +17 -13
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/documentation_manager.py +4 -4
- claude_mpm/services/project/enhanced_analyzer.py +19 -8
- claude_mpm/services/project/registry.py +4 -4
- claude_mpm/services/project_port_allocator.py +7 -12
- claude_mpm/services/session_management_service.py +1 -1
- claude_mpm/services/socketio/event_normalizer.py +1 -1
- claude_mpm/services/socketio/handlers/code_analysis.py +14 -12
- claude_mpm/services/socketio/handlers/file.py +1 -1
- claude_mpm/services/socketio/migration_utils.py +1 -1
- claude_mpm/services/socketio/server/core.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +1 -1
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +4 -4
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +1 -1
- claude_mpm/services/unified/config_strategies/config_schema.py +4 -4
- claude_mpm/services/unified/config_strategies/context_strategy.py +8 -6
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +10 -10
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +5 -5
- claude_mpm/services/unified/config_strategies/unified_config_service.py +8 -8
- claude_mpm/services/unified/config_strategies/validation_strategy.py +15 -15
- claude_mpm/services/unified/deployment_strategies/base.py +4 -4
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +15 -15
- claude_mpm/services/unified/deployment_strategies/local.py +11 -11
- claude_mpm/services/unified/deployment_strategies/utils.py +11 -9
- claude_mpm/services/unified/deployment_strategies/vercel.py +7 -9
- claude_mpm/services/unified/unified_config.py +5 -5
- claude_mpm/services/unified/unified_deployment.py +2 -2
- claude_mpm/services/utility_service.py +1 -1
- claude_mpm/services/version_control/conflict_resolution.py +2 -2
- claude_mpm/services/version_control/git_operations.py +3 -3
- claude_mpm/services/version_control/semantic_versioning.py +13 -13
- claude_mpm/services/version_control/version_parser.py +1 -1
- claude_mpm/storage/state_storage.py +12 -13
- claude_mpm/tools/code_tree_analyzer.py +5 -5
- claude_mpm/tools/code_tree_builder.py +4 -4
- claude_mpm/tools/socketio_debug.py +1 -1
- claude_mpm/utils/agent_dependency_loader.py +4 -4
- claude_mpm/utils/common.py +2 -2
- claude_mpm/utils/config_manager.py +3 -3
- claude_mpm/utils/dependency_cache.py +2 -2
- claude_mpm/utils/dependency_strategies.py +6 -6
- claude_mpm/utils/file_utils.py +11 -11
- claude_mpm/utils/log_cleanup.py +1 -1
- claude_mpm/utils/path_operations.py +1 -1
- claude_mpm/validation/agent_validator.py +2 -2
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/RECORD +190 -190
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.5.11.dist-info → claude_mpm-4.5.13.dist-info}/top_level.txt +0 -0
@@ -64,14 +64,14 @@ class SimpleAgentManager:
|
|
64
64
|
def _load_states(self):
|
65
65
|
"""Load agent states from file."""
|
66
66
|
if self.config_file.exists():
|
67
|
-
with
|
67
|
+
with self.config_file.open() as f:
|
68
68
|
self.states = json.load(f)
|
69
69
|
else:
|
70
70
|
self.states = {}
|
71
71
|
|
72
72
|
def _save_states(self):
|
73
73
|
"""Save agent states to file."""
|
74
|
-
with
|
74
|
+
with self.config_file.open("w") as f:
|
75
75
|
json.dump(self.states, f, indent=2)
|
76
76
|
|
77
77
|
def is_agent_enabled(self, agent_name: str) -> bool:
|
@@ -105,7 +105,7 @@ class SimpleAgentManager:
|
|
105
105
|
continue
|
106
106
|
|
107
107
|
try:
|
108
|
-
with open(
|
108
|
+
with template_file.open() as f:
|
109
109
|
template_data = json.load(f)
|
110
110
|
|
111
111
|
# Extract agent information from template
|
@@ -205,7 +205,7 @@ class ConfigureCommand(BaseCommand):
|
|
205
205
|
|
206
206
|
return None
|
207
207
|
|
208
|
-
def run(self, args) -> CommandResult:
|
208
|
+
def run(self, args) -> CommandResult:
|
209
209
|
"""Execute the configure command."""
|
210
210
|
# Set configuration scope
|
211
211
|
self.current_scope = getattr(args, "scope", "project")
|
@@ -447,7 +447,7 @@ class ConfigureCommand(BaseCommand):
|
|
447
447
|
try:
|
448
448
|
template_path = self._get_agent_template_path(agent.name)
|
449
449
|
if template_path.exists():
|
450
|
-
with open(
|
450
|
+
with template_path.open() as f:
|
451
451
|
template = json.load(f)
|
452
452
|
model = template.get("capabilities", {}).get("model", "default")
|
453
453
|
tools_display = f"Model: {model}"
|
@@ -542,7 +542,7 @@ class ConfigureCommand(BaseCommand):
|
|
542
542
|
template_path = self._get_agent_template_path(agent.name)
|
543
543
|
|
544
544
|
if template_path.exists():
|
545
|
-
with open(
|
545
|
+
with template_path.open() as f:
|
546
546
|
template = json.load(f)
|
547
547
|
is_system = str(template_path).startswith(
|
548
548
|
str(self.agent_manager.templates_dir)
|
@@ -693,11 +693,11 @@ class ConfigureCommand(BaseCommand):
|
|
693
693
|
subprocess.call([editor, temp_path])
|
694
694
|
|
695
695
|
# Read back the edited content
|
696
|
-
with open(
|
696
|
+
with temp_path.open() as f:
|
697
697
|
new_template = json.load(f)
|
698
698
|
|
699
699
|
# Save to actual template path
|
700
|
-
with open(
|
700
|
+
with template_path.open("w") as f:
|
701
701
|
json.dump(new_template, f, indent=2)
|
702
702
|
|
703
703
|
self.console.print("[green]Template updated successfully![/green]")
|
@@ -732,7 +732,7 @@ class ConfigureCommand(BaseCommand):
|
|
732
732
|
current[parts[-1]] = value
|
733
733
|
|
734
734
|
# Save the template
|
735
|
-
with open(
|
735
|
+
with template_path.open("w") as f:
|
736
736
|
json.dump(template, f, indent=2)
|
737
737
|
|
738
738
|
self.console.print(
|
@@ -765,7 +765,7 @@ class ConfigureCommand(BaseCommand):
|
|
765
765
|
del current[parts[-1]]
|
766
766
|
|
767
767
|
# Save the template
|
768
|
-
with open(
|
768
|
+
with template_path.open("w") as f:
|
769
769
|
json.dump(template, f, indent=2)
|
770
770
|
|
771
771
|
self.console.print(
|
@@ -802,7 +802,7 @@ class ConfigureCommand(BaseCommand):
|
|
802
802
|
return
|
803
803
|
|
804
804
|
# Save the template copy
|
805
|
-
with open(
|
805
|
+
with custom_path.open("w") as f:
|
806
806
|
json.dump(template, f, indent=2)
|
807
807
|
|
808
808
|
self.console.print(f"[green]Created custom template at: {custom_path}[/green]")
|
@@ -839,7 +839,7 @@ class ConfigureCommand(BaseCommand):
|
|
839
839
|
|
840
840
|
if template_path.exists():
|
841
841
|
try:
|
842
|
-
with open(
|
842
|
+
with template_path.open() as f:
|
843
843
|
template = json.load(f)
|
844
844
|
|
845
845
|
# Extract additional information
|
@@ -1675,7 +1675,7 @@ Directory: {self.project_dir}
|
|
1675
1675
|
|
1676
1676
|
# Write to file
|
1677
1677
|
output_path = Path(file_path)
|
1678
|
-
with open(
|
1678
|
+
with output_path.open("w") as f:
|
1679
1679
|
json.dump(config_data, f, indent=2)
|
1680
1680
|
|
1681
1681
|
return CommandResult.success_result(
|
@@ -1692,7 +1692,7 @@ Directory: {self.project_dir}
|
|
1692
1692
|
if not input_path.exists():
|
1693
1693
|
return CommandResult.error_result(f"File not found: {file_path}")
|
1694
1694
|
|
1695
|
-
with open(
|
1695
|
+
with input_path.open() as f:
|
1696
1696
|
config_data = json.load(f)
|
1697
1697
|
|
1698
1698
|
# Apply agent states
|
@@ -65,7 +65,7 @@ class DashboardCommand(BaseCommand):
|
|
65
65
|
self.logger.error(f"Error executing dashboard command: {e}", exc_info=True)
|
66
66
|
return CommandResult.error_result(f"Error executing dashboard command: {e}")
|
67
67
|
|
68
|
-
def _start_dashboard(self, args) -> CommandResult:
|
68
|
+
def _start_dashboard(self, args) -> CommandResult:
|
69
69
|
"""Start the dashboard server."""
|
70
70
|
port = getattr(args, "port", 8765)
|
71
71
|
host = getattr(args, "host", "localhost")
|
claude_mpm/cli/commands/debug.py
CHANGED
@@ -21,7 +21,7 @@ from typing import Any, Dict
|
|
21
21
|
from ...core.logger import get_logger
|
22
22
|
|
23
23
|
|
24
|
-
def manage_debug(args):
|
24
|
+
def manage_debug(args):
|
25
25
|
"""
|
26
26
|
Main entry point for debug commands.
|
27
27
|
|
@@ -446,7 +446,7 @@ def debug_agents(args, logger):
|
|
446
446
|
|
447
447
|
# Try to load and analyze memory
|
448
448
|
try:
|
449
|
-
with open(
|
449
|
+
with mem_file.open() as f:
|
450
450
|
memory_data = json.load(f)
|
451
451
|
|
452
452
|
entry_count = (
|
@@ -509,7 +509,7 @@ def debug_agents(args, logger):
|
|
509
509
|
print(f" Size: {agent_file.stat().st_size:,} bytes")
|
510
510
|
|
511
511
|
# Read first few lines for type detection
|
512
|
-
with open(
|
512
|
+
with agent_file.open() as f:
|
513
513
|
lines = f.readlines()[:10]
|
514
514
|
for line in lines:
|
515
515
|
if "role:" in line.lower():
|
@@ -181,7 +181,7 @@ def doctor_command(args):
|
|
181
181
|
import sys
|
182
182
|
|
183
183
|
original_stdout = sys.stdout
|
184
|
-
with open(
|
184
|
+
with output_file.open("w") as f:
|
185
185
|
sys.stdout = f
|
186
186
|
reporter.report(summary, format=output_format)
|
187
187
|
sys.stdout = original_stdout
|
claude_mpm/cli/commands/mcp.py
CHANGED
@@ -61,10 +61,10 @@ def manage_mcp(args):
|
|
61
61
|
|
62
62
|
# Allow install command to proceed
|
63
63
|
if args.mcp_command == MCPCommands.INSTALL.value:
|
64
|
-
MCPConfiguration = None
|
65
|
-
MCPServiceRegistry = None
|
66
|
-
ToolRegistry = None
|
67
|
-
MCPGateway = None
|
64
|
+
MCPConfiguration = None
|
65
|
+
MCPServiceRegistry = None
|
66
|
+
ToolRegistry = None
|
67
|
+
MCPGateway = None
|
68
68
|
else:
|
69
69
|
print(
|
70
70
|
"\nError: MCP Gateway services not fully available",
|
@@ -120,7 +120,7 @@ def _show_status(
|
|
120
120
|
MCPConfiguration,
|
121
121
|
MCPServiceRegistry,
|
122
122
|
ToolRegistry,
|
123
|
-
MCPGateway,
|
123
|
+
MCPGateway,
|
124
124
|
):
|
125
125
|
"""
|
126
126
|
Show MCP Gateway status when no subcommand is provided.
|
@@ -151,7 +151,7 @@ def _show_status(
|
|
151
151
|
if config_path.exists():
|
152
152
|
print(f" Config file: {config_path}")
|
153
153
|
try:
|
154
|
-
with open(
|
154
|
+
with config_path.open() as f:
|
155
155
|
config = json.load(f)
|
156
156
|
if "servers" in config:
|
157
157
|
print(f" Configured servers: {len(config.get('servers', {}))}")
|
@@ -171,7 +171,7 @@ def _show_status(
|
|
171
171
|
if claude_config.exists():
|
172
172
|
print(f"\n🖥️ Claude Code Config: {claude_config}")
|
173
173
|
try:
|
174
|
-
with open(
|
174
|
+
with claude_config.open() as f:
|
175
175
|
config = json.load(f)
|
176
176
|
mcp_servers = config.get("mcpServers", {})
|
177
177
|
if "claude-mpm" in mcp_servers:
|
@@ -16,7 +16,7 @@ class MCPCommandRouter:
|
|
16
16
|
"""Initialize the command router."""
|
17
17
|
self.logger = logger
|
18
18
|
|
19
|
-
def route_command(self, args) -> int:
|
19
|
+
def route_command(self, args) -> int:
|
20
20
|
"""Route command to appropriate handler."""
|
21
21
|
if args.mcp_command == MCPCommands.START.value:
|
22
22
|
return asyncio.run(self._start_server(args))
|
@@ -62,7 +62,7 @@ class MCPConfigCommand(BaseCommand):
|
|
62
62
|
# Show the updated configuration
|
63
63
|
config_path = Path.cwd() / ".mcp.json"
|
64
64
|
if config_path.exists():
|
65
|
-
with open(
|
65
|
+
with config_path.open() as f:
|
66
66
|
config = json.load(f)
|
67
67
|
return CommandResult(
|
68
68
|
success=True,
|
@@ -120,7 +120,7 @@ class MCPConfigCommand(BaseCommand):
|
|
120
120
|
current_config = {}
|
121
121
|
if config_path.exists():
|
122
122
|
try:
|
123
|
-
with open(
|
123
|
+
with config_path.open() as f:
|
124
124
|
current_config = json.load(f)
|
125
125
|
except Exception:
|
126
126
|
pass
|
@@ -12,7 +12,7 @@ class MCPExternalCommands:
|
|
12
12
|
"""Initialize the MCP external commands handler."""
|
13
13
|
self.logger = logger
|
14
14
|
|
15
|
-
def manage_external(self, args):
|
15
|
+
def manage_external(self, args):
|
16
16
|
"""Manage external MCP services.
|
17
17
|
|
18
18
|
Args:
|
@@ -135,7 +135,7 @@ class MCPExternalCommands:
|
|
135
135
|
print(f"\n📄 Found config: {config_path}")
|
136
136
|
|
137
137
|
try:
|
138
|
-
with open(
|
138
|
+
with config_path.open() as f:
|
139
139
|
config = json.load(f)
|
140
140
|
|
141
141
|
mcp_servers = config.get("mcpServers", {})
|
@@ -270,7 +270,7 @@ class MCPInstallCommands:
|
|
270
270
|
if not force:
|
271
271
|
# Check if claude-mpm-gateway already exists
|
272
272
|
try:
|
273
|
-
with open(
|
273
|
+
with config_path.open() as f:
|
274
274
|
existing_config = json.load(f)
|
275
275
|
|
276
276
|
if (
|
@@ -305,7 +305,7 @@ class MCPInstallCommands:
|
|
305
305
|
else:
|
306
306
|
# Force mode - create backup but proceed
|
307
307
|
try:
|
308
|
-
with open(
|
308
|
+
with config_path.open() as f:
|
309
309
|
existing_config = json.load(f)
|
310
310
|
config = existing_config
|
311
311
|
print(" Force mode: Overwriting existing configuration")
|
@@ -335,7 +335,7 @@ class MCPInstallCommands:
|
|
335
335
|
config_path.parent.mkdir(parents=True, exist_ok=True)
|
336
336
|
|
337
337
|
# Write configuration with nice formatting
|
338
|
-
with open(
|
338
|
+
with config_path.open("w") as f:
|
339
339
|
json.dump(config, f, indent=2)
|
340
340
|
|
341
341
|
print(f"\n✅ Configuration saved to {config_path}")
|
@@ -110,7 +110,7 @@ def configure_mcp_for_pipx(args) -> int:
|
|
110
110
|
existing_config = {}
|
111
111
|
if config_path.exists():
|
112
112
|
try:
|
113
|
-
with open(
|
113
|
+
with config_path.open() as f:
|
114
114
|
existing_config = json.load(f)
|
115
115
|
print("✅ Existing config loaded")
|
116
116
|
except json.JSONDecodeError:
|
@@ -145,7 +145,7 @@ def configure_mcp_for_pipx(args) -> int:
|
|
145
145
|
# Write config
|
146
146
|
if not args.dry_run:
|
147
147
|
try:
|
148
|
-
with open(
|
148
|
+
with config_path.open("w") as f:
|
149
149
|
json.dump(existing_config, f, indent=2)
|
150
150
|
print(f"\n✅ Configuration written to: {config_path}")
|
151
151
|
except Exception as e:
|
@@ -621,7 +621,7 @@ class MCPExternalServicesSetup:
|
|
621
621
|
"""
|
622
622
|
try:
|
623
623
|
if config_path.exists():
|
624
|
-
with open(
|
624
|
+
with config_path.open() as f:
|
625
625
|
config = json.load(f)
|
626
626
|
# Ensure mcpServers key exists
|
627
627
|
if "mcpServers" not in config:
|
@@ -664,7 +664,7 @@ class MCPExternalServicesSetup:
|
|
664
664
|
print(f" 📁 Created backup: {backup_path}")
|
665
665
|
|
666
666
|
# Write configuration with proper formatting
|
667
|
-
with open(
|
667
|
+
with config_path.open("w") as f:
|
668
668
|
json.dump(config, f, indent=2)
|
669
669
|
f.write("\n") # Add newline at end of file
|
670
670
|
|
@@ -830,7 +830,7 @@ class MCPExternalServicesSetup:
|
|
830
830
|
|
831
831
|
if mcp_config_path.exists():
|
832
832
|
try:
|
833
|
-
with open(
|
833
|
+
with mcp_config_path.open() as f:
|
834
834
|
mcp_config = json.load(f)
|
835
835
|
print(f"\n📁 Project MCP config: {mcp_config_path}")
|
836
836
|
except Exception:
|
@@ -37,7 +37,7 @@ class MonitorCommand(BaseCommand):
|
|
37
37
|
|
38
38
|
return None
|
39
39
|
|
40
|
-
def run(self, args) -> CommandResult:
|
40
|
+
def run(self, args) -> CommandResult:
|
41
41
|
"""Execute the monitor command using unified monitoring daemon."""
|
42
42
|
try:
|
43
43
|
self.logger.info("Monitor command using unified monitoring daemon")
|
@@ -769,7 +769,7 @@ class AgentWizard:
|
|
769
769
|
|
770
770
|
output_file = output_dir / f"{template.agent_id}.json"
|
771
771
|
|
772
|
-
with open(
|
772
|
+
with output_file.open("w") as f:
|
773
773
|
json.dump(template.to_json(), f, indent=2)
|
774
774
|
|
775
775
|
return True, f"Agent exported to {output_file}"
|
@@ -190,7 +190,7 @@ Examples:
|
|
190
190
|
return search_parser
|
191
191
|
|
192
192
|
|
193
|
-
def validate_search_args(args: argparse.Namespace) -> Optional[str]:
|
193
|
+
def validate_search_args(args: argparse.Namespace) -> Optional[str]:
|
194
194
|
"""
|
195
195
|
Validate search command arguments.
|
196
196
|
|
@@ -7,14 +7,14 @@ across multiple CLI commands.
|
|
7
7
|
|
8
8
|
import argparse
|
9
9
|
from pathlib import Path
|
10
|
-
from typing import Any, Dict, List, Optional
|
10
|
+
from typing import Any, ClassVar, Dict, List, Optional
|
11
11
|
|
12
12
|
|
13
13
|
class CommonArguments:
|
14
14
|
"""Registry of common argument patterns used across CLI commands."""
|
15
15
|
|
16
16
|
# Logging arguments
|
17
|
-
VERBOSE = {
|
17
|
+
VERBOSE: ClassVar[Dict[str, Any]] = {
|
18
18
|
"flags": ["-v", "--verbose"],
|
19
19
|
"action": "store_true",
|
20
20
|
"help": "Enable verbose output",
|
@@ -183,7 +183,7 @@ class BaseCommand(ABC):
|
|
183
183
|
|
184
184
|
if hasattr(args, "output") and args.output:
|
185
185
|
# Write to file
|
186
|
-
with
|
186
|
+
with args.output.open("w") as f:
|
187
187
|
f.write(formatted_output)
|
188
188
|
self.logger.info(f"Output written to {args.output}")
|
189
189
|
else:
|
@@ -303,7 +303,7 @@ class StartupStatusLogger:
|
|
303
303
|
|
304
304
|
import json
|
305
305
|
|
306
|
-
with open(
|
306
|
+
with claude_json_path.open() as f:
|
307
307
|
config = json.load(f)
|
308
308
|
|
309
309
|
result["found"] = True
|
@@ -716,9 +716,11 @@ def start_vector_search_indexing(project_root: Optional[Path] = None) -> None:
|
|
716
716
|
try:
|
717
717
|
# Try to get the current event loop
|
718
718
|
loop = asyncio.get_running_loop()
|
719
|
-
# If we're in an event loop, create a task
|
720
|
-
|
721
|
-
|
719
|
+
# If we're in an event loop, create a task (fire-and-forget)
|
720
|
+
_task = loop.create_task(
|
721
|
+
trigger_vector_search_indexing(project_root)
|
722
|
+
)
|
723
|
+
# Fire-and-forget: task will complete in background
|
722
724
|
except RuntimeError:
|
723
725
|
# No event loop running - use subprocess directly to avoid event loop lifecycle issues
|
724
726
|
# The async approach with asyncio.run() creates and closes a loop which causes
|
@@ -64,7 +64,7 @@ class ExperimentalFeatures:
|
|
64
64
|
"""
|
65
65
|
if self._config_file and self._config_file.exists():
|
66
66
|
try:
|
67
|
-
with
|
67
|
+
with self._config_file.open() as f:
|
68
68
|
config = json.load(f)
|
69
69
|
experimental = config.get("experimental_features", {})
|
70
70
|
self._features.update(experimental)
|
@@ -125,7 +125,7 @@ class ExperimentalFeatures:
|
|
125
125
|
accepted_file = Path.home() / ".claude-mpm" / ".experimental_accepted"
|
126
126
|
if accepted_file.exists():
|
127
127
|
try:
|
128
|
-
with open(
|
128
|
+
with accepted_file.open() as f:
|
129
129
|
accepted = json.load(f)
|
130
130
|
if feature in accepted.get("features", []):
|
131
131
|
return False
|
@@ -148,7 +148,7 @@ class ExperimentalFeatures:
|
|
148
148
|
|
149
149
|
try:
|
150
150
|
if accepted_file.exists():
|
151
|
-
with open(
|
151
|
+
with accepted_file.open() as f:
|
152
152
|
data = json.load(f)
|
153
153
|
else:
|
154
154
|
data = {"features": [], "timestamp": {}}
|
@@ -159,7 +159,7 @@ class ExperimentalFeatures:
|
|
159
159
|
"CLAUDE_MPM_TIMESTAMP", str(Path.cwd())
|
160
160
|
)
|
161
161
|
|
162
|
-
with open(
|
162
|
+
with accepted_file.open("w") as f:
|
163
163
|
json.dump(data, f, indent=2)
|
164
164
|
except Exception:
|
165
165
|
# Silently ignore errors in acceptance tracking
|
@@ -249,7 +249,7 @@ class ConfigManager:
|
|
249
249
|
for config_path in self.config_search_paths:
|
250
250
|
if config_path.exists():
|
251
251
|
try:
|
252
|
-
with open(
|
252
|
+
with config_path.open() as f:
|
253
253
|
return json.load(f)
|
254
254
|
except Exception as e:
|
255
255
|
print(f"Warning: Failed to load config from {config_path}: {e}")
|
@@ -267,7 +267,7 @@ class ConfigManager:
|
|
267
267
|
path = config_dir / self.config_file_name
|
268
268
|
|
269
269
|
try:
|
270
|
-
with open(
|
270
|
+
with path.open("w") as f:
|
271
271
|
json.dump(config.to_dict(), f, indent=2)
|
272
272
|
return True
|
273
273
|
except Exception as e:
|
@@ -209,7 +209,7 @@ class AgentSessionManager:
|
|
209
209
|
"agent_sessions": dict(self.agent_sessions),
|
210
210
|
"updated_at": datetime.now(timezone.utc).isoformat(),
|
211
211
|
}
|
212
|
-
with open(
|
212
|
+
with session_file.open("w") as f:
|
213
213
|
json.dump(data, f, indent=2)
|
214
214
|
except Exception as e:
|
215
215
|
logger.error(f"Failed to save agent sessions: {e}")
|
@@ -219,7 +219,7 @@ class AgentSessionManager:
|
|
219
219
|
session_file = self.session_dir / "agent_sessions.json"
|
220
220
|
if session_file.exists():
|
221
221
|
try:
|
222
|
-
with open(
|
222
|
+
with session_file.open() as f:
|
223
223
|
data = json.load(f)
|
224
224
|
self.agent_sessions = defaultdict(
|
225
225
|
dict, data.get("agent_sessions", {})
|
claude_mpm/core/api_validator.py
CHANGED
@@ -84,7 +84,7 @@ class APIKeyValidator:
|
|
84
84
|
|
85
85
|
return not bool(self.errors), self.errors, self.warnings
|
86
86
|
|
87
|
-
def _validate_openai_key(self, api_key: str) -> bool:
|
87
|
+
def _validate_openai_key(self, api_key: str) -> bool:
|
88
88
|
"""Validate OpenAI API key.
|
89
89
|
|
90
90
|
Args:
|
@@ -133,7 +133,7 @@ class APIKeyValidator:
|
|
133
133
|
self.errors.append(f"❌ OpenAI API validation failed with error: {e}")
|
134
134
|
return False
|
135
135
|
|
136
|
-
def _validate_anthropic_key(self, api_key: str) -> bool:
|
136
|
+
def _validate_anthropic_key(self, api_key: str) -> bool:
|
137
137
|
"""Validate Anthropic API key.
|
138
138
|
|
139
139
|
Args:
|
@@ -196,7 +196,7 @@ class APIKeyValidator:
|
|
196
196
|
self.errors.append(f"❌ Anthropic API validation failed with error: {e}")
|
197
197
|
return False
|
198
198
|
|
199
|
-
def _validate_github_token(self, token: str) -> bool:
|
199
|
+
def _validate_github_token(self, token: str) -> bool:
|
200
200
|
"""Validate GitHub personal access token.
|
201
201
|
|
202
202
|
Args:
|
claude_mpm/core/base_service.py
CHANGED
@@ -428,7 +428,16 @@ class BaseService(LoggerMixin, ABC):
|
|
428
428
|
self.logger.info(
|
429
429
|
f"Received signal {signum}, initiating graceful shutdown..."
|
430
430
|
)
|
431
|
-
|
431
|
+
# Get the event loop and create a tracked shutdown task
|
432
|
+
try:
|
433
|
+
loop = asyncio.get_event_loop()
|
434
|
+
task = loop.create_task(self.stop())
|
435
|
+
# Store reference to prevent GC during shutdown
|
436
|
+
if not hasattr(self, "_shutdown_task"):
|
437
|
+
self._shutdown_task = task
|
438
|
+
except RuntimeError:
|
439
|
+
# No event loop, call stop synchronously
|
440
|
+
self.logger.warning("No event loop available for graceful shutdown")
|
432
441
|
|
433
442
|
signal.signal(signal.SIGINT, signal_handler)
|
434
443
|
signal.signal(signal.SIGTERM, signal_handler)
|
claude_mpm/core/cache.py
CHANGED
@@ -391,7 +391,7 @@ class FileSystemCache:
|
|
391
391
|
|
392
392
|
try:
|
393
393
|
self.persist_path.parent.mkdir(parents=True, exist_ok=True)
|
394
|
-
with
|
394
|
+
with self.persist_path.open("wb") as f:
|
395
395
|
pickle.dump(self._cache, f)
|
396
396
|
self._logger.debug(f"Cache persisted to {self.persist_path}")
|
397
397
|
except Exception as e:
|
@@ -403,7 +403,7 @@ class FileSystemCache:
|
|
403
403
|
return
|
404
404
|
|
405
405
|
try:
|
406
|
-
with
|
406
|
+
with self.persist_path.open("rb") as f:
|
407
407
|
loaded_cache = pickle.load(f)
|
408
408
|
|
409
409
|
# Rebuild cache with validation
|
claude_mpm/core/config.py
CHANGED
@@ -253,7 +253,7 @@ class Config:
|
|
253
253
|
"operation": "read",
|
254
254
|
"error_type": type(e).__name__,
|
255
255
|
},
|
256
|
-
)
|
256
|
+
) from e
|
257
257
|
except Exception as e:
|
258
258
|
# Catch any remaining unexpected errors and wrap them as configuration errors
|
259
259
|
raise ConfigurationError(
|
@@ -263,7 +263,7 @@ class Config:
|
|
263
263
|
"error_type": type(e).__name__,
|
264
264
|
"original_error": str(e),
|
265
265
|
},
|
266
|
-
)
|
266
|
+
) from e
|
267
267
|
|
268
268
|
def _load_env_vars(self) -> None:
|
269
269
|
"""Load configuration from environment variables."""
|
@@ -651,7 +651,7 @@ class Config:
|
|
651
651
|
"format": format,
|
652
652
|
"error_type": type(e).__name__,
|
653
653
|
},
|
654
|
-
)
|
654
|
+
) from e
|
655
655
|
except Exception as e:
|
656
656
|
# Re-raise ConfigurationError as-is, wrap others
|
657
657
|
if isinstance(e, ConfigurationError):
|
@@ -663,7 +663,7 @@ class Config:
|
|
663
663
|
"format": format,
|
664
664
|
"error_type": type(e).__name__,
|
665
665
|
},
|
666
|
-
)
|
666
|
+
) from e
|
667
667
|
|
668
668
|
def validate(self, schema: Dict[str, Any]) -> bool:
|
669
669
|
"""
|
@@ -88,7 +88,7 @@ class ConfigAliasManager:
|
|
88
88
|
self.config_mgr.save_json(aliases, self.aliases_file, sort_keys=True)
|
89
89
|
except Exception as e:
|
90
90
|
logger.error(f"Failed to save aliases: {e}")
|
91
|
-
raise ConfigAliasError(f"Failed to save aliases: {e}")
|
91
|
+
raise ConfigAliasError(f"Failed to save aliases: {e}") from e
|
92
92
|
|
93
93
|
def create_alias(self, alias_name: str, directory_path: str) -> None:
|
94
94
|
"""
|
@@ -211,7 +211,7 @@ class ConfigAliasManager:
|
|
211
211
|
except Exception as e:
|
212
212
|
raise InvalidDirectoryError(
|
213
213
|
f"Cannot create directory '{directory_path}': {e}"
|
214
|
-
)
|
214
|
+
) from e
|
215
215
|
|
216
216
|
# Verify we can write to the directory
|
217
217
|
test_file = directory_path / ".claude_pm_test"
|
@@ -221,14 +221,14 @@ class ConfigAliasManager:
|
|
221
221
|
except Exception as e:
|
222
222
|
raise InvalidDirectoryError(
|
223
223
|
f"Directory '{directory_path}' is not writable: {e}"
|
224
|
-
)
|
224
|
+
) from e
|
225
225
|
|
226
226
|
return directory_path
|
227
227
|
|
228
228
|
except InvalidDirectoryError:
|
229
229
|
raise
|
230
230
|
except Exception as e:
|
231
|
-
raise InvalidDirectoryError(f"Invalid directory path '{path}': {e}")
|
231
|
+
raise InvalidDirectoryError(f"Invalid directory path '{path}': {e}") from e
|
232
232
|
|
233
233
|
def get_alias(self, alias_name: str) -> Optional[str]:
|
234
234
|
"""
|
claude_mpm/core/error_handler.py
CHANGED
@@ -218,7 +218,7 @@ class ErrorHandler:
|
|
218
218
|
return handler(error, error_context)
|
219
219
|
except Exception as recovery_error:
|
220
220
|
self.logger.error(f"Recovery failed: {recovery_error}")
|
221
|
-
raise error
|
221
|
+
raise error from recovery_error
|
222
222
|
|
223
223
|
# No recovery handler available
|
224
224
|
self.logger.warning(f"No recovery handler for {error_type.__name__}")
|