claude-mpm 3.9.11__py3-none-any.whl → 4.0.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +2 -2
- claude_mpm/__main__.py +3 -2
- claude_mpm/agents/__init__.py +85 -79
- claude_mpm/agents/agent_loader.py +464 -1003
- claude_mpm/agents/agent_loader_integration.py +45 -45
- claude_mpm/agents/agents_metadata.py +29 -30
- claude_mpm/agents/async_agent_loader.py +156 -138
- claude_mpm/agents/base_agent.json +1 -1
- claude_mpm/agents/base_agent_loader.py +179 -151
- claude_mpm/agents/frontmatter_validator.py +229 -130
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +213 -147
- claude_mpm/agents/templates/__init__.py +13 -13
- claude_mpm/agents/templates/code_analyzer.json +2 -2
- claude_mpm/agents/templates/data_engineer.json +1 -1
- claude_mpm/agents/templates/documentation.json +23 -11
- claude_mpm/agents/templates/engineer.json +22 -6
- claude_mpm/agents/templates/memory_manager.json +1 -1
- claude_mpm/agents/templates/ops.json +2 -2
- claude_mpm/agents/templates/project_organizer.json +1 -1
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/refactoring_engineer.json +222 -0
- claude_mpm/agents/templates/research.json +20 -14
- claude_mpm/agents/templates/security.json +1 -1
- claude_mpm/agents/templates/ticketing.json +2 -2
- claude_mpm/agents/templates/version_control.json +1 -1
- claude_mpm/agents/templates/web_qa.json +3 -1
- claude_mpm/agents/templates/web_ui.json +2 -2
- claude_mpm/cli/__init__.py +79 -51
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +20 -20
- claude_mpm/cli/commands/agents.py +279 -247
- claude_mpm/cli/commands/aggregate.py +138 -157
- claude_mpm/cli/commands/cleanup.py +147 -147
- claude_mpm/cli/commands/config.py +93 -76
- claude_mpm/cli/commands/info.py +17 -16
- claude_mpm/cli/commands/mcp.py +140 -905
- claude_mpm/cli/commands/mcp_command_router.py +139 -0
- claude_mpm/cli/commands/mcp_config_commands.py +20 -0
- claude_mpm/cli/commands/mcp_install_commands.py +20 -0
- claude_mpm/cli/commands/mcp_server_commands.py +175 -0
- claude_mpm/cli/commands/mcp_tool_commands.py +34 -0
- claude_mpm/cli/commands/memory.py +239 -203
- claude_mpm/cli/commands/monitor.py +330 -86
- claude_mpm/cli/commands/run.py +380 -429
- claude_mpm/cli/commands/run_config_checker.py +160 -0
- claude_mpm/cli/commands/socketio_monitor.py +235 -0
- claude_mpm/cli/commands/tickets.py +363 -220
- claude_mpm/cli/parser.py +24 -1156
- claude_mpm/cli/parsers/__init__.py +29 -0
- claude_mpm/cli/parsers/agents_parser.py +136 -0
- claude_mpm/cli/parsers/base_parser.py +331 -0
- claude_mpm/cli/parsers/config_parser.py +85 -0
- claude_mpm/cli/parsers/mcp_parser.py +152 -0
- claude_mpm/cli/parsers/memory_parser.py +138 -0
- claude_mpm/cli/parsers/monitor_parser.py +124 -0
- claude_mpm/cli/parsers/run_parser.py +147 -0
- claude_mpm/cli/parsers/tickets_parser.py +203 -0
- claude_mpm/cli/ticket_cli.py +7 -3
- claude_mpm/cli/utils.py +55 -37
- claude_mpm/cli_module/__init__.py +6 -6
- claude_mpm/cli_module/args.py +188 -140
- claude_mpm/cli_module/commands.py +79 -70
- claude_mpm/cli_module/migration_example.py +38 -60
- claude_mpm/config/__init__.py +32 -25
- claude_mpm/config/agent_config.py +151 -119
- claude_mpm/config/experimental_features.py +71 -73
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +35 -18
- claude_mpm/core/__init__.py +9 -6
- claude_mpm/core/agent_name_normalizer.py +68 -71
- claude_mpm/core/agent_registry.py +372 -521
- claude_mpm/core/agent_session_manager.py +74 -63
- claude_mpm/core/base_service.py +116 -87
- claude_mpm/core/cache.py +119 -153
- claude_mpm/core/claude_runner.py +425 -1120
- claude_mpm/core/config.py +263 -168
- claude_mpm/core/config_aliases.py +69 -61
- claude_mpm/core/config_constants.py +292 -0
- claude_mpm/core/constants.py +57 -99
- claude_mpm/core/container.py +211 -178
- claude_mpm/core/exceptions.py +233 -89
- claude_mpm/core/factories.py +92 -54
- claude_mpm/core/framework_loader.py +378 -220
- claude_mpm/core/hook_manager.py +198 -83
- claude_mpm/core/hook_performance_config.py +136 -0
- claude_mpm/core/injectable_service.py +61 -55
- claude_mpm/core/interactive_session.py +165 -155
- claude_mpm/core/interfaces.py +221 -195
- claude_mpm/core/lazy.py +96 -96
- claude_mpm/core/logger.py +133 -107
- claude_mpm/core/logging_config.py +185 -157
- claude_mpm/core/minimal_framework_loader.py +20 -15
- claude_mpm/core/mixins.py +30 -29
- claude_mpm/core/oneshot_session.py +215 -181
- claude_mpm/core/optimized_agent_loader.py +134 -138
- claude_mpm/core/optimized_startup.py +159 -157
- claude_mpm/core/pm_hook_interceptor.py +85 -72
- claude_mpm/core/service_registry.py +103 -101
- claude_mpm/core/session_manager.py +97 -87
- claude_mpm/core/socketio_pool.py +212 -158
- claude_mpm/core/tool_access_control.py +58 -51
- claude_mpm/core/types.py +46 -24
- claude_mpm/core/typing_utils.py +166 -82
- claude_mpm/core/unified_agent_registry.py +721 -0
- claude_mpm/core/unified_config.py +550 -0
- claude_mpm/core/unified_paths.py +549 -0
- claude_mpm/dashboard/index.html +1 -1
- claude_mpm/dashboard/open_dashboard.py +51 -17
- claude_mpm/dashboard/static/built/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/built/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/built/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/built/dashboard.js +2 -0
- claude_mpm/dashboard/static/built/socket-client.js +2 -0
- claude_mpm/dashboard/static/css/dashboard.css +27 -8
- claude_mpm/dashboard/static/dist/components/agent-inference.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/export-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +2 -0
- claude_mpm/dashboard/static/dist/components/module-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/session-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +2 -0
- claude_mpm/dashboard/static/dist/components/working-directory.js +2 -0
- claude_mpm/dashboard/static/dist/dashboard.js +2 -0
- claude_mpm/dashboard/static/dist/socket-client.js +2 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +80 -76
- claude_mpm/dashboard/static/js/components/event-processor.js +71 -67
- claude_mpm/dashboard/static/js/components/event-viewer.js +93 -72
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +110 -96
- claude_mpm/dashboard/static/js/components/hud-library-loader.js +11 -11
- claude_mpm/dashboard/static/js/components/hud-manager.js +73 -73
- claude_mpm/dashboard/static/js/components/hud-visualizer.js +163 -163
- claude_mpm/dashboard/static/js/components/module-viewer.js +305 -233
- claude_mpm/dashboard/static/js/components/session-manager.js +32 -29
- claude_mpm/dashboard/static/js/components/socket-manager.js +27 -20
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +21 -18
- claude_mpm/dashboard/static/js/components/working-directory.js +74 -71
- claude_mpm/dashboard/static/js/dashboard.js +178 -453
- claude_mpm/dashboard/static/js/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/js/socket-client.js +133 -53
- claude_mpm/dashboard/templates/index.html +40 -50
- claude_mpm/experimental/cli_enhancements.py +60 -58
- claude_mpm/generators/__init__.py +1 -1
- claude_mpm/generators/agent_profile_generator.py +75 -65
- claude_mpm/hooks/__init__.py +1 -1
- claude_mpm/hooks/base_hook.py +33 -28
- claude_mpm/hooks/claude_hooks/__init__.py +1 -1
- claude_mpm/hooks/claude_hooks/connection_pool.py +120 -0
- claude_mpm/hooks/claude_hooks/event_handlers.py +743 -0
- claude_mpm/hooks/claude_hooks/hook_handler.py +415 -1331
- claude_mpm/hooks/claude_hooks/hook_wrapper.sh +4 -4
- claude_mpm/hooks/claude_hooks/memory_integration.py +221 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +348 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +230 -0
- claude_mpm/hooks/memory_integration_hook.py +140 -100
- claude_mpm/hooks/tool_call_interceptor.py +89 -76
- claude_mpm/hooks/validation_hooks.py +57 -49
- claude_mpm/init.py +145 -121
- claude_mpm/models/__init__.py +9 -9
- claude_mpm/models/agent_definition.py +33 -23
- claude_mpm/models/agent_session.py +228 -200
- claude_mpm/scripts/__init__.py +1 -1
- claude_mpm/scripts/socketio_daemon.py +192 -75
- claude_mpm/scripts/socketio_server_manager.py +328 -0
- claude_mpm/scripts/start_activity_logging.py +25 -22
- claude_mpm/services/__init__.py +68 -43
- claude_mpm/services/agent_capabilities_service.py +271 -0
- claude_mpm/services/agents/__init__.py +23 -32
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +310 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +359 -0
- claude_mpm/services/agents/deployment/agent_definition_factory.py +84 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +415 -2113
- claude_mpm/services/agents/deployment/agent_discovery_service.py +387 -0
- claude_mpm/services/agents/deployment/agent_environment_manager.py +293 -0
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +387 -0
- claude_mpm/services/agents/deployment/agent_format_converter.py +453 -0
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +161 -0
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +345 -495
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +279 -0
- claude_mpm/services/agents/deployment/agent_restore_handler.py +88 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +406 -0
- claude_mpm/services/agents/deployment/agent_validator.py +352 -0
- claude_mpm/services/agents/deployment/agent_version_manager.py +313 -0
- claude_mpm/services/agents/deployment/agent_versioning.py +6 -9
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +79 -0
- claude_mpm/services/agents/deployment/async_agent_deployment.py +298 -234
- claude_mpm/services/agents/deployment/config/__init__.py +13 -0
- claude_mpm/services/agents/deployment/config/deployment_config.py +182 -0
- claude_mpm/services/agents/deployment/config/deployment_config_manager.py +200 -0
- claude_mpm/services/agents/deployment/deployment_config_loader.py +54 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +124 -0
- claude_mpm/services/agents/deployment/facade/__init__.py +18 -0
- claude_mpm/services/agents/deployment/facade/async_deployment_executor.py +159 -0
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +73 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +270 -0
- claude_mpm/services/agents/deployment/facade/sync_deployment_executor.py +178 -0
- claude_mpm/services/agents/deployment/interface_adapter.py +227 -0
- claude_mpm/services/agents/deployment/lifecycle_health_checker.py +85 -0
- claude_mpm/services/agents/deployment/lifecycle_performance_tracker.py +100 -0
- claude_mpm/services/agents/deployment/pipeline/__init__.py +32 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +158 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +159 -0
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +169 -0
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +19 -0
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +195 -0
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +119 -0
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +79 -0
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +90 -0
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +100 -0
- claude_mpm/services/agents/deployment/processors/__init__.py +15 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_context.py +98 -0
- claude_mpm/services/agents/deployment/processors/agent_deployment_result.py +235 -0
- claude_mpm/services/agents/deployment/processors/agent_processor.py +258 -0
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +318 -0
- claude_mpm/services/agents/deployment/results/__init__.py +13 -0
- claude_mpm/services/agents/deployment/results/deployment_metrics.py +200 -0
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +249 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +25 -0
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +119 -0
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +150 -0
- claude_mpm/services/agents/deployment/strategies/strategy_selector.py +117 -0
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +116 -0
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +137 -0
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +108 -0
- claude_mpm/services/agents/deployment/validation/__init__.py +19 -0
- claude_mpm/services/agents/deployment/validation/agent_validator.py +323 -0
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +238 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +299 -0
- claude_mpm/services/agents/deployment/validation/validation_result.py +226 -0
- claude_mpm/services/agents/loading/__init__.py +2 -2
- claude_mpm/services/agents/loading/agent_profile_loader.py +259 -229
- claude_mpm/services/agents/loading/base_agent_manager.py +90 -81
- claude_mpm/services/agents/loading/framework_agent_loader.py +154 -129
- claude_mpm/services/agents/management/__init__.py +2 -2
- claude_mpm/services/agents/management/agent_capabilities_generator.py +72 -58
- claude_mpm/services/agents/management/agent_management_service.py +209 -156
- claude_mpm/services/agents/memory/__init__.py +9 -6
- claude_mpm/services/agents/memory/agent_memory_manager.py +218 -1152
- claude_mpm/services/agents/memory/agent_persistence_service.py +20 -16
- claude_mpm/services/agents/memory/analyzer.py +430 -0
- claude_mpm/services/agents/memory/content_manager.py +376 -0
- claude_mpm/services/agents/memory/template_generator.py +468 -0
- claude_mpm/services/agents/registry/__init__.py +7 -10
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +122 -97
- claude_mpm/services/agents/registry/modification_tracker.py +351 -285
- claude_mpm/services/async_session_logger.py +187 -153
- claude_mpm/services/claude_session_logger.py +87 -72
- claude_mpm/services/command_handler_service.py +217 -0
- claude_mpm/services/communication/__init__.py +3 -2
- claude_mpm/services/core/__init__.py +50 -97
- claude_mpm/services/core/base.py +60 -53
- claude_mpm/services/core/interfaces/__init__.py +188 -0
- claude_mpm/services/core/interfaces/agent.py +351 -0
- claude_mpm/services/core/interfaces/communication.py +343 -0
- claude_mpm/services/core/interfaces/infrastructure.py +413 -0
- claude_mpm/services/core/interfaces/service.py +434 -0
- claude_mpm/services/core/interfaces.py +19 -944
- claude_mpm/services/event_aggregator.py +208 -170
- claude_mpm/services/exceptions.py +387 -308
- claude_mpm/services/framework_claude_md_generator/__init__.py +75 -79
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +69 -60
- claude_mpm/services/framework_claude_md_generator/content_validator.py +65 -61
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +68 -49
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +34 -34
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +25 -22
- claude_mpm/services/framework_claude_md_generator/section_generators/claude_pm_init.py +10 -10
- claude_mpm/services/framework_claude_md_generator/section_generators/core_responsibilities.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/delegation_constraints.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/environment_config.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/footer.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/header.py +8 -7
- claude_mpm/services/framework_claude_md_generator/section_generators/orchestration_principles.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/role_designation.py +6 -5
- claude_mpm/services/framework_claude_md_generator/section_generators/subprocess_validation.py +9 -8
- claude_mpm/services/framework_claude_md_generator/section_generators/todo_task_tools.py +4 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/troubleshooting.py +5 -4
- claude_mpm/services/framework_claude_md_generator/section_manager.py +28 -27
- claude_mpm/services/framework_claude_md_generator/version_manager.py +30 -28
- claude_mpm/services/hook_service.py +106 -114
- claude_mpm/services/infrastructure/__init__.py +7 -5
- claude_mpm/services/infrastructure/context_preservation.py +233 -199
- claude_mpm/services/infrastructure/daemon_manager.py +279 -0
- claude_mpm/services/infrastructure/logging.py +83 -76
- claude_mpm/services/infrastructure/monitoring.py +547 -404
- claude_mpm/services/mcp_gateway/__init__.py +30 -13
- claude_mpm/services/mcp_gateway/config/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/config/config_loader.py +61 -56
- claude_mpm/services/mcp_gateway/config/config_schema.py +50 -41
- claude_mpm/services/mcp_gateway/config/configuration.py +82 -75
- claude_mpm/services/mcp_gateway/core/__init__.py +13 -20
- claude_mpm/services/mcp_gateway/core/base.py +80 -67
- claude_mpm/services/mcp_gateway/core/exceptions.py +60 -46
- claude_mpm/services/mcp_gateway/core/interfaces.py +87 -84
- claude_mpm/services/mcp_gateway/main.py +287 -137
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +97 -94
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +105 -110
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +105 -107
- claude_mpm/services/mcp_gateway/server/stdio_server.py +691 -0
- claude_mpm/services/mcp_gateway/tools/__init__.py +4 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +109 -119
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +283 -215
- claude_mpm/services/mcp_gateway/tools/hello_world.py +122 -120
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +652 -0
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +606 -0
- claude_mpm/services/memory/__init__.py +2 -2
- claude_mpm/services/memory/builder.py +451 -362
- claude_mpm/services/memory/cache/__init__.py +2 -2
- claude_mpm/services/memory/cache/shared_prompt_cache.py +232 -194
- claude_mpm/services/memory/cache/simple_cache.py +107 -93
- claude_mpm/services/memory/indexed_memory.py +195 -193
- claude_mpm/services/memory/optimizer.py +267 -234
- claude_mpm/services/memory/router.py +571 -263
- claude_mpm/services/memory_hook_service.py +237 -0
- claude_mpm/services/port_manager.py +575 -0
- claude_mpm/services/project/__init__.py +3 -3
- claude_mpm/services/project/analyzer.py +451 -305
- claude_mpm/services/project/registry.py +262 -240
- claude_mpm/services/recovery_manager.py +287 -231
- claude_mpm/services/response_tracker.py +87 -67
- claude_mpm/services/runner_configuration_service.py +587 -0
- claude_mpm/services/session_management_service.py +304 -0
- claude_mpm/services/socketio/__init__.py +4 -4
- claude_mpm/services/socketio/client_proxy.py +174 -0
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +44 -30
- claude_mpm/services/socketio/handlers/connection.py +166 -64
- claude_mpm/services/socketio/handlers/file.py +123 -108
- claude_mpm/services/socketio/handlers/git.py +607 -373
- claude_mpm/services/socketio/handlers/hook.py +185 -0
- claude_mpm/services/socketio/handlers/memory.py +4 -4
- claude_mpm/services/socketio/handlers/project.py +4 -4
- claude_mpm/services/socketio/handlers/registry.py +53 -38
- claude_mpm/services/socketio/server/__init__.py +18 -0
- claude_mpm/services/socketio/server/broadcaster.py +252 -0
- claude_mpm/services/socketio/server/core.py +399 -0
- claude_mpm/services/socketio/server/main.py +323 -0
- claude_mpm/services/socketio_client_manager.py +160 -133
- claude_mpm/services/socketio_server.py +36 -1885
- claude_mpm/services/subprocess_launcher_service.py +316 -0
- claude_mpm/services/system_instructions_service.py +258 -0
- claude_mpm/services/ticket_manager.py +19 -533
- claude_mpm/services/utility_service.py +285 -0
- claude_mpm/services/version_control/__init__.py +18 -21
- claude_mpm/services/version_control/branch_strategy.py +20 -10
- claude_mpm/services/version_control/conflict_resolution.py +37 -13
- claude_mpm/services/version_control/git_operations.py +52 -21
- claude_mpm/services/version_control/semantic_versioning.py +92 -53
- claude_mpm/services/version_control/version_parser.py +145 -125
- claude_mpm/services/version_service.py +270 -0
- claude_mpm/storage/__init__.py +2 -2
- claude_mpm/storage/state_storage.py +177 -181
- claude_mpm/ticket_wrapper.py +2 -2
- claude_mpm/utils/__init__.py +2 -2
- claude_mpm/utils/agent_dependency_loader.py +453 -243
- claude_mpm/utils/config_manager.py +157 -118
- claude_mpm/utils/console.py +1 -1
- claude_mpm/utils/dependency_cache.py +102 -107
- claude_mpm/utils/dependency_manager.py +52 -47
- claude_mpm/utils/dependency_strategies.py +131 -96
- claude_mpm/utils/environment_context.py +110 -102
- claude_mpm/utils/error_handler.py +75 -55
- claude_mpm/utils/file_utils.py +80 -67
- claude_mpm/utils/framework_detection.py +12 -11
- claude_mpm/utils/import_migration_example.py +12 -60
- claude_mpm/utils/imports.py +48 -45
- claude_mpm/utils/path_operations.py +100 -93
- claude_mpm/utils/robust_installer.py +172 -164
- claude_mpm/utils/session_logging.py +30 -23
- claude_mpm/utils/subprocess_utils.py +99 -61
- claude_mpm/validation/__init__.py +1 -1
- claude_mpm/validation/agent_validator.py +151 -111
- claude_mpm/validation/frontmatter_validator.py +92 -71
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/METADATA +90 -22
- claude_mpm-4.0.4.dist-info/RECORD +417 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/cli/commands/run_guarded.py +0 -511
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/config/memory_guardian_yaml.py +0 -335
- claude_mpm/core/config_paths.py +0 -150
- claude_mpm/core/memory_aware_runner.py +0 -353
- claude_mpm/dashboard/static/js/dashboard-original.js +0 -4134
- claude_mpm/deployment_paths.py +0 -261
- claude_mpm/hooks/claude_hooks/hook_handler_fixed.py +0 -454
- claude_mpm/models/state_models.py +0 -433
- claude_mpm/services/agent/__init__.py +0 -24
- claude_mpm/services/agent/deployment.py +0 -2548
- claude_mpm/services/agent/management.py +0 -598
- claude_mpm/services/agent/registry.py +0 -813
- claude_mpm/services/agents/registry/agent_registry.py +0 -813
- claude_mpm/services/communication/socketio.py +0 -1935
- claude_mpm/services/communication/websocket.py +0 -479
- claude_mpm/services/framework_claude_md_generator.py +0 -624
- claude_mpm/services/health_monitor.py +0 -893
- claude_mpm/services/infrastructure/graceful_degradation.py +0 -616
- claude_mpm/services/infrastructure/health_monitor.py +0 -775
- claude_mpm/services/infrastructure/memory_dashboard.py +0 -479
- claude_mpm/services/infrastructure/memory_guardian.py +0 -944
- claude_mpm/services/infrastructure/restart_protection.py +0 -642
- claude_mpm/services/infrastructure/state_manager.py +0 -774
- claude_mpm/services/mcp_gateway/manager.py +0 -334
- claude_mpm/services/optimized_hook_service.py +0 -542
- claude_mpm/services/project_analyzer.py +0 -864
- claude_mpm/services/project_registry.py +0 -608
- claude_mpm/services/standalone_socketio_server.py +0 -1300
- claude_mpm/services/ticket_manager_di.py +0 -318
- claude_mpm/services/ticketing_service_original.py +0 -510
- claude_mpm/utils/paths.py +0 -395
- claude_mpm/utils/platform_memory.py +0 -524
- claude_mpm-3.9.11.dist-info/RECORD +0 -306
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.11.dist-info → claude_mpm-4.0.4.dist-info}/top_level.txt +0 -0
    
        claude_mpm/core/hook_manager.py
    CHANGED
    
    | @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            from pathlib import Path
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            """Hook manager for manually triggering hook events in PM operations.
         | 
| 2 4 |  | 
| 3 5 | 
             
            This module provides a way for the PM agent to manually trigger hook events
         | 
| @@ -12,47 +14,147 @@ WHY this is needed: | |
| 12 14 |  | 
| 13 15 | 
             
            import json
         | 
| 14 16 | 
             
            import os
         | 
| 17 | 
            +
            import queue
         | 
| 15 18 | 
             
            import subprocess
         | 
| 19 | 
            +
            import threading
         | 
| 16 20 | 
             
            import uuid
         | 
| 17 21 | 
             
            from datetime import datetime
         | 
| 18 | 
            -
            from typing import  | 
| 19 | 
            -
            from pathlib import Path
         | 
| 22 | 
            +
            from typing import Any, Dict, Optional
         | 
| 20 23 |  | 
| 21 24 | 
             
            from ..core.logger import get_logger
         | 
| 22 | 
            -
            from  | 
| 25 | 
            +
            from .config_constants import ConfigConstants
         | 
| 26 | 
            +
            from .hook_performance_config import get_hook_performance_config
         | 
| 27 | 
            +
            from .unified_paths import get_package_root
         | 
| 23 28 |  | 
| 24 29 |  | 
| 25 30 | 
             
            class HookManager:
         | 
| 26 31 | 
             
                """Manager for manually triggering hook events from PM operations.
         | 
