claude-mpm 4.1.1__py3-none-any.whl → 4.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/engineer.json +33 -11
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +50 -2
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +648 -1098
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +339 -967
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +233 -542
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +280 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +22 -29
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +500 -680
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -17
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +99 -154
- claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
- claude_mpm/services/agents/memory/memory_file_service.py +103 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +11 -7
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +407 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +589 -0
- claude_mpm/services/cli/dashboard_launcher.py +424 -0
- claude_mpm/services/cli/memory_crud_service.py +617 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/session_manager.py +513 -0
- claude_mpm/services/cli/socketio_manager.py +498 -0
- claude_mpm/services/cli/startup_checker.py +370 -0
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/cache_manager.py +311 -0
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/core/memory_manager.py +637 -0
- claude_mpm/services/core/path_resolver.py +498 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/METADATA +1 -1
- claude_mpm-4.1.3.dist-info/RECORD +528 -0
- claude_mpm/cli/commands/run_config_checker.py +0 -160
- claude_mpm-4.1.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
|
@@ -20,11 +20,10 @@ import json
|
|
|
20
20
|
import os
|
|
21
21
|
import signal
|
|
22
22
|
import subprocess
|
|
23
|
-
import sys
|
|
24
23
|
import threading
|
|
25
24
|
import time
|
|
26
25
|
from pathlib import Path
|
|
27
|
-
from typing import Any, Dict,
|
|
26
|
+
from typing import Any, Dict, Optional
|
|
28
27
|
|
|
29
28
|
from claude_mpm.config.paths import paths
|
|
30
29
|
from claude_mpm.core.logger import get_logger
|
|
@@ -33,14 +32,14 @@ from claude_mpm.core.logger import get_logger
|
|
|
33
32
|
class MCPProcessPool:
|
|
34
33
|
"""
|
|
35
34
|
Manages a pool of MCP server processes for efficient resource utilization.
|
|
36
|
-
|
|
35
|
+
|
|
37
36
|
WHY: Prevent multiple MCP server instances from being spawned and
|
|
38
37
|
reduce startup overhead by reusing existing processes.
|
|
39
38
|
"""
|
|
40
|
-
|
|
41
|
-
_instance: Optional[
|
|
39
|
+
|
|
40
|
+
_instance: Optional["MCPProcessPool"] = None
|
|
42
41
|
_lock = threading.Lock()
|
|
43
|
-
|
|
42
|
+
|
|
44
43
|
def __new__(cls):
|
|
45
44
|
"""Singleton pattern implementation."""
|
|
46
45
|
with cls._lock:
|
|
@@ -48,97 +47,105 @@ class MCPProcessPool:
|
|
|
48
47
|
cls._instance = super().__new__(cls)
|
|
49
48
|
cls._instance._initialized = False
|
|
50
49
|
return cls._instance
|
|
51
|
-
|
|
50
|
+
|
|
52
51
|
def __init__(self):
|
|
53
52
|
"""Initialize the process pool manager."""
|
|
54
53
|
if self._initialized:
|
|
55
54
|
return
|
|
56
|
-
|
|
55
|
+
|
|
57
56
|
self.logger = get_logger("MCPProcessPool")
|
|
58
57
|
self._initialized = True
|
|
59
|
-
|
|
58
|
+
|
|
60
59
|
# Process tracking
|
|
61
60
|
self._processes: Dict[str, subprocess.Popen] = {}
|
|
62
61
|
self._process_info: Dict[str, Dict] = {}
|
|
63
62
|
self._startup_times: Dict[str, float] = {}
|
|
64
|
-
|
|
63
|
+
|
|
65
64
|
# Configuration
|
|
66
65
|
self.max_processes = 3 # Maximum number of pooled processes
|
|
67
66
|
self.process_timeout = 300 # 5 minutes idle timeout
|
|
68
67
|
self.health_check_interval = 30 # Check process health every 30s
|
|
69
|
-
|
|
68
|
+
|
|
70
69
|
# Paths
|
|
71
70
|
self.pool_dir = paths.claude_mpm_dir_hidden / "mcp" / "pool"
|
|
72
71
|
self.pool_dir.mkdir(parents=True, exist_ok=True)
|
|
73
|
-
|
|
72
|
+
|
|
74
73
|
# Pre-warming flag
|
|
75
74
|
self._pre_warmed = False
|
|
76
|
-
|
|
75
|
+
|
|
77
76
|
# Background health check task
|
|
78
77
|
self._health_check_task: Optional[asyncio.Task] = None
|
|
79
|
-
|
|
78
|
+
|
|
80
79
|
# Setup cleanup handlers
|
|
81
80
|
self._setup_cleanup_handlers()
|
|
82
|
-
|
|
81
|
+
|
|
83
82
|
self.logger.info("MCP Process Pool initialized")
|
|
84
|
-
|
|
83
|
+
|
|
85
84
|
def _setup_cleanup_handlers(self):
|
|
86
85
|
"""Setup signal handlers for cleanup on termination."""
|
|
86
|
+
|
|
87
87
|
def cleanup_handler(signum, frame):
|
|
88
88
|
self.logger.info(f"Received signal {signum}, cleaning up process pool")
|
|
89
89
|
self.cleanup_all()
|
|
90
|
-
|
|
90
|
+
|
|
91
91
|
signal.signal(signal.SIGTERM, cleanup_handler)
|
|
92
92
|
signal.signal(signal.SIGINT, cleanup_handler)
|
|
93
|
-
|
|
94
|
-
def get_or_create_process(
|
|
93
|
+
|
|
94
|
+
def get_or_create_process(
|
|
95
|
+
self, server_name: str, config: Dict
|
|
96
|
+
) -> Optional[subprocess.Popen]:
|
|
95
97
|
"""
|
|
96
98
|
Get an existing process or create a new one for the given server.
|
|
97
|
-
|
|
99
|
+
|
|
98
100
|
Args:
|
|
99
101
|
server_name: Name of the MCP server
|
|
100
102
|
config: Server configuration including command and args
|
|
101
|
-
|
|
103
|
+
|
|
102
104
|
Returns:
|
|
103
105
|
Process handle or None if failed
|
|
104
106
|
"""
|
|
105
107
|
start_time = time.time()
|
|
106
|
-
|
|
108
|
+
|
|
107
109
|
# Check if we have a healthy existing process
|
|
108
110
|
if server_name in self._processes:
|
|
109
111
|
process = self._processes[server_name]
|
|
110
112
|
if self._is_process_healthy(process):
|
|
111
|
-
self.logger.info(
|
|
113
|
+
self.logger.info(
|
|
114
|
+
f"Reusing existing process for {server_name} (PID: {process.pid})"
|
|
115
|
+
)
|
|
112
116
|
return process
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
# Process is dead, clean it up
|
|
118
|
+
self.logger.warning(f"Process for {server_name} is dead, cleaning up")
|
|
119
|
+
self._cleanup_process(server_name)
|
|
120
|
+
|
|
118
121
|
# Check if we've hit the process limit
|
|
119
122
|
if len(self._processes) >= self.max_processes:
|
|
120
123
|
# Find and clean up the oldest idle process
|
|
121
124
|
self._cleanup_oldest_idle_process()
|
|
122
|
-
|
|
125
|
+
|
|
123
126
|
# Create new process
|
|
124
127
|
self.logger.info(f"Creating new process for {server_name}")
|
|
125
128
|
process = self._create_process(server_name, config)
|
|
126
|
-
|
|
129
|
+
|
|
127
130
|
if process:
|
|
128
131
|
create_time = time.time() - start_time
|
|
129
|
-
self.logger.info(
|
|
132
|
+
self.logger.info(
|
|
133
|
+
f"Process created for {server_name} in {create_time:.2f}s (PID: {process.pid})"
|
|
134
|
+
)
|
|
130
135
|
self._startup_times[server_name] = create_time
|
|
131
|
-
|
|
136
|
+
|
|
132
137
|
return process
|
|
133
|
-
|
|
134
|
-
def _create_process(
|
|
138
|
+
|
|
139
|
+
def _create_process(
|
|
140
|
+
self, server_name: str, config: Dict
|
|
141
|
+
) -> Optional[subprocess.Popen]:
|
|
135
142
|
"""
|
|
136
143
|
Create a new MCP server process.
|
|
137
|
-
|
|
144
|
+
|
|
138
145
|
Args:
|
|
139
146
|
server_name: Name of the MCP server
|
|
140
147
|
config: Server configuration
|
|
141
|
-
|
|
148
|
+
|
|
142
149
|
Returns:
|
|
143
150
|
Process handle or None if failed
|
|
144
151
|
"""
|
|
@@ -148,18 +155,18 @@ class MCPProcessPool:
|
|
|
148
155
|
args = config.get("args", [])
|
|
149
156
|
env = config.get("env", {})
|
|
150
157
|
cwd = config.get("cwd")
|
|
151
|
-
|
|
158
|
+
|
|
152
159
|
# Build full command
|
|
153
|
-
full_command = [command
|
|
154
|
-
|
|
160
|
+
full_command = [command, *args]
|
|
161
|
+
|
|
155
162
|
# Merge environment variables
|
|
156
163
|
process_env = os.environ.copy()
|
|
157
164
|
process_env.update(env)
|
|
158
|
-
|
|
165
|
+
|
|
159
166
|
# Add timing instrumentation
|
|
160
167
|
process_env["MCP_STARTUP_TRACKING"] = "1"
|
|
161
168
|
process_env["MCP_SERVER_NAME"] = server_name
|
|
162
|
-
|
|
169
|
+
|
|
163
170
|
# Start the process
|
|
164
171
|
process = subprocess.Popen(
|
|
165
172
|
full_command,
|
|
@@ -168,49 +175,49 @@ class MCPProcessPool:
|
|
|
168
175
|
stderr=subprocess.PIPE,
|
|
169
176
|
env=process_env,
|
|
170
177
|
cwd=cwd,
|
|
171
|
-
bufsize=0 # Unbuffered for real-time communication
|
|
178
|
+
bufsize=0, # Unbuffered for real-time communication
|
|
172
179
|
)
|
|
173
|
-
|
|
180
|
+
|
|
174
181
|
# Store process info
|
|
175
182
|
self._processes[server_name] = process
|
|
176
183
|
self._process_info[server_name] = {
|
|
177
184
|
"pid": process.pid,
|
|
178
185
|
"started_at": time.time(),
|
|
179
186
|
"last_used": time.time(),
|
|
180
|
-
"config": config
|
|
187
|
+
"config": config,
|
|
181
188
|
}
|
|
182
|
-
|
|
189
|
+
|
|
183
190
|
# Write process info to file for debugging
|
|
184
191
|
info_file = self.pool_dir / f"{server_name}_{process.pid}.json"
|
|
185
|
-
with open(info_file,
|
|
192
|
+
with open(info_file, "w") as f:
|
|
186
193
|
json.dump(self._process_info[server_name], f, indent=2)
|
|
187
|
-
|
|
194
|
+
|
|
188
195
|
return process
|
|
189
|
-
|
|
196
|
+
|
|
190
197
|
except Exception as e:
|
|
191
198
|
self.logger.error(f"Failed to create process for {server_name}: {e}")
|
|
192
199
|
return None
|
|
193
|
-
|
|
200
|
+
|
|
194
201
|
def _is_process_healthy(self, process: subprocess.Popen) -> bool:
|
|
195
202
|
"""Check if a process is still running and healthy."""
|
|
196
203
|
if process.poll() is not None:
|
|
197
204
|
# Process has terminated
|
|
198
205
|
return False
|
|
199
|
-
|
|
206
|
+
|
|
200
207
|
try:
|
|
201
208
|
# Send signal 0 to check if process is alive
|
|
202
209
|
os.kill(process.pid, 0)
|
|
203
210
|
return True
|
|
204
211
|
except (OSError, ProcessLookupError):
|
|
205
212
|
return False
|
|
206
|
-
|
|
213
|
+
|
|
207
214
|
def _cleanup_process(self, server_name: str):
|
|
208
215
|
"""Clean up a specific process."""
|
|
209
216
|
if server_name not in self._processes:
|
|
210
217
|
return
|
|
211
|
-
|
|
218
|
+
|
|
212
219
|
process = self._processes[server_name]
|
|
213
|
-
|
|
220
|
+
|
|
214
221
|
try:
|
|
215
222
|
# Try graceful shutdown first
|
|
216
223
|
if self._is_process_healthy(process):
|
|
@@ -221,50 +228,49 @@ class MCPProcessPool:
|
|
|
221
228
|
# Force kill if graceful shutdown fails
|
|
222
229
|
process.kill()
|
|
223
230
|
process.wait()
|
|
224
|
-
|
|
231
|
+
|
|
225
232
|
# Remove from tracking
|
|
226
233
|
del self._processes[server_name]
|
|
227
234
|
del self._process_info[server_name]
|
|
228
|
-
|
|
235
|
+
|
|
229
236
|
# Clean up info file
|
|
230
237
|
for info_file in self.pool_dir.glob(f"{server_name}_*.json"):
|
|
231
238
|
info_file.unlink()
|
|
232
|
-
|
|
239
|
+
|
|
233
240
|
self.logger.info(f"Cleaned up process for {server_name}")
|
|
234
|
-
|
|
241
|
+
|
|
235
242
|
except Exception as e:
|
|
236
243
|
self.logger.warning(f"Error cleaning up process for {server_name}: {e}")
|
|
237
|
-
|
|
244
|
+
|
|
238
245
|
def _cleanup_oldest_idle_process(self):
|
|
239
246
|
"""Find and clean up the oldest idle process."""
|
|
240
247
|
if not self._process_info:
|
|
241
248
|
return
|
|
242
|
-
|
|
249
|
+
|
|
243
250
|
# Find process with oldest last_used time
|
|
244
251
|
oldest_server = min(
|
|
245
252
|
self._process_info.keys(),
|
|
246
|
-
key=lambda k: self._process_info[k].get("last_used", 0)
|
|
253
|
+
key=lambda k: self._process_info[k].get("last_used", 0),
|
|
247
254
|
)
|
|
248
|
-
|
|
255
|
+
|
|
249
256
|
self.logger.info(f"Cleaning up oldest idle process: {oldest_server}")
|
|
250
257
|
self._cleanup_process(oldest_server)
|
|
251
|
-
|
|
258
|
+
|
|
252
259
|
async def pre_warm_servers(self, configs: Dict[str, Dict]):
|
|
253
260
|
"""
|
|
254
261
|
Pre-warm MCP servers during framework initialization.
|
|
255
|
-
|
|
262
|
+
|
|
256
263
|
Args:
|
|
257
264
|
configs: Dictionary of server configurations
|
|
258
265
|
"""
|
|
259
266
|
if self._pre_warmed:
|
|
260
267
|
self.logger.info("Servers already pre-warmed")
|
|
261
268
|
return
|
|
262
|
-
|
|
269
|
+
|
|
263
270
|
self.logger.info(f"Pre-warming {len(configs)} MCP servers")
|
|
264
271
|
start_time = time.time()
|
|
265
|
-
|
|
272
|
+
|
|
266
273
|
# Start all servers in parallel
|
|
267
|
-
tasks = []
|
|
268
274
|
for server_name, config in configs.items():
|
|
269
275
|
# Only pre-warm critical servers (like vector search)
|
|
270
276
|
if "vector" in server_name.lower() or config.get("pre_warm", False):
|
|
@@ -272,36 +278,36 @@ class MCPProcessPool:
|
|
|
272
278
|
process = self.get_or_create_process(server_name, config)
|
|
273
279
|
if process:
|
|
274
280
|
self.logger.info(f"Pre-warmed {server_name} (PID: {process.pid})")
|
|
275
|
-
|
|
281
|
+
|
|
276
282
|
self._pre_warmed = True
|
|
277
283
|
total_time = time.time() - start_time
|
|
278
284
|
self.logger.info(f"Pre-warming completed in {total_time:.2f}s")
|
|
279
|
-
|
|
285
|
+
|
|
280
286
|
async def start_health_monitoring(self):
|
|
281
287
|
"""Start background health monitoring of processes."""
|
|
282
288
|
if self._health_check_task and not self._health_check_task.done():
|
|
283
289
|
return
|
|
284
|
-
|
|
290
|
+
|
|
285
291
|
self._health_check_task = asyncio.create_task(self._health_check_loop())
|
|
286
292
|
self.logger.info("Started health monitoring")
|
|
287
|
-
|
|
293
|
+
|
|
288
294
|
async def _health_check_loop(self):
|
|
289
295
|
"""Background loop to check process health."""
|
|
290
296
|
while True:
|
|
291
297
|
try:
|
|
292
298
|
await asyncio.sleep(self.health_check_interval)
|
|
293
|
-
|
|
299
|
+
|
|
294
300
|
# Check each process
|
|
295
301
|
dead_processes = []
|
|
296
302
|
for server_name, process in self._processes.items():
|
|
297
303
|
if not self._is_process_healthy(process):
|
|
298
304
|
dead_processes.append(server_name)
|
|
299
|
-
|
|
305
|
+
|
|
300
306
|
# Clean up dead processes
|
|
301
307
|
for server_name in dead_processes:
|
|
302
308
|
self.logger.warning(f"Process {server_name} is dead, cleaning up")
|
|
303
309
|
self._cleanup_process(server_name)
|
|
304
|
-
|
|
310
|
+
|
|
305
311
|
# Check for idle timeout
|
|
306
312
|
current_time = time.time()
|
|
307
313
|
idle_processes = []
|
|
@@ -309,24 +315,24 @@ class MCPProcessPool:
|
|
|
309
315
|
last_used = info.get("last_used", current_time)
|
|
310
316
|
if current_time - last_used > self.process_timeout:
|
|
311
317
|
idle_processes.append(server_name)
|
|
312
|
-
|
|
318
|
+
|
|
313
319
|
# Clean up idle processes
|
|
314
320
|
for server_name in idle_processes:
|
|
315
321
|
self.logger.info(f"Process {server_name} idle timeout, cleaning up")
|
|
316
322
|
self._cleanup_process(server_name)
|
|
317
|
-
|
|
323
|
+
|
|
318
324
|
except Exception as e:
|
|
319
325
|
self.logger.error(f"Error in health check loop: {e}")
|
|
320
|
-
|
|
326
|
+
|
|
321
327
|
def mark_process_used(self, server_name: str):
|
|
322
328
|
"""Mark a process as recently used."""
|
|
323
329
|
if server_name in self._process_info:
|
|
324
330
|
self._process_info[server_name]["last_used"] = time.time()
|
|
325
|
-
|
|
331
|
+
|
|
326
332
|
def get_startup_metrics(self) -> Dict[str, float]:
|
|
327
333
|
"""Get startup time metrics for all servers."""
|
|
328
334
|
return self._startup_times.copy()
|
|
329
|
-
|
|
335
|
+
|
|
330
336
|
def get_pool_status(self) -> Dict[str, Any]:
|
|
331
337
|
"""Get current status of the process pool."""
|
|
332
338
|
return {
|
|
@@ -337,25 +343,25 @@ class MCPProcessPool:
|
|
|
337
343
|
name: {
|
|
338
344
|
"pid": info.get("pid"),
|
|
339
345
|
"uptime": time.time() - info.get("started_at", time.time()),
|
|
340
|
-
"idle_time": time.time() - info.get("last_used", time.time())
|
|
346
|
+
"idle_time": time.time() - info.get("last_used", time.time()),
|
|
341
347
|
}
|
|
342
348
|
for name, info in self._process_info.items()
|
|
343
349
|
},
|
|
344
|
-
"startup_metrics": self._startup_times
|
|
350
|
+
"startup_metrics": self._startup_times,
|
|
345
351
|
}
|
|
346
|
-
|
|
352
|
+
|
|
347
353
|
def cleanup_all(self):
|
|
348
354
|
"""Clean up all processes in the pool."""
|
|
349
355
|
self.logger.info("Cleaning up all processes in pool")
|
|
350
|
-
|
|
356
|
+
|
|
351
357
|
# Stop health monitoring
|
|
352
358
|
if self._health_check_task:
|
|
353
359
|
self._health_check_task.cancel()
|
|
354
|
-
|
|
360
|
+
|
|
355
361
|
# Clean up all processes
|
|
356
362
|
for server_name in list(self._processes.keys()):
|
|
357
363
|
self._cleanup_process(server_name)
|
|
358
|
-
|
|
364
|
+
|
|
359
365
|
self.logger.info("Process pool cleanup completed")
|
|
360
366
|
|
|
361
367
|
|
|
@@ -374,38 +380,38 @@ def get_process_pool() -> MCPProcessPool:
|
|
|
374
380
|
async def pre_warm_mcp_servers():
|
|
375
381
|
"""Pre-warm MCP servers from configuration."""
|
|
376
382
|
pool = get_process_pool()
|
|
377
|
-
|
|
383
|
+
|
|
378
384
|
# Load MCP configurations
|
|
379
385
|
configs = {}
|
|
380
|
-
|
|
386
|
+
|
|
381
387
|
# Check .claude.json for MCP server configs
|
|
382
388
|
claude_config_path = Path.home() / ".claude.json"
|
|
383
389
|
if not claude_config_path.exists():
|
|
384
390
|
# Try project-local config
|
|
385
391
|
claude_config_path = Path.cwd() / ".claude.json"
|
|
386
|
-
|
|
392
|
+
|
|
387
393
|
if claude_config_path.exists():
|
|
388
394
|
try:
|
|
389
|
-
with open(claude_config_path
|
|
395
|
+
with open(claude_config_path) as f:
|
|
390
396
|
config_data = json.load(f)
|
|
391
397
|
mcp_servers = config_data.get("mcpServers", {})
|
|
392
398
|
configs.update(mcp_servers)
|
|
393
399
|
except Exception as e:
|
|
394
400
|
get_logger("MCPProcessPool").warning(f"Failed to load Claude config: {e}")
|
|
395
|
-
|
|
401
|
+
|
|
396
402
|
# Check .mcp.json for additional configs
|
|
397
403
|
mcp_config_path = Path.cwd() / ".mcp.json"
|
|
398
404
|
if mcp_config_path.exists():
|
|
399
405
|
try:
|
|
400
|
-
with open(mcp_config_path
|
|
406
|
+
with open(mcp_config_path) as f:
|
|
401
407
|
config_data = json.load(f)
|
|
402
408
|
mcp_servers = config_data.get("mcpServers", {})
|
|
403
409
|
configs.update(mcp_servers)
|
|
404
410
|
except Exception as e:
|
|
405
411
|
get_logger("MCPProcessPool").warning(f"Failed to load MCP config: {e}")
|
|
406
|
-
|
|
412
|
+
|
|
407
413
|
if configs:
|
|
408
414
|
await pool.pre_warm_servers(configs)
|
|
409
415
|
await pool.start_health_monitoring()
|
|
410
|
-
|
|
411
|
-
return pool
|
|
416
|
+
|
|
417
|
+
return pool
|