claude-mpm 3.9.9__py3-none-any.whl → 4.0.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/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 +155 -0
- 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 +1 -1
- 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 +90 -49
- claude_mpm/cli/__main__.py +3 -2
- claude_mpm/cli/commands/__init__.py +21 -18
- 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 +143 -762
- 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 +203 -81
- 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 +305 -197
- claude_mpm/cli/parser.py +24 -1150
- 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 +104 -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 +217 -0
- claude_mpm/config/paths.py +94 -208
- claude_mpm/config/socketio_config.py +84 -73
- claude_mpm/constants.py +36 -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/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 +74 -70
- claude_mpm/dashboard/static/js/components/export-manager.js +31 -28
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +106 -92
- 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 +120 -54
- 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 +571 -0
- 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 +40 -23
- 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 +14 -21
- 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 +97 -93
- claude_mpm/services/mcp_gateway/main.py +307 -127
- claude_mpm/services/mcp_gateway/registry/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +100 -101
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +135 -126
- claude_mpm/services/mcp_gateway/server/__init__.py +4 -4
- claude_mpm/services/mcp_gateway/server/{mcp_server.py → mcp_gateway.py} +149 -153
- 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 +110 -121
- 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 +223 -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 +145 -65
- 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 +170 -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 +20 -534
- 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 +9 -0
- claude_mpm/storage/state_storage.py +552 -0
- 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.9.dist-info → claude_mpm-4.0.3.dist-info}/METADATA +51 -2
- claude_mpm-4.0.3.dist-info/RECORD +402 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/entry_points.txt +1 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/licenses/LICENSE +1 -1
- claude_mpm/config/memory_guardian_config.py +0 -325
- claude_mpm/core/config_paths.py +0 -150
- 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/memory_guardian.py +0 -770
- claude_mpm/services/mcp_gateway/server/mcp_server_simple.py +0 -444
- 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.9.dist-info/RECORD +0 -293
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/WHEEL +0 -0
- {claude_mpm-3.9.9.dist-info → claude_mpm-4.0.3.dist-info}/top_level.txt +0 -0
| @@ -12,147 +12,160 @@ WHY this is needed: | |
| 12 12 | 
             
            """
         | 
| 13 13 |  | 
| 14 14 | 
             
            import functools
         | 
| 15 | 
            -
            import json
         | 
| 16 15 | 
             
            import os
         | 
| 17 16 | 
             
            import threading
         | 
| 18 17 | 
             
            import time
         | 
| 19 | 
            -
            from typing import Dict, Any, List, Optional
         | 
| 20 18 | 
             
            from datetime import datetime
         | 
| 19 | 
            +
            from typing import Any, Dict, List, Optional
         | 
| 21 20 |  | 
| 22 | 
            -
            from ..core.logger import get_logger
         | 
| 23 21 | 
             
            from ..core.hook_manager import get_hook_manager
         | 
| 22 | 
            +
            from ..core.logger import get_logger
         | 
| 24 23 |  | 
| 25 24 |  | 
| 26 25 | 
             
            class PMHookInterceptor:
         | 
| 27 26 | 
             
                """Interceptor for PM operations that ensures hook events are triggered.
         | 
| 28 | 
            -
             | 
| 27 | 
            +
             | 
| 29 28 | 
             
                WHY this design:
         | 
| 30 29 | 
             
                - Acts as a transparent proxy for tool operations
         | 
| 31 30 | 
             
                - Automatically triggers pre/post hook events
         | 
| 32 31 | 
             
                - Maintains session consistency with regular Claude Code operations
         | 
| 33 32 | 
             
                - Provides real-time event streaming for PM operations
         | 
| 34 33 | 
             
                """
         | 
| 35 | 
            -
             | 
| 34 | 
            +
             | 
| 36 35 | 
             
                def __init__(self):
         | 
| 37 36 | 
             
                    self.logger = get_logger("pm_hook_interceptor")
         | 
| 38 37 | 
             
                    self.hook_manager = get_hook_manager()
         | 
| 39 38 | 
             
                    self._in_intercept = threading.local()  # Prevent recursion
         | 
| 40 | 
            -
             | 
| 39 | 
            +
             | 
| 41 40 | 
             
                def intercept_todowrite(self, original_function):
         | 
| 42 41 | 
             
                    """Decorator to intercept TodoWrite calls and trigger hooks.
         | 
| 43 | 
            -
             | 
| 42 | 
            +
             | 
| 44 43 | 
             
                    Args:
         | 
| 45 44 | 
             
                        original_function: The original TodoWrite function
         | 
| 46 | 
            -
             | 
| 45 | 
            +
             | 
| 47 46 | 
             
                    Returns:
         | 
| 48 47 | 
             
                        Wrapped function that triggers hooks
         | 
