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
| @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            """Project-specific agent deployment strategy."""
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            from pathlib import Path
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            from .base_strategy import BaseDeploymentStrategy, DeploymentContext
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            class ProjectAgentDeploymentStrategy(BaseDeploymentStrategy):
         | 
| 9 | 
            +
                """Strategy for deploying project-specific agents.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                Project agents are deployed to the project's .claude/agents/
         | 
| 12 | 
            +
                directory and are specific to that project.
         | 
| 13 | 
            +
                """
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def __init__(self):
         | 
| 16 | 
            +
                    super().__init__("Project Agent Deployment")
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def can_handle(self, context: DeploymentContext) -> bool:
         | 
| 19 | 
            +
                    """Check if this is a project-specific deployment.
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    Project deployment when:
         | 
| 22 | 
            +
                    - Working directory is set AND
         | 
| 23 | 
            +
                    - Target directory is within the working directory, OR
         | 
| 24 | 
            +
                    - Templates directory is within working directory's .claude-mpm/agents/
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    Args:
         | 
| 27 | 
            +
                        context: Deployment context
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    Returns:
         | 
| 30 | 
            +
                        True if this should handle project agent deployment
         | 
| 31 | 
            +
                    """
         | 
| 32 | 
            +
                    if not context.working_directory:
         | 
| 33 | 
            +
                        return False
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    # Check if target_dir is within working directory
         | 
| 36 | 
            +
                    if context.target_dir:
         | 
| 37 | 
            +
                        try:
         | 
| 38 | 
            +
                            # Check if target is within working directory
         | 
| 39 | 
            +
                            context.target_dir.resolve().relative_to(
         | 
| 40 | 
            +
                                context.working_directory.resolve()
         | 
| 41 | 
            +
                            )
         | 
| 42 | 
            +
                            return True
         | 
| 43 | 
            +
                        except ValueError:
         | 
| 44 | 
            +
                            # target_dir is not within working_directory
         | 
| 45 | 
            +
                            pass
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    # Check if templates_dir suggests project deployment
         | 
| 48 | 
            +
                    if context.templates_dir:
         | 
| 49 | 
            +
                        project_agents_dir = context.working_directory / ".claude-mpm" / "agents"
         | 
| 50 | 
            +
                        try:
         | 
| 51 | 
            +
                            context.templates_dir.resolve().relative_to(
         | 
| 52 | 
            +
                                project_agents_dir.resolve()
         | 
| 53 | 
            +
                            )
         | 
| 54 | 
            +
                            return True
         | 
| 55 | 
            +
                        except ValueError:
         | 
| 56 | 
            +
                            # templates_dir is not within project agents directory
         | 
| 57 | 
            +
                            pass
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    # Check if deployment_mode is "project" - this should be sufficient
         | 
| 60 | 
            +
                    if context.deployment_mode == "project":
         | 
| 61 | 
            +
                        return True
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    return False
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def determine_target_directory(self, context: DeploymentContext) -> Path:
         | 
| 66 | 
            +
                    """Determine target directory for project agents.
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    Project agents are deployed to {working_directory}/.claude/agents/
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    Args:
         | 
| 71 | 
            +
                        context: Deployment context
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    Returns:
         | 
| 74 | 
            +
                        Path to project's .claude/agents/ directory
         | 
| 75 | 
            +
                    """
         | 
| 76 | 
            +
                    if context.target_dir:
         | 
| 77 | 
            +
                        return context.target_dir
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    if context.working_directory:
         | 
| 80 | 
            +
                        return context.working_directory / ".claude" / "agents"
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    # Fallback to current directory
         | 
| 83 | 
            +
                    return Path.cwd() / ".claude" / "agents"
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def get_templates_directory(self, context: DeploymentContext) -> Path:
         | 
| 86 | 
            +
                    """Get templates directory for project agents.
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    Args:
         | 
| 89 | 
            +
                        context: Deployment context
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                    Returns:
         | 
| 92 | 
            +
                        Path to project templates directory or system fallback
         | 
| 93 | 
            +
                    """
         | 
| 94 | 
            +
                    if context.templates_dir:
         | 
| 95 | 
            +
                        return context.templates_dir
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    if context.working_directory:
         | 
| 98 | 
            +
                        # Try project-specific agents directory first
         | 
| 99 | 
            +
                        project_agents_dir = context.working_directory / ".claude-mpm" / "agents"
         | 