| 27 | 
            -
             | 
| 32 | 
            +
             | 
| 28 33 | 
             
                WHY this design:
         | 
| 29 34 | 
             
                - Mimics Claude Code's hook event structure exactly
         | 
| 30 35 | 
             
                - Uses the same hook handler that regular agents use
         | 
| 31 36 | 
             
                - Provides session tracking consistent with regular hook events
         | 
| 32 37 | 
             
                - Enables PM operations to appear in Socket.IO dashboard
         | 
| 33 38 | 
             
                """
         | 
| 34 | 
            -
             | 
| 39 | 
            +
             | 
| 35 40 | 
             
                def __init__(self):
         | 
| 36 41 | 
             
                    self.logger = get_logger("hook_manager")
         | 
| 37 42 | 
             
                    self.session_id = self._get_or_create_session_id()
         | 
| 38 43 | 
             
                    self.hook_handler_path = self._find_hook_handler()
         | 
| 39 | 
            -
             | 
| 44 | 
            +
             | 
| 45 | 
            +
                    # Initialize background hook processing for async execution
         | 
| 46 | 
            +
                    self.performance_config = get_hook_performance_config()
         | 
| 47 | 
            +
                    queue_config = self.performance_config.get_queue_config()
         | 
| 48 | 
            +
                    self.hook_queue = queue.Queue(maxsize=queue_config['maxsize'])
         | 
| 49 | 
            +
                    self.background_thread = None
         | 
| 50 | 
            +
                    self.shutdown_event = threading.Event()
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    # Start background processing if hook handler is available
         | 
| 53 | 
            +
                    if self.hook_handler_path:
         | 
| 54 | 
            +
                        self._start_background_processor()
         | 
| 55 | 
            +
                        self.logger.debug(f"Hook handler found with async processing: {self.hook_handler_path}")
         | 
| 56 | 
            +
                    else:
         | 
| 57 | 
            +
                        self.logger.debug("Hook handler not found - hooks will be skipped")
         | 
| 58 | 
            +
             | 
| 40 59 | 
             
                def _get_or_create_session_id(self) -> str:
         | 
| 41 60 | 
             
                    """Get or create a session ID for hook events."""
         | 
| 42 61 | 
             
                    # Try to get session ID from environment (set by ClaudeRunner)
         | 
| 43 | 
            -
                    session_id = os.environ.get( | 
| 62 | 
            +
                    session_id = os.environ.get("CLAUDE_MPM_SESSION_ID")
         | 
| 44 63 | 
             
                    if not session_id:
         | 
| 45 64 | 
             
                        # Generate new session ID
         | 
| 46 65 | 
             
                        session_id = str(uuid.uuid4())
         | 
| 47 | 
            -
                        os.environ[ | 
| 66 | 
            +
                        os.environ["CLAUDE_MPM_SESSION_ID"] = session_id
         | 
| 48 67 | 
             
                    return session_id
         | 
| 49 | 
            -
             | 
| 68 | 
            +
             | 
| 69 | 
            +
                def _start_background_processor(self):
         | 
| 70 | 
            +
                    """Start background thread to process hooks asynchronously."""
         | 
| 71 | 
            +
                    def process_hooks():
         | 
| 72 | 
            +
                        """Background thread function to process hook queue."""
         | 
| 73 | 
            +
                        while not self.shutdown_event.is_set():
         | 
| 74 | 
            +
                            try:
         | 
| 75 | 
            +
                                # Get hook data with timeout to allow shutdown checking
         | 
| 76 | 
            +
                                hook_data = self.hook_queue.get(timeout=1.0)
         | 
| 77 | 
            +
                                if hook_data is None:  # Shutdown signal
         | 
| 78 | 
            +
                                    break
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                                # Process the hook synchronously in background thread
         | 
| 81 | 
            +
                                self._execute_hook_sync(hook_data)
         | 
| 82 | 
            +
                                self.hook_queue.task_done()
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                            except queue.Empty:
         | 
| 85 | 
            +
                                # Timeout - continue to check shutdown event
         | 
| 86 | 
            +
                                continue
         | 
| 87 | 
            +
                            except Exception as e:
         | 
| 88 | 
            +
                                self.logger.error(f"Hook processing error: {e}")
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    self.background_thread = threading.Thread(
         | 
| 91 | 
            +
                        target=process_hooks,
         | 
| 92 | 
            +
                        name="hook-processor",
         | 
| 93 | 
            +
                        daemon=True
         | 
| 94 | 
            +
                    )
         | 
| 95 | 
            +
                    self.background_thread.start()
         | 
| 96 | 
            +
                    self.logger.debug("Started background hook processor thread")
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def _execute_hook_sync(self, hook_data: Dict[str, Any]):
         | 
| 99 | 
            +
                    """Execute a single hook synchronously in the background thread."""
         | 
| 100 | 
            +
                    try:
         | 
| 101 | 
            +
                        hook_type = hook_data['hook_type']
         | 
| 102 | 
            +
                        event_data = hook_data['event_data']
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                        # Create the hook event
         | 
| 105 | 
            +
                        hook_event = {
         | 
| 106 | 
            +
                            "hook_event_name": hook_type,
         | 
| 107 | 
            +
                            "session_id": self.session_id,
         | 
| 108 | 
            +
                            "timestamp": hook_data.get('timestamp', datetime.utcnow().isoformat()),
         | 
| 109 | 
            +
                            **event_data,
         | 
| 110 | 
            +
                        }
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                        event_json = json.dumps(hook_event)
         | 
| 113 | 
            +
                        env = os.environ.copy()
         | 
| 114 | 
            +
                        env["CLAUDE_MPM_HOOK_DEBUG"] = "true"
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                        # Execute with timeout in background thread
         | 
| 117 | 
            +
                        result = subprocess.run(
         | 
| 118 | 
            +
                            ["python", str(self.hook_handler_path)],
         | 
| 119 | 
            +
                            input=event_json,
         | 
| 120 | 
            +
                            text=True,
         | 
| 121 | 
            +
                            capture_output=True,
         | 
| 122 | 
            +
                            env=env,
         | 
| 123 | 
            +
                            timeout=self.performance_config.background_timeout,
         | 
| 124 | 
            +
                        )
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                        if result.returncode != 0:
         | 
| 127 | 
            +
                            self.logger.debug(f"Hook {hook_type} returned code {result.returncode}")
         | 
| 128 | 
            +
                            if result.stderr:
         | 
| 129 | 
            +
                                self.logger.debug(f"Hook stderr: {result.stderr}")
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                    except subprocess.TimeoutExpired:
         | 
| 132 | 
            +
                        self.logger.debug(f"Hook {hook_data.get('hook_type', 'unknown')} timed out in background")
         | 
| 133 | 
            +
                    except Exception as e:
         | 
| 134 | 
            +
                        self.logger.debug(f"Background hook execution error: {e}")
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                def shutdown(self):
         | 
| 137 | 
            +
                    """Shutdown the background hook processor."""
         | 
| 138 | 
            +
                    if self.background_thread and self.background_thread.is_alive():
         | 
| 139 | 
            +
                        self.shutdown_event.set()
         | 
| 140 | 
            +
                        # Signal shutdown by putting None in queue
         | 
| 141 | 
            +
                        try:
         | 
| 142 | 
            +
                            self.hook_queue.put_nowait(None)
         | 
| 143 | 
            +
                        except queue.Full:
         | 
| 144 | 
            +
                            pass
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                        # Wait for thread to finish
         | 
| 147 | 
            +
                        self.background_thread.join(timeout=2.0)
         | 
| 148 | 
            +
                        self.logger.debug("Background hook processor shutdown")
         | 
| 149 | 
            +
             | 
| 50 150 | 
             
                def _find_hook_handler(self) -> Optional[Path]:
         | 
| 51 151 | 
             
                    """Find the hook handler script."""
         | 
| 52 152 | 
             
                    try:
         | 
| 53 153 | 
             
                        # Look for hook handler in the expected location
         | 
| 54 | 
            -
                        hook_handler =  | 
| 55 | 
            -
             | 
| 154 | 
            +
                        hook_handler = (
         | 
| 155 | 
            +
                            get_package_root() / "hooks" / "claude_hooks" / "hook_handler.py"
         | 
| 156 | 
            +
                        )
         | 
| 157 | 
            +
             | 
| 56 158 | 
             
                        if hook_handler.exists():
         | 
| 57 159 | 
             
                            return hook_handler
         | 
| 58 160 | 
             
                        else:
         | 
| @@ -61,108 +163,105 @@ class HookManager: | |
| 61 163 | 
             
                    except Exception as e:
         | 
| 62 164 | 
             
                        self.logger.error(f"Error finding hook handler: {e}")
         | 
| 63 165 | 
             
                        return None
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                def trigger_pre_tool_hook( | 
| 166 | 
            +
             | 
| 167 | 
            +
                def trigger_pre_tool_hook(
         | 
| 168 | 
            +
                    self, tool_name: str, tool_args: Dict[str, Any] = None
         | 
| 169 | 
            +
                ) -> bool:
         | 
| 66 170 | 
             
                    """Trigger PreToolUse hook event.
         | 
