claude-mpm 4.1.1__py3-none-any.whl → 4.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/engineer.json +33 -11
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +50 -2
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +648 -1098
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +339 -967
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +233 -542
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +280 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +22 -29
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +500 -680
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -17
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +99 -154
- claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
- claude_mpm/services/agents/memory/memory_file_service.py +103 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +11 -7
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +407 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +589 -0
- claude_mpm/services/cli/dashboard_launcher.py +424 -0
- claude_mpm/services/cli/memory_crud_service.py +617 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/session_manager.py +513 -0
- claude_mpm/services/cli/socketio_manager.py +498 -0
- claude_mpm/services/cli/startup_checker.py +370 -0
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/cache_manager.py +311 -0
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/core/memory_manager.py +637 -0
- claude_mpm/services/core/path_resolver.py +498 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/METADATA +1 -1
- claude_mpm-4.1.3.dist-info/RECORD +528 -0
- claude_mpm/cli/commands/run_config_checker.py +0 -160
- claude_mpm-4.1.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
|
@@ -27,24 +27,15 @@ ROLLBACK PROCEDURES:
|
|
|
27
27
|
- Version tracking allows targeted rollbacks
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
|
-
import logging
|
|
31
|
-
import os
|
|
32
|
-
import shutil
|
|
33
30
|
import time
|
|
34
31
|
from pathlib import Path
|
|
35
32
|
from typing import Any, Dict, List, Optional, Tuple
|
|
36
33
|
|
|
37
34
|
from claude_mpm.config.paths import paths
|
|
38
|
-
from claude_mpm.constants import
|
|
35
|
+
from claude_mpm.constants import Paths
|
|
39
36
|
from claude_mpm.core.config import Config
|
|
40
|
-
from claude_mpm.core.constants import ResourceLimits, SystemLimits, TimeoutConfig
|
|
41
37
|
from claude_mpm.core.exceptions import AgentDeploymentError
|
|
42
38
|
from claude_mpm.core.interfaces import AgentDeploymentInterface
|
|
43
|
-
from claude_mpm.core.logging_config import (
|
|
44
|
-
get_logger,
|
|
45
|
-
log_operation,
|
|
46
|
-
log_performance_context,
|
|
47
|
-
)
|
|
48
39
|
from claude_mpm.services.shared import ConfigServiceBase
|
|
49
40
|
|
|
50
41
|
from .agent_configuration_manager import AgentConfigurationManager
|
|
@@ -56,7 +47,10 @@ from .agent_metrics_collector import AgentMetricsCollector
|
|
|
56
47
|
from .agent_template_builder import AgentTemplateBuilder
|
|
57
48
|
from .agent_validator import AgentValidator
|
|
58
49
|
from .agent_version_manager import AgentVersionManager
|
|
50
|
+
from .base_agent_locator import BaseAgentLocator
|
|
51
|
+
from .deployment_results_manager import DeploymentResultsManager
|
|
59
52
|
from .multi_source_deployment_service import MultiSourceAgentDeploymentService
|
|
53
|
+
from .single_agent_deployer import SingleAgentDeployer
|
|
60
54
|
|
|
61
55
|
|
|
62
56
|
class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
@@ -129,26 +123,29 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
129
123
|
# Initialize validator service
|
|
130
124
|
self.validator = AgentValidator()
|
|
131
125
|
|
|
126
|
+
# Initialize base agent locator service
|
|
127
|
+
self.base_agent_locator = BaseAgentLocator(self.logger)
|
|
128
|
+
|
|
129
|
+
# Initialize deployment results manager
|
|
130
|
+
self.results_manager = DeploymentResultsManager(self.logger)
|
|
131
|
+
|
|
132
|
+
# Initialize single agent deployer
|
|
133
|
+
self.single_agent_deployer = SingleAgentDeployer(
|
|
134
|
+
self.template_builder,
|
|
135
|
+
self.version_manager,
|
|
136
|
+
self.results_manager,
|
|
137
|
+
self.logger,
|
|
138
|
+
)
|
|
139
|
+
|
|
132
140
|
# Initialize filesystem manager service
|
|
133
141
|
self.filesystem_manager = AgentFileSystemManager()
|
|
134
142
|
|
|
135
|
-
# Initialize deployment metrics tracking
|
|
136
|
-
self._deployment_metrics = {
|
|
137
|
-
"total_deployments": 0,
|
|
138
|
-
"successful_deployments": 0,
|
|
139
|
-
"failed_deployments": 0,
|
|
140
|
-
"migrations_performed": 0,
|
|
141
|
-
"version_migration_count": 0,
|
|
142
|
-
"agent_type_counts": {},
|
|
143
|
-
"deployment_errors": {},
|
|
144
|
-
}
|
|
145
|
-
|
|
146
143
|
# Determine the actual working directory using configuration
|
|
147
144
|
# Priority: param > config > environment > current directory
|
|
148
145
|
self.working_directory = self.get_config_value(
|
|
149
146
|
"working_directory",
|
|
150
147
|
default=working_directory or Path.cwd(),
|
|
151
|
-
config_type=Path
|
|
148
|
+
config_type=Path,
|
|
152
149
|
)
|
|
153
150
|
self.logger.info(f"Working directory for deployment: {self.working_directory}")
|
|
154
151
|
|
|
@@ -157,25 +154,29 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
157
154
|
self.templates_dir = self.get_config_value(
|
|
158
155
|
"templates_dir",
|
|
159
156
|
default=templates_dir or paths.agents_dir / "templates",
|
|
160
|
-
config_type=Path
|
|
157
|
+
config_type=Path,
|
|
161
158
|
)
|
|
162
159
|
|
|
163
160
|
# Initialize discovery service (after templates_dir is set)
|
|
164
161
|
self.discovery_service = AgentDiscoveryService(self.templates_dir)
|
|
165
|
-
|
|
162
|
+
|
|
166
163
|
# Initialize multi-source deployment service for version comparison
|
|
167
164
|
self.multi_source_service = MultiSourceAgentDeploymentService()
|
|
168
165
|
|
|
169
166
|
# Find base agent file using configuration
|
|
170
167
|
# Priority: param > config > search
|
|
171
|
-
configured_base_agent = self.get_config_value(
|
|
168
|
+
configured_base_agent = self.get_config_value(
|
|
169
|
+
"base_agent_path", config_type=Path
|
|
170
|
+
)
|
|
172
171
|
if base_agent_path:
|
|
173
172
|
self.base_agent_path = Path(base_agent_path)
|
|
174
173
|
elif configured_base_agent:
|
|
175
174
|
self.base_agent_path = configured_base_agent
|
|
176
175
|
else:
|
|
177
176
|
# Priority-based search for base_agent.json
|
|
178
|
-
self.base_agent_path = self.
|
|
177
|
+
self.base_agent_path = self.base_agent_locator.find_base_agent_file(
|
|
178
|
+
paths.agents_dir
|
|
179
|
+
)
|
|
179
180
|
|
|
180
181
|
# Initialize configuration manager (after base_agent_path is set)
|
|
181
182
|
self.configuration_manager = AgentConfigurationManager(self.base_agent_path)
|
|
@@ -185,68 +186,6 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
185
186
|
|
|
186
187
|
self.logger.info(f"Templates directory: {self.templates_dir}")
|
|
187
188
|
self.logger.info(f"Base agent path: {self.base_agent_path}")
|
|
188
|
-
|
|
189
|
-
def _find_base_agent_file(self) -> Path:
|
|
190
|
-
"""Find base agent file with priority-based search.
|
|
191
|
-
|
|
192
|
-
Priority order:
|
|
193
|
-
1. Environment variable override (CLAUDE_MPM_BASE_AGENT_PATH)
|
|
194
|
-
2. Current working directory (for local development)
|
|
195
|
-
3. Known development locations
|
|
196
|
-
4. User override location (~/.claude/agents/)
|
|
197
|
-
5. Framework agents directory (from paths)
|
|
198
|
-
"""
|
|
199
|
-
# Priority 0: Check environment variable override
|
|
200
|
-
env_path = os.environ.get("CLAUDE_MPM_BASE_AGENT_PATH")
|
|
201
|
-
if env_path:
|
|
202
|
-
env_base_agent = Path(env_path)
|
|
203
|
-
if env_base_agent.exists():
|
|
204
|
-
self.logger.info(f"Using environment variable base_agent: {env_base_agent}")
|
|
205
|
-
return env_base_agent
|
|
206
|
-
else:
|
|
207
|
-
self.logger.warning(f"CLAUDE_MPM_BASE_AGENT_PATH set but file doesn't exist: {env_base_agent}")
|
|
208
|
-
|
|
209
|
-
# Priority 1: Check current working directory for local development
|
|
210
|
-
cwd = Path.cwd()
|
|
211
|
-
cwd_base_agent = cwd / "src" / "claude_mpm" / "agents" / "base_agent.json"
|
|
212
|
-
if cwd_base_agent.exists():
|
|
213
|
-
self.logger.info(f"Using local development base_agent from cwd: {cwd_base_agent}")
|
|
214
|
-
return cwd_base_agent
|
|
215
|
-
|
|
216
|
-
# Priority 2: Check known development locations
|
|
217
|
-
known_dev_paths = [
|
|
218
|
-
Path("/Users/masa/Projects/claude-mpm/src/claude_mpm/agents/base_agent.json"),
|
|
219
|
-
Path.home() / "Projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
|
|
220
|
-
Path.home() / "projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
|
|
221
|
-
]
|
|
222
|
-
|
|
223
|
-
for dev_path in known_dev_paths:
|
|
224
|
-
if dev_path.exists():
|
|
225
|
-
self.logger.info(f"Using development base_agent: {dev_path}")
|
|
226
|
-
return dev_path
|
|
227
|
-
|
|
228
|
-
# Priority 3: Check user override location
|
|
229
|
-
user_base_agent = Path.home() / ".claude" / "agents" / "base_agent.json"
|
|
230
|
-
if user_base_agent.exists():
|
|
231
|
-
self.logger.info(f"Using user override base_agent: {user_base_agent}")
|
|
232
|
-
return user_base_agent
|
|
233
|
-
|
|
234
|
-
# Priority 4: Use framework agents directory (fallback)
|
|
235
|
-
framework_base_agent = paths.agents_dir / "base_agent.json"
|
|
236
|
-
if framework_base_agent.exists():
|
|
237
|
-
self.logger.info(f"Using framework base_agent: {framework_base_agent}")
|
|
238
|
-
return framework_base_agent
|
|
239
|
-
|
|
240
|
-
# If still not found, log all searched locations and raise error
|
|
241
|
-
self.logger.error("Base agent file not found in any location:")
|
|
242
|
-
self.logger.error(f" 1. CWD: {cwd_base_agent}")
|
|
243
|
-
self.logger.error(f" 2. Dev paths: {known_dev_paths}")
|
|
244
|
-
self.logger.error(f" 3. User: {user_base_agent}")
|
|
245
|
-
self.logger.error(f" 4. Framework: {framework_base_agent}")
|
|
246
|
-
|
|
247
|
-
# Final fallback to framework path even if it doesn't exist
|
|
248
|
-
# (will fail later with better error message)
|
|
249
|
-
return framework_base_agent
|
|
250
189
|
|
|
251
190
|
def deploy_agents(
|
|
252
191
|
self,
|
|
@@ -349,7 +288,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
349
288
|
agents_dir = self._determine_agents_directory(target_dir)
|
|
350
289
|
|
|
351
290
|
# Initialize results dictionary
|
|
352
|
-
results = self.
|
|
291
|
+
results = self.results_manager.initialize_deployment_results(
|
|
292
|
+
agents_dir, deployment_start_time
|
|
293
|
+
)
|
|
353
294
|
|
|
354
295
|
try:
|
|
355
296
|
# Create agents directory if needed
|
|
@@ -359,7 +300,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
359
300
|
self._repair_existing_agents(agents_dir, results)
|
|
360
301
|
|
|
361
302
|
# Log deployment source tier
|
|
362
|
-
source_tier = self.
|
|
303
|
+
source_tier = self.base_agent_locator.determine_source_tier(
|
|
304
|
+
self.templates_dir
|
|
305
|
+
)
|
|
363
306
|
self.logger.info(
|
|
364
307
|
f"Building and deploying {source_tier} agents to: {agents_dir}"
|
|
365
308
|
)
|
|
@@ -382,17 +325,19 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
382
325
|
|
|
383
326
|
# Check if we should use multi-source deployment
|
|
384
327
|
use_multi_source = self._should_use_multi_source_deployment(deployment_mode)
|
|
385
|
-
|
|
328
|
+
|
|
386
329
|
if use_multi_source:
|
|
387
330
|
# Use multi-source deployment to get highest version agents
|
|
388
|
-
template_files, agent_sources, cleanup_results =
|
|
389
|
-
|
|
331
|
+
template_files, agent_sources, cleanup_results = (
|
|
332
|
+
self._get_multi_source_templates(
|
|
333
|
+
excluded_agents, config, agents_dir, force_rebuild
|
|
334
|
+
)
|
|
390
335
|
)
|
|
391
336
|
results["total"] = len(template_files)
|
|
392
337
|
results["multi_source"] = True
|
|
393
338
|
results["agent_sources"] = agent_sources
|
|
394
339
|
results["cleanup"] = cleanup_results
|
|
395
|
-
|
|
340
|
+
|
|
396
341
|
# Log cleanup results if any agents were removed
|
|
397
342
|
if cleanup_results.get("removed"):
|
|
398
343
|
self.logger.info(
|
|
@@ -410,13 +355,21 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
410
355
|
|
|
411
356
|
# Deploy each agent template
|
|
412
357
|
for template_file in template_files:
|
|
413
|
-
template_file_path =
|
|
358
|
+
template_file_path = (
|
|
359
|
+
template_file
|
|
360
|
+
if isinstance(template_file, Path)
|
|
361
|
+
else Path(template_file)
|
|
362
|
+
)
|
|
414
363
|
agent_name = template_file_path.stem
|
|
415
|
-
|
|
364
|
+
|
|
416
365
|
# Get source info for this agent (agent_sources now uses file stems as keys)
|
|
417
|
-
source_info =
|
|
418
|
-
|
|
419
|
-
|
|
366
|
+
source_info = (
|
|
367
|
+
agent_sources.get(agent_name, "unknown")
|
|
368
|
+
if agent_sources
|
|
369
|
+
else "single"
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
self.single_agent_deployer.deploy_single_agent(
|
|
420
373
|
template_file=template_file_path,
|
|
421
374
|
agents_dir=agents_dir,
|
|
422
375
|
base_agent_data=base_agent_data,
|
|
@@ -455,31 +408,24 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
455
408
|
results["errors"].append(error_msg)
|
|
456
409
|
|
|
457
410
|
# METRICS: Track deployment failure
|
|
458
|
-
self.
|
|
459
|
-
error_type = type(e).__name__
|
|
460
|
-
self._deployment_metrics["deployment_errors"][error_type] = (
|
|
461
|
-
self._deployment_metrics["deployment_errors"].get(error_type, 0) + 1
|
|
462
|
-
)
|
|
411
|
+
self.results_manager.update_deployment_metrics(False, type(e).__name__)
|
|
463
412
|
|
|
464
413
|
# METRICS: Calculate final deployment metrics
|
|
465
|
-
|
|
466
|
-
deployment_duration = (deployment_end_time - deployment_start_time) * 1000 # ms
|
|
467
|
-
|
|
468
|
-
results["metrics"]["end_time"] = deployment_end_time
|
|
469
|
-
results["metrics"]["duration_ms"] = deployment_duration
|
|
414
|
+
self.results_manager.finalize_results(results, deployment_start_time)
|
|
470
415
|
|
|
471
416
|
# METRICS: Update rolling averages and statistics
|
|
417
|
+
deployment_duration = results["metrics"].get("duration_ms", 0)
|
|
472
418
|
self.metrics_collector.update_deployment_metrics(deployment_duration, results)
|
|
473
419
|
|
|
474
420
|
return results
|
|
475
421
|
|
|
476
422
|
def get_deployment_metrics(self) -> Dict[str, Any]:
|
|
477
423
|
"""Get current deployment metrics."""
|
|
478
|
-
return self.
|
|
424
|
+
return self.results_manager.get_deployment_metrics()
|
|
479
425
|
|
|
480
426
|
def reset_metrics(self) -> None:
|
|
481
427
|
"""Reset deployment metrics."""
|
|
482
|
-
return self.
|
|
428
|
+
return self.results_manager.reset_metrics()
|
|
483
429
|
|
|
484
430
|
def set_claude_environment(
|
|
485
431
|
self, config_dir: Optional[Path] = None
|
|
@@ -520,75 +466,15 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
520
466
|
- Properly loads base_agent_data before building agent content
|
|
521
467
|
"""
|
|
522
468
|
try:
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
# target_dir should already be the agents directory
|
|
531
|
-
target_dir.mkdir(parents=True, exist_ok=True)
|
|
532
|
-
|
|
533
|
-
# Build and deploy the agent
|
|
534
|
-
target_file = target_dir / f"{agent_name}.md"
|
|
535
|
-
|
|
536
|
-
# Check if update is needed
|
|
537
|
-
if not force_rebuild and target_file.exists():
|
|
538
|
-
# Load base agent data for version checking
|
|
539
|
-
base_agent_data = {}
|
|
540
|
-
base_agent_version = (0, 0, 0)
|
|
541
|
-
if self.base_agent_path.exists():
|
|
542
|
-
try:
|
|
543
|
-
import json
|
|
544
|
-
|
|
545
|
-
base_agent_data = json.loads(self.base_agent_path.read_text())
|
|
546
|
-
base_agent_version = self.version_manager.parse_version(
|
|
547
|
-
base_agent_data.get("base_version")
|
|
548
|
-
or base_agent_data.get("version", 0)
|
|
549
|
-
)
|
|
550
|
-
except Exception as e:
|
|
551
|
-
self.logger.warning(
|
|
552
|
-
f"Could not load base agent for version check: {e}"
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
needs_update, reason = self.version_manager.check_agent_needs_update(
|
|
556
|
-
target_file, template_file, base_agent_version
|
|
557
|
-
)
|
|
558
|
-
if not needs_update:
|
|
559
|
-
self.logger.info(f"Agent {agent_name} is up to date")
|
|
560
|
-
return True
|
|
561
|
-
else:
|
|
562
|
-
self.logger.info(f"Updating agent {agent_name}: {reason}")
|
|
563
|
-
|
|
564
|
-
# Load base agent data for building
|
|
565
|
-
base_agent_data = {}
|
|
566
|
-
if self.base_agent_path.exists():
|
|
567
|
-
try:
|
|
568
|
-
import json
|
|
569
|
-
|
|
570
|
-
base_agent_data = json.loads(self.base_agent_path.read_text())
|
|
571
|
-
except Exception as e:
|
|
572
|
-
self.logger.warning(f"Could not load base agent: {e}")
|
|
573
|
-
|
|
574
|
-
# Build the agent markdown
|
|
575
|
-
# For single agent deployment, determine source from template location
|
|
576
|
-
source_info = self._determine_agent_source(template_file)
|
|
577
|
-
agent_content = self.template_builder.build_agent_markdown(
|
|
578
|
-
agent_name, template_file, base_agent_data, source_info
|
|
579
|
-
)
|
|
580
|
-
if not agent_content:
|
|
581
|
-
self.logger.error(f"Failed to build agent content for {agent_name}")
|
|
582
|
-
return False
|
|
583
|
-
|
|
584
|
-
# Write to target file
|
|
585
|
-
target_file.write_text(agent_content)
|
|
586
|
-
self.logger.info(
|
|
587
|
-
f"Successfully deployed agent: {agent_name} to {target_file}"
|
|
469
|
+
return self.single_agent_deployer.deploy_agent(
|
|
470
|
+
agent_name,
|
|
471
|
+
self.templates_dir,
|
|
472
|
+
target_dir,
|
|
473
|
+
self.base_agent_path,
|
|
474
|
+
force_rebuild,
|
|
475
|
+
self.working_directory,
|
|
588
476
|
)
|
|
589
477
|
|
|
590
|
-
return True
|
|
591
|
-
|
|
592
478
|
except AgentDeploymentError:
|
|
593
479
|
# Re-raise our custom exceptions
|
|
594
480
|
raise
|
|
@@ -628,25 +514,23 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
628
514
|
from .system_instructions_deployer import SystemInstructionsDeployer
|
|
629
515
|
|
|
630
516
|
deployer = SystemInstructionsDeployer(self.logger, self.working_directory)
|
|
631
|
-
deployer.deploy_system_instructions(
|
|
632
|
-
target_dir, force_rebuild, results
|
|
633
|
-
)
|
|
517
|
+
deployer.deploy_system_instructions(target_dir, force_rebuild, results)
|
|
634
518
|
|
|
635
519
|
def deploy_system_instructions_explicit(
|
|
636
520
|
self, target_dir: Optional[Path] = None, force_rebuild: bool = False
|
|
637
521
|
) -> Dict[str, Any]:
|
|
638
522
|
"""
|
|
639
523
|
Explicitly deploy system instructions when requested by user.
|
|
640
|
-
|
|
524
|
+
|
|
641
525
|
This method should ONLY be called when the user explicitly requests
|
|
642
526
|
deployment of system instructions through agent-manager commands.
|
|
643
527
|
It will deploy INSTRUCTIONS.md, MEMORY.md, and WORKFLOW.md to .claude/
|
|
644
528
|
directory in the project.
|
|
645
|
-
|
|
529
|
+
|
|
646
530
|
Args:
|
|
647
531
|
target_dir: Target directory for deployment (ignored - always uses .claude/)
|
|
648
532
|
force_rebuild: Force rebuild even if files exist
|
|
649
|
-
|
|
533
|
+
|
|
650
534
|
Returns:
|
|
651
535
|
Dict with deployment results
|
|
652
536
|
"""
|
|
@@ -656,35 +540,34 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
656
540
|
"skipped": [],
|
|
657
541
|
"errors": [],
|
|
658
542
|
}
|
|
659
|
-
|
|
543
|
+
|
|
660
544
|
try:
|
|
661
545
|
# Always use project's .claude directory
|
|
662
546
|
target_dir = self.working_directory / ".claude"
|
|
663
|
-
|
|
547
|
+
|
|
664
548
|
# Ensure directory exists
|
|
665
549
|
target_dir.mkdir(parents=True, exist_ok=True)
|
|
666
|
-
|
|
550
|
+
|
|
667
551
|
# Deploy using the deployer (targeting .claude/)
|
|
668
552
|
from .system_instructions_deployer import SystemInstructionsDeployer
|
|
553
|
+
|
|
669
554
|
deployer = SystemInstructionsDeployer(self.logger, self.working_directory)
|
|
670
|
-
|
|
555
|
+
|
|
671
556
|
# Deploy to .claude directory
|
|
672
|
-
deployer.deploy_system_instructions(
|
|
673
|
-
|
|
674
|
-
)
|
|
675
|
-
|
|
557
|
+
deployer.deploy_system_instructions(target_dir, force_rebuild, results)
|
|
558
|
+
|
|
676
559
|
self.logger.info(
|
|
677
560
|
f"Explicitly deployed system instructions to {target_dir}: "
|
|
678
561
|
f"deployed={len(results['deployed'])}, "
|
|
679
562
|
f"updated={len(results['updated'])}, "
|
|
680
563
|
f"skipped={len(results['skipped'])}"
|
|
681
564
|
)
|
|
682
|
-
|
|
565
|
+
|
|
683
566
|
except Exception as e:
|
|
684
567
|
error_msg = f"Failed to deploy system instructions: {e}"
|
|
685
568
|
self.logger.error(error_msg)
|
|
686
569
|
results["errors"].append(error_msg)
|
|
687
|
-
|
|
570
|
+
|
|
688
571
|
return results
|
|
689
572
|
|
|
690
573
|
def _convert_yaml_to_md(self, target_dir: Path) -> Dict[str, Any]:
|
|
@@ -745,11 +628,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
745
628
|
self.logger.info(f"Async deployment completed in {duration_ms:.1f}ms")
|
|
746
629
|
|
|
747
630
|
# Update internal metrics
|
|
748
|
-
self.
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
else:
|
|
752
|
-
self._deployment_metrics["failed_deployments"] += 1
|
|
631
|
+
self.results_manager.update_deployment_metrics(
|
|
632
|
+
not results.get("errors")
|
|
633
|
+
)
|
|
753
634
|
|
|
754
635
|
return results
|
|
755
636
|
|
|
@@ -774,44 +655,6 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
774
655
|
resolver = AgentsDirectoryResolver(self.working_directory)
|
|
775
656
|
return resolver.determine_agents_directory(target_dir)
|
|
776
657
|
|
|
777
|
-
|
|
778
|
-
def _initialize_deployment_results(
|
|
779
|
-
self, agents_dir: Path, deployment_start_time: float
|
|
780
|
-
) -> Dict[str, Any]:
|
|
781
|
-
"""
|
|
782
|
-
Initialize the deployment results dictionary.
|
|
783
|
-
|
|
784
|
-
WHY: Consistent result structure ensures all deployment
|
|
785
|
-
operations return the same format for easier processing.
|
|
786
|
-
|
|
787
|
-
Args:
|
|
788
|
-
agents_dir: Target agents directory
|
|
789
|
-
deployment_start_time: Start time for metrics
|
|
790
|
-
|
|
791
|
-
Returns:
|
|
792
|
-
Initialized results dictionary
|
|
793
|
-
"""
|
|
794
|
-
return {
|
|
795
|
-
"target_dir": str(agents_dir),
|
|
796
|
-
"deployed": [],
|
|
797
|
-
"errors": [],
|
|
798
|
-
"skipped": [],
|
|
799
|
-
"updated": [],
|
|
800
|
-
"migrated": [], # Track agents migrated from old format
|
|
801
|
-
"converted": [], # Track YAML to MD conversions
|
|
802
|
-
"repaired": [], # Track agents with repaired frontmatter
|
|
803
|
-
"total": 0,
|
|
804
|
-
# METRICS: Add detailed timing and performance data to results
|
|
805
|
-
"metrics": {
|
|
806
|
-
"start_time": deployment_start_time,
|
|
807
|
-
"end_time": None,
|
|
808
|
-
"duration_ms": None,
|
|
809
|
-
"agent_timings": {}, # Track individual agent deployment times
|
|
810
|
-
"validation_times": {}, # Track template validation times
|
|
811
|
-
"resource_usage": {}, # Could track memory/CPU if needed
|
|
812
|
-
},
|
|
813
|
-
}
|
|
814
|
-
|
|
815
658
|
def _repair_existing_agents(
|
|
816
659
|
self, agents_dir: Path, results: Dict[str, Any]
|
|
817
660
|
) -> None:
|
|
@@ -834,12 +677,6 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
834
677
|
for agent_name in repair_results["repaired"]:
|
|
835
678
|
self.logger.debug(f" - Repaired: {agent_name}")
|
|
836
679
|
|
|
837
|
-
def _determine_source_tier(self) -> str:
|
|
838
|
-
"""Determine the source tier for logging."""
|
|
839
|
-
from .deployment_type_detector import DeploymentTypeDetector
|
|
840
|
-
|
|
841
|
-
return DeploymentTypeDetector.determine_source_tier(self.templates_dir)
|
|
842
|
-
|
|
843
680
|
def _load_base_agent(self) -> tuple:
|
|
844
681
|
"""Load base agent content and version."""
|
|
845
682
|
return self.configuration_manager.load_base_agent()
|
|
@@ -848,279 +685,51 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
848
685
|
"""Get and filter template files based on exclusion rules."""
|
|
849
686
|
return self.discovery_service.get_filtered_templates(excluded_agents, config)
|
|
850
687
|
|
|
851
|
-
def _deploy_single_agent(
|
|
852
|
-
self,
|
|
853
|
-
template_file: Path,
|
|
854
|
-
agents_dir: Path,
|
|
855
|
-
base_agent_data: dict,
|
|
856
|
-
base_agent_version: tuple,
|
|
857
|
-
force_rebuild: bool,
|
|
858
|
-
deployment_mode: str,
|
|
859
|
-
results: Dict[str, Any],
|
|
860
|
-
source_info: str = "unknown",
|
|
861
|
-
) -> None:
|
|
862
|
-
"""
|
|
863
|
-
Deploy a single agent template.
|
|
864
|
-
|
|
865
|
-
WHY: Extracting single agent deployment logic reduces complexity
|
|
866
|
-
and makes the main deployment loop more readable.
|
|
867
|
-
|
|
868
|
-
Args:
|
|
869
|
-
template_file: Agent template file
|
|
870
|
-
agents_dir: Target agents directory
|
|
871
|
-
base_agent_data: Base agent data
|
|
872
|
-
base_agent_version: Base agent version
|
|
873
|
-
force_rebuild: Whether to force rebuild
|
|
874
|
-
deployment_mode: Deployment mode (update/project)
|
|
875
|
-
results: Results dictionary to update
|
|
876
|
-
source_info: Source of the agent (system/project/user)
|
|
877
|
-
"""
|
|
878
|
-
try:
|
|
879
|
-
# METRICS: Track individual agent deployment time
|
|
880
|
-
agent_start_time = time.time()
|
|
881
|
-
|
|
882
|
-
agent_name = template_file.stem
|
|
883
|
-
target_file = agents_dir / f"{agent_name}.md"
|
|
884
|
-
|
|
885
|
-
# Check if agent needs update
|
|
886
|
-
needs_update, is_migration, reason = self._check_update_status(
|
|
887
|
-
target_file,
|
|
888
|
-
template_file,
|
|
889
|
-
base_agent_version,
|
|
890
|
-
force_rebuild,
|
|
891
|
-
deployment_mode,
|
|
892
|
-
)
|
|
893
|
-
|
|
894
|
-
# Skip if exists and doesn't need update (only in update mode)
|
|
895
|
-
if (
|
|
896
|
-
target_file.exists()
|
|
897
|
-
and not needs_update
|
|
898
|
-
and deployment_mode != "project"
|
|
899
|
-
):
|
|
900
|
-
results["skipped"].append(agent_name)
|
|
901
|
-
self.logger.debug(f"Skipped up-to-date agent: {agent_name}")
|
|
902
|
-
return
|
|
903
|
-
|
|
904
|
-
# Build the agent file as markdown with YAML frontmatter
|
|
905
|
-
agent_content = self.template_builder.build_agent_markdown(
|
|
906
|
-
agent_name, template_file, base_agent_data, source_info
|
|
907
|
-
)
|
|
908
|
-
|
|
909
|
-
# Write the agent file
|
|
910
|
-
is_update = target_file.exists()
|
|
911
|
-
target_file.write_text(agent_content)
|
|
912
|
-
|
|
913
|
-
# Record metrics and update results
|
|
914
|
-
self._record_agent_deployment(
|
|
915
|
-
agent_name,
|
|
916
|
-
template_file,
|
|
917
|
-
target_file,
|
|
918
|
-
is_update,
|
|
919
|
-
is_migration,
|
|
920
|
-
reason,
|
|
921
|
-
agent_start_time,
|
|
922
|
-
results,
|
|
923
|
-
)
|
|
924
|
-
|
|
925
|
-
except AgentDeploymentError as e:
|
|
926
|
-
# Re-raise our custom exceptions
|
|
927
|
-
self.logger.error(str(e))
|
|
928
|
-
results["errors"].append(str(e))
|
|
929
|
-
except Exception as e:
|
|
930
|
-
# Wrap generic exceptions with context
|
|
931
|
-
error_msg = f"Failed to build {template_file.name}: {e}"
|
|
932
|
-
self.logger.error(error_msg)
|
|
933
|
-
results["errors"].append(error_msg)
|
|
934
|
-
|
|
935
|
-
def _check_update_status(
|
|
936
|
-
self,
|
|
937
|
-
target_file: Path,
|
|
938
|
-
template_file: Path,
|
|
939
|
-
base_agent_version: tuple,
|
|
940
|
-
force_rebuild: bool,
|
|
941
|
-
deployment_mode: str,
|
|
942
|
-
) -> tuple:
|
|
943
|
-
"""
|
|
944
|
-
Check if agent needs update and determine status.
|
|
945
|
-
|
|
946
|
-
WHY: Centralized update checking logic ensures consistent
|
|
947
|
-
version comparison and migration detection.
|
|
948
|
-
|
|
949
|
-
Args:
|
|
950
|
-
target_file: Target agent file
|
|
951
|
-
template_file: Template file
|
|
952
|
-
base_agent_version: Base agent version
|
|
953
|
-
force_rebuild: Whether to force rebuild
|
|
954
|
-
deployment_mode: Deployment mode
|
|
955
|
-
|
|
956
|
-
Returns:
|
|
957
|
-
Tuple of (needs_update, is_migration, reason)
|
|
958
|
-
"""
|
|
959
|
-
needs_update = force_rebuild
|
|
960
|
-
is_migration = False
|
|
961
|
-
reason = ""
|
|
962
|
-
|
|
963
|
-
# In project deployment mode, always deploy regardless of version
|
|
964
|
-
if deployment_mode == "project":
|
|
965
|
-
if target_file.exists():
|
|
966
|
-
needs_update = True
|
|
967
|
-
self.logger.debug(
|
|
968
|
-
f"Project deployment mode: will deploy {template_file.stem}"
|
|
969
|
-
)
|
|
970
|
-
else:
|
|
971
|
-
needs_update = True
|
|
972
|
-
elif not needs_update and target_file.exists():
|
|
973
|
-
# In update mode, check version compatibility
|
|
974
|
-
needs_update, reason = self.version_manager.check_agent_needs_update(
|
|
975
|
-
target_file, template_file, base_agent_version
|
|
976
|
-
)
|
|
977
|
-
if needs_update:
|
|
978
|
-
# Check if this is a migration from old format
|
|
979
|
-
if "migration needed" in reason:
|
|
980
|
-
is_migration = True
|
|
981
|
-
self.logger.info(f"Migrating agent {template_file.stem}: {reason}")
|
|
982
|
-
else:
|
|
983
|
-
self.logger.info(
|
|
984
|
-
f"Agent {template_file.stem} needs update: {reason}"
|
|
985
|
-
)
|
|
986
|
-
|
|
987
|
-
return needs_update, is_migration, reason
|
|
988
|
-
|
|
989
|
-
def _record_agent_deployment(
|
|
990
|
-
self,
|
|
991
|
-
agent_name: str,
|
|
992
|
-
template_file: Path,
|
|
993
|
-
target_file: Path,
|
|
994
|
-
is_update: bool,
|
|
995
|
-
is_migration: bool,
|
|
996
|
-
reason: str,
|
|
997
|
-
agent_start_time: float,
|
|
998
|
-
results: Dict[str, Any],
|
|
999
|
-
) -> None:
|
|
1000
|
-
"""
|
|
1001
|
-
Record deployment metrics and update results.
|
|
1002
|
-
|
|
1003
|
-
WHY: Centralized metrics recording ensures consistent tracking
|
|
1004
|
-
of deployment performance and statistics.
|
|
1005
|
-
|
|
1006
|
-
Args:
|
|
1007
|
-
agent_name: Name of the agent
|
|
1008
|
-
template_file: Template file
|
|
1009
|
-
target_file: Target file
|
|
1010
|
-
is_update: Whether this is an update
|
|
1011
|
-
is_migration: Whether this is a migration
|
|
1012
|
-
reason: Update/migration reason
|
|
1013
|
-
agent_start_time: Start time for this agent
|
|
1014
|
-
results: Results dictionary to update
|
|
1015
|
-
"""
|
|
1016
|
-
# METRICS: Record deployment time for this agent
|
|
1017
|
-
agent_deployment_time = (time.time() - agent_start_time) * 1000 # Convert to ms
|
|
1018
|
-
results["metrics"]["agent_timings"][agent_name] = agent_deployment_time
|
|
1019
|
-
|
|
1020
|
-
# METRICS: Update agent type deployment counts
|
|
1021
|
-
self._deployment_metrics["agent_type_counts"][agent_name] = (
|
|
1022
|
-
self._deployment_metrics["agent_type_counts"].get(agent_name, 0) + 1
|
|
1023
|
-
)
|
|
1024
|
-
|
|
1025
|
-
deployment_info = {
|
|
1026
|
-
"name": agent_name,
|
|
1027
|
-
"template": str(template_file),
|
|
1028
|
-
"target": str(target_file),
|
|
1029
|
-
"deployment_time_ms": agent_deployment_time,
|
|
1030
|
-
}
|
|
1031
|
-
|
|
1032
|
-
if is_migration:
|
|
1033
|
-
deployment_info["reason"] = reason
|
|
1034
|
-
results["migrated"].append(deployment_info)
|
|
1035
|
-
self.logger.info(
|
|
1036
|
-
f"Successfully migrated agent: {agent_name} to semantic versioning"
|
|
1037
|
-
)
|
|
1038
|
-
|
|
1039
|
-
# METRICS: Track migration statistics
|
|
1040
|
-
self._deployment_metrics["migrations_performed"] += 1
|
|
1041
|
-
self._deployment_metrics["version_migration_count"] += 1
|
|
1042
|
-
|
|
1043
|
-
elif is_update:
|
|
1044
|
-
results["updated"].append(deployment_info)
|
|
1045
|
-
self.logger.debug(f"Updated agent: {agent_name}")
|
|
1046
|
-
else:
|
|
1047
|
-
results["deployed"].append(deployment_info)
|
|
1048
|
-
self.logger.debug(f"Built and deployed agent: {agent_name}")
|
|
1049
|
-
|
|
1050
688
|
def _validate_and_repair_existing_agents(self, agents_dir: Path) -> Dict[str, Any]:
|
|
1051
689
|
"""Validate and repair broken frontmatter in existing agent files."""
|
|
1052
690
|
from .agent_frontmatter_validator import AgentFrontmatterValidator
|
|
1053
691
|
|
|
1054
692
|
validator = AgentFrontmatterValidator(self.logger)
|
|
1055
693
|
return validator.validate_and_repair_existing_agents(agents_dir)
|
|
1056
|
-
|
|
1057
|
-
def _determine_agent_source(self, template_path: Path) -> str:
|
|
1058
|
-
"""Determine the source of an agent from its template path.
|
|
1059
|
-
|
|
1060
|
-
WHY: When deploying single agents, we need to track their source
|
|
1061
|
-
for proper version management and debugging.
|
|
1062
|
-
|
|
1063
|
-
Args:
|
|
1064
|
-
template_path: Path to the agent template
|
|
1065
|
-
|
|
1066
|
-
Returns:
|
|
1067
|
-
Source string (system/project/user/unknown)
|
|
1068
|
-
"""
|
|
1069
|
-
template_str = str(template_path.resolve())
|
|
1070
|
-
|
|
1071
|
-
# Check if it's a system template
|
|
1072
|
-
if "/claude_mpm/agents/templates/" in template_str or "/src/claude_mpm/agents/templates/" in template_str:
|
|
1073
|
-
return "system"
|
|
1074
|
-
|
|
1075
|
-
# Check if it's a project agent
|
|
1076
|
-
if "/.claude-mpm/agents/" in template_str:
|
|
1077
|
-
# Check if it's in the current working directory
|
|
1078
|
-
if str(self.working_directory) in template_str:
|
|
1079
|
-
return "project"
|
|
1080
|
-
# Check if it's in user home
|
|
1081
|
-
elif str(Path.home()) in template_str:
|
|
1082
|
-
return "user"
|
|
1083
|
-
|
|
1084
|
-
return "unknown"
|
|
1085
|
-
|
|
694
|
+
|
|
1086
695
|
def _should_use_multi_source_deployment(self, deployment_mode: str) -> bool:
|
|
1087
696
|
"""Determine if multi-source deployment should be used.
|
|
1088
|
-
|
|
697
|
+
|
|
1089
698
|
WHY: Multi-source deployment ensures the highest version wins,
|
|
1090
699
|
but we may want to preserve backward compatibility in some modes.
|
|
1091
|
-
|
|
700
|
+
|
|
1092
701
|
Args:
|
|
1093
702
|
deployment_mode: Current deployment mode
|
|
1094
|
-
|
|
703
|
+
|
|
1095
704
|
Returns:
|
|
1096
705
|
True if multi-source deployment should be used
|
|
1097
706
|
"""
|
|
1098
707
|
# Always use multi-source for update mode to get highest versions
|
|
1099
708
|
if deployment_mode == "update":
|
|
1100
709
|
return True
|
|
1101
|
-
|
|
710
|
+
|
|
1102
711
|
# For project mode, also use multi-source to ensure highest version wins
|
|
1103
712
|
# This is the key change - project mode should also compare versions
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
return False
|
|
1108
|
-
|
|
713
|
+
return deployment_mode == "project"
|
|
714
|
+
|
|
1109
715
|
def _get_multi_source_templates(
|
|
1110
|
-
self,
|
|
1111
|
-
|
|
716
|
+
self,
|
|
717
|
+
excluded_agents: List[str],
|
|
718
|
+
config: Config,
|
|
719
|
+
agents_dir: Path,
|
|
720
|
+
force_rebuild: bool = False,
|
|
1112
721
|
) -> Tuple[List[Path], Dict[str, str], Dict[str, Any]]:
|
|
1113
722
|
"""Get agent templates from multiple sources with version comparison.
|
|
1114
|
-
|
|
723
|
+
|
|
1115
724
|
WHY: This method uses the multi-source service to discover agents
|
|
1116
725
|
from all available sources and select the highest version of each.
|
|
1117
|
-
|
|
726
|
+
|
|
1118
727
|
Args:
|
|
1119
728
|
excluded_agents: List of agents to exclude
|
|
1120
729
|
config: Configuration object
|
|
1121
730
|
agents_dir: Target deployment directory
|
|
1122
731
|
force_rebuild: Whether to force rebuild
|
|
1123
|
-
|
|
732
|
+
|
|
1124
733
|
Returns:
|
|
1125
734
|
Tuple of (template_files, agent_sources, cleanup_results)
|
|
1126
735
|
"""
|
|
@@ -1128,70 +737,79 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
1128
737
|
system_templates_dir = self.templates_dir
|
|
1129
738
|
project_agents_dir = None
|
|
1130
739
|
user_agents_dir = None
|
|
1131
|
-
|
|
740
|
+
|
|
1132
741
|
# Check for project agents
|
|
1133
742
|
if self.working_directory:
|
|
1134
743
|
potential_project_dir = self.working_directory / ".claude-mpm" / "agents"
|
|
1135
744
|
if potential_project_dir.exists():
|
|
1136
745
|
project_agents_dir = potential_project_dir
|
|
1137
746
|
self.logger.info(f"Found project agents at: {project_agents_dir}")
|
|
1138
|
-
|
|
747
|
+
|
|
1139
748
|
# Check for user agents
|
|
1140
749
|
user_home = Path.home()
|
|
1141
750
|
potential_user_dir = user_home / ".claude-mpm" / "agents"
|
|
1142
751
|
if potential_user_dir.exists():
|
|
1143
752
|
user_agents_dir = potential_user_dir
|
|
1144
753
|
self.logger.info(f"Found user agents at: {user_agents_dir}")
|
|
1145
|
-
|
|
754
|
+
|
|
1146
755
|
# Get agents with version comparison and cleanup
|
|
1147
|
-
agents_to_deploy, agent_sources, cleanup_results =
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
756
|
+
agents_to_deploy, agent_sources, cleanup_results = (
|
|
757
|
+
self.multi_source_service.get_agents_for_deployment(
|
|
758
|
+
system_templates_dir=system_templates_dir,
|
|
759
|
+
project_agents_dir=project_agents_dir,
|
|
760
|
+
user_agents_dir=user_agents_dir,
|
|
761
|
+
working_directory=self.working_directory,
|
|
762
|
+
excluded_agents=excluded_agents,
|
|
763
|
+
config=config,
|
|
764
|
+
cleanup_outdated=True, # Enable cleanup by default
|
|
765
|
+
)
|
|
1155
766
|
)
|
|
1156
|
-
|
|
767
|
+
|
|
1157
768
|
# Compare with deployed versions if agents directory exists
|
|
1158
769
|
if agents_dir.exists():
|
|
1159
770
|
comparison_results = self.multi_source_service.compare_deployed_versions(
|
|
1160
771
|
deployed_agents_dir=agents_dir,
|
|
1161
772
|
agents_to_deploy=agents_to_deploy,
|
|
1162
|
-
agent_sources=agent_sources
|
|
773
|
+
agent_sources=agent_sources,
|
|
1163
774
|
)
|
|
1164
|
-
|
|
775
|
+
|
|
1165
776
|
# Log version upgrades and source changes
|
|
1166
777
|
if comparison_results.get("version_upgrades"):
|
|
1167
|
-
self.logger.info(
|
|
778
|
+
self.logger.info(
|
|
779
|
+
f"Version upgrades available for {len(comparison_results['version_upgrades'])} agents"
|
|
780
|
+
)
|
|
1168
781
|
if comparison_results.get("source_changes"):
|
|
1169
|
-
self.logger.info(
|
|
1170
|
-
|
|
782
|
+
self.logger.info(
|
|
783
|
+
f"Source changes for {len(comparison_results['source_changes'])} agents"
|
|
784
|
+
)
|
|
785
|
+
|
|
1171
786
|
# Filter agents based on comparison results (unless force_rebuild is set)
|
|
1172
787
|
if not force_rebuild:
|
|
1173
788
|
# Only deploy agents that need updates or are new
|
|
1174
789
|
agents_needing_update = set(comparison_results.get("needs_update", []))
|
|
1175
|
-
|
|
790
|
+
|
|
1176
791
|
# Extract agent names from new_agents list (which contains dicts)
|
|
1177
792
|
new_agent_names = [
|
|
1178
793
|
agent["name"] if isinstance(agent, dict) else agent
|
|
1179
794
|
for agent in comparison_results.get("new_agents", [])
|
|
1180
795
|
]
|
|
1181
796
|
agents_needing_update.update(new_agent_names)
|
|
1182
|
-
|
|
797
|
+
|
|
1183
798
|
# Filter agents_to_deploy to only include those needing updates
|
|
1184
799
|
filtered_agents = {
|
|
1185
|
-
name: path
|
|
800
|
+
name: path
|
|
801
|
+
for name, path in agents_to_deploy.items()
|
|
1186
802
|
if name in agents_needing_update
|
|
1187
803
|
}
|
|
1188
804
|
agents_to_deploy = filtered_agents
|
|
1189
|
-
|
|
1190
|
-
self.logger.info(
|
|
1191
|
-
|
|
805
|
+
|
|
806
|
+
self.logger.info(
|
|
807
|
+
f"Filtered to {len(agents_to_deploy)} agents needing deployment"
|
|
808
|
+
)
|
|
809
|
+
|
|
1192
810
|
# Convert to list of Path objects
|
|
1193
811
|
template_files = list(agents_to_deploy.values())
|
|
1194
|
-
|
|
812
|
+
|
|
1195
813
|
return template_files, agent_sources, cleanup_results
|
|
1196
814
|
|
|
1197
815
|
# ================================================================================
|
|
@@ -1243,7 +861,7 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
|
|
|
1243
861
|
return len(errors) == 0, errors
|
|
1244
862
|
|
|
1245
863
|
except Exception as e:
|
|
1246
|
-
return False, [f"Validation error: {
|
|
864
|
+
return False, [f"Validation error: {e!s}"]
|
|
1247
865
|
|
|
1248
866
|
def get_deployment_status(self) -> Dict[str, Any]:
|
|
1249
867
|
"""Get current deployment status and metrics."""
|