| 100 | 
            +
                        if project_agents_dir.exists():
         | 
| 101 | 
            +
                            return project_agents_dir
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                    # Fallback to system templates
         | 
| 104 | 
            +
                    from claude_mpm.core.unified_paths import get_path_manager
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                    return get_path_manager().get_user_agents_dir() / "templates"
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                def get_excluded_agents(self, context: DeploymentContext) -> List[str]:
         | 
| 109 | 
            +
                    """Get excluded agents for project deployment.
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    Project deployment may have project-specific exclusions.
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    Args:
         | 
| 114 | 
            +
                        context: Deployment context
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    Returns:
         | 
| 117 | 
            +
                        List of excluded agent names
         | 
| 118 | 
            +
                    """
         | 
| 119 | 
            +
                    if not context.config:
         | 
| 120 | 
            +
                        return []
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    # Project deployments might have different exclusion rules
         | 
| 123 | 
            +
                    excluded = context.config.get("agent_deployment.excluded_agents", [])
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                    # In project mode, we might want to include all agents by default
         | 
| 126 | 
            +
                    if context.deployment_mode == "project":
         | 
| 127 | 
            +
                        return []
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                    return excluded
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def should_deploy_system_instructions(self, context: DeploymentContext) -> bool:
         | 
| 132 | 
            +
                    """Project deployment should deploy system instructions.
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                    Args:
         | 
| 135 | 
            +
                        context: Deployment context
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                    Returns:
         | 
| 138 | 
            +
                        True - project deployment includes instructions
         | 
| 139 | 
            +
                    """
         | 
| 140 | 
            +
                    return True
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                def get_deployment_priority(self) -> int:
         | 
| 143 | 
            +
                    """Project deployment has medium priority.
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                    Higher priority than system, lower than user.
         | 
| 146 | 
            +
             | 
| 147 | 
            +
                    Returns:
         | 
| 148 | 
            +
                        Priority 50 (medium priority)
         | 
| 149 | 
            +
                    """
         | 
| 150 | 
            +
                    return 50
         | 
| @@ -0,0 +1,117 @@ | |
| 1 | 
            +
            """Strategy selector for choosing the appropriate deployment strategy."""
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            from typing import List, Optional
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            from claude_mpm.core.logger import get_logger
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            from .base_strategy import BaseDeploymentStrategy, DeploymentContext
         | 
| 8 | 
            +
            from .project_strategy import ProjectAgentDeploymentStrategy
         | 
| 9 | 
            +
            from .system_strategy import SystemAgentDeploymentStrategy
         | 
| 10 | 
            +
            from .user_strategy import UserAgentDeploymentStrategy
         | 
| 11 | 
            +
             | 
| 12 | 
            +
             | 
| 13 | 
            +
            class DeploymentStrategySelector:
         | 
| 14 | 
            +
                """Selects the appropriate deployment strategy based on context.
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                This class manages all available deployment strategies and selects
         | 
| 17 | 
            +
                the most appropriate one based on the deployment context.
         | 
| 18 | 
            +
                """
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def __init__(self):
         | 
| 21 | 
            +
                    """Initialize the strategy selector with all available strategies."""
         | 
| 22 | 
            +
                    self.logger = get_logger(__name__)
         | 
| 23 | 
            +
                    self._strategies: List[BaseDeploymentStrategy] = [
         | 
| 24 | 
            +
                        UserAgentDeploymentStrategy(),
         | 
| 25 | 
            +
                        ProjectAgentDeploymentStrategy(),
         | 
| 26 | 
            +
                        SystemAgentDeploymentStrategy(),
         | 
| 27 | 
            +
                    ]
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    # Sort strategies by priority (lower number = higher priority)
         | 
| 30 | 
            +
                    self._strategies.sort(key=lambda s: s.get_deployment_priority())
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    self.logger.debug(
         | 
| 33 | 
            +
                        f"Initialized with {len(self._strategies)} deployment strategies"
         | 
| 34 | 
            +
                    )
         | 
| 35 | 
            +
                    for strategy in self._strategies:
         | 
| 36 | 
            +
                        self.logger.debug(f"  - {strategy}")
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def select_strategy(self, context: DeploymentContext) -> BaseDeploymentStrategy:
         | 