| 67 | 
            -
             | 
| 171 | 
            +
             | 
| 68 172 | 
             
                    Args:
         | 
| 69 173 | 
             
                        tool_name: Name of the tool being used (e.g., "TodoWrite")
         | 
| 70 174 | 
             
                        tool_args: Arguments passed to the tool
         | 
| 71 | 
            -
             | 
| 175 | 
            +
             | 
| 72 176 | 
             
                    Returns:
         | 
| 73 177 | 
             
                        bool: True if hook was triggered successfully
         | 
| 74 178 | 
             
                    """
         | 
| 75 | 
            -
                    return self._trigger_hook_event( | 
| 76 | 
            -
                        " | 
| 77 | 
            -
                         | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 179 | 
            +
                    return self._trigger_hook_event(
         | 
| 180 | 
            +
                        "PreToolUse",
         | 
| 181 | 
            +
                        {
         | 
| 182 | 
            +
                            "tool_name": tool_name,
         | 
| 183 | 
            +
                            "tool_args": tool_args or {},
         | 
| 184 | 
            +
                            "timestamp": datetime.utcnow().isoformat(),
         | 
| 185 | 
            +
                        },
         | 
| 186 | 
            +
                    )
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                def trigger_post_tool_hook(
         | 
| 189 | 
            +
                    self, tool_name: str, exit_code: int = 0, result: Any = None
         | 
| 190 | 
            +
                ) -> bool:
         | 
| 82 191 | 
             
                    """Trigger PostToolUse hook event.
         | 