| 49 48 | 
             
                    """
         | 
| 49 | 
            +
             | 
| 50 50 | 
             
                    @functools.wraps(original_function)
         | 
| 51 51 | 
             
                    def wrapper(*args, **kwargs):
         | 
| 52 52 | 
             
                        # Prevent recursive interception
         | 
| 53 | 
            -
                        if getattr(self._in_intercept,  | 
| 53 | 
            +
                        if getattr(self._in_intercept, "active", False):
         | 
| 54 54 | 
             
                            return original_function(*args, **kwargs)
         | 
| 55 | 
            -
             | 
| 55 | 
            +
             | 
| 56 56 | 
             
                        self._in_intercept.active = True
         | 
| 57 | 
            -
             | 
| 57 | 
            +
             | 
| 58 58 | 
             
                        try:
         | 
| 59 59 | 
             
                            # Extract todos from arguments
         | 
| 60 60 | 
             
                            todos = self._extract_todos_from_args(args, kwargs)
         | 
| 61 | 
            -
             | 
| 61 | 
            +
             | 
| 62 62 | 
             
                            # Trigger pre-tool hook
         | 
| 63 | 
            -
                            self.hook_manager.trigger_pre_tool_hook( | 
| 64 | 
            -
                                "todos": todos,
         | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
                            })
         | 
| 68 | 
            -
                            
         | 
| 63 | 
            +
                            self.hook_manager.trigger_pre_tool_hook(
         | 
| 64 | 
            +
                                "TodoWrite", {"todos": todos, "source": "PM", "intercepted": True}
         | 
| 65 | 
            +
                            )
         | 
| 66 | 
            +
             | 
| 69 67 | 
             
                            # Call the original function
         | 
| 70 68 | 
             
                            result = original_function(*args, **kwargs)
         | 
| 71 | 
            -
             | 
| 69 | 
            +
             | 
| 72 70 | 
             
                            # Trigger post-tool hook
         | 
| 73 | 
            -
                            self.hook_manager.trigger_post_tool_hook( | 
| 74 | 
            -
                                " | 
| 75 | 
            -
                                 | 
| 76 | 
            -
                                 | 
| 77 | 
            -
             | 
| 78 | 
            -
             | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 71 | 
            +
                            self.hook_manager.trigger_post_tool_hook(
         | 
| 72 | 
            +
                                "TodoWrite",
         | 
| 73 | 
            +
                                0,
         | 
| 74 | 
            +
                                {
         | 
| 75 | 
            +
                                    "todos_count": len(todos) if todos else 0,
         | 
| 76 | 
            +
                                    "source": "PM",
         | 
| 77 | 
            +
                                    "success": True,
         | 
| 78 | 
            +
                                },
         | 
| 79 | 
            +
                            )
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                            self.logger.debug(
         | 
| 82 | 
            +
                                f"Successfully intercepted TodoWrite with {len(todos) if todos else 0} todos"
         | 
| 83 | 
            +
                            )
         | 
| 84 | 
            +
             | 
| 81 85 | 
             
                            return result
         | 
| 82 | 
            -
             | 
| 86 | 
            +
             | 
| 83 87 | 
             
                        except Exception as e:
         | 
| 84 88 | 
             
                            # Trigger post-tool hook with error
         | 
| 85 | 
            -
                            self.hook_manager.trigger_post_tool_hook( | 
| 86 | 
            -
                                "error": str(e),
         | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
                            })
         | 
| 90 | 
            -
                            
         | 
| 89 | 
            +
                            self.hook_manager.trigger_post_tool_hook(
         | 
| 90 | 
            +
                                "TodoWrite", 1, {"error": str(e), "source": "PM", "success": False}
         | 
| 91 | 
            +
                            )
         | 
| 92 | 
            +
             | 
| 91 93 | 
             
                            self.logger.error(f"Error in TodoWrite interception: {e}")
         | 
| 92 94 | 
             
                            raise
         | 
| 93 95 | 
             
                        finally:
         | 
| 94 96 | 
             
                            self._in_intercept.active = False
         | 
| 95 | 
            -
             | 
| 97 | 
            +
             | 
| 96 98 | 
             
                    return wrapper
         | 
| 97 | 
            -
             | 
| 99 | 
            +
             | 
| 98 100 | 
             
                def _extract_todos_from_args(self, args, kwargs) -> List[Dict[str, Any]]:
         | 
| 99 101 | 
             
                    """Extract todos from function arguments.
         | 
| 100 | 
            -
             | 
| 102 | 
            +
             | 
| 101 103 | 
             
                    Args:
         | 
| 102 104 | 
             
                        args: Positional arguments
         | 
| 103 105 | 
             
                        kwargs: Keyword arguments
         | 
| 104 | 
            -
             | 
| 106 | 
            +
             | 
| 105 107 | 
             
                    Returns:
         | 
| 106 108 | 
             
                        List of todo dictionaries
         | 