| 39 | 
            +
                    """Select the most appropriate deployment strategy.
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                    Iterates through strategies in priority order and returns the first
         | 
| 42 | 
            +
                    one that can handle the given context.
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    Args:
         | 
| 45 | 
            +
                        context: Deployment context with parameters
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    Returns:
         | 
| 48 | 
            +
                        The selected deployment strategy
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    Raises:
         | 
| 51 | 
            +
                        RuntimeError: If no strategy can handle the context
         | 
| 52 | 
            +
                    """
         | 
| 53 | 
            +
                    self.logger.debug(f"Selecting deployment strategy for context: {context}")
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    for strategy in self._strategies:
         | 
| 56 | 
            +
                        if strategy.can_handle(context):
         | 
| 57 | 
            +
                            self.logger.info(f"Selected deployment strategy: {strategy.name}")
         | 
| 58 | 
            +
                            return strategy
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                    # This should never happen as SystemAgentDeploymentStrategy
         | 
| 61 | 
            +
                    # should handle any context as a fallback
         | 
| 62 | 
            +
                    raise RuntimeError(f"No deployment strategy can handle context: {context}")
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def get_available_strategies(self) -> List[BaseDeploymentStrategy]:
         | 
| 65 | 
            +
                    """Get list of all available strategies.
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    Returns:
         | 
| 68 | 
            +
                        List of all registered deployment strategies
         | 
| 69 | 
            +
                    """
         | 
| 70 | 
            +
                    return self._strategies.copy()
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                def add_strategy(self, strategy: BaseDeploymentStrategy) -> None:
         | 
| 73 | 
            +
                    """Add a new deployment strategy.
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                    Args:
         | 
| 76 | 
            +
                        strategy: The strategy to add
         | 
| 77 | 
            +
                    """
         | 
| 78 | 
            +
                    self._strategies.append(strategy)
         | 
| 79 | 
            +
                    # Re-sort by priority
         | 
| 80 | 
            +
                    self._strategies.sort(key=lambda s: s.get_deployment_priority())
         | 
| 81 | 
            +
                    self.logger.debug(f"Added strategy: {strategy}")
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                def remove_strategy(self, strategy_class: type) -> bool:
         | 
| 84 | 
            +
                    """Remove a deployment strategy by class type.
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    Args:
         | 
| 87 | 
            +
                        strategy_class: The class type of strategy to remove
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    Returns:
         | 
| 90 | 
            +
                        True if strategy was removed, False if not found
         | 
| 91 | 
            +
                    """
         | 
| 92 | 
            +
                    original_count = len(self._strategies)
         | 
| 93 | 
            +
                    self._strategies = [
         | 
| 94 | 
            +
                        s for s in self._strategies if not isinstance(s, strategy_class)
         | 
| 95 | 
            +
                    ]
         | 
| 96 | 
            +
                    removed = len(self._strategies) < original_count
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    if removed:
         | 
| 99 | 
            +
                        self.logger.debug(f"Removed strategy of type: {strategy_class.__name__}")
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                    return removed
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                def get_strategy_for_context(
         | 
| 104 | 
            +
                    self, context: DeploymentContext
         | 
| 105 | 
            +
                ) -> Optional[BaseDeploymentStrategy]:
         | 
| 106 | 
            +
                    """Get strategy for context without raising exceptions.
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                    Args:
         | 
| 109 | 
            +
                        context: Deployment context
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    Returns:
         | 
| 112 | 
            +
                        Selected strategy or None if no strategy can handle the context
         | 
| 113 | 
            +
                    """
         | 
| 114 | 
            +
                    try:
         | 
| 115 | 
            +
                        return self.select_strategy(context)
         | 
| 116 | 
            +
                    except RuntimeError:
         | 
| 117 | 
            +
                        return None
         | 
| @@ -0,0 +1,116 @@ | |
| 1 | 
            +
            """System agent deployment strategy."""
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            from pathlib import Path
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            from claude_mpm.core.unified_paths import get_path_manager
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            from .base_strategy import BaseDeploymentStrategy, DeploymentContext
         | 
| 8 | 
            +
             | 
| 9 | 
            +
             | 
| 10 | 
            +
            class SystemAgentDeploymentStrategy(BaseDeploymentStrategy):
         | 