| 83 | 
            -
             | 
| 192 | 
            +
             | 
| 84 193 | 
             
                    Args:
         | 
| 85 194 | 
             
                        tool_name: Name of the tool that was used
         | 
| 86 195 | 
             
                        exit_code: Exit code (0 for success, non-zero for error)
         | 
| 87 196 | 
             
                        result: Result returned by the tool
         | 
| 88 | 
            -
             | 
| 197 | 
            +
             | 
| 89 198 | 
             
                    Returns:
         | 
| 90 199 | 
             
                        bool: True if hook was triggered successfully
         | 
| 91 200 | 
             
                    """
         | 
| 92 | 
            -
                    return self._trigger_hook_event( | 
| 93 | 
            -
                        " | 
| 94 | 
            -
                         | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 201 | 
            +
                    return self._trigger_hook_event(
         | 
| 202 | 
            +
                        "PostToolUse",
         | 
| 203 | 
            +
                        {
         | 
| 204 | 
            +
                            "tool_name": tool_name,
         | 
| 205 | 
            +
                            "exit_code": exit_code,
         | 
| 206 | 
            +
                            "result": str(result) if result is not None else None,
         | 
| 207 | 
            +
                            "timestamp": datetime.utcnow().isoformat(),
         | 
| 208 | 
            +
                        },
         | 
| 209 | 
            +
                    )
         | 
| 210 | 
            +
             | 
| 99 211 | 
             
                def trigger_user_prompt_hook(self, prompt: str) -> bool:
         | 
| 100 212 | 
             
                    """Trigger UserPromptSubmit hook event.
         | 