| 107 109 | 
             
                    """
         | 
| 108 110 | 
             
                    # Look for todos in kwargs first
         | 
| 109 | 
            -
                    if  | 
| 110 | 
            -
                        return kwargs[ | 
| 111 | 
            -
             | 
| 111 | 
            +
                    if "todos" in kwargs:
         | 
| 112 | 
            +
                        return kwargs["todos"]
         | 
| 113 | 
            +
             | 
| 112 114 | 
             
                    # Look for todos in positional args
         | 
| 113 115 | 
             
                    for arg in args:
         | 
| 114 116 | 
             
                        if isinstance(arg, list) and arg and isinstance(arg[0], dict):
         | 
| 115 117 | 
             
                            # Check if this looks like a todos list
         | 
| 116 | 
            -
                            if  | 
| 118 | 
            +
                            if "content" in arg[0] or "id" in arg[0]:
         | 
| 117 119 | 
             
                                return arg
         | 
| 118 | 
            -
             | 
| 120 | 
            +
             | 
| 119 121 | 
             
                    return []
         | 
| 120 | 
            -
             | 
| 122 | 
            +
             | 
| 121 123 | 
             
                def trigger_manual_todowrite_hooks(self, todos: List[Dict[str, Any]]):
         | 
| 122 124 | 
             
                    """Manually trigger TodoWrite hooks for given todos.
         | 
| 123 | 
            -
             | 
| 125 | 
            +
             | 
| 124 126 | 
             
                    This method can be called directly when TodoWrite operations
         | 
| 125 127 | 
             
                    are detected outside of function interception.
         | 
| 126 | 
            -
             | 
| 128 | 
            +
             | 
| 127 129 | 
             
                    Args:
         | 
| 128 130 | 
             
                        todos: List of todo dictionaries
         | 
| 129 131 | 
             
                    """
         | 
| 130 132 | 
             
                    try:
         | 
| 131 133 | 
             
                        # Trigger pre-tool hook
         | 
| 132 | 
            -
                        success1 = self.hook_manager.trigger_pre_tool_hook( | 
| 133 | 
            -
                            " | 
| 134 | 
            -
                             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 134 | 
            +
                        success1 = self.hook_manager.trigger_pre_tool_hook(
         | 
| 135 | 
            +
                            "TodoWrite",
         | 
| 136 | 
            +
                            {
         | 
| 137 | 
            +
                                "todos": todos,
         | 
| 138 | 
            +
                                "source": "PM_Manual",
         | 
| 139 | 
            +
                                "timestamp": datetime.utcnow().isoformat(),
         | 
| 140 | 
            +
                            },
         | 
| 141 | 
            +
                        )
         | 
| 142 | 
            +
             | 
| 138 143 | 
             
                        # Small delay to ensure proper event ordering
         | 
| 139 144 | 
             
                        time.sleep(0.1)
         | 
| 140 | 
            -
             | 
| 145 | 
            +
             | 
| 141 146 | 
             
                        # Trigger post-tool hook
         | 
| 142 | 
            -
                        success2 = self.hook_manager.trigger_post_tool_hook( | 
| 143 | 
            -
                            " | 
| 144 | 
            -
                             | 
| 145 | 
            -
                             | 
| 146 | 
            -
             | 
| 147 | 
            -
             | 
| 148 | 
            -
             | 
| 147 | 
            +
                        success2 = self.hook_manager.trigger_post_tool_hook(
         | 
| 148 | 
            +
                            "TodoWrite",
         | 
| 149 | 
            +
                            0,
         | 
| 150 | 
            +
                            {
         | 
| 151 | 
            +
                                "todos_count": len(todos),
         | 
| 152 | 
            +
                                "source": "PM_Manual",
         | 
| 153 | 
            +
                                "success": True,
         | 
| 154 | 
            +
                                "timestamp": datetime.utcnow().isoformat(),
         | 
| 155 | 
            +
                            },
         | 
| 156 | 
            +
                        )
         | 
| 157 | 
            +
             | 
| 149 158 | 
             
                        if success1 and success2:
         | 
| 150 | 
            -
                            self.logger.info( | 
| 159 | 
            +
                            self.logger.info(
         | 
| 160 | 
            +
                                f"Manually triggered TodoWrite hooks for {len(todos)} todos"
         | 
| 161 | 
            +
                            )
         | 
| 151 162 | 
             
                        else:
         | 
| 152 | 
            -
                            self.logger.warning( | 
| 153 | 
            -
             | 
| 163 | 
            +
                            self.logger.warning(
         | 
| 164 | 
            +
                                f"Hook triggering partially failed: pre={success1}, post={success2}"
         | 
| 165 | 
            +
                            )
         | 
| 166 | 
            +
             | 
| 154 167 | 
             
                        return success1 and success2
         | 
| 155 | 
            -
             | 
| 168 | 
            +
             | 
| 156 169 | 
             
                    except Exception as e:
         | 
| 157 170 | 
             
                        self.logger.error(f"Error manually triggering TodoWrite hooks: {e}")
         | 
| 158 171 | 
             
                        return False
         | 
| @@ -172,10 +185,10 @@ def get_pm_hook_interceptor() -> PMHookInterceptor: | |
| 172 185 |  | 
| 173 186 | 
             
            def trigger_pm_todowrite_hooks(todos: List[Dict[str, Any]]) -> bool:
         | 
| 174 187 | 
             
                """Convenience function to trigger PM TodoWrite hooks.
         | 
| 175 | 
            -
             | 
| 188 | 
            +
             | 
| 176 189 | 
             
                Args:
         | 
| 177 190 | 
             
                    todos: List of todo dictionaries
         | 
| 178 | 
            -
             | 
| 191 | 
            +
             | 