| 11 | 
            +
                """Strategy for deploying system-wide agents.
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                System agents are the default agents provided by claude-mpm,
         | 
| 14 | 
            +
                deployed to ~/.claude/agents/ for global availability.
         | 
| 15 | 
            +
                """
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def __init__(self):
         | 
| 18 | 
            +
                    super().__init__("System Agent Deployment")
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def can_handle(self, context: DeploymentContext) -> bool:
         | 
| 21 | 
            +
                    """Check if this is a system agent deployment.
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    System deployment is the default when:
         | 
| 24 | 
            +
                    - No specific target directory is provided, OR
         | 
| 25 | 
            +
                    - Templates directory points to system templates, OR
         | 
| 26 | 
            +
                    - Working directory is not set (CLI usage)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    Args:
         | 
| 29 | 
            +
                        context: Deployment context
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    Returns:
         | 
| 32 | 
            +
                        True if this should handle system agent deployment
         | 
| 33 | 
            +
                    """
         | 
| 34 | 
            +
                    # If templates_dir points to system templates, this is system deployment
         | 
| 35 | 
            +
                    if context.templates_dir:
         | 
| 36 | 
            +
                        system_templates_dir = (
         | 
| 37 | 
            +
                            get_path_manager().get_user_agents_dir() / "templates"
         | 
| 38 | 
            +
                        )
         | 
| 39 | 
            +
                        if context.templates_dir.resolve() == system_templates_dir.resolve():
         | 
| 40 | 
            +
                            return True
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    # If no target_dir specified and no working_directory, assume system deployment
         | 
| 43 | 
            +
                    if not context.target_dir and not context.working_directory:
         | 
| 44 | 
            +
                        return True
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    # If target_dir points to user's home .claude directory
         | 
| 47 | 
            +
                    if context.target_dir:
         | 
| 48 | 
            +
                        home_claude_dir = Path.home() / ".claude" / "agents"
         | 
| 49 | 
            +
                        if context.target_dir.resolve() == home_claude_dir.resolve():
         | 
| 50 | 
            +
                            return True
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    return False
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def determine_target_directory(self, context: DeploymentContext) -> Path:
         | 
| 55 | 
            +
                    """Determine target directory for system agents.
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                    System agents are always deployed to ~/.claude/agents/
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    Args:
         | 
| 60 | 
            +
                        context: Deployment context
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    Returns:
         | 
| 63 | 
            +
                        Path to ~/.claude/agents/
         | 
| 64 | 
            +
                    """
         | 
| 65 | 
            +
                    return Path.home() / ".claude" / "agents"
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def get_templates_directory(self, context: DeploymentContext) -> Path:
         | 
| 68 | 
            +
                    """Get templates directory for system agents.
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    Args:
         | 
| 71 | 
            +
                        context: Deployment context
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    Returns:
         | 
| 74 | 
            +
                        Path to system templates directory
         | 
| 75 | 
            +
                    """
         | 
| 76 | 
            +
                    if context.templates_dir:
         | 
| 77 | 
            +
                        return context.templates_dir
         | 
| 78 | 
            +
                    return get_path_manager().get_user_agents_dir() / "templates"
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                def get_excluded_agents(self, context: DeploymentContext) -> List[str]:
         | 
| 81 | 
            +
                    """Get excluded agents for system deployment.
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    System deployment respects global exclusion configuration.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    Args:
         | 
| 86 | 
            +
                        context: Deployment context
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    Returns:
         | 
| 89 | 
            +
                        List of excluded agent names
         | 
| 90 | 
            +
                    """
         | 
| 91 | 
            +
                    if not context.config:
         | 
| 92 | 
            +
                        return []
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    return context.config.get("agent_deployment.excluded_agents", [])
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                def should_deploy_system_instructions(self, context: DeploymentContext) -> bool:
         | 
| 97 | 
            +
                    """System deployment should deploy system instructions.
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                    Args:
         | 
| 100 | 
            +
                        context: Deployment context
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    Returns:
         | 
| 103 | 
            +
                        True - system deployment includes instructions
         | 
| 104 | 
            +
                    """
         | 
| 105 | 
            +
                    return True
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def get_deployment_priority(self) -> int:
         | 
| 108 | 
            +
                    """System deployment has lowest priority (highest number).
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    This ensures project and user deployments take precedence
         | 
| 111 | 
            +
                    when multiple strategies could handle the same context.
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    Returns:
         | 
| 114 | 
            +
                        Priority 100 (lowest priority)
         | 
| 115 | 
            +
                    """
         | 