| 101 | 
            -
             | 
| 213 | 
            +
             | 
| 102 214 | 
             
                    Args:
         | 
| 103 215 | 
             
                        prompt: The user prompt
         | 
| 104 | 
            -
             | 
| 216 | 
            +
             | 
| 105 217 | 
             
                    Returns:
         | 
| 106 218 | 
             
                        bool: True if hook was triggered successfully
         | 
| 107 219 | 
             
                    """
         | 
| 108 | 
            -
                    return self._trigger_hook_event( | 
| 109 | 
            -
                        " | 
| 110 | 
            -
                        "timestamp": datetime.utcnow().isoformat()
         | 
| 111 | 
            -
                     | 
| 112 | 
            -
             | 
| 220 | 
            +
                    return self._trigger_hook_event(
         | 
| 221 | 
            +
                        "UserPromptSubmit",
         | 
| 222 | 
            +
                        {"prompt": prompt, "timestamp": datetime.utcnow().isoformat()},
         | 
| 223 | 
            +
                    )
         | 
| 224 | 
            +
             | 
| 113 225 | 
             
                def _trigger_hook_event(self, hook_type: str, event_data: Dict[str, Any]) -> bool:
         | 
| 114 | 
            -
                    """Trigger a hook event by  | 
| 115 | 
            -
             | 
