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
|
@@ -24,6 +24,7 @@ import time
|
|
|
24
24
|
from collections import deque
|
|
25
25
|
from datetime import datetime
|
|
26
26
|
from pathlib import Path
|
|
27
|
+
from typing import Optional
|
|
27
28
|
|
|
28
29
|
# Add parent path for imports
|
|
29
30
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
|
@@ -31,6 +32,7 @@ sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
|
|
31
32
|
# Import EventBus
|
|
32
33
|
try:
|
|
33
34
|
from claude_mpm.services.event_bus import EventBus
|
|
35
|
+
|
|
34
36
|
EVENTBUS_AVAILABLE = True
|
|
35
37
|
except ImportError:
|
|
36
38
|
EVENTBUS_AVAILABLE = False
|
|
@@ -44,16 +46,23 @@ except ImportError:
|
|
|
44
46
|
class EventNormalizer:
|
|
45
47
|
def normalize(self, event_data, source="hook"):
|
|
46
48
|
"""Simple fallback normalizer that returns event as-is."""
|
|
47
|
-
return type(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
return type(
|
|
50
|
+
"NormalizedEvent",
|
|
51
|
+
(),
|
|
52
|
+
{
|
|
53
|
+
"to_dict": lambda: {
|
|
54
|
+
"event": "claude_event",
|
|
55
|
+
"type": event_data.get("type", "unknown"),
|
|
56
|
+
"subtype": event_data.get("subtype", "generic"),
|
|
57
|
+
"timestamp": event_data.get(
|
|
58
|
+
"timestamp", datetime.now().isoformat()
|
|
59
|
+
),
|
|
60
|
+
"data": event_data.get("data", event_data),
|
|
61
|
+
"source": source,
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
57
66
|
|
|
58
67
|
# Import constants for configuration
|
|
59
68
|
try:
|
|
@@ -63,16 +72,17 @@ except ImportError:
|
|
|
63
72
|
class TimeoutConfig:
|
|
64
73
|
QUICK_TIMEOUT = 2.0
|
|
65
74
|
|
|
75
|
+
|
|
66
76
|
# Import other handler modules
|
|
67
77
|
try:
|
|
78
|
+
from .event_handlers import EventHandlers
|
|
68
79
|
from .memory_integration import MemoryHookManager
|
|
69
80
|
from .response_tracking import ResponseTrackingManager
|
|
70
|
-
from .event_handlers import EventHandlers
|
|
71
81
|
except ImportError:
|
|
72
82
|
# Fallback for direct execution
|
|
83
|
+
from event_handlers import EventHandlers
|
|
73
84
|
from memory_integration import MemoryHookManager
|
|
74
85
|
from response_tracking import ResponseTrackingManager
|
|
75
|
-
from event_handlers import EventHandlers
|
|
76
86
|
|
|
77
87
|
# Debug mode is enabled by default for better visibility into hook processing
|
|
78
88
|
DEBUG = os.environ.get("CLAUDE_MPM_HOOK_DEBUG", "true").lower() != "false"
|
|
@@ -88,74 +98,77 @@ _events_lock = threading.Lock()
|
|
|
88
98
|
|
|
89
99
|
class HookHandler:
|
|
90
100
|
"""Main hook handler class using EventBus for event emission.
|
|
91
|
-
|
|
101
|
+
|
|
92
102
|
WHY EventBus integration:
|
|
93
103
|
- Replaces direct Socket.IO connections with EventBus publishing
|
|
94
104
|
- Events are published once and consumed by multiple listeners
|
|
95
105
|
- Failures in one consumer don't affect others
|
|
96
106
|
- Simplified testing without Socket.IO dependencies
|
|
97
107
|
"""
|
|
98
|
-
|
|
108
|
+
|
|
99
109
|
# Tracking dictionaries with size limits
|
|
100
110
|
MAX_DELEGATION_TRACKING = 100
|
|
101
111
|
MAX_PROMPT_TRACKING = 50
|
|
102
112
|
MAX_CACHE_AGE_SECONDS = 1800 # 30 minutes
|
|
103
|
-
|
|
113
|
+
|
|
104
114
|
def __init__(self):
|
|
105
115
|
"""Initialize the hook handler with EventBus."""
|
|
106
116
|
# Initialize EventBus if available
|
|
107
117
|
self.event_bus = EventBus.get_instance() if EVENTBUS_AVAILABLE else None
|
|
108
118
|
self.event_normalizer = EventNormalizer()
|
|
109
|
-
|
|
119
|
+
|
|
110
120
|
# Initialize tracking managers
|
|
111
121
|
self.memory_manager = MemoryHookManager()
|
|
112
122
|
self.response_tracker = ResponseTrackingManager()
|
|
113
123
|
self.event_handlers = EventHandlers(self)
|
|
114
|
-
|
|
124
|
+
|
|
115
125
|
# Delegation tracking
|
|
116
126
|
self.active_delegations = {}
|
|
117
127
|
self.delegation_requests = {}
|
|
118
128
|
self.delegation_history = deque(maxlen=20)
|
|
119
|
-
|
|
129
|
+
|
|
120
130
|
# Prompt tracking
|
|
121
131
|
self.pending_prompts = {}
|
|
122
|
-
|
|
132
|
+
|
|
123
133
|
# Git branch caching
|
|
124
134
|
self._git_branch_cache = {}
|
|
125
135
|
self._git_branch_cache_time = {}
|
|
126
|
-
|
|
136
|
+
|
|
127
137
|
# Session tracking
|
|
128
138
|
self.current_session_id = None
|
|
129
|
-
|
|
139
|
+
|
|
130
140
|
# Cleanup old entries periodically
|
|
131
141
|
self._last_cleanup = time.time()
|
|
132
|
-
|
|
142
|
+
|
|
133
143
|
if self.event_bus:
|
|
134
144
|
logger_msg = "HookHandler initialized with EventBus"
|
|
135
145
|
else:
|
|
136
146
|
logger_msg = "HookHandler initialized (EventBus not available)"
|
|
137
|
-
|
|
147
|
+
|
|
138
148
|
if DEBUG:
|
|
139
149
|
print(f"š {logger_msg}", file=sys.stderr)
|
|
140
|
-
|
|
150
|
+
|
|
141
151
|
def _emit_event(self, event_type: str, data: dict):
|
|
142
152
|
"""Emit an event through the EventBus.
|
|
143
|
-
|
|
153
|
+
|
|
144
154
|
WHY this approach:
|
|
145
155
|
- Single point of event emission
|
|
146
156
|
- Consistent event normalization
|
|
147
157
|
- Graceful fallback if EventBus unavailable
|
|
148
158
|
- Easy to add metrics and monitoring
|
|
149
|
-
|
|
159
|
+
|
|
150
160
|
Args:
|
|
151
161
|
event_type: The event type (e.g., 'pre_tool', 'subagent_stop')
|
|
152
162
|
data: The event data
|
|
153
163
|
"""
|
|
154
164
|
if not self.event_bus:
|
|
155
165
|
if DEBUG:
|
|
156
|
-
print(
|
|
166
|
+
print(
|
|
167
|
+
f"EventBus not available, cannot emit: hook.{event_type}",
|
|
168
|
+
file=sys.stderr,
|
|
169
|
+
)
|
|
157
170
|
return
|
|
158
|
-
|
|
171
|
+
|
|
159
172
|
try:
|
|
160
173
|
# Create event data for normalization
|
|
161
174
|
raw_event = {
|
|
@@ -164,86 +177,99 @@ class HookHandler:
|
|
|
164
177
|
"timestamp": datetime.now().isoformat(),
|
|
165
178
|
"data": data,
|
|
166
179
|
"source": "claude_hooks",
|
|
167
|
-
"session_id": data.get("sessionId", self.current_session_id)
|
|
180
|
+
"session_id": data.get("sessionId", self.current_session_id),
|
|
168
181
|
}
|
|
169
|
-
|
|
182
|
+
|
|
170
183
|
# Normalize the event
|
|
171
184
|
normalized_event = self.event_normalizer.normalize(raw_event, source="hook")
|
|
172
185
|
event_data = normalized_event.to_dict()
|
|
173
|
-
|
|
186
|
+
|
|
174
187
|
# Publish to EventBus
|
|
175
188
|
success = self.event_bus.publish(f"hook.{event_type}", event_data)
|
|
176
|
-
|
|
189
|
+
|
|
177
190
|
if DEBUG:
|
|
178
191
|
if success:
|
|
179
|
-
print(
|
|
192
|
+
print(
|
|
193
|
+
f"ā
Published to EventBus: hook.{event_type}", file=sys.stderr
|
|
194
|
+
)
|
|
180
195
|
else:
|
|
181
|
-
print(
|
|
182
|
-
|
|
196
|
+
print(
|
|
197
|
+
f"ā ļø EventBus rejected event: hook.{event_type}", file=sys.stderr
|
|
198
|
+
)
|
|
199
|
+
|
|
183
200
|
# Log important events
|
|
184
201
|
if DEBUG and event_type in ["subagent_stop", "pre_tool"]:
|
|
185
202
|
if event_type == "subagent_stop":
|
|
186
203
|
agent_type = data.get("agent_type", "unknown")
|
|
187
|
-
print(
|
|
204
|
+
print(
|
|
205
|
+
f"š¤ Published SubagentStop for agent '{agent_type}'",
|
|
206
|
+
file=sys.stderr,
|
|
207
|
+
)
|
|
188
208
|
elif event_type == "pre_tool" and data.get("tool_name") == "Task":
|
|
189
209
|
delegation = data.get("delegation_details", {})
|
|
190
210
|
agent_type = delegation.get("agent_type", "unknown")
|
|
191
|
-
print(
|
|
192
|
-
|
|
211
|
+
print(
|
|
212
|
+
f"š¤ Published Task delegation to agent '{agent_type}'",
|
|
213
|
+
file=sys.stderr,
|
|
214
|
+
)
|
|
215
|
+
|
|
193
216
|
except Exception as e:
|
|
194
217
|
if DEBUG:
|
|
195
|
-
print(
|
|
196
|
-
|
|
197
|
-
|
|
218
|
+
print(
|
|
219
|
+
f"ā Failed to publish event hook.{event_type}: {e}",
|
|
220
|
+
file=sys.stderr,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
def _get_git_branch(self, working_dir: Optional[str] = None) -> str:
|
|
198
224
|
"""Get git branch for the given directory with caching."""
|
|
199
225
|
# Use current working directory if not specified
|
|
200
226
|
if not working_dir:
|
|
201
227
|
working_dir = os.getcwd()
|
|
202
|
-
|
|
228
|
+
|
|
203
229
|
# Check cache first (cache for 30 seconds)
|
|
204
230
|
current_time = time.time()
|
|
205
231
|
cache_key = working_dir
|
|
206
|
-
|
|
232
|
+
|
|
207
233
|
if (
|
|
208
234
|
cache_key in self._git_branch_cache
|
|
209
235
|
and cache_key in self._git_branch_cache_time
|
|
210
236
|
and current_time - self._git_branch_cache_time[cache_key] < 30
|
|
211
237
|
):
|
|
212
238
|
return self._git_branch_cache[cache_key]
|
|
213
|
-
|
|
239
|
+
|
|
214
240
|
# Try to get git branch
|
|
215
241
|
try:
|
|
216
242
|
# Change to the working directory temporarily
|
|
217
243
|
original_cwd = os.getcwd()
|
|
218
244
|
os.chdir(working_dir)
|
|
219
|
-
|
|
245
|
+
|
|
220
246
|
# Run git command to get current branch
|
|
221
247
|
result = subprocess.run(
|
|
222
248
|
["git", "branch", "--show-current"],
|
|
223
249
|
capture_output=True,
|
|
224
250
|
text=True,
|
|
225
|
-
timeout=TimeoutConfig.QUICK_TIMEOUT
|
|
251
|
+
timeout=TimeoutConfig.QUICK_TIMEOUT,
|
|
252
|
+
check=False,
|
|
226
253
|
)
|
|
227
|
-
|
|
254
|
+
|
|
228
255
|
# Restore original directory
|
|
229
256
|
os.chdir(original_cwd)
|
|
230
|
-
|
|
257
|
+
|
|
231
258
|
if result.returncode == 0 and result.stdout.strip():
|
|
232
259
|
branch = result.stdout.strip()
|
|
233
260
|
# Cache the result
|
|
234
261
|
self._git_branch_cache[cache_key] = branch
|
|
235
262
|
self._git_branch_cache_time[cache_key] = current_time
|
|
236
263
|
return branch
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
264
|
+
return "unknown"
|
|
265
|
+
|
|
240
266
|
except Exception:
|
|
241
267
|
return "unknown"
|
|
242
|
-
|
|
268
|
+
|
|
243
269
|
def _cleanup_old_entries(self):
|
|
244
270
|
"""Clean up old entries to prevent memory growth."""
|
|
245
|
-
|
|
246
|
-
|
|
271
|
+
time.time() - self.MAX_CACHE_AGE_SECONDS
|
|
272
|
+
|
|
247
273
|
# Clean up delegation tracking dictionaries
|
|
248
274
|
for storage in [self.active_delegations, self.delegation_requests]:
|
|
249
275
|
if len(storage) > self.MAX_DELEGATION_TRACKING:
|
|
@@ -252,14 +278,14 @@ class HookHandler:
|
|
|
252
278
|
excess = len(storage) - self.MAX_DELEGATION_TRACKING
|
|
253
279
|
for key in sorted_keys[:excess]:
|
|
254
280
|
del storage[key]
|
|
255
|
-
|
|
281
|
+
|
|
256
282
|
# Clean up pending prompts
|
|
257
283
|
if len(self.pending_prompts) > self.MAX_PROMPT_TRACKING:
|
|
258
284
|
sorted_keys = sorted(self.pending_prompts.keys())
|
|
259
285
|
excess = len(self.pending_prompts) - self.MAX_PROMPT_TRACKING
|
|
260
286
|
for key in sorted_keys[:excess]:
|
|
261
287
|
del self.pending_prompts[key]
|
|
262
|
-
|
|
288
|
+
|
|
263
289
|
# Clean up git branch cache
|
|
264
290
|
expired_keys = [
|
|
265
291
|
key
|
|
@@ -269,10 +295,10 @@ class HookHandler:
|
|
|
269
295
|
for key in expired_keys:
|
|
270
296
|
self._git_branch_cache.pop(key, None)
|
|
271
297
|
self._git_branch_cache_time.pop(key, None)
|
|
272
|
-
|
|
298
|
+
|
|
273
299
|
def handle_event(self, event: dict):
|
|
274
300
|
"""Process an event from Claude Code.
|
|
275
|
-
|
|
301
|
+
|
|
276
302
|
Args:
|
|
277
303
|
event: The event dictionary from Claude
|
|
278
304
|
"""
|
|
@@ -281,24 +307,26 @@ class HookHandler:
|
|
|
281
307
|
if current_time - self._last_cleanup > 300: # Every 5 minutes
|
|
282
308
|
self._cleanup_old_entries()
|
|
283
309
|
self._last_cleanup = current_time
|
|
284
|
-
|
|
310
|
+
|
|
285
311
|
# Extract event details
|
|
286
312
|
event_type = event.get("type", "")
|
|
287
313
|
event_name = event.get("name", "")
|
|
288
|
-
|
|
314
|
+
|
|
289
315
|
# Update session ID if present
|
|
290
316
|
if "sessionId" in event:
|
|
291
317
|
self.current_session_id = event["sessionId"]
|
|
292
|
-
|
|
318
|
+
|
|
293
319
|
# Detect duplicate events
|
|
294
|
-
event_signature =
|
|
320
|
+
event_signature = (
|
|
321
|
+
f"{event_type}:{event_name}:{json.dumps(event.get('data', ''))[:100]}"
|
|
322
|
+
)
|
|
295
323
|
with _events_lock:
|
|
296
324
|
if event_signature in _recent_events:
|
|
297
325
|
if DEBUG:
|
|
298
326
|
print(f"Skipping duplicate event: {event_type}", file=sys.stderr)
|
|
299
327
|
return
|
|
300
328
|
_recent_events.append(event_signature)
|
|
301
|
-
|
|
329
|
+
|
|
302
330
|
# Route to appropriate handler
|
|
303
331
|
if event_type == "Start":
|
|
304
332
|
self.event_handlers.handle_start(event)
|
|
@@ -321,15 +349,14 @@ class HookHandler:
|
|
|
321
349
|
elif event_type == "PromptCachingBetaStats":
|
|
322
350
|
# Ignore caching stats events
|
|
323
351
|
pass
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
print(f"Unhandled event type: {event_type}", file=sys.stderr)
|
|
352
|
+
# Log unhandled events in debug mode
|
|
353
|
+
elif DEBUG:
|
|
354
|
+
print(f"Unhandled event type: {event_type}", file=sys.stderr)
|
|
328
355
|
|
|
329
356
|
|
|
330
357
|
def get_handler() -> HookHandler:
|
|
331
358
|
"""Get or create the global hook handler instance.
|
|
332
|
-
|
|
359
|
+
|
|
333
360
|
Returns:
|
|
334
361
|
HookHandler: The singleton handler instance
|
|
335
362
|
"""
|
|
@@ -345,18 +372,18 @@ def main():
|
|
|
345
372
|
"""Main entry point for the hook handler."""
|
|
346
373
|
if DEBUG:
|
|
347
374
|
print("šÆ EventBus Hook Handler starting...", file=sys.stderr)
|
|
348
|
-
|
|
375
|
+
|
|
349
376
|
handler = get_handler()
|
|
350
|
-
|
|
377
|
+
|
|
351
378
|
# Set up signal handling for clean shutdown
|
|
352
379
|
def signal_handler(signum, frame):
|
|
353
380
|
if DEBUG:
|
|
354
381
|
print("\nš Hook handler shutting down...", file=sys.stderr)
|
|
355
382
|
sys.exit(0)
|
|
356
|
-
|
|
383
|
+
|
|
357
384
|
signal.signal(signal.SIGINT, signal_handler)
|
|
358
385
|
signal.signal(signal.SIGTERM, signal_handler)
|
|
359
|
-
|
|
386
|
+
|
|
360
387
|
# Process events from stdin
|
|
361
388
|
try:
|
|
362
389
|
while True:
|
|
@@ -366,15 +393,15 @@ def main():
|
|
|
366
393
|
line = sys.stdin.readline()
|
|
367
394
|
if not line:
|
|
368
395
|
break
|
|
369
|
-
|
|
396
|
+
|
|
370
397
|
try:
|
|
371
398
|
event = json.loads(line.strip())
|
|
372
399
|
handler.handle_event(event)
|
|
373
|
-
|
|
400
|
+
|
|
374
401
|
# Acknowledge event
|
|
375
402
|
print(json.dumps({"status": "ok"}))
|
|
376
403
|
sys.stdout.flush()
|
|
377
|
-
|
|
404
|
+
|
|
378
405
|
except json.JSONDecodeError as e:
|
|
379
406
|
if DEBUG:
|
|
380
407
|
print(f"Invalid JSON: {e}", file=sys.stderr)
|
|
@@ -385,7 +412,7 @@ def main():
|
|
|
385
412
|
print(f"Error processing event: {e}", file=sys.stderr)
|
|
386
413
|
print(json.dumps({"status": "error", "message": str(e)}))
|
|
387
414
|
sys.stdout.flush()
|
|
388
|
-
|
|
415
|
+
|
|
389
416
|
except KeyboardInterrupt:
|
|
390
417
|
if DEBUG:
|
|
391
418
|
print("\nš Hook handler interrupted", file=sys.stderr)
|
|
@@ -395,4 +422,4 @@ def main():
|
|
|
395
422
|
|
|
396
423
|
|
|
397
424
|
if __name__ == "__main__":
|
|
398
|
-
main()
|
|
425
|
+
main()
|