| 116 | 
            +
                    return 100
         | 
| @@ -0,0 +1,137 @@ | |
| 1 | 
            +
            """User-specific agent deployment strategy."""
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            from pathlib import Path
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            from .base_strategy import BaseDeploymentStrategy, DeploymentContext
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            class UserAgentDeploymentStrategy(BaseDeploymentStrategy):
         | 
| 9 | 
            +
                """Strategy for deploying user-specific agents.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                User agents are custom agents created by the user,
         | 
| 12 | 
            +
                deployed to user-specific directories.
         | 
| 13 | 
            +
                """
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def __init__(self):
         | 
| 16 | 
            +
                    super().__init__("User Agent Deployment")
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def can_handle(self, context: DeploymentContext) -> bool:
         | 
| 19 | 
            +
                    """Check if this is a user-specific deployment.
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    User deployment when:
         | 
| 22 | 
            +
                    - Templates directory is in ~/.claude-mpm/agents/, OR
         | 
| 23 | 
            +
                    - Target directory is explicitly set to user directory, OR
         | 
| 24 | 
            +
                    - Environment variable CLAUDE_MPM_USER_PWD is set
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    Args:
         | 
| 27 | 
            +
                        context: Deployment context
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                    Returns:
         | 
| 30 | 
            +
                        True if this should handle user agent deployment
         | 
| 31 | 
            +
                    """
         | 
| 32 | 
            +
                    # Check if templates_dir is in user's home directory
         | 
| 33 | 
            +
                    if context.templates_dir:
         | 
| 34 | 
            +
                        user_agents_dir = Path.home() / ".claude-mpm" / "agents"
         | 
| 35 | 
            +
                        try:
         | 
| 36 | 
            +
                            context.templates_dir.resolve().relative_to(user_agents_dir.resolve())
         | 
| 37 | 
            +
                            return True
         | 
| 38 | 
            +
                        except ValueError:
         | 
| 39 | 
            +
                            # templates_dir is not within user agents directory
         | 
| 40 | 
            +
                            pass
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    # Check if target_dir is explicitly set to user directory
         | 
| 43 | 
            +
                    if context.target_dir:
         | 
| 44 | 
            +
                        user_claude_dir = Path.home() / ".claude-mpm" / "agents"
         | 
| 45 | 
            +
                        if context.target_dir.resolve() == user_claude_dir.resolve():
         | 
| 46 | 
            +
                            return True
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    # Check for user-specific environment variable
         | 
| 49 | 
            +
                    import os
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    if "CLAUDE_MPM_USER_PWD" in os.environ:
         | 
| 52 | 
            +
                        return True
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    return False
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def determine_target_directory(self, context: DeploymentContext) -> Path:
         | 
| 57 | 
            +
                    """Determine target directory for user agents.
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    User agents can be deployed to various user-specific locations.
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    Args:
         | 
| 62 | 
            +
                        context: Deployment context
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    Returns:
         | 
| 65 | 
            +
                        Path to user agents directory
         | 
| 66 | 
            +
                    """
         | 
| 67 | 
            +
                    if context.target_dir:
         | 
| 68 | 
            +
                        return context.target_dir
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    # Check for user-specific environment variable
         | 
| 71 | 
            +
                    import os
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    if "CLAUDE_MPM_USER_PWD" in os.environ:
         | 
| 74 | 
            +
                        user_pwd = Path(os.environ["CLAUDE_MPM_USER_PWD"])
         | 
| 75 | 
            +
                        return user_pwd / ".claude" / "agents"
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    # Default to user's home directory
         | 
| 78 | 
            +
                    return Path.home() / ".claude-mpm" / "agents"
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                def get_templates_directory(self, context: DeploymentContext) -> Path:
         | 
| 81 | 
            +
                    """Get templates directory for user agents.
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                    Args:
         | 
| 84 | 
            +
                        context: Deployment context
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    Returns:
         | 
| 87 | 
            +
                        Path to user templates directory
         | 
| 88 | 
            +
                    """
         | 
| 89 | 
            +
                    if context.templates_dir:
         | 
| 90 | 
            +
                        return context.templates_dir
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    # User-specific templates directory
         | 
| 93 | 
            +
                    return Path.home() / ".claude-mpm" / "agents"
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def get_excluded_agents(self, context: DeploymentContext) -> List[str]:
         | 