| 226 | 
            +
                    """Trigger a hook event by queuing it for background processing.
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                    This method uses a background queue to process hooks asynchronously,
         | 
| 229 | 
            +
                    providing minimal overhead on the main execution thread.
         | 
| 230 | 
            +
             | 
| 116 231 | 
             
                    Args:
         | 
| 117 232 | 
             
                        hook_type: Type of hook event
         | 
| 118 233 | 
             
                        event_data: Event data
         | 
| 119 | 
            -
             | 
| 234 | 
            +
             | 
| 120 235 | 
             
                    Returns:
         | 
| 121 | 
            -
                        bool: True if hook was  | 
| 236 | 
            +
                        bool: True if hook was queued successfully (not execution success)
         | 
| 122 237 | 
             
                    """
         | 
| 123 238 | 
             
                    if not self.hook_handler_path:
         | 
| 124 239 | 
             
                        self.logger.debug("Hook handler not available - skipping hook event")
         | 
| 125 240 | 
             
                        return False
         | 
| 126 | 
            -
             | 
| 241 | 
            +
             | 
| 242 | 
            +
                    # Check if this hook type is enabled
         | 
| 243 | 
            +
                    if not self.performance_config.is_hook_enabled(hook_type):
         | 
| 244 | 
            +
                        self.logger.debug(f"Hook type {hook_type} disabled by configuration")
         | 
| 245 | 
            +
                        return True
         | 
| 246 | 
            +
             | 
| 127 247 | 
             
                    try:
         | 
| 128 | 
            -
                        #  | 
| 129 | 
            -
                         | 
| 130 | 
            -
                             | 
| 131 | 
            -
                             | 
| 132 | 
            -
                             | 
| 133 | 
            -
                            **event_data
         | 
| 248 | 
            +
                        # Queue hook for background processing
         | 
| 249 | 
            +
                        hook_data = {
         | 
| 250 | 
            +
                            'hook_type': hook_type,
         | 
| 251 | 
            +
                            'event_data': event_data,
         | 
| 252 | 
            +
                            'timestamp': datetime.utcnow().isoformat()
         | 
| 134 253 | 
             
                        }
         | 
| 135 | 
            -
             | 
| 136 | 
            -
                        #  | 
| 137 | 
            -
                         | 
| 138 | 
            -
                        
         | 
| 139 | 
            -
                         | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
                        
         | 
| 143 | 
            -
                        result = subprocess.run(
         | 
| 144 | 
            -
                            ["python", str(self.hook_handler_path)],
         | 
| 145 | 
            -
                            input=event_json,
         | 
| 146 | 
            -
                            text=True,
         | 
| 147 | 
            -
                            capture_output=True,
         | 
| 148 | 
            -
                            env=env,
         | 
| 149 | 
            -
                            timeout=5  # 5 second timeout to prevent hanging
         | 
| 150 | 
            -
                        )
         | 
| 151 | 
            -
                        
         | 
| 152 | 
            -
                        if result.returncode == 0:
         | 
| 153 | 
            -
                            self.logger.debug(f"Successfully triggered {hook_type} hook")
         | 
| 154 | 
            -
                            return True
         | 
| 155 | 
            -
                        else:
         | 
| 156 | 
            -
                            self.logger.warning(f"Hook handler returned non-zero exit code: {result.returncode}")
         | 
| 157 | 
            -
                            if result.stderr:
         | 
| 158 | 
            -
                                self.logger.warning(f"Hook handler stderr: {result.stderr}")
         | 
| 159 | 
            -
                            return False
         | 
| 160 | 
            -
                            
         | 
| 161 | 
            -
                    except subprocess.TimeoutExpired:
         | 
| 162 | 
            -
                        self.logger.warning(f"Hook handler timed out for {hook_type}")
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                        # Try to queue without blocking
         | 
| 256 | 
            +
                        self.hook_queue.put_nowait(hook_data)
         | 
| 257 | 
            +
                        self.logger.debug(f"Successfully queued {hook_type} hook for background processing")
         | 
| 258 | 
            +
                        return True
         | 
| 259 | 
            +
             | 
| 260 | 
            +
                    except queue.Full:
         | 
| 261 | 
            +
                        self.logger.warning(f"Hook queue full, dropping {hook_type} event")
         | 