| 179 192 | 
             
                Returns:
         | 
| 180 193 | 
             
                    bool: True if hooks were triggered successfully
         | 
| 181 194 | 
             
                """
         | 
| @@ -185,21 +198,21 @@ def trigger_pm_todowrite_hooks(todos: List[Dict[str, Any]]) -> bool: | |
| 185 198 |  | 
| 186 199 | 
             
            def simulate_pm_todowrite_operation(todos: List[Dict[str, Any]]):
         | 
| 187 200 | 
             
                """Simulate a PM TodoWrite operation with proper hook triggering.
         | 
| 188 | 
            -
             | 
| 201 | 
            +
             | 
| 189 202 | 
             
                This function is useful for testing and for cases where we want to
         | 
| 190 203 | 
             
                simulate a TodoWrite operation from the PM agent.
         | 
| 191 | 
            -
             | 
| 204 | 
            +
             | 
| 192 205 | 
             
                Args:
         | 
| 193 206 | 
             
                    todos: List of todo dictionaries
         | 
| 194 207 | 
             
                """
         | 
| 195 208 | 
             
                interceptor = get_pm_hook_interceptor()
         | 
| 196 | 
            -
             | 
| 209 | 
            +
             | 
| 197 210 | 
             
                # Log the operation
         | 
| 198 211 | 
             
                logger = get_logger("pm_todowrite_simulation")
         | 
| 199 212 | 
             
                logger.info(f"Simulating PM TodoWrite operation with {len(todos)} todos")
         | 
| 200 | 
            -
             | 
| 213 | 
            +
             | 
| 201 214 | 
             
                # Trigger hooks
         | 
| 202 215 | 
             
                interceptor.trigger_manual_todowrite_hooks(todos)
         | 
| 203 | 
            -
             | 
| 216 | 
            +
             | 
| 204 217 | 
             
                # Log completion
         | 
| 205 | 
            -
                logger.info("PM TodoWrite simulation completed")
         | 
| 218 | 
            +
                logger.info("PM TodoWrite simulation completed")
         | 
| @@ -5,14 +5,12 @@ Provides centralized service registration and discovery, working with | |
| 5 5 | 
             
            the DI container to manage application services.
         | 
| 6 6 | 
             
            """
         | 
| 7 7 |  | 
| 8 | 
            -
            import  | 
| 9 | 
            -
            from pathlib import Path
         | 
| 10 | 
            -
            from typing import Any, Dict, List, Optional, Type, Union, TYPE_CHECKING
         | 
| 8 | 
            +
            from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union
         | 
| 11 9 |  | 
| 12 | 
            -
            from .container import DIContainer, ServiceLifetime, get_container
         | 
| 13 10 | 
             
            from .base_service import BaseService
         | 
| 14 | 
            -
            from .logger import get_logger
         | 
| 15 11 | 
             
            from .config import Config
         | 
| 12 | 
            +
            from .container import DIContainer, ServiceLifetime, get_container
         | 
| 13 | 
            +
            from .logger import get_logger
         | 
| 16 14 |  | 
| 17 15 | 
             
            if TYPE_CHECKING:
         | 
| 18 16 | 
             
                from claude_mpm.services.agents.deployment import AgentDeploymentService
         | 
| @@ -23,91 +21,87 @@ logger = get_logger(__name__) | |
| 23 21 | 
             
            class ServiceRegistry:
         | 
| 24 22 | 
             
                """
         | 
| 25 23 | 
             
                Central registry for all application services.
         | 
| 26 | 
            -
             | 
| 24 | 
            +
             | 
| 27 25 | 
             
                Manages service registration, configuration, and lifecycle.
         | 
| 28 26 | 
             
                """
         | 
| 29 | 
            -
             | 
| 27 | 
            +
             | 
| 30 28 | 
             
                def __init__(self, container: Optional[DIContainer] = None):
         | 
| 31 29 | 
             
                    """
         | 
| 32 30 | 
             
                    Initialize service registry.
         | 
| 33 | 
            -
             | 
| 31 | 
            +
             | 
| 34 32 | 
             
                    Args:
         | 
| 35 33 | 
             
                        container: DI container to use (uses global if not provided)
         | 
| 36 34 | 
             
                    """
         | 
| 37 35 | 
             
                    self.container = container or get_container()
         | 
| 38 36 | 
             
                    self._services: Dict[str, Type[BaseService]] = {}
         | 
| 39 37 | 
             
                    self._initialized = False
         | 
| 40 | 
            -
             | 
| 38 | 
            +
             | 
| 41 39 | 
             
                def register_core_services(self) -> None:
         | 
| 42 40 | 
             
                    """Register all core framework services."""
         | 
| 43 | 
            -
                    from claude_mpm.services.memory.cache.shared_prompt_cache import  | 
| 44 | 
            -
             | 
| 41 | 
            +
                    from claude_mpm.services.memory.cache.shared_prompt_cache import (
         | 
| 42 | 
            +
                        SharedPromptCache,
         | 
| 43 | 
            +
                    )
         | 
| 44 | 
            +
             | 
| 45 45 | 
             
                    from ..services import AgentDeploymentService
         | 