| 96 | 
            +
                    """Get excluded agents for user deployment.
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    User deployment typically has minimal exclusions.
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    Args:
         | 
| 101 | 
            +
                        context: Deployment context
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                    Returns:
         | 
| 104 | 
            +
                        List of excluded agent names (usually empty for user deployment)
         | 
| 105 | 
            +
                    """
         | 
| 106 | 
            +
                    if not context.config:
         | 
| 107 | 
            +
                        return []
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                    # User deployments might have different exclusion rules
         | 
| 110 | 
            +
                    # or might ignore global exclusions
         | 
| 111 | 
            +
                    return context.config.get("agent_deployment.user_excluded_agents", [])
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                def should_deploy_system_instructions(self, context: DeploymentContext) -> bool:
         | 
| 114 | 
            +
                    """User deployment may or may not deploy system instructions.
         | 
| 115 | 
            +
             | 
| 116 | 
            +
                    Depends on user preferences and configuration.
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    Args:
         | 
| 119 | 
            +
                        context: Deployment context
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                    Returns:
         | 
| 122 | 
            +
                        True if user wants system instructions deployed
         | 
| 123 | 
            +
                    """
         | 
| 124 | 
            +
                    if context.config:
         | 
| 125 | 
            +
                        return context.config.get("agent_deployment.deploy_user_instructions", True)
         | 
| 126 | 
            +
                    return True
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                def get_deployment_priority(self) -> int:
         | 
| 129 | 
            +
                    """User deployment has highest priority.
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                    User-specific deployments should take precedence over
         | 
| 132 | 
            +
                    system and project deployments.
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                    Returns:
         | 
| 135 | 
            +
                        Priority 10 (highest priority)
         | 
| 136 | 
            +
                    """
         | 
| 137 | 
            +
                    return 10
         | 
| @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            """System instructions deployment for agent deployment service.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This module handles deployment of system instructions and framework files.
         | 
| 4 | 
            +
            Extracted from AgentDeploymentService to reduce complexity and improve maintainability.
         | 
| 5 | 
            +
            """
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            import logging
         | 
| 8 | 
            +
            from pathlib import Path
         | 
| 9 | 
            +
            from typing import Any, Dict
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
            class SystemInstructionsDeployer:
         | 
| 13 | 
            +
                """Handles deployment of system instructions and framework files."""
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def __init__(self, logger: logging.Logger, working_directory: Path):
         | 
| 16 | 
            +
                    """Initialize the deployer with logger and working directory."""
         | 
| 17 | 
            +
                    self.logger = logger
         | 
| 18 | 
            +
                    self.working_directory = working_directory
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def deploy_system_instructions(
         | 
| 21 | 
            +
                    self,
         | 
| 22 | 
            +
                    target_dir: Path,
         | 
| 23 | 
            +
                    force_rebuild: bool,
         | 
| 24 | 
            +
                    results: Dict[str, Any],
         | 
| 25 | 
            +
                    is_project_specific: bool,
         | 
| 26 | 
            +
                ) -> None:
         | 
| 27 | 
            +
                    """
         | 
| 28 | 
            +
                    Deploy system instructions and framework files for PM framework.
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    Deploys INSTRUCTIONS.md, WORKFLOW.md, and MEMORY.md files following hierarchy:
         | 
| 31 | 
            +
                    - System/User versions → Deploy to ~/.claude/
         | 
| 32 | 
            +
                    - Project-specific versions → Deploy to <project>/.claude/
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                    Args:
         | 
| 35 | 
            +
                        target_dir: Target directory for deployment
         | 
| 36 | 
            +
                        force_rebuild: Force rebuild even if exists
         | 
| 37 | 
            +
                        results: Results dictionary to update
         | 
| 38 | 
            +
                        is_project_specific: Whether this is a project-specific deployment
         | 
| 39 | 
            +
                    """
         | 
| 40 | 
            +
                    try:
         | 
| 41 | 
            +
                        # Determine target location based on deployment type
         | 
| 42 | 
            +
                        if is_project_specific:
         | 
| 43 | 
            +
                            # Project-specific files go to project's .claude directory
         | 
| 44 | 
            +
                            claude_dir = self.working_directory / ".claude"
         | 
| 45 | 
            +
                        else:
         | 