| 163 262 | 
             
                        return False
         | 
| 164 263 | 
             
                    except Exception as e:
         | 
| 165 | 
            -
                        self.logger.error(f"Error  | 
| 264 | 
            +
                        self.logger.error(f"Error queuing {hook_type} hook: {e}")
         | 
| 166 265 | 
             
                        return False
         | 
| 167 266 |  | 
| 168 267 |  | 
| @@ -175,12 +274,28 @@ def get_hook_manager() -> HookManager: | |
| 175 274 | 
             
                global _hook_manager
         | 
| 176 275 | 
             
                if _hook_manager is None:
         | 
| 177 276 | 
             
                    _hook_manager = HookManager()
         | 
| 277 | 
            +
                    # Register cleanup on exit
         | 
| 278 | 
            +
                    import atexit
         | 
| 279 | 
            +
                    atexit.register(_cleanup_hook_manager)
         | 
| 178 280 | 
             
                return _hook_manager
         | 
| 179 281 |  | 
| 180 282 |  | 
| 181 | 
            -
            def  | 
| 283 | 
            +
            def _cleanup_hook_manager():
         | 
| 284 | 
            +
                """Cleanup function to shutdown hook manager on exit."""
         | 
| 285 | 
            +
                global _hook_manager
         | 
| 286 | 
            +
                if _hook_manager is not None:
         | 
| 287 | 
            +
                    _hook_manager.shutdown()
         | 
| 288 | 
            +
                    _hook_manager = None
         | 
| 289 | 
            +
             | 
| 290 | 
            +
             | 
| 291 | 
            +
            def trigger_tool_hooks(
         | 
| 292 | 
            +
                tool_name: str,
         | 
| 293 | 
            +
                tool_args: Dict[str, Any] = None,
         | 
| 294 | 
            +
                result: Any = None,
         | 
| 295 | 
            +
                exit_code: int = 0,
         | 
| 296 | 
            +
            ):
         | 
| 182 297 | 
             
                """Convenience function to trigger both pre and post tool hooks.
         | 
| 183 | 
            -
             | 
| 298 | 
            +
             | 
| 184 299 | 
             
                Args:
         | 
| 185 300 | 
             
                    tool_name: Name of the tool
         | 
| 186 301 | 
             
                    tool_args: Arguments passed to the tool
         | 
| @@ -188,9 +303,9 @@ def trigger_tool_hooks(tool_name: str, tool_args: Dict[str, Any] = None, result: | |
| 188 303 | 
             
                    exit_code: Exit code (0 for success)
         | 
| 189 304 | 
             
                """
         | 
| 190 305 | 
             
                manager = get_hook_manager()
         | 
| 191 | 
            -
             | 
| 306 | 
            +
             | 
| 192 307 | 
             
                # Trigger pre-tool hook
         | 
| 193 308 | 
             
                manager.trigger_pre_tool_hook(tool_name, tool_args)
         | 
| 194 | 
            -
             | 
| 309 | 
            +
             | 
| 195 310 | 
             
                # Trigger post-tool hook
         | 
| 196 | 
            -
                manager.trigger_post_tool_hook(tool_name, exit_code, result)
         | 
| 311 | 
            +
                manager.trigger_post_tool_hook(tool_name, exit_code, result)
         | 
| @@ -0,0 +1,136 @@ | |
| 1 | 
            +
            """Hook performance configuration for Claude MPM.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This module provides configuration options to optimize hook performance
         | 
| 4 | 
            +
            and enable/disable hooks based on performance requirements.
         | 
| 5 | 
            +
            """
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            import os
         | 
| 8 | 
            +
            from typing import Dict, Optional
         | 
| 9 | 
            +
             | 
| 10 | 
            +
             | 
| 11 | 
            +
            class HookPerformanceConfig:
         | 
| 12 | 
            +
                """Configuration for hook performance optimization."""
         | 
| 13 | 
            +
                
         | 
| 14 | 
            +
                def __init__(self):
         | 
| 15 | 
            +
                    """Initialize hook performance configuration from environment."""
         | 
| 16 | 
            +
                    self._load_config()
         | 
| 17 | 
            +
                
         | 
| 18 | 
            +
                def _load_config(self):
         | 
| 19 | 
            +
                    """Load configuration from environment variables."""
         | 
| 20 | 
            +
                    # Performance mode - disables all hooks for maximum speed
         | 
| 21 | 
            +
                    self.performance_mode = os.getenv('CLAUDE_MPM_PERFORMANCE_MODE', 'false').lower() == 'true'
         | 
| 22 | 
            +
                    
         | 
| 23 | 
            +
                    # Individual hook type controls
         | 
| 24 | 
            +
                    self.enable_pre_tool_hooks = os.getenv('CLAUDE_MPM_HOOKS_PRE_TOOL', 'true').lower() == 'true'
         | 
| 25 | 
            +
                    self.enable_post_tool_hooks = os.getenv('CLAUDE_MPM_HOOKS_POST_TOOL', 'true').lower() == 'true'
         | 
| 26 | 
            +
                    self.enable_user_prompt_hooks = os.getenv('CLAUDE_MPM_HOOKS_USER_PROMPT', 'true').lower() == 'true'
         | 
| 27 | 
            +
                    self.enable_delegation_hooks = os.getenv('CLAUDE_MPM_HOOKS_DELEGATION', 'true').lower() == 'true'
         | 
| 28 | 
            +
                    
         | 
| 29 | 
            +
                    # Background processing settings
         | 
| 30 | 
            +
                    self.queue_size = int(os.getenv('CLAUDE_MPM_HOOK_QUEUE_SIZE', '1000'))
         | 
| 31 | 
            +
                    self.background_timeout = float(os.getenv('CLAUDE_MPM_HOOK_BG_TIMEOUT', '2.0'))
         | 
| 32 | 
            +
                    
         | 
| 33 | 
            +
                    # Batching settings (for future implementation)
         | 
| 34 | 
            +
                    self.enable_batching = os.getenv('CLAUDE_MPM_HOOK_BATCHING', 'false').lower() == 'true'
         | 
| 35 | 
            +
                    self.batch_size = int(os.getenv('CLAUDE_MPM_HOOK_BATCH_SIZE', '10'))
         | 
| 36 | 
            +
                    self.batch_timeout_ms = int(os.getenv('CLAUDE_MPM_HOOK_BATCH_TIMEOUT_MS', '100'))
         | 
| 37 | 
            +
                
         | 
| 38 | 
            +
                def is_hook_enabled(self, hook_type: str) -> bool:
         | 
| 39 | 
            +
                    """Check if a specific hook type is enabled.
         | 
| 40 | 
            +
                    
         | 
| 41 | 
            +
                    Args:
         | 
| 42 | 
            +
                        hook_type: Type of hook (PreToolUse, PostToolUse, UserPromptSubmit, etc.)
         | 
| 43 | 
            +
                        
         | 
| 44 | 
            +
                    Returns:
         | 
| 45 | 
            +
                        bool: True if hook should be processed
         | 
| 46 | 
            +
                    """
         | 
| 47 | 
            +
                    if self.performance_mode:
         | 
| 48 | 
            +
                        return False
         | 
| 49 | 
            +
                    
         | 
| 50 | 
            +
                    hook_type_lower = hook_type.lower()
         | 
| 51 | 
            +
                    
         | 
| 52 | 
            +
                    if 'pretool' in hook_type_lower or 'pre_tool' in hook_type_lower:
         | 
| 53 | 
            +
                        return self.enable_pre_tool_hooks
         | 
| 54 | 
            +
                    elif 'posttool' in hook_type_lower or 'post_tool' in hook_type_lower:
         | 
| 55 | 
            +
                        return self.enable_post_tool_hooks
         | 
| 56 | 
            +
                    elif 'userprompt' in hook_type_lower or 'user_prompt' in hook_type_lower:
         | 
| 57 | 
            +
                        return self.enable_user_prompt_hooks
         | 
| 58 | 
            +
                    elif 'delegation' in hook_type_lower:
         | 
| 59 | 
            +
                        return self.enable_delegation_hooks
         | 
| 60 | 
            +
                    
         | 
| 61 | 
            +
                    # Default to enabled for unknown hook types
         | 
| 62 | 
            +
                    return True
         | 
| 63 | 
            +
                
         | 
| 64 | 
            +
                def get_queue_config(self) -> Dict[str, int]:
         | 
| 65 | 
            +
                    """Get queue configuration for background processing."""
         | 
| 66 | 
            +
                    return {
         | 
| 67 | 
            +
                        'maxsize': self.queue_size,
         | 
| 68 | 
            +
                        'timeout': self.background_timeout
         | 
| 69 | 
            +
                    }
         | 
| 70 | 
            +
                
         | 
| 71 | 
            +
                def get_batch_config(self) -> Dict[str, any]:
         | 
| 72 | 
            +
                    """Get batching configuration (for future use)."""
         | 
| 73 | 
            +
                    return {
         | 
| 74 | 
            +
                        'enabled': self.enable_batching,
         | 
| 75 | 
            +
                        'batch_size': self.batch_size,
         | 
| 76 | 
            +
                        'timeout_ms': self.batch_timeout_ms
         | 
| 77 | 
            +
                    }
         | 
| 78 | 
            +
                
         | 
| 79 | 
            +
                def print_config(self) -> str:
         | 
| 80 | 
            +
                    """Return a string representation of current configuration."""
         | 
| 81 | 
            +
                    config_lines = [
         | 
| 82 | 
            +
                        "Hook Performance Configuration:",
         | 
| 83 | 
            +
                        f"  Performance Mode: {self.performance_mode}",
         | 
| 84 | 
            +
                        f"  Pre-tool Hooks: {self.enable_pre_tool_hooks}",
         | 
| 85 | 
            +
                        f"  Post-tool Hooks: {self.enable_post_tool_hooks}",
         | 
| 86 | 
            +
                        f"  User Prompt Hooks: {self.enable_user_prompt_hooks}",
         | 
| 87 | 
            +
                        f"  Delegation Hooks: {self.enable_delegation_hooks}",
         | 
| 88 | 
            +
                        f"  Queue Size: {self.queue_size}",
         | 
| 89 | 
            +
                        f"  Background Timeout: {self.background_timeout}s",
         | 
| 90 | 
            +
                        f"  Batching Enabled: {self.enable_batching}",
         | 
| 91 | 
            +
                    ]
         | 
| 92 | 
            +
                    return "\n".join(config_lines)
         | 
| 93 | 
            +
             | 
| 94 | 
            +
             | 
| 95 | 
            +
            # Global configuration instance
         | 
| 96 | 
            +
            _hook_config: Optional[HookPerformanceConfig] = None
         | 
| 97 | 
            +
             | 
| 98 | 
            +
             | 
| 99 | 
            +
            def get_hook_performance_config() -> HookPerformanceConfig:
         | 
| 100 | 
            +
                """Get the global hook performance configuration instance."""
         | 
| 101 | 
            +
                global _hook_config
         | 
| 102 | 
            +
                if _hook_config is None:
         | 
| 103 | 
            +
                    _hook_config = HookPerformanceConfig()
         | 
| 104 | 
            +
                return _hook_config
         | 
| 105 | 
            +
             | 
| 106 | 
            +
             | 
| 107 | 
            +
            def set_performance_mode(enabled: bool):
         | 
| 108 | 
            +
                """Enable or disable performance mode programmatically.
         | 
| 109 | 
            +
                
         | 
| 110 | 
            +
                Args:
         | 
| 111 | 
            +
                    enabled: True to enable performance mode (disable all hooks)
         | 
| 112 | 
            +
                """
         | 
| 113 | 
            +
                os.environ['CLAUDE_MPM_PERFORMANCE_MODE'] = 'true' if enabled else 'false'
         | 
| 114 | 
            +
                # Reload configuration
         | 
| 115 | 
            +
                global _hook_config
         | 
| 116 | 
            +
                _hook_config = None
         | 
| 117 | 
            +
             | 
| 118 | 
            +
             | 
| 119 | 
            +
            def is_performance_mode() -> bool:
         | 
| 120 | 
            +
                """Check if performance mode is currently enabled."""
         | 
| 121 | 
            +
                return get_hook_performance_config().performance_mode
         | 
| 122 | 
            +
             | 
| 123 | 
            +
             | 
| 124 | 
            +
            # Environment variable documentation for users
         | 
| 125 | 
            +
            ENVIRONMENT_VARIABLES = {
         | 
| 126 | 
            +
                'CLAUDE_MPM_PERFORMANCE_MODE': 'Set to "true" to disable all hooks for maximum performance',
         | 
| 127 | 
            +
                'CLAUDE_MPM_HOOKS_PRE_TOOL': 'Set to "false" to disable pre-tool hooks',
         | 
| 128 | 
            +
                'CLAUDE_MPM_HOOKS_POST_TOOL': 'Set to "false" to disable post-tool hooks',
         | 
| 129 | 
            +
                'CLAUDE_MPM_HOOKS_USER_PROMPT': 'Set to "false" to disable user prompt hooks',
         | 
| 130 | 
            +
                'CLAUDE_MPM_HOOKS_DELEGATION': 'Set to "false" to disable delegation hooks',
         | 
| 131 | 
            +
                'CLAUDE_MPM_HOOK_QUEUE_SIZE': 'Maximum number of hooks in background queue (default: 1000)',
         | 
| 132 | 
            +
                'CLAUDE_MPM_HOOK_BG_TIMEOUT': 'Timeout for background hook processing in seconds (default: 2.0)',
         | 
| 133 | 
            +
                'CLAUDE_MPM_HOOK_BATCHING': 'Set to "true" to enable hook batching (experimental)',
         | 
| 134 | 
            +
                'CLAUDE_MPM_HOOK_BATCH_SIZE': 'Number of hooks to batch together (default: 10)',
         | 
| 135 | 
            +
                'CLAUDE_MPM_HOOK_BATCH_TIMEOUT_MS': 'Batch timeout in milliseconds (default: 100)',
         | 
| 136 | 
            +
            }
         |