| 46 | 
            -
                    from .session_manager import SessionManager
         | 
| 47 46 | 
             
                    from .agent_session_manager import AgentSessionManager
         | 
| 48 | 
            -
                    
         | 
| 47 | 
            +
                    from .session_manager import SessionManager
         | 
| 48 | 
            +
             | 
| 49 49 | 
             
                    # Register configuration as singleton with name
         | 
| 50 50 | 
             
                    config = Config()
         | 
| 51 51 | 
             
                    self.container.register_singleton(Config, instance=config, name="main_config")
         | 
| 52 | 
            -
             | 
| 52 | 
            +
             | 
| 53 53 | 
             
                    # Register core services with proper lifetime management
         | 
| 54 54 | 
             
                    self.register_service(
         | 
| 55 | 
            -
                        "session_manager",
         | 
| 56 | 
            -
                        SessionManager,
         | 
| 57 | 
            -
                        lifetime=ServiceLifetime.SINGLETON
         | 
| 55 | 
            +
                        "session_manager", SessionManager, lifetime=ServiceLifetime.SINGLETON
         | 
| 58 56 | 
             
                    )
         | 
| 59 | 
            -
             | 
| 57 | 
            +
             | 
| 60 58 | 
             
                    self.register_service(
         | 
| 61 59 | 
             
                        "agent_session_manager",
         | 
| 62 60 | 
             
                        AgentSessionManager,
         | 
| 63 61 | 
             
                        lifetime=ServiceLifetime.SINGLETON,
         | 
| 64 | 
            -
                        dependencies={
         | 
| 65 | 
            -
                            'session_dir': lambda c: c.get(Config).get('session_dir')
         | 
| 66 | 
            -
                        }
         | 
| 62 | 
            +
                        dependencies={"session_dir": lambda c: c.get(Config).get("session_dir")},
         | 
| 67 63 | 
             
                    )
         | 
| 68 | 
            -
             | 
| 64 | 
            +
             | 
| 69 65 | 
             
                    # Register shared cache as singleton with factory
         | 
| 70 66 | 
             
                    self.container.register_factory(
         | 
| 71 67 | 
             
                        SharedPromptCache,
         | 
| 72 68 | 
             
                        lambda c: SharedPromptCache.get_instance(),
         | 
| 73 69 | 
             
                        lifetime=ServiceLifetime.SINGLETON,
         | 
| 74 | 
            -
                        name="prompt_cache"
         | 
| 75 | 
            -
                    )
         | 
| 76 | 
            -
                    
         | 
| 77 | 
            -
                    # Register ticket manager as scoped (per-request)
         | 
| 78 | 
            -
                    self.container.register_scoped(
         | 
| 79 | 
            -
                        TicketManager,
         | 
| 80 | 
            -
                        TicketManager,
         | 
| 81 | 
            -
                        name="ticket_manager"
         | 
| 70 | 
            +
                        name="prompt_cache",
         | 
| 82 71 | 
             
                    )
         | 
| 83 | 
            -
             | 
| 72 | 
            +
             | 
| 73 | 
            +
                    # Ticket manager removed - use claude-mpm tickets CLI commands instead
         | 
| 74 | 
            +
             | 
| 84 75 | 
             
                    # Register agent deployment service with factory for better initialization
         | 
| 85 76 | 
             
                    self.container.register_factory(
         | 
| 86 77 | 
             
                        AgentDeploymentService,
         | 
| 87 78 | 
             
                        lambda c: self._create_agent_deployment_service(c),
         | 
| 88 79 | 
             
                        lifetime=ServiceLifetime.TRANSIENT,
         | 
| 89 | 
            -
                        name="agent_deployment"
         | 
| 80 | 
            +
                        name="agent_deployment",
         | 
| 90 81 | 
             
                    )
         | 
| 91 | 
            -
             | 
| 82 | 
            +
             | 
| 92 83 | 
             
                    logger.info("Core services registered with enhanced DI container")
         | 
| 93 | 
            -
             | 