| 46 | 
            +
                            # System and user files go to home ~/.claude directory
         | 
| 47 | 
            +
                            claude_dir = Path.home() / ".claude"
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                        # Ensure .claude directory exists
         | 
| 50 | 
            +
                        claude_dir.mkdir(parents=True, exist_ok=True)
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                        # Framework files to deploy
         | 
| 53 | 
            +
                        framework_files = [
         | 
| 54 | 
            +
                            (
         | 
| 55 | 
            +
                                "INSTRUCTIONS.md",
         | 
| 56 | 
            +
                                "CLAUDE.md",
         | 
| 57 | 
            +
                            ),  # INSTRUCTIONS.md deploys as CLAUDE.md
         | 
| 58 | 
            +
                            ("WORKFLOW.md", "WORKFLOW.md"),
         | 
| 59 | 
            +
                            ("MEMORY.md", "MEMORY.md"),
         | 
| 60 | 
            +
                        ]
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                        # Find the agents directory with framework files
         | 
| 63 | 
            +
                        # Use centralized paths for consistency
         | 
| 64 | 
            +
                        from claude_mpm.config.paths import paths
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                        agents_path = paths.agents_dir
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                        for source_name, target_name in framework_files:
         | 
| 69 | 
            +
                            source_path = agents_path / source_name
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                            if not source_path.exists():
         | 
| 72 | 
            +
                                self.logger.warning(f"Framework file not found: {source_path}")
         | 
| 73 | 
            +
                                continue
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                            target_file = claude_dir / target_name
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                            # Check if update needed
         | 
| 78 | 
            +
                            if not force_rebuild and target_file.exists():
         | 
| 79 | 
            +
                                # Compare modification times
         | 
| 80 | 
            +
                                if target_file.stat().st_mtime >= source_path.stat().st_mtime:
         | 
| 81 | 
            +
                                    results["skipped"].append(target_name)
         | 
| 82 | 
            +
                                    self.logger.debug(f"Framework file {target_name} up to date")
         | 
| 83 | 
            +
                                    continue
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                            # Read and deploy framework file
         | 
| 86 | 
            +
                            file_content = source_path.read_text()
         | 
| 87 | 
            +
                            target_file.write_text(file_content)
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                            # Track deployment
         | 
| 90 | 
            +
                            file_existed = target_file.exists()
         | 
| 91 | 
            +
                            deployment_info = {
         | 
| 92 | 
            +
                                "name": target_name,
         | 
| 93 | 
            +
                                "template": str(source_path),
         | 
| 94 | 
            +
                                "target": str(target_file),
         | 
| 95 | 
            +
                            }
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                            if file_existed:
         | 
| 98 | 
            +
                                results["updated"].append(deployment_info)
         | 
| 99 | 
            +
                                self.logger.info(f"Updated framework file: {target_name}")
         | 
| 100 | 
            +
                            else:
         | 
| 101 | 
            +
                                results["deployed"].append(deployment_info)
         | 
| 102 | 
            +
                                self.logger.info(f"Deployed framework file: {target_name}")
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                    except Exception as e:
         | 
| 105 | 
            +
                        error_msg = f"Failed to deploy system instructions: {e}"
         | 
| 106 | 
            +
                        self.logger.error(error_msg)
         | 
| 107 | 
            +
                        results["errors"].append(error_msg)
         | 
| 108 | 
            +
                        # Not raising AgentDeploymentError as this is non-critical
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            """Validation services for agent deployment.
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            This module provides validation services for agent deployment,
         | 
| 4 | 
            +
            including template validation, agent file validation, and
         | 
| 5 | 
            +
            deployment environment validation.
         | 
| 6 | 
            +
            """
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            from .agent_validator import AgentValidator
         | 
| 9 | 
            +
            from .deployment_validator import DeploymentValidator
         | 
| 10 | 
            +
            from .template_validator import TemplateValidator
         | 
| 11 | 
            +
            from .validation_result import ValidationResult, ValidationSeverity
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            __all__ = [
         | 
| 14 | 
            +
                "DeploymentValidator",
         | 
| 15 | 
            +
                "AgentValidator",
         | 
| 16 | 
            +
                "TemplateValidator",
         | 
| 17 | 
            +
                "ValidationResult",
         | 
| 18 | 
            +
                "ValidationSeverity",
         | 
| 19 | 
            +
            ]
         |