| 94 | 
            -
                def _create_agent_deployment_service( | 
| 84 | 
            +
             | 
| 85 | 
            +
                def _create_agent_deployment_service(
         | 
| 86 | 
            +
                    self, container: DIContainer
         | 
| 87 | 
            +
                ) -> "AgentDeploymentService":
         | 
| 95 88 | 
             
                    """Factory method for creating agent deployment service."""
         | 
| 96 89 | 
             
                    import os
         | 
| 97 90 | 
             
                    from pathlib import Path
         | 
| 98 | 
            -
             | 
| 91 | 
            +
             | 
| 99 92 | 
             
                    config = container.get(Config)
         | 
| 100 | 
            -
             | 
| 93 | 
            +
             | 
| 101 94 | 
             
                    # Get working directory from environment or config
         | 
| 102 | 
            -
                    if  | 
| 103 | 
            -
                        working_dir = Path(os.environ[ | 
| 95 | 
            +
                    if "CLAUDE_MPM_USER_PWD" in os.environ:
         | 
| 96 | 
            +
                        working_dir = Path(os.environ["CLAUDE_MPM_USER_PWD"])
         | 
| 104 97 | 
             
                    else:
         | 
| 105 | 
            -
                        working_dir = Path(config.get( | 
| 106 | 
            -
             | 
| 98 | 
            +
                        working_dir = Path(config.get("project.dir", "."))
         | 
| 99 | 
            +
             | 
| 107 100 | 
             
                    # Lazy import to avoid circular dependencies
         | 
| 108 101 | 
             
                    from claude_mpm.services.agents.deployment import AgentDeploymentService
         | 
| 102 | 
            +
             | 
| 109 103 | 
             
                    return AgentDeploymentService(working_directory=working_dir)
         | 
| 110 | 
            -
             | 
| 104 | 
            +
             | 
| 111 105 | 
             
                def register_service(
         | 
| 112 106 | 
             
                    self,
         | 
| 113 107 | 
             
                    name: str,
         | 
| @@ -115,11 +109,11 @@ class ServiceRegistry: | |
| 115 109 | 
             
                    lifetime: ServiceLifetime = ServiceLifetime.SINGLETON,
         | 
| 116 110 | 
             
                    factory: Optional[Any] = None,
         | 
| 117 111 | 
             
                    dependencies: Optional[Dict[str, Any]] = None,
         | 
| 118 | 
            -
                    config: Optional[Dict[str, Any]] = None
         | 
| 112 | 
            +
                    config: Optional[Dict[str, Any]] = None,
         | 
| 119 113 | 
             
                ) -> None:
         | 
| 120 114 | 
             
                    """
         | 
| 121 115 | 
             
                    Register a service with the registry.
         | 
| 122 | 
            -
             | 
| 116 | 
            +
             | 
| 123 117 | 
             
                    Args:
         | 
| 124 118 | 
             
                        name: Service name for lookup
         | 
| 125 119 | 
             
                        service_class: Service class (must inherit from BaseService)
         | 
| @@ -130,31 +124,28 @@ class ServiceRegistry: | |
| 130 124 | 
             
                    """
         | 
| 131 125 | 
             
                    # Store service metadata
         | 
| 132 126 | 
             
                    self._services[name] = service_class
         | 
| 133 | 
            -
             | 
| 127 | 
            +
             | 
| 134 128 | 
             
                    # Create factory wrapper if config provided
         | 
| 135 129 | 
             
                    if config and not factory:
         | 
| 136 130 | 
             
                        factory = lambda c: service_class(name=name, config=config, container=c)
         | 
| 137 131 | 
             
                    elif not factory:
         | 
| 138 132 | 
             
                        # Default factory with container injection
         | 
| 139 133 | 
             
                        factory = lambda c: service_class(name=name, container=c)
         | 
| 140 | 
            -
             | 
| 134 | 
            +
             | 
| 141 135 | 
             
                    # Register with DI container
         | 
| 142 136 | 
             
                    self.container.register(
         | 
| 143 | 
            -
                        service_class,
         | 
| 144 | 
            -
                        factory=factory,
         | 
| 145 | 
            -
                        lifetime=lifetime,
         | 
| 146 | 
            -
                        dependencies=dependencies
         | 
| 137 | 
            +
                        service_class, factory=factory, lifetime=lifetime, dependencies=dependencies
         | 
| 147 138 | 
             
                    )
         | 
| 148 | 
            -
             | 
| 139 | 
            +
             | 
| 149 140 | 
             
                    logger.debug(f"Registered service: {name} ({service_class.__name__})")
         | 
| 150 | 
            -
             | 
| 141 | 
            +
             | 
| 151 142 | 
             
                def get_service(self, service_type: Union[str, Type[BaseService]]) -> BaseService:
         | 
| 152 143 | 
             
                    """
         | 
| 153 144 | 
             
                    Get a service instance.
         | 
| 154 | 
            -
             | 
| 145 | 
            +
             | 
| 155 146 | 
             
                    Args:
         | 
| 156 147 | 
             
                        service_type: Service name or class
         | 
| 157 | 
            -
             | 
| 148 | 
            +
             | 
| 158 149 | 
             
                    Returns:
         | 
| 159 150 | 
             
                        Service instance
         | 
| 160 151 | 
             
                    """
         | 
| @@ -172,110 +163,121 @@ class ServiceRegistry: | |
| 172 163 | 
             
                    else:
         | 
| 173 164 | 
             
                        # Direct class resolution
         | 
| 174 165 | 
             
                        return self.container.get(service_type)
         | 
| 175 | 
            -
             | 
| 166 | 
            +
             | 
| 176 167 | 
             
                def get_service_optional(
         | 
| 177 168 | 
             
                    self,
         | 
| 178 169 | 
             
                    service_type: Union[str, Type[BaseService]],
         | 
| 179 | 
            -
                    default: Optional[BaseService] = None
         | 
| 170 | 
            +
                    default: Optional[BaseService] = None,
         | 
| 180 171 | 
             
                ) -> Optional[BaseService]:
         | 
| 181 172 | 
             
                    """Get a service if available, otherwise return default."""
         | 
| 182 173 | 
             
                    try:
         | 
| 183 174 | 
             
                        return self.get_service(service_type)
         | 
| 184 175 | 
             
                    except (KeyError, Exception):
         | 
| 185 176 | 
             
                        return default
         | 
| 186 | 
            -
             | 
| 177 | 
            +
             | 
| 187 178 | 
             
                def start_all_services(self) -> None:
         | 
| 188 179 | 
             
                    """Start all registered singleton services."""
         | 
| 189 180 | 
             
                    import asyncio
         | 
| 190 | 
            -
             | 
| 181 | 
            +
             | 
| 191 182 | 
             
                    async def _start_all():
         | 
| 192 183 | 
             
                        for name, service_class in self._services.items():
         | 
| 193 184 | 
             
                            try:
         | 
| 194 185 | 
             
                                # Only start singleton services
         | 
| 195 | 
            -
                                registration = self.container.get_all_registrations().get( | 
| 196 | 
            -
             | 
| 186 | 
            +
                                registration = self.container.get_all_registrations().get(
         | 
| 187 | 
            +
                                    service_class
         | 
| 188 | 
            +
                                )
         | 
| 189 | 
            +
                                if (
         | 
| 190 | 
            +
                                    registration
         | 
| 191 | 
            +
                                    and registration.lifetime == ServiceLifetime.SINGLETON
         | 
| 192 | 
            +
                                ):
         | 
| 197 193 | 
             
                                    service = self.get_service(service_class)
         | 
| 198 | 
            -
                                    if hasattr(service,  | 
| 194 | 
            +
                                    if hasattr(service, "start"):
         | 
| 199 195 | 
             
                                        await service.start()
         | 
| 200 196 | 
             
                                        logger.info(f"Started service: {name}")
         | 
| 201 197 | 
             
                            except Exception as e:
         | 
| 202 198 | 
             
                                logger.error(f"Failed to start service {name}: {e}")
         | 
| 203 | 
            -
             | 
| 199 | 
            +
             | 
| 204 200 | 
             
                    asyncio.run(_start_all())
         | 
| 205 201 | 
             
                    self._initialized = True
         | 
| 206 | 
            -
             | 
| 202 | 
            +
             | 
| 207 203 | 
             
                def stop_all_services(self) -> None:
         | 
| 208 204 | 
             
                    """Stop all running singleton services."""
         | 
| 209 205 | 
             
                    import asyncio
         | 
| 210 | 
            -
             | 
| 206 | 
            +
             | 
| 211 207 | 
             
                    async def _stop_all():
         | 
| 212 208 | 
             
                        for name, service_class in reversed(list(self._services.items())):
         | 
| 213 209 | 
             
                            try:
         | 
| 214 210 | 
             
                                # Only stop singleton services
         | 
| 215 | 
            -
                                registration = self.container.get_all_registrations().get( | 
| 216 | 
            -
             | 
| 211 | 
            +
                                registration = self.container.get_all_registrations().get(
         | 
| 212 | 
            +
                                    service_class
         | 
| 213 | 
            +
                                )
         | 
| 214 | 
            +
                                if (
         | 
| 215 | 
            +
                                    registration
         | 
| 216 | 
            +
                                    and registration.lifetime == ServiceLifetime.SINGLETON
         | 
| 217 | 
            +
                                ):
         | 
| 217 218 | 
             
                                    if service_class in self.container._singletons:
         | 
| 218 219 | 
             
                                        service = self.container._singletons[service_class]
         | 
| 219 | 
            -
                                        if hasattr(service,  | 
| 220 | 
            +
                                        if hasattr(service, "stop") and service.running:
         | 
| 220 221 | 
             
                                            await service.stop()
         | 
| 221 222 | 
             
                                            logger.info(f"Stopped service: {name}")
         | 
| 222 223 | 
             
                            except Exception as e:
         | 
| 223 224 | 
             
                                logger.error(f"Failed to stop service {name}: {e}")
         | 
| 224 | 
            -
             | 
| 225 | 
            +
             | 
| 225 226 | 
             
                    asyncio.run(_stop_all())
         | 
| 226 | 
            -
             | 
| 227 | 
            +
             | 
| 227 228 | 
             
                def get_service_health(self) -> Dict[str, Dict[str, Any]]:
         | 
| 228 229 | 
             
                    """Get health status of all services."""
         | 
| 229 230 | 
             
                    import asyncio
         | 
| 230 | 
            -
             | 
| 231 | 
            +
             | 
| 231 232 | 
             
                    async def _get_health():
         | 
| 232 233 | 
             
                        health_status = {}
         | 
| 233 | 
            -
             | 
| 234 | 
            +
             | 
| 234 235 | 
             
                        for name, service_class in self._services.items():
         | 
| 235 236 | 
             
                            try:
         | 
| 236 237 | 
             
                                if service_class in self.container._singletons:
         | 
| 237 238 | 
             
                                    service = self.container._singletons[service_class]
         | 
| 238 | 
            -
                                    if hasattr(service,  | 
| 239 | 
            +
                                    if hasattr(service, "health_check"):
         | 
| 239 240 | 
             
                                        health = await service.health_check()
         | 
| 240 241 | 
             
                                        health_status[name] = {
         | 
| 241 | 
            -
                                             | 
| 242 | 
            -
                                             | 
| 243 | 
            -
                                             | 
| 242 | 
            +
                                            "status": health.status,
         | 
| 243 | 
            +
                                            "message": health.message,
         | 
| 244 | 
            +
                                            "metrics": health.metrics,
         | 
| 244 245 | 
             
                                        }
         | 
| 245 246 | 
             
                            except Exception as e:
         | 
| 246 | 
            -
                                health_status[name] = {
         | 
| 247 | 
            -
             | 
| 248 | 
            -
                                    'message': str(e)
         | 
| 249 | 
            -
                                }
         | 
| 250 | 
            -
                                
         | 
| 247 | 
            +
                                health_status[name] = {"status": "error", "message": str(e)}
         | 
| 248 | 
            +
             | 
| 251 249 | 
             
                        return health_status
         | 
| 252 | 
            -
             | 
| 250 | 
            +
             | 
| 253 251 | 
             
                    return asyncio.run(_get_health())
         | 
| 254 | 
            -
             | 
| 252 | 
            +
             | 
| 255 253 | 
             
                def list_services(self) -> List[Dict[str, Any]]:
         | 
| 256 254 | 
             
                    """List all registered services with their metadata."""
         | 
| 257 255 | 
             
                    services = []
         | 
| 258 | 
            -
             | 
| 256 | 
            +
             | 
| 259 257 | 
             
                    for name, service_class in self._services.items():
         | 
| 260 258 | 
             
                        registration = self.container.get_all_registrations().get(service_class)
         | 
| 261 | 
            -
             | 
| 259 | 
            +
             | 
| 262 260 | 
             
                        service_info = {
         | 
| 263 | 
            -
                             | 
| 264 | 
            -
                             | 
| 265 | 
            -
                             | 
| 266 | 
            -
                             | 
| 267 | 
            -
                             | 
| 268 | 
            -
             | 
| 261 | 
            +
                            "name": name,
         | 
| 262 | 
            +
                            "class": service_class.__name__,
         | 
| 263 | 
            +
                            "module": service_class.__module__,
         | 
| 264 | 
            +
                            "lifetime": registration.lifetime.value if registration else "unknown",
         | 
| 265 | 
            +
                            "is_singleton": (
         | 
| 266 | 
            +
                                registration.lifetime == ServiceLifetime.SINGLETON
         | 
| 267 | 
            +
                                if registration
         | 
| 268 | 
            +
                                else False
         | 
| 269 | 
            +
                            ),
         | 
| 270 | 
            +
                            "is_running": False,
         | 
| 269 271 | 
             
                        }
         | 
| 270 | 
            -
             | 
| 272 | 
            +
             | 
| 271 273 | 
             
                        # Check if singleton is running
         | 
| 272 274 | 
             
                        if service_class in self.container._singletons:
         | 
| 273 275 | 
             
                            service = self.container._singletons[service_class]
         | 
| 274 | 
            -
                            if hasattr(service,  | 
| 275 | 
            -
                                service_info[ | 
| 276 | 
            -
             | 
| 276 | 
            +
                            if hasattr(service, "running"):
         | 
| 277 | 
            +
                                service_info["is_running"] = service.running
         | 
| 278 | 
            +
             | 
| 277 279 | 
             
                        services.append(service_info)
         | 
| 278 | 
            -
             | 
| 280 | 
            +
             | 
| 279 281 | 
             
                    return services
         | 
| 280 282 |  | 
| 281 283 |  | 
| @@ -295,23 +297,23 @@ def get_service_registry() -> ServiceRegistry: | |
| 295 297 | 
             
            def initialize_services(config: Optional[Dict[str, Any]] = None) -> ServiceRegistry:
         | 
| 296 298 | 
             
                """
         | 
| 297 299 | 
             
                Initialize all application services.
         | 
| 298 | 
            -
             | 
| 300 | 
            +
             | 
| 299 301 | 
             
                Args:
         | 
| 300 302 | 
             
                    config: Optional configuration overrides
         | 
| 301 | 
            -
             | 
| 303 | 
            +
             | 
| 302 304 | 
             
                Returns:
         | 
| 303 305 | 
             
                    Initialized service registry
         | 
| 304 306 | 
             
                """
         | 
| 305 307 | 
             
                registry = get_service_registry()
         | 
| 306 | 
            -
             | 
| 308 | 
            +
             | 
| 307 309 | 
             
                if config:
         | 
| 308 310 | 
             
                    # Apply configuration overrides
         | 
| 309 311 | 
             
                    config_service = registry.container.resolve(Config)
         | 
| 310 312 | 
             
                    for key, value in config.items():
         | 
| 311 313 | 
             
                        config_service.set(key, value)
         | 
| 312 | 
            -
             | 
| 314 | 
            +
             | 
| 313 315 | 
             
                # Start all services
         | 
| 314 316 | 
             
                if not registry._initialized:
         | 
| 315 317 | 
             
                    registry.start_all_services()
         | 
| 316 | 
            -
             | 
| 317 | 
            -
                return registry
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                return registry
         |