claude-mpm 4.1.26__py3-none-any.whl ā 5.0.9__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.
Potentially problematic release.
This version of claude-mpm might be problematic. Click here for more details.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__init__.py +20 -5
- claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
- claude_mpm/agents/BASE_DOCUMENTATION.md +53 -0
- claude_mpm/agents/BASE_ENGINEER.md +658 -0
- claude_mpm/agents/BASE_OPS.md +219 -0
- claude_mpm/agents/BASE_PM.md +432 -158
- claude_mpm/agents/BASE_PROMPT_ENGINEER.md +787 -0
- claude_mpm/agents/BASE_QA.md +167 -0
- claude_mpm/agents/BASE_RESEARCH.md +53 -0
- claude_mpm/agents/OUTPUT_STYLE.md +254 -29
- claude_mpm/agents/PM_INSTRUCTIONS.md +969 -0
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
- claude_mpm/agents/WORKFLOW.md +355 -191
- claude_mpm/agents/__init__.py +6 -0
- claude_mpm/agents/agent_loader.py +41 -14
- claude_mpm/agents/agent_loader_integration.py +3 -2
- claude_mpm/agents/async_agent_loader.py +3 -3
- claude_mpm/agents/base_agent.json +6 -3
- claude_mpm/agents/base_agent_loader.py +21 -44
- claude_mpm/agents/frontmatter_validator.py +292 -252
- claude_mpm/agents/system_agent_config.py +3 -2
- claude_mpm/agents/templates/README.md +465 -0
- claude_mpm/agents/templates/circuit-breakers.md +1005 -0
- claude_mpm/agents/templates/context-management-examples.md +544 -0
- claude_mpm/agents/templates/git-file-tracking.md +584 -0
- claude_mpm/agents/templates/pm-examples.md +474 -0
- claude_mpm/agents/templates/pm-red-flags.md +310 -0
- claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
- claude_mpm/agents/templates/research-gate-examples.md +669 -0
- claude_mpm/agents/templates/response-format.md +583 -0
- claude_mpm/agents/templates/structured-questions-examples.md +615 -0
- claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
- claude_mpm/agents/templates/ticketing-examples.md +277 -0
- claude_mpm/agents/templates/validation-templates.md +312 -0
- claude_mpm/cli/__init__.py +72 -376
- claude_mpm/cli/commands/__init__.py +4 -0
- claude_mpm/cli/commands/agent_manager.py +675 -20
- claude_mpm/cli/commands/agent_source.py +774 -0
- claude_mpm/cli/commands/agent_state_manager.py +344 -0
- claude_mpm/cli/commands/agents.py +1673 -178
- claude_mpm/cli/commands/agents_cleanup.py +210 -0
- claude_mpm/cli/commands/agents_detect.py +380 -0
- claude_mpm/cli/commands/agents_discover.py +338 -0
- claude_mpm/cli/commands/agents_recommend.py +309 -0
- claude_mpm/cli/commands/aggregate.py +11 -7
- claude_mpm/cli/commands/analyze.py +18 -13
- claude_mpm/cli/commands/analyze_code.py +8 -4
- claude_mpm/cli/commands/auto_configure.py +566 -0
- claude_mpm/cli/commands/cleanup.py +12 -12
- claude_mpm/cli/commands/config.py +54 -17
- claude_mpm/cli/commands/configure.py +1184 -1055
- claude_mpm/cli/commands/configure_agent_display.py +261 -0
- claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
- claude_mpm/cli/commands/configure_hook_manager.py +225 -0
- claude_mpm/cli/commands/configure_models.py +18 -0
- claude_mpm/cli/commands/configure_navigation.py +184 -0
- claude_mpm/cli/commands/configure_paths.py +104 -0
- claude_mpm/cli/commands/configure_persistence.py +254 -0
- claude_mpm/cli/commands/configure_startup_manager.py +646 -0
- claude_mpm/cli/commands/configure_template_editor.py +497 -0
- claude_mpm/cli/commands/configure_validators.py +73 -0
- claude_mpm/cli/commands/dashboard.py +50 -52
- claude_mpm/cli/commands/debug.py +19 -19
- claude_mpm/cli/commands/doctor.py +51 -7
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/info.py +3 -4
- claude_mpm/cli/commands/local_deploy.py +534 -0
- claude_mpm/cli/commands/mcp.py +17 -10
- claude_mpm/cli/commands/mcp_command_router.py +11 -0
- claude_mpm/cli/commands/mcp_config.py +154 -0
- claude_mpm/cli/commands/mcp_external_commands.py +249 -0
- claude_mpm/cli/commands/mcp_install_commands.py +101 -32
- claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
- claude_mpm/cli/commands/mcp_setup_external.py +868 -0
- claude_mpm/cli/commands/memory.py +55 -21
- claude_mpm/cli/commands/monitor.py +160 -70
- claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +573 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +114 -4
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/run.py +252 -167
- claude_mpm/cli/commands/search.py +458 -0
- claude_mpm/cli/commands/skill_source.py +694 -0
- claude_mpm/cli/commands/skills.py +1225 -0
- claude_mpm/cli/commands/uninstall.py +176 -0
- claude_mpm/cli/commands/upgrade.py +152 -0
- claude_mpm/cli/commands/verify.py +119 -0
- claude_mpm/cli/executor.py +279 -0
- claude_mpm/cli/helpers.py +105 -0
- claude_mpm/cli/interactive/__init__.py +21 -0
- claude_mpm/cli/interactive/agent_wizard.py +1872 -0
- claude_mpm/cli/interactive/skills_wizard.py +491 -0
- claude_mpm/cli/parser.py +79 -2
- claude_mpm/cli/parsers/__init__.py +7 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +161 -1
- claude_mpm/cli/parsers/agent_source_parser.py +171 -0
- claude_mpm/cli/parsers/agents_parser.py +369 -1
- claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
- claude_mpm/cli/parsers/base_parser.py +196 -3
- claude_mpm/cli/parsers/config_parser.py +96 -43
- claude_mpm/cli/parsers/configure_parser.py +11 -15
- claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
- claude_mpm/cli/parsers/mcp_parser.py +15 -0
- claude_mpm/cli/parsers/monitor_parser.py +12 -2
- claude_mpm/cli/parsers/mpm_init_parser.py +179 -9
- claude_mpm/cli/parsers/run_parser.py +5 -0
- claude_mpm/cli/parsers/search_parser.py +245 -0
- claude_mpm/cli/parsers/skill_source_parser.py +169 -0
- claude_mpm/cli/parsers/skills_parser.py +282 -0
- claude_mpm/cli/parsers/source_parser.py +138 -0
- claude_mpm/cli/shared/argument_patterns.py +20 -13
- claude_mpm/cli/shared/base_command.py +2 -2
- claude_mpm/cli/shared/output_formatters.py +28 -19
- claude_mpm/cli/startup.py +994 -0
- claude_mpm/cli/startup_display.py +480 -0
- claude_mpm/cli/startup_logging.py +179 -13
- claude_mpm/cli/utils.py +54 -3
- claude_mpm/cli_module/commands.py +1 -1
- claude_mpm/commands/mpm-agents-auto-configure.md +278 -0
- claude_mpm/commands/mpm-agents-detect.md +177 -0
- claude_mpm/commands/mpm-agents-list.md +131 -0
- claude_mpm/commands/mpm-agents-recommend.md +223 -0
- claude_mpm/commands/mpm-config-view.md +150 -0
- claude_mpm/commands/mpm-doctor.md +9 -0
- claude_mpm/commands/mpm-help.md +297 -5
- claude_mpm/commands/mpm-init.md +401 -17
- claude_mpm/commands/mpm-monitor.md +418 -0
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/mpm-session-resume.md +381 -0
- claude_mpm/commands/mpm-status.md +79 -8
- claude_mpm/commands/mpm-ticket-organize.md +304 -0
- claude_mpm/commands/mpm-ticket-view.md +552 -0
- claude_mpm/commands/mpm-version.md +122 -0
- claude_mpm/commands/mpm.md +12 -0
- claude_mpm/config/agent_config.py +4 -4
- claude_mpm/config/agent_presets.py +488 -0
- claude_mpm/config/agent_sources.py +325 -0
- claude_mpm/config/experimental_features.py +7 -7
- claude_mpm/config/model_config.py +428 -0
- claude_mpm/config/paths.py +3 -2
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/config/skill_sources.py +590 -0
- claude_mpm/config/socketio_config.py +3 -3
- claude_mpm/constants.py +28 -1
- claude_mpm/core/__init__.py +53 -17
- claude_mpm/core/agent_name_normalizer.py +3 -2
- claude_mpm/core/agent_registry.py +2 -2
- claude_mpm/core/agent_session_manager.py +10 -10
- claude_mpm/core/api_validator.py +330 -0
- claude_mpm/core/base_service.py +33 -23
- claude_mpm/core/cache.py +9 -9
- claude_mpm/core/claude_runner.py +24 -42
- claude_mpm/core/config.py +101 -8
- claude_mpm/core/config_aliases.py +7 -6
- claude_mpm/core/constants.py +66 -1
- claude_mpm/core/container.py +11 -5
- claude_mpm/core/enums.py +452 -0
- claude_mpm/core/error_handler.py +623 -0
- claude_mpm/core/factories.py +1 -1
- claude_mpm/core/file_utils.py +764 -0
- claude_mpm/core/framework/__init__.py +25 -0
- claude_mpm/core/framework/formatters/__init__.py +11 -0
- claude_mpm/core/framework/formatters/capability_generator.py +367 -0
- claude_mpm/core/framework/formatters/content_formatter.py +288 -0
- claude_mpm/core/framework/formatters/context_generator.py +185 -0
- claude_mpm/core/framework/loaders/__init__.py +13 -0
- claude_mpm/core/framework/loaders/agent_loader.py +210 -0
- claude_mpm/core/framework/loaders/file_loader.py +176 -0
- claude_mpm/core/framework/loaders/instruction_loader.py +181 -0
- claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
- claude_mpm/core/framework/processors/__init__.py +11 -0
- claude_mpm/core/framework/processors/memory_processor.py +230 -0
- claude_mpm/core/framework/processors/metadata_processor.py +146 -0
- claude_mpm/core/framework/processors/template_processor.py +244 -0
- claude_mpm/core/framework_loader.py +321 -1631
- claude_mpm/core/hook_error_memory.py +381 -0
- claude_mpm/core/hook_manager.py +49 -8
- claude_mpm/core/injectable_service.py +11 -8
- claude_mpm/core/instruction_reinforcement_hook.py +4 -3
- claude_mpm/core/interactive_session.py +146 -18
- claude_mpm/core/interfaces.py +56 -1
- claude_mpm/core/lazy.py +3 -3
- claude_mpm/core/log_manager.py +92 -23
- claude_mpm/core/logger.py +22 -15
- claude_mpm/core/logging_config.py +6 -2
- claude_mpm/core/logging_utils.py +520 -0
- claude_mpm/core/oneshot_session.py +122 -15
- claude_mpm/core/optimized_agent_loader.py +9 -9
- claude_mpm/core/optimized_startup.py +1 -1
- claude_mpm/core/output_style_manager.py +12 -192
- claude_mpm/core/pm_hook_interceptor.py +18 -12
- claude_mpm/core/protocols/__init__.py +23 -0
- claude_mpm/core/protocols/runner_protocol.py +103 -0
- claude_mpm/core/protocols/session_protocol.py +131 -0
- claude_mpm/core/service_registry.py +7 -3
- claude_mpm/core/session_manager.py +14 -12
- claude_mpm/core/shared/config_loader.py +1 -1
- claude_mpm/core/shared/singleton_manager.py +11 -4
- claude_mpm/core/socketio_pool.py +15 -15
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/tool_access_control.py +3 -2
- claude_mpm/core/types.py +4 -11
- claude_mpm/core/typing_utils.py +7 -6
- claude_mpm/core/unified_agent_registry.py +115 -11
- claude_mpm/core/unified_config.py +6 -6
- claude_mpm/core/unified_paths.py +23 -20
- claude_mpm/dashboard/analysis_runner.py +4 -4
- claude_mpm/dashboard/api/simple_directory.py +261 -0
- claude_mpm/dashboard/static/css/activity.css +69 -69
- claude_mpm/dashboard/static/css/connection-status.css +10 -10
- claude_mpm/dashboard/static/css/dashboard.css +600 -18
- claude_mpm/dashboard/static/js/components/activity-tree.js +181 -195
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +105 -102
- claude_mpm/dashboard/static/js/components/agent-inference.js +34 -31
- claude_mpm/dashboard/static/js/components/build-tracker.js +67 -59
- claude_mpm/dashboard/static/js/components/code-simple.js +857 -0
- claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +50 -13
- claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +36 -16
- claude_mpm/dashboard/static/js/components/file-viewer.js +580 -0
- claude_mpm/dashboard/static/js/components/module-viewer.js +49 -23
- claude_mpm/dashboard/static/js/components/session-manager.js +19 -19
- claude_mpm/dashboard/static/js/components/socket-manager.js +5 -1
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +356 -41
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +520 -88
- claude_mpm/dashboard/static/js/components/working-directory.js +46 -11
- claude_mpm/dashboard/static/js/connection-manager.js +76 -76
- claude_mpm/dashboard/static/js/dashboard.js +309 -178
- claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/js/socket-client.js +183 -139
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/socket.io.min.js +7 -0
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
- claude_mpm/dashboard/templates/code_simple.html +153 -0
- claude_mpm/dashboard/templates/index.html +125 -122
- claude_mpm/experimental/cli_enhancements.py +5 -7
- claude_mpm/generators/agent_profile_generator.py +5 -3
- claude_mpm/hooks/__init__.py +37 -1
- claude_mpm/hooks/base_hook.py +5 -4
- claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +24 -19
- claude_mpm/hooks/claude_hooks/hook_handler.py +29 -22
- claude_mpm/hooks/claude_hooks/installer.py +67 -22
- claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
- claude_mpm/hooks/claude_hooks/response_tracking.py +57 -17
- claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +62 -64
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +140 -76
- claude_mpm/hooks/claude_hooks/services/state_manager.py +11 -9
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
- claude_mpm/hooks/failure_learning/__init__.py +54 -0
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
- claude_mpm/hooks/instruction_reinforcement.py +301 -0
- claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
- claude_mpm/hooks/kuzu_memory_hook.py +386 -0
- claude_mpm/hooks/kuzu_response_hook.py +179 -0
- claude_mpm/hooks/memory_integration_hook.py +1 -1
- claude_mpm/hooks/session_resume_hook.py +121 -0
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/hooks/tool_call_interceptor.py +8 -5
- claude_mpm/hooks/validation_hooks.py +3 -3
- claude_mpm/init.py +23 -4
- claude_mpm/models/agent_session.py +8 -6
- claude_mpm/models/git_repository.py +198 -0
- claude_mpm/models/resume_log.py +340 -0
- claude_mpm/scripts/claude-hook-handler.sh +35 -9
- claude_mpm/scripts/launch_monitor.py +85 -0
- claude_mpm/scripts/mcp_server.py +3 -5
- claude_mpm/scripts/mpm_doctor.py +3 -2
- claude_mpm/scripts/socketio_daemon.py +159 -512
- claude_mpm/scripts/start_activity_logging.py +3 -1
- claude_mpm/services/__init__.py +144 -160
- claude_mpm/services/agents/__init__.py +18 -5
- claude_mpm/services/agents/agent_builder.py +56 -18
- claude_mpm/services/agents/agent_preset_service.py +238 -0
- claude_mpm/services/agents/agent_selection_service.py +484 -0
- claude_mpm/services/agents/auto_config_manager.py +796 -0
- claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
- claude_mpm/services/agents/deployment/agent_deployment.py +164 -17
- claude_mpm/services/agents/deployment/agent_discovery_service.py +191 -41
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_format_converter.py +56 -12
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -7
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
- claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +4 -4
- claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
- claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
- claude_mpm/services/agents/deployment/agent_template_builder.py +939 -50
- claude_mpm/services/agents/deployment/agent_validator.py +31 -7
- claude_mpm/services/agents/deployment/agent_version_manager.py +8 -5
- claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
- claude_mpm/services/agents/deployment/async_agent_deployment.py +3 -2
- claude_mpm/services/agents/deployment/deployment_config_loader.py +131 -7
- claude_mpm/services/agents/deployment/deployment_type_detector.py +10 -14
- claude_mpm/services/agents/deployment/deployment_wrapper.py +58 -0
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
- claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
- claude_mpm/services/agents/deployment/local_template_deployment.py +360 -0
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +249 -53
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +8 -7
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +7 -5
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +10 -10
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
- claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -43
- claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/template_validator.py +64 -44
- claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
- claude_mpm/services/agents/git_source_manager.py +629 -0
- claude_mpm/services/agents/loading/agent_profile_loader.py +10 -9
- claude_mpm/services/agents/loading/base_agent_manager.py +16 -6
- claude_mpm/services/agents/loading/framework_agent_loader.py +11 -14
- claude_mpm/services/agents/local_template_manager.py +784 -0
- claude_mpm/services/agents/management/agent_capabilities_generator.py +3 -2
- claude_mpm/services/agents/management/agent_management_service.py +5 -5
- claude_mpm/services/agents/memory/agent_memory_manager.py +32 -29
- claude_mpm/services/agents/memory/content_manager.py +17 -9
- claude_mpm/services/agents/memory/memory_categorization_service.py +4 -2
- claude_mpm/services/agents/memory/memory_file_service.py +32 -6
- claude_mpm/services/agents/memory/memory_format_service.py +6 -4
- claude_mpm/services/agents/memory/memory_limits_service.py +4 -2
- claude_mpm/services/agents/memory/template_generator.py +3 -3
- claude_mpm/services/agents/observers.py +547 -0
- claude_mpm/services/agents/recommender.py +615 -0
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +3 -3
- claude_mpm/services/agents/registry/modification_tracker.py +30 -19
- claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
- claude_mpm/services/agents/sources/__init__.py +13 -0
- claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
- claude_mpm/services/agents/sources/git_source_sync_service.py +1087 -0
- claude_mpm/services/agents/startup_sync.py +239 -0
- claude_mpm/services/agents/toolchain_detector.py +474 -0
- claude_mpm/services/analysis/__init__.py +25 -0
- claude_mpm/services/analysis/postmortem_reporter.py +474 -0
- claude_mpm/services/analysis/postmortem_service.py +765 -0
- claude_mpm/services/async_session_logger.py +141 -98
- claude_mpm/services/claude_session_logger.py +82 -74
- claude_mpm/services/cli/agent_cleanup_service.py +5 -0
- claude_mpm/services/cli/agent_listing_service.py +5 -5
- claude_mpm/services/cli/agent_validation_service.py +3 -1
- claude_mpm/services/cli/memory_crud_service.py +12 -7
- claude_mpm/services/cli/memory_output_formatter.py +2 -2
- claude_mpm/services/cli/resume_service.py +617 -0
- claude_mpm/services/cli/session_manager.py +104 -13
- claude_mpm/services/cli/session_pause_manager.py +504 -0
- claude_mpm/services/cli/session_resume_helper.py +372 -0
- claude_mpm/services/cli/startup_checker.py +13 -10
- claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
- claude_mpm/services/command_deployment_service.py +209 -13
- claude_mpm/services/command_handler_service.py +11 -5
- claude_mpm/services/core/__init__.py +33 -1
- claude_mpm/services/core/base.py +31 -11
- claude_mpm/services/core/interfaces/__init__.py +88 -3
- claude_mpm/services/core/interfaces/agent.py +184 -0
- claude_mpm/services/core/interfaces/health.py +169 -0
- claude_mpm/services/core/interfaces/model.py +281 -0
- claude_mpm/services/core/interfaces/process.py +372 -0
- claude_mpm/services/core/interfaces/project.py +121 -0
- claude_mpm/services/core/interfaces/restart.py +307 -0
- claude_mpm/services/core/interfaces/stability.py +260 -0
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/memory_manager.py +92 -47
- claude_mpm/services/core/models/__init__.py +70 -0
- claude_mpm/services/core/models/agent_config.py +384 -0
- claude_mpm/services/core/models/health.py +162 -0
- claude_mpm/services/core/models/process.py +239 -0
- claude_mpm/services/core/models/restart.py +302 -0
- claude_mpm/services/core/models/stability.py +264 -0
- claude_mpm/services/core/models/toolchain.py +306 -0
- claude_mpm/services/core/path_resolver.py +36 -14
- claude_mpm/services/diagnostics/__init__.py +2 -2
- claude_mpm/services/diagnostics/checks/__init__.py +8 -2
- claude_mpm/services/diagnostics/checks/agent_check.py +30 -34
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
- claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
- claude_mpm/services/diagnostics/checks/common_issues_check.py +28 -27
- claude_mpm/services/diagnostics/checks/configuration_check.py +26 -25
- claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
- claude_mpm/services/diagnostics/checks/installation_check.py +165 -60
- claude_mpm/services/diagnostics/checks/instructions_check.py +21 -21
- claude_mpm/services/diagnostics/checks/mcp_check.py +57 -44
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
- claude_mpm/services/diagnostics/checks/monitor_check.py +24 -24
- claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
- claude_mpm/services/diagnostics/checks/startup_log_check.py +14 -11
- claude_mpm/services/diagnostics/diagnostic_runner.py +31 -13
- claude_mpm/services/diagnostics/doctor_reporter.py +305 -47
- claude_mpm/services/diagnostics/models.py +37 -21
- claude_mpm/services/event_aggregator.py +5 -3
- claude_mpm/services/event_bus/direct_relay.py +11 -7
- claude_mpm/services/event_bus/event_bus.py +51 -9
- claude_mpm/services/event_bus/relay.py +33 -14
- claude_mpm/services/events/consumers/dead_letter.py +7 -5
- claude_mpm/services/events/consumers/logging.py +1 -2
- claude_mpm/services/events/core.py +5 -6
- claude_mpm/services/events/producers/hook.py +6 -6
- claude_mpm/services/events/producers/system.py +8 -8
- claude_mpm/services/exceptions.py +5 -5
- claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +5 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +2 -2
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
- claude_mpm/services/git/__init__.py +21 -0
- claude_mpm/services/git/git_operations_service.py +494 -0
- claude_mpm/services/github/__init__.py +21 -0
- claude_mpm/services/github/github_cli_service.py +397 -0
- claude_mpm/services/hook_installer_service.py +506 -0
- claude_mpm/services/hook_service.py +5 -6
- claude_mpm/services/infrastructure/context_preservation.py +13 -11
- claude_mpm/services/infrastructure/daemon_manager.py +9 -9
- claude_mpm/services/infrastructure/logging.py +2 -2
- claude_mpm/services/infrastructure/monitoring/__init__.py +2 -6
- claude_mpm/services/infrastructure/monitoring/aggregator.py +13 -18
- claude_mpm/services/infrastructure/monitoring/base.py +5 -13
- claude_mpm/services/infrastructure/monitoring/network.py +7 -6
- claude_mpm/services/infrastructure/monitoring/process.py +13 -12
- claude_mpm/services/infrastructure/monitoring/resources.py +8 -7
- claude_mpm/services/infrastructure/monitoring/service.py +16 -15
- claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
- claude_mpm/services/instructions/__init__.py +9 -0
- claude_mpm/services/instructions/instruction_cache_service.py +374 -0
- claude_mpm/services/local_ops/__init__.py +155 -0
- claude_mpm/services/local_ops/crash_detector.py +257 -0
- claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
- claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
- claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
- claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
- claude_mpm/services/local_ops/health_manager.py +427 -0
- claude_mpm/services/local_ops/log_monitor.py +396 -0
- claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
- claude_mpm/services/local_ops/process_manager.py +595 -0
- claude_mpm/services/local_ops/resource_monitor.py +331 -0
- claude_mpm/services/local_ops/restart_manager.py +401 -0
- claude_mpm/services/local_ops/restart_policy.py +387 -0
- claude_mpm/services/local_ops/state_manager.py +372 -0
- claude_mpm/services/local_ops/unified_manager.py +600 -0
- claude_mpm/services/mcp_config_manager.py +1542 -0
- claude_mpm/services/mcp_gateway/__init__.py +97 -93
- claude_mpm/services/mcp_gateway/auto_configure.py +43 -38
- claude_mpm/services/mcp_gateway/config/config_loader.py +3 -3
- claude_mpm/services/mcp_gateway/config/configuration.py +24 -5
- claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
- claude_mpm/services/mcp_gateway/core/base.py +20 -33
- claude_mpm/services/mcp_gateway/core/process_pool.py +591 -31
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
- claude_mpm/services/mcp_gateway/core/startup_verification.py +3 -3
- claude_mpm/services/mcp_gateway/main.py +90 -15
- claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +12 -9
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +5 -10
- claude_mpm/services/mcp_gateway/server/stdio_server.py +9 -17
- claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +10 -9
- claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +654 -0
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +36 -34
- claude_mpm/services/mcp_gateway/tools/hello_world.py +8 -8
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +555 -0
- claude_mpm/services/mcp_gateway/utils/__init__.py +14 -0
- claude_mpm/services/mcp_gateway/utils/package_version_checker.py +160 -0
- claude_mpm/services/mcp_gateway/utils/update_preferences.py +170 -0
- claude_mpm/services/mcp_service_verifier.py +732 -0
- claude_mpm/services/memory/builder.py +9 -8
- claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
- claude_mpm/services/memory/cache/simple_cache.py +2 -2
- claude_mpm/services/memory/failure_tracker.py +578 -0
- claude_mpm/services/memory/indexed_memory.py +8 -8
- claude_mpm/services/memory/optimizer.py +8 -9
- claude_mpm/services/memory/router.py +3 -3
- claude_mpm/services/memory_hook_service.py +165 -4
- claude_mpm/services/model/__init__.py +147 -0
- claude_mpm/services/model/base_provider.py +365 -0
- claude_mpm/services/model/claude_provider.py +412 -0
- claude_mpm/services/model/model_router.py +452 -0
- claude_mpm/services/model/ollama_provider.py +415 -0
- claude_mpm/services/monitor/__init__.py +20 -0
- claude_mpm/services/monitor/daemon.py +691 -0
- claude_mpm/services/monitor/daemon_manager.py +1040 -0
- claude_mpm/services/monitor/event_emitter.py +350 -0
- claude_mpm/services/monitor/handlers/__init__.py +21 -0
- claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
- claude_mpm/services/monitor/handlers/dashboard.py +299 -0
- claude_mpm/services/monitor/handlers/file.py +264 -0
- claude_mpm/services/monitor/handlers/hooks.py +512 -0
- claude_mpm/services/monitor/management/__init__.py +18 -0
- claude_mpm/services/monitor/management/health.py +124 -0
- claude_mpm/services/monitor/management/lifecycle.py +724 -0
- claude_mpm/services/monitor/server.py +817 -0
- claude_mpm/services/monitor_build_service.py +2 -2
- claude_mpm/services/native_agent_converter.py +356 -0
- claude_mpm/services/orphan_detection.py +786 -0
- claude_mpm/services/port_manager.py +3 -3
- claude_mpm/services/pr/__init__.py +14 -0
- claude_mpm/services/pr/pr_template_service.py +329 -0
- claude_mpm/services/project/__init__.py +23 -0
- claude_mpm/services/project/analyzer.py +3 -3
- claude_mpm/services/project/architecture_analyzer.py +5 -5
- claude_mpm/services/project/archive_manager.py +1045 -0
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/detection_strategies.py +719 -0
- claude_mpm/services/project/documentation_manager.py +554 -0
- claude_mpm/services/project/enhanced_analyzer.py +572 -0
- claude_mpm/services/project/metrics_collector.py +4 -4
- claude_mpm/services/project/project_organizer.py +1005 -0
- claude_mpm/services/project/registry.py +13 -7
- claude_mpm/services/project/toolchain_analyzer.py +583 -0
- claude_mpm/services/project_port_allocator.py +596 -0
- claude_mpm/services/response_tracker.py +21 -10
- claude_mpm/services/runner_configuration_service.py +17 -3
- claude_mpm/services/self_upgrade_service.py +500 -0
- claude_mpm/services/session_management_service.py +23 -9
- claude_mpm/services/session_manager.py +380 -0
- claude_mpm/services/shared/__init__.py +2 -1
- claude_mpm/services/shared/async_service_base.py +16 -27
- claude_mpm/services/shared/config_service_base.py +17 -14
- claude_mpm/services/shared/lifecycle_service_base.py +1 -14
- claude_mpm/services/shared/service_factory.py +8 -5
- claude_mpm/services/skills/__init__.py +18 -0
- claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
- claude_mpm/services/skills/skill_discovery_service.py +568 -0
- claude_mpm/services/skills_config.py +547 -0
- claude_mpm/services/skills_deployer.py +955 -0
- claude_mpm/services/socketio/client_proxy.py +60 -5
- claude_mpm/services/socketio/dashboard_server.py +361 -0
- claude_mpm/services/socketio/event_normalizer.py +10 -6
- claude_mpm/services/socketio/handlers/__init__.py +5 -2
- claude_mpm/services/socketio/handlers/base.py +2 -2
- claude_mpm/services/socketio/handlers/code_analysis.py +90 -27
- claude_mpm/services/socketio/handlers/connection.py +22 -41
- claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
- claude_mpm/services/socketio/handlers/file.py +46 -10
- claude_mpm/services/socketio/handlers/git.py +9 -9
- claude_mpm/services/socketio/handlers/hook.py +29 -17
- claude_mpm/services/socketio/handlers/registry.py +4 -2
- claude_mpm/services/socketio/monitor_client.py +364 -0
- claude_mpm/services/socketio/server/broadcaster.py +9 -7
- claude_mpm/services/socketio/server/connection_manager.py +2 -2
- claude_mpm/services/socketio/server/core.py +142 -8
- claude_mpm/services/socketio/server/eventbus_integration.py +20 -14
- claude_mpm/services/socketio/server/main.py +24 -24
- claude_mpm/services/socketio_client_manager.py +4 -4
- claude_mpm/services/subprocess_launcher_service.py +19 -15
- claude_mpm/services/system_instructions_service.py +3 -5
- claude_mpm/services/ticket_services/formatter_service.py +1 -1
- claude_mpm/services/ticket_services/validation_service.py +5 -5
- claude_mpm/services/unified/__init__.py +65 -0
- claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
- claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
- claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
- claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
- claude_mpm/services/unified/config_strategies/__init__.py +175 -0
- claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
- claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
- claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
- claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
- claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
- claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
- claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
- claude_mpm/services/unified/deployment_strategies/base.py +553 -0
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
- claude_mpm/services/unified/deployment_strategies/local.py +607 -0
- claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
- claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
- claude_mpm/services/unified/interfaces.py +475 -0
- claude_mpm/services/unified/migration.py +509 -0
- claude_mpm/services/unified/strategies.py +534 -0
- claude_mpm/services/unified/unified_analyzer.py +542 -0
- claude_mpm/services/unified/unified_config.py +691 -0
- claude_mpm/services/unified/unified_deployment.py +466 -0
- claude_mpm/services/utility_service.py +6 -3
- claude_mpm/services/version_control/branch_strategy.py +2 -2
- claude_mpm/services/version_control/conflict_resolution.py +14 -8
- claude_mpm/services/version_control/git_operations.py +26 -24
- claude_mpm/services/version_control/semantic_versioning.py +14 -14
- claude_mpm/services/version_control/version_parser.py +14 -11
- claude_mpm/services/version_service.py +104 -1
- claude_mpm/services/visualization/__init__.py +1 -5
- claude_mpm/services/visualization/mermaid_generator.py +2 -3
- claude_mpm/skills/__init__.py +42 -0
- claude_mpm/skills/agent_skills_injector.py +324 -0
- claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
- claude_mpm/skills/bundled/__init__.py +6 -0
- claude_mpm/skills/bundled/api-documentation.md +393 -0
- claude_mpm/skills/bundled/async-testing.md +571 -0
- claude_mpm/skills/bundled/code-review.md +143 -0
- claude_mpm/skills/bundled/database-migration.md +199 -0
- claude_mpm/skills/bundled/docker-containerization.md +194 -0
- claude_mpm/skills/bundled/express-local-dev.md +1429 -0
- claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
- claude_mpm/skills/bundled/git-workflow.md +414 -0
- claude_mpm/skills/bundled/imagemagick.md +204 -0
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/json-data-handling.md +223 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
- claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
- claude_mpm/skills/bundled/pdf.md +141 -0
- claude_mpm/skills/bundled/performance-profiling.md +573 -0
- claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
- claude_mpm/skills/bundled/security-scanning.md +327 -0
- claude_mpm/skills/bundled/systematic-debugging.md +473 -0
- claude_mpm/skills/bundled/test-driven-development.md +378 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
- claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
- claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
- claude_mpm/skills/bundled/xlsx.md +157 -0
- claude_mpm/skills/registry.py +286 -0
- claude_mpm/skills/skill_manager.py +310 -0
- claude_mpm/skills/skills_registry.py +347 -0
- claude_mpm/skills/skills_service.py +739 -0
- claude_mpm/storage/state_storage.py +31 -31
- claude_mpm/templates/questions/__init__.py +38 -0
- claude_mpm/templates/questions/base.py +193 -0
- claude_mpm/templates/questions/pr_strategy.py +311 -0
- claude_mpm/templates/questions/project_init.py +385 -0
- claude_mpm/templates/questions/ticket_mgmt.py +394 -0
- claude_mpm/tools/__main__.py +9 -9
- claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/tools/code_tree_builder.py +6 -6
- claude_mpm/tools/code_tree_events.py +14 -10
- claude_mpm/tools/socketio_debug.py +11 -11
- claude_mpm/utils/agent_dependency_loader.py +184 -36
- claude_mpm/utils/agent_filters.py +288 -0
- claude_mpm/utils/common.py +544 -0
- claude_mpm/utils/config_manager.py +12 -6
- claude_mpm/utils/database_connector.py +298 -0
- claude_mpm/utils/dependency_cache.py +5 -3
- claude_mpm/utils/dependency_strategies.py +15 -10
- claude_mpm/utils/display_helper.py +260 -0
- claude_mpm/utils/environment_context.py +4 -3
- claude_mpm/utils/error_handler.py +5 -3
- claude_mpm/utils/file_utils.py +13 -14
- claude_mpm/utils/git_analyzer.py +407 -0
- claude_mpm/utils/gitignore.py +241 -0
- claude_mpm/utils/log_cleanup.py +627 -0
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/path_operations.py +7 -4
- claude_mpm/utils/progress.py +387 -0
- claude_mpm/utils/robust_installer.py +131 -24
- claude_mpm/utils/session_logging.py +2 -2
- claude_mpm/utils/structured_questions.py +619 -0
- claude_mpm/utils/subprocess_utils.py +9 -8
- claude_mpm/validation/agent_validator.py +6 -6
- claude_mpm/validation/frontmatter_validator.py +6 -6
- claude_mpm-5.0.9.dist-info/METADATA +1028 -0
- claude_mpm-5.0.9.dist-info/RECORD +864 -0
- {claude_mpm-4.1.26.dist-info ā claude_mpm-5.0.9.dist-info}/entry_points.txt +1 -0
- claude_mpm/agents/INSTRUCTIONS.md +0 -261
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
- claude_mpm/agents/templates/agent-manager.json +0 -270
- claude_mpm/agents/templates/agent-manager.md +0 -619
- claude_mpm/agents/templates/agentic_coder_optimizer.json +0 -222
- claude_mpm/agents/templates/api_qa.json +0 -171
- claude_mpm/agents/templates/code_analyzer.json +0 -95
- claude_mpm/agents/templates/data_engineer.json +0 -152
- claude_mpm/agents/templates/documentation.json +0 -175
- claude_mpm/agents/templates/engineer.json +0 -176
- claude_mpm/agents/templates/imagemagick.json +0 -261
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
- claude_mpm/agents/templates/memory_manager.json +0 -155
- claude_mpm/agents/templates/ops.json +0 -175
- claude_mpm/agents/templates/project_organizer.json +0 -130
- claude_mpm/agents/templates/qa.json +0 -223
- claude_mpm/agents/templates/refactoring_engineer.json +0 -266
- claude_mpm/agents/templates/research.json +0 -163
- claude_mpm/agents/templates/security.json +0 -153
- claude_mpm/agents/templates/ticketing.json +0 -169
- claude_mpm/agents/templates/vercel_ops_agent.json +0 -281
- claude_mpm/agents/templates/version_control.json +0 -147
- claude_mpm/agents/templates/web_qa.json +0 -254
- claude_mpm/agents/templates/web_ui.json +0 -176
- claude_mpm/cli/commands/configure_tui.py +0 -1927
- claude_mpm/cli/commands/mpm_init.py +0 -594
- claude_mpm/cli/commands/socketio_monitor.py +0 -233
- claude_mpm/commands/mpm-agents.md +0 -12
- claude_mpm/commands/mpm-config.md +0 -18
- claude_mpm/commands/mpm-tickets.md +0 -102
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
- claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/built/dashboard.js +0 -2
- claude_mpm/dashboard/static/built/socket-client.js +0 -2
- claude_mpm/dashboard/static/css/code-tree.css +0 -1408
- claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
- claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
- claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
- claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
- claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
- claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
- claude_mpm/dashboard/static/dist/dashboard.js +0 -2
- claude_mpm/dashboard/static/dist/socket-client.js +0 -2
- claude_mpm/dashboard/static/js/components/code-tree.js +0 -3220
- claude_mpm/dashboard/static/js/components/code-viewer.js +0 -480
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1040
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
- claude_mpm/scripts/socketio_daemon_hardened.py +0 -937
- claude_mpm/scripts/socketio_daemon_wrapper.py +0 -78
- claude_mpm/scripts/socketio_server_manager.py +0 -349
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
- claude_mpm/services/cli/dashboard_launcher.py +0 -423
- claude_mpm/services/cli/socketio_manager.py +0 -537
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +0 -286
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
- claude_mpm/services/project/analyzer_refactored.py +0 -450
- claude_mpm/tools/code_tree_analyzer.py +0 -1693
- claude_mpm-4.1.26.dist-info/METADATA +0 -332
- claude_mpm-4.1.26.dist-info/RECORD +0 -606
- {claude_mpm-4.1.26.dist-info ā claude_mpm-5.0.9.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.26.dist-info ā claude_mpm-5.0.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.26.dist-info ā claude_mpm-5.0.9.dist-info}/top_level.txt +0 -0
|
@@ -12,18 +12,26 @@ DESIGN DECISIONS:
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
|
+
from pathlib import Path
|
|
15
16
|
|
|
16
17
|
from ...constants import AgentCommands
|
|
18
|
+
from ...core.enums import OutputFormat
|
|
17
19
|
from ...services.cli.agent_cleanup_service import AgentCleanupService
|
|
18
20
|
from ...services.cli.agent_dependency_service import AgentDependencyService
|
|
19
21
|
from ...services.cli.agent_listing_service import AgentListingService
|
|
20
22
|
from ...services.cli.agent_output_formatter import AgentOutputFormatter
|
|
21
23
|
from ...services.cli.agent_validation_service import AgentValidationService
|
|
22
|
-
from ..shared import
|
|
23
|
-
AgentCommand,
|
|
24
|
-
CommandResult,
|
|
25
|
-
)
|
|
24
|
+
from ..shared import AgentCommand, CommandResult
|
|
26
25
|
from ..utils import get_agent_versions_display
|
|
26
|
+
from .agents_cleanup import handle_agents_cleanup
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _is_structured_output(args) -> bool:
|
|
30
|
+
"""Check if args specify structured output format (JSON/YAML)."""
|
|
31
|
+
if hasattr(args, "format"):
|
|
32
|
+
fmt = str(args.format).lower()
|
|
33
|
+
return fmt in (OutputFormat.JSON, OutputFormat.YAML)
|
|
34
|
+
return False
|
|
27
35
|
|
|
28
36
|
|
|
29
37
|
class AgentsCommand(AgentCommand):
|
|
@@ -50,8 +58,8 @@ class AgentsCommand(AgentCommand):
|
|
|
50
58
|
|
|
51
59
|
base_service = AgentDeploymentService()
|
|
52
60
|
self._deployment_service = DeploymentServiceWrapper(base_service)
|
|
53
|
-
except ImportError:
|
|
54
|
-
raise ImportError("Agent deployment service not available")
|
|
61
|
+
except ImportError as e:
|
|
62
|
+
raise ImportError("Agent deployment service not available") from e
|
|
55
63
|
return self._deployment_service
|
|
56
64
|
|
|
57
65
|
@property
|
|
@@ -86,6 +94,31 @@ class AgentsCommand(AgentCommand):
|
|
|
86
94
|
)
|
|
87
95
|
return self._cleanup_service
|
|
88
96
|
|
|
97
|
+
def _get_output_format(self, args) -> str:
|
|
98
|
+
"""
|
|
99
|
+
Get output format from args with enum default.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
args: Command arguments
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Output format string (compatible with both enum and string usage)
|
|
106
|
+
"""
|
|
107
|
+
return getattr(args, "format", OutputFormat.TEXT)
|
|
108
|
+
|
|
109
|
+
def _is_structured_format(self, format_str: str) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Check if format is structured (JSON/YAML).
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
format_str: Format string to check
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
True if format is JSON or YAML
|
|
118
|
+
"""
|
|
119
|
+
fmt = str(format_str).lower()
|
|
120
|
+
return fmt in (OutputFormat.JSON, OutputFormat.YAML)
|
|
121
|
+
|
|
89
122
|
def validate_args(self, args) -> str:
|
|
90
123
|
"""Validate command arguments."""
|
|
91
124
|
# Most agent commands are optional, so basic validation
|
|
@@ -114,7 +147,32 @@ class AgentsCommand(AgentCommand):
|
|
|
114
147
|
"deps-install": self._install_agent_dependencies,
|
|
115
148
|
"deps-list": self._list_agent_dependencies,
|
|
116
149
|
"deps-fix": self._fix_agent_dependencies,
|
|
150
|
+
"cleanup": lambda a: self._handle_cleanup_command(a),
|
|
117
151
|
"cleanup-orphaned": self._cleanup_orphaned_agents,
|
|
152
|
+
# Local agent management commands
|
|
153
|
+
"create": self._create_local_agent,
|
|
154
|
+
"edit": self._edit_local_agent,
|
|
155
|
+
"delete": self._delete_local_agent,
|
|
156
|
+
"manage": self._manage_local_agents,
|
|
157
|
+
"configure": self._configure_deployment,
|
|
158
|
+
# Migration command (DEPRECATION support)
|
|
159
|
+
"migrate-to-project": self._migrate_to_project,
|
|
160
|
+
# Auto-configuration commands (TSK-0054 Phase 5)
|
|
161
|
+
"detect": self._detect_toolchain,
|
|
162
|
+
"recommend": self._recommend_agents,
|
|
163
|
+
# Agent selection modes (Phase 3: 1M-382)
|
|
164
|
+
"deploy-minimal": self._deploy_minimal_configuration,
|
|
165
|
+
"deploy-auto": self._deploy_auto_configure,
|
|
166
|
+
# Agent source management (Phase 2: 1M-442)
|
|
167
|
+
"available": self._list_available_from_sources,
|
|
168
|
+
# Agent discovery with rich filtering (Phase 1: Discovery & Browsing)
|
|
169
|
+
"discover": self._discover_agents,
|
|
170
|
+
# Cache git management commands
|
|
171
|
+
"cache-status": self._cache_status,
|
|
172
|
+
"cache-pull": self._cache_pull,
|
|
173
|
+
"cache-push": self._cache_push,
|
|
174
|
+
"cache-sync": self._cache_sync,
|
|
175
|
+
"cache-commit": self._cache_commit,
|
|
118
176
|
}
|
|
119
177
|
|
|
120
178
|
if args.agents_command in command_map:
|
|
@@ -135,14 +193,14 @@ class AgentsCommand(AgentCommand):
|
|
|
135
193
|
try:
|
|
136
194
|
agent_versions = get_agent_versions_display()
|
|
137
195
|
|
|
138
|
-
output_format =
|
|
139
|
-
if output_format
|
|
196
|
+
output_format = self._get_output_format(args)
|
|
197
|
+
if self._is_structured_format(output_format):
|
|
140
198
|
# Parse the agent versions display into structured data
|
|
141
199
|
if agent_versions:
|
|
142
200
|
data = {"agent_versions": agent_versions, "has_agents": True}
|
|
143
201
|
formatted = (
|
|
144
202
|
self._formatter.format_as_json(data)
|
|
145
|
-
if output_format ==
|
|
203
|
+
if str(output_format).lower() == OutputFormat.JSON
|
|
146
204
|
else self._formatter.format_as_yaml(data)
|
|
147
205
|
)
|
|
148
206
|
print(formatted)
|
|
@@ -156,7 +214,7 @@ class AgentsCommand(AgentCommand):
|
|
|
156
214
|
}
|
|
157
215
|
formatted = (
|
|
158
216
|
self._formatter.format_as_json(data)
|
|
159
|
-
if output_format ==
|
|
217
|
+
if str(output_format).lower() == OutputFormat.JSON
|
|
160
218
|
else self._formatter.format_as_yaml(data)
|
|
161
219
|
)
|
|
162
220
|
print(formatted)
|
|
@@ -178,7 +236,7 @@ class AgentsCommand(AgentCommand):
|
|
|
178
236
|
def _list_agents(self, args) -> CommandResult:
|
|
179
237
|
"""List available or deployed agents."""
|
|
180
238
|
try:
|
|
181
|
-
output_format =
|
|
239
|
+
output_format = self._get_output_format(args)
|
|
182
240
|
|
|
183
241
|
if hasattr(args, "by_tier") and args.by_tier:
|
|
184
242
|
return self._list_agents_by_tier(args)
|
|
@@ -189,7 +247,7 @@ class AgentsCommand(AgentCommand):
|
|
|
189
247
|
# Default: show usage
|
|
190
248
|
usage_msg = "Use --system to list system agents, --deployed to list deployed agents, or --by-tier to group by precedence"
|
|
191
249
|
|
|
192
|
-
if output_format
|
|
250
|
+
if self._is_structured_format(output_format):
|
|
193
251
|
return CommandResult.error_result(
|
|
194
252
|
"No list option specified",
|
|
195
253
|
data={
|
|
@@ -210,7 +268,7 @@ class AgentsCommand(AgentCommand):
|
|
|
210
268
|
verbose = getattr(args, "verbose", False)
|
|
211
269
|
agents = self.listing_service.list_system_agents(verbose=verbose)
|
|
212
270
|
|
|
213
|
-
output_format =
|
|
271
|
+
output_format = self._get_output_format(args)
|
|
214
272
|
quiet = getattr(args, "quiet", False)
|
|
215
273
|
|
|
216
274
|
# Convert AgentInfo objects to dicts for formatter
|
|
@@ -219,6 +277,7 @@ class AgentsCommand(AgentCommand):
|
|
|
219
277
|
"name": agent.name,
|
|
220
278
|
"type": agent.type,
|
|
221
279
|
"path": agent.path,
|
|
280
|
+
"file": Path(agent.path).name if agent.path else "Unknown",
|
|
222
281
|
"description": agent.description,
|
|
223
282
|
"specializations": agent.specializations,
|
|
224
283
|
"version": agent.version,
|
|
@@ -248,7 +307,7 @@ class AgentsCommand(AgentCommand):
|
|
|
248
307
|
verbose=verbose
|
|
249
308
|
)
|
|
250
309
|
|
|
251
|
-
output_format =
|
|
310
|
+
output_format = self._get_output_format(args)
|
|
252
311
|
quiet = getattr(args, "quiet", False)
|
|
253
312
|
|
|
254
313
|
# Convert AgentInfo objects to dicts for formatter
|
|
@@ -258,6 +317,7 @@ class AgentsCommand(AgentCommand):
|
|
|
258
317
|
"type": agent.type,
|
|
259
318
|
"tier": agent.tier,
|
|
260
319
|
"path": agent.path,
|
|
320
|
+
"file": Path(agent.path).name if agent.path else "Unknown",
|
|
261
321
|
"description": agent.description,
|
|
262
322
|
"specializations": agent.specializations,
|
|
263
323
|
"version": agent.version,
|
|
@@ -272,7 +332,7 @@ class AgentsCommand(AgentCommand):
|
|
|
272
332
|
print(formatted)
|
|
273
333
|
|
|
274
334
|
# Add warnings for text output
|
|
275
|
-
if output_format ==
|
|
335
|
+
if str(output_format).lower() == OutputFormat.TEXT and warnings:
|
|
276
336
|
print("\nWarnings:")
|
|
277
337
|
for warning in warnings:
|
|
278
338
|
print(f" ā ļø {warning}")
|
|
@@ -294,7 +354,7 @@ class AgentsCommand(AgentCommand):
|
|
|
294
354
|
"""List agents grouped by tier/precedence."""
|
|
295
355
|
try:
|
|
296
356
|
tier_info = self.listing_service.list_agents_by_tier()
|
|
297
|
-
output_format =
|
|
357
|
+
output_format = self._get_output_format(args)
|
|
298
358
|
|
|
299
359
|
# Convert to format expected by formatter
|
|
300
360
|
agents_by_tier = {
|
|
@@ -350,34 +410,213 @@ class AgentsCommand(AgentCommand):
|
|
|
350
410
|
self.logger.error(f"Error listing agents by tier: {e}", exc_info=True)
|
|
351
411
|
return CommandResult.error_result(f"Error listing agents by tier: {e}")
|
|
352
412
|
|
|
413
|
+
def _list_available_from_sources(self, args) -> CommandResult:
|
|
414
|
+
"""List available agents from all configured git sources.
|
|
415
|
+
|
|
416
|
+
This command shows agents discovered from configured agent sources
|
|
417
|
+
(Git repositories) after syncing their cache. Implements Phase 2 of 1M-442.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
args: Command arguments with optional source filter and format
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
CommandResult with agent list or error
|
|
424
|
+
"""
|
|
425
|
+
try:
|
|
426
|
+
from ...config.agent_sources import AgentSourceConfiguration
|
|
427
|
+
from ...services.agents.git_source_manager import GitSourceManager
|
|
428
|
+
|
|
429
|
+
# Load agent sources configuration
|
|
430
|
+
config = AgentSourceConfiguration.load()
|
|
431
|
+
enabled_repos = [r for r in config.repositories if r.enabled]
|
|
432
|
+
|
|
433
|
+
if not enabled_repos:
|
|
434
|
+
message = (
|
|
435
|
+
"No agent sources configured.\n\n"
|
|
436
|
+
"Configure sources with:\n"
|
|
437
|
+
" claude-mpm agent-source add <url>\n\n"
|
|
438
|
+
"Example:\n"
|
|
439
|
+
" claude-mpm agent-source add https://github.com/owner/repo/agents"
|
|
440
|
+
)
|
|
441
|
+
print(message)
|
|
442
|
+
return CommandResult.error_result("No agent sources configured")
|
|
443
|
+
|
|
444
|
+
# Initialize git source manager
|
|
445
|
+
manager = GitSourceManager()
|
|
446
|
+
|
|
447
|
+
# Sync all configured sources (with timeout)
|
|
448
|
+
self.logger.info(f"Syncing {len(enabled_repos)} agent sources...")
|
|
449
|
+
sync_results = {}
|
|
450
|
+
|
|
451
|
+
for repo in enabled_repos:
|
|
452
|
+
try:
|
|
453
|
+
result = manager.sync_repository(repo, force=False)
|
|
454
|
+
sync_results[repo.identifier] = result
|
|
455
|
+
except Exception as e:
|
|
456
|
+
self.logger.warning(f"Failed to sync {repo.identifier}: {e}")
|
|
457
|
+
sync_results[repo.identifier] = {"synced": False, "error": str(e)}
|
|
458
|
+
|
|
459
|
+
# Get source filter from args
|
|
460
|
+
source_filter = getattr(args, "source", None)
|
|
461
|
+
|
|
462
|
+
# List all cached agents
|
|
463
|
+
all_agents = manager.list_cached_agents(repo_identifier=source_filter)
|
|
464
|
+
|
|
465
|
+
if not all_agents:
|
|
466
|
+
message = "No agents found in configured sources."
|
|
467
|
+
if sync_results:
|
|
468
|
+
failed_count = sum(
|
|
469
|
+
1 for r in sync_results.values() if not r.get("synced")
|
|
470
|
+
)
|
|
471
|
+
if failed_count > 0:
|
|
472
|
+
message += f"\n\n{failed_count} source(s) failed to sync. Check logs for details."
|
|
473
|
+
print(message)
|
|
474
|
+
return CommandResult.success_result(message, data={"agents": []})
|
|
475
|
+
|
|
476
|
+
# Format output
|
|
477
|
+
output_format = getattr(args, "format", "table")
|
|
478
|
+
|
|
479
|
+
if output_format == "json":
|
|
480
|
+
import json
|
|
481
|
+
|
|
482
|
+
print(json.dumps(all_agents, indent=2))
|
|
483
|
+
elif output_format == "simple":
|
|
484
|
+
for agent in all_agents:
|
|
485
|
+
name = agent.get("metadata", {}).get(
|
|
486
|
+
"name", agent.get("agent_id", "unknown")
|
|
487
|
+
)
|
|
488
|
+
repo = agent.get("repository", "unknown")
|
|
489
|
+
print(f"{name} (from {repo})")
|
|
490
|
+
else: # table format
|
|
491
|
+
print(f"\n{'Agent Name':<30} {'Repository':<40} {'Version':<15}")
|
|
492
|
+
print("=" * 85)
|
|
493
|
+
for agent in all_agents:
|
|
494
|
+
name = agent.get("metadata", {}).get(
|
|
495
|
+
"name", agent.get("agent_id", "unknown")
|
|
496
|
+
)
|
|
497
|
+
repo = agent.get("repository", "unknown")
|
|
498
|
+
version = agent.get("version", "unknown")[:12]
|
|
499
|
+
print(f"{name:<30} {repo:<40} {version:<15}")
|
|
500
|
+
print(
|
|
501
|
+
f"\nTotal: {len(all_agents)} agents from {len(sync_results)} sources"
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
return CommandResult.success_result(
|
|
505
|
+
f"Listed {len(all_agents)} agents from sources",
|
|
506
|
+
data={"agents": all_agents, "sync_results": sync_results},
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
except Exception as e:
|
|
510
|
+
self.logger.error(f"Error listing available agents: {e}", exc_info=True)
|
|
511
|
+
return CommandResult.error_result(f"Error listing available agents: {e}")
|
|
512
|
+
|
|
513
|
+
def _discover_agents(self, args) -> CommandResult:
|
|
514
|
+
"""Discover agents with rich filtering capabilities.
|
|
515
|
+
|
|
516
|
+
This command extends the 'available' command by adding semantic filtering
|
|
517
|
+
based on AUTO-DEPLOY-INDEX.md categories. Users can filter by category,
|
|
518
|
+
language, framework, platform, and specialization.
|
|
519
|
+
|
|
520
|
+
Design Decision: Delegate to agents_discover.py module
|
|
521
|
+
|
|
522
|
+
Rationale: Keep CLI command logic separate from routing logic for better
|
|
523
|
+
testability and maintainability. The discover_command function handles
|
|
524
|
+
all the complex filtering and formatting logic.
|
|
525
|
+
|
|
526
|
+
Args:
|
|
527
|
+
args: Command arguments with filter options:
|
|
528
|
+
- source: Source repository filter
|
|
529
|
+
- category: Category filter (e.g., 'engineer/backend')
|
|
530
|
+
- language: Language filter (e.g., 'python')
|
|
531
|
+
- framework: Framework filter (e.g., 'react')
|
|
532
|
+
- platform: Platform filter (e.g., 'vercel')
|
|
533
|
+
- specialization: Specialization filter (e.g., 'data')
|
|
534
|
+
- format: Output format (table, json, simple)
|
|
535
|
+
- verbose: Show descriptions and metadata
|
|
536
|
+
|
|
537
|
+
Returns:
|
|
538
|
+
CommandResult with filtered agent list or error
|
|
539
|
+
|
|
540
|
+
Example:
|
|
541
|
+
>>> # Called via: claude-mpm agents discover --category engineer/backend
|
|
542
|
+
>>> _discover_agents(args)
|
|
543
|
+
CommandResult(success=True, message="Discovered 8 agents")
|
|
544
|
+
"""
|
|
545
|
+
try:
|
|
546
|
+
from .agents_discover import discover_command
|
|
547
|
+
|
|
548
|
+
# Call discover_command and convert exit code to CommandResult
|
|
549
|
+
exit_code = discover_command(args)
|
|
550
|
+
|
|
551
|
+
if exit_code == 0:
|
|
552
|
+
return CommandResult.success_result("Agent discovery complete")
|
|
553
|
+
return CommandResult.error_result("Agent discovery failed")
|
|
554
|
+
|
|
555
|
+
except Exception as e:
|
|
556
|
+
self.logger.error(f"Error discovering agents: {e}", exc_info=True)
|
|
557
|
+
return CommandResult.error_result(f"Error discovering agents: {e}")
|
|
558
|
+
|
|
353
559
|
def _deploy_agents(self, args, force=False) -> CommandResult:
|
|
354
|
-
"""Deploy
|
|
560
|
+
"""Deploy agents using two-phase sync: cache ā deploy.
|
|
561
|
+
|
|
562
|
+
Phase 3 Integration (1M-486): Uses Git sync service for deployment.
|
|
563
|
+
- Phase 1: Sync agents to ~/.claude-mpm/cache/remote-agents/ (if needed)
|
|
564
|
+
- Phase 2: Deploy from cache to project .claude-mpm/agents/
|
|
565
|
+
|
|
566
|
+
This replaces the old single-tier deployment with a multi-project
|
|
567
|
+
architecture where one cache serves multiple project deployments.
|
|
568
|
+
"""
|
|
355
569
|
try:
|
|
356
|
-
#
|
|
357
|
-
|
|
570
|
+
# Handle preset deployment (uses different path)
|
|
571
|
+
if hasattr(args, "preset") and args.preset:
|
|
572
|
+
return self._deploy_preset(args)
|
|
573
|
+
|
|
574
|
+
from ...services.agents.sources.git_source_sync_service import (
|
|
575
|
+
GitSourceSyncService,
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
# Initialize git sync service
|
|
579
|
+
git_sync = GitSourceSyncService()
|
|
580
|
+
project_dir = Path.cwd()
|
|
581
|
+
|
|
582
|
+
self.logger.info("Phase 1: Syncing agents to cache...")
|
|
583
|
+
|
|
584
|
+
# Sync to cache (downloads from GitHub if needed)
|
|
585
|
+
sync_result = git_sync.sync_repository(force=force)
|
|
586
|
+
|
|
587
|
+
if not sync_result.get("synced"):
|
|
588
|
+
error_msg = sync_result.get("error", "Unknown sync error")
|
|
589
|
+
self.logger.error(f"Sync failed: {error_msg}")
|
|
590
|
+
return CommandResult.error_result(f"Sync failed: {error_msg}")
|
|
591
|
+
|
|
592
|
+
self.logger.info(
|
|
593
|
+
f"Phase 1 complete: {sync_result.get('agent_count', 0)} agents in cache"
|
|
594
|
+
)
|
|
595
|
+
self.logger.info(f"Phase 2: Deploying agents to {project_dir}...")
|
|
358
596
|
|
|
359
|
-
# Deploy
|
|
360
|
-
|
|
597
|
+
# Deploy from cache to project directory
|
|
598
|
+
deploy_result = git_sync.deploy_agents_to_project(
|
|
599
|
+
project_dir=project_dir,
|
|
600
|
+
agent_list=None, # Deploy all cached agents
|
|
601
|
+
force=force,
|
|
602
|
+
)
|
|
361
603
|
|
|
362
|
-
#
|
|
604
|
+
# Format combined results for output
|
|
363
605
|
combined_result = {
|
|
364
|
-
"deployed_count":
|
|
365
|
-
+
|
|
366
|
-
"deployed":
|
|
367
|
-
|
|
368
|
-
"
|
|
369
|
-
|
|
370
|
-
"
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
+ project_result.get("errors", []),
|
|
376
|
-
"target_dir": system_result.get("target_dir")
|
|
377
|
-
or project_result.get("target_dir"),
|
|
606
|
+
"deployed_count": len(deploy_result.get("deployed", []))
|
|
607
|
+
+ len(deploy_result.get("updated", [])),
|
|
608
|
+
"deployed": deploy_result.get("deployed", []),
|
|
609
|
+
"updated": deploy_result.get("updated", []),
|
|
610
|
+
"skipped": deploy_result.get("skipped", []),
|
|
611
|
+
"errors": deploy_result.get("failed", []),
|
|
612
|
+
"target_dir": deploy_result.get("deployment_dir", ""),
|
|
613
|
+
"sync_info": {
|
|
614
|
+
"cached_agents": sync_result.get("agent_count", 0),
|
|
615
|
+
"cache_dir": sync_result.get("cache_dir", ""),
|
|
616
|
+
},
|
|
378
617
|
}
|
|
379
618
|
|
|
380
|
-
output_format =
|
|
619
|
+
output_format = self._get_output_format(args)
|
|
381
620
|
verbose = getattr(args, "verbose", False)
|
|
382
621
|
|
|
383
622
|
formatted = self._formatter.format_deployment_result(
|
|
@@ -385,12 +624,15 @@ class AgentsCommand(AgentCommand):
|
|
|
385
624
|
)
|
|
386
625
|
print(formatted)
|
|
387
626
|
|
|
627
|
+
success_count = len(deploy_result["deployed"]) + len(
|
|
628
|
+
deploy_result["updated"]
|
|
629
|
+
)
|
|
388
630
|
return CommandResult.success_result(
|
|
389
|
-
f"Deployed {
|
|
631
|
+
f"Deployed {success_count} agents from cache",
|
|
390
632
|
data={
|
|
391
|
-
"
|
|
392
|
-
"
|
|
393
|
-
"total_deployed":
|
|
633
|
+
"sync_result": sync_result,
|
|
634
|
+
"deploy_result": deploy_result,
|
|
635
|
+
"total_deployed": success_count,
|
|
394
636
|
},
|
|
395
637
|
)
|
|
396
638
|
|
|
@@ -398,12 +640,179 @@ class AgentsCommand(AgentCommand):
|
|
|
398
640
|
self.logger.error(f"Error deploying agents: {e}", exc_info=True)
|
|
399
641
|
return CommandResult.error_result(f"Error deploying agents: {e}")
|
|
400
642
|
|
|
643
|
+
def _deploy_preset(self, args) -> CommandResult:
|
|
644
|
+
"""Deploy agents by preset name.
|
|
645
|
+
|
|
646
|
+
This method implements Phase 2 of the agents/skills CLI redesign,
|
|
647
|
+
enabling preset-based deployment like:
|
|
648
|
+
claude-mpm agents deploy --preset python-dev
|
|
649
|
+
|
|
650
|
+
Args:
|
|
651
|
+
args: Command arguments with preset name and optional flags
|
|
652
|
+
|
|
653
|
+
Returns:
|
|
654
|
+
CommandResult with deployment status
|
|
655
|
+
"""
|
|
656
|
+
try:
|
|
657
|
+
from pathlib import Path
|
|
658
|
+
|
|
659
|
+
from ...config.agent_sources import AgentSourceConfiguration
|
|
660
|
+
from ...services.agents.agent_preset_service import AgentPresetService
|
|
661
|
+
from ...services.agents.git_source_manager import GitSourceManager
|
|
662
|
+
from ...services.agents.single_tier_deployment_service import (
|
|
663
|
+
SingleTierDeploymentService,
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
preset_name = args.preset
|
|
667
|
+
dry_run = getattr(args, "dry_run", False)
|
|
668
|
+
|
|
669
|
+
# Initialize services
|
|
670
|
+
config = AgentSourceConfiguration.load()
|
|
671
|
+
deployment_dir = Path.home() / ".claude" / "agents"
|
|
672
|
+
git_source_manager = GitSourceManager()
|
|
673
|
+
preset_service = AgentPresetService(git_source_manager)
|
|
674
|
+
deployment_service = SingleTierDeploymentService(config, deployment_dir)
|
|
675
|
+
|
|
676
|
+
# Validate preset
|
|
677
|
+
if not preset_service.validate_preset(preset_name):
|
|
678
|
+
available = preset_service.list_presets()
|
|
679
|
+
print(f"ā Unknown preset: {preset_name}")
|
|
680
|
+
print("\nš Available presets:")
|
|
681
|
+
for preset in available:
|
|
682
|
+
print(
|
|
683
|
+
f" ⢠{preset['name']}: {preset['description']} ({preset['agent_count']} agents)"
|
|
684
|
+
)
|
|
685
|
+
print(f" Use cases: {', '.join(preset['use_cases'])}")
|
|
686
|
+
return CommandResult.error_result(f"Unknown preset: {preset_name}")
|
|
687
|
+
|
|
688
|
+
# Resolve preset to agent list
|
|
689
|
+
print(f"\nš Resolving preset: {preset_name}")
|
|
690
|
+
resolution = preset_service.resolve_agents(
|
|
691
|
+
preset_name, validate_availability=True
|
|
692
|
+
)
|
|
693
|
+
|
|
694
|
+
# Show preset info
|
|
695
|
+
preset_info = resolution["preset_info"]
|
|
696
|
+
print(f"\nšÆ Preset: {preset_info['description']}")
|
|
697
|
+
print(f" Agents: {preset_info['agent_count']}")
|
|
698
|
+
print(f" Use cases: {', '.join(preset_info['use_cases'])}")
|
|
699
|
+
|
|
700
|
+
# Show warnings for missing agents
|
|
701
|
+
if resolution["missing_agents"]:
|
|
702
|
+
print("\nā ļø Missing agents (not found in configured sources):")
|
|
703
|
+
for agent_id in resolution["missing_agents"]:
|
|
704
|
+
print(f" ⢠{agent_id}")
|
|
705
|
+
print("\nš” These agents are not available in your configured sources.")
|
|
706
|
+
print(" Deployment will continue with available agents.")
|
|
707
|
+
|
|
708
|
+
# Show conflicts
|
|
709
|
+
if resolution["conflicts"]:
|
|
710
|
+
print("\nā ļø Priority conflicts detected:")
|
|
711
|
+
for conflict in resolution["conflicts"]:
|
|
712
|
+
sources = ", ".join(conflict["sources"])
|
|
713
|
+
print(f" ⢠{conflict['agent_id']} (found in: {sources})")
|
|
714
|
+
print(" Using highest priority source for each")
|
|
715
|
+
|
|
716
|
+
# Dry run mode
|
|
717
|
+
if dry_run:
|
|
718
|
+
print("\nš DRY RUN: Preview agent deployment\n")
|
|
719
|
+
print("Agents to deploy:")
|
|
720
|
+
for agent in resolution["agents"]:
|
|
721
|
+
source = agent.get("source", "unknown")
|
|
722
|
+
print(f" ā {agent['agent_id']} (from {source})")
|
|
723
|
+
print(
|
|
724
|
+
"\nš” This is a dry run. Run without --dry-run to actually deploy."
|
|
725
|
+
)
|
|
726
|
+
return CommandResult.success_result(
|
|
727
|
+
"Dry run complete",
|
|
728
|
+
data={
|
|
729
|
+
"preset": preset_name,
|
|
730
|
+
"agents": resolution["agents"],
|
|
731
|
+
"missing": resolution["missing_agents"],
|
|
732
|
+
},
|
|
733
|
+
)
|
|
734
|
+
|
|
735
|
+
# Deploy agents
|
|
736
|
+
print(f"\nš¦ Deploying {len(resolution['agents'])} agents...")
|
|
737
|
+
deployed_count = 0
|
|
738
|
+
failed_count = 0
|
|
739
|
+
skipped_count = len(resolution["missing_agents"])
|
|
740
|
+
deployed_agents = []
|
|
741
|
+
failed_agents = []
|
|
742
|
+
|
|
743
|
+
for agent in resolution["agents"]:
|
|
744
|
+
agent_id = agent["agent_id"]
|
|
745
|
+
try:
|
|
746
|
+
# Deploy using single-tier deployment service
|
|
747
|
+
result = deployment_service.deploy_agent(
|
|
748
|
+
agent_id, source_repo=agent.get("source"), dry_run=False
|
|
749
|
+
)
|
|
750
|
+
|
|
751
|
+
if result.get("deployed"):
|
|
752
|
+
deployed_count += 1
|
|
753
|
+
deployed_agents.append(agent_id)
|
|
754
|
+
print(f" ā {agent_id}")
|
|
755
|
+
else:
|
|
756
|
+
failed_count += 1
|
|
757
|
+
failed_agents.append(
|
|
758
|
+
{
|
|
759
|
+
"agent_id": agent_id,
|
|
760
|
+
"error": result.get("error", "Unknown"),
|
|
761
|
+
}
|
|
762
|
+
)
|
|
763
|
+
print(f" ā {agent_id}: {result.get('error', 'Failed')}")
|
|
764
|
+
|
|
765
|
+
except Exception as e:
|
|
766
|
+
failed_count += 1
|
|
767
|
+
failed_agents.append({"agent_id": agent_id, "error": str(e)})
|
|
768
|
+
print(f" ā {agent_id}: {e}")
|
|
769
|
+
|
|
770
|
+
# Summary
|
|
771
|
+
print(f"\n{'=' * 60}")
|
|
772
|
+
print("š Deployment Summary")
|
|
773
|
+
print(f"{'=' * 60}")
|
|
774
|
+
print(f" ā
Deployed: {deployed_count}")
|
|
775
|
+
print(f" ā Failed: {failed_count}")
|
|
776
|
+
print(f" āļø Skipped: {skipped_count} (missing from sources)")
|
|
777
|
+
print(f"{'=' * 60}\n")
|
|
778
|
+
|
|
779
|
+
if failed_agents:
|
|
780
|
+
print("ā Failed agents:")
|
|
781
|
+
for failure in failed_agents:
|
|
782
|
+
print(f" ⢠{failure['agent_id']}: {failure['error']}")
|
|
783
|
+
print()
|
|
784
|
+
|
|
785
|
+
if deployed_count > 0:
|
|
786
|
+
print(f"ā
Successfully deployed {deployed_count} agents!")
|
|
787
|
+
return CommandResult.success_result(
|
|
788
|
+
f"Deployed {deployed_count} agents from preset '{preset_name}'",
|
|
789
|
+
data={
|
|
790
|
+
"preset": preset_name,
|
|
791
|
+
"deployed": deployed_agents,
|
|
792
|
+
"failed": failed_agents,
|
|
793
|
+
"skipped": resolution["missing_agents"],
|
|
794
|
+
},
|
|
795
|
+
)
|
|
796
|
+
return CommandResult.error_result(
|
|
797
|
+
f"No agents deployed from preset '{preset_name}'",
|
|
798
|
+
data={
|
|
799
|
+
"preset": preset_name,
|
|
800
|
+
"failed": failed_agents,
|
|
801
|
+
"skipped": resolution["missing_agents"],
|
|
802
|
+
},
|
|
803
|
+
)
|
|
804
|
+
|
|
805
|
+
except Exception as e:
|
|
806
|
+
self.logger.error(f"Error deploying preset: {e}", exc_info=True)
|
|
807
|
+
print(f"\nā Error deploying preset: {e}")
|
|
808
|
+
return CommandResult.error_result(f"Error deploying preset: {e}")
|
|
809
|
+
|
|
401
810
|
def _clean_agents(self, args) -> CommandResult:
|
|
402
811
|
"""Clean deployed agents."""
|
|
403
812
|
try:
|
|
404
813
|
result = self.cleanup_service.clean_deployed_agents()
|
|
405
814
|
|
|
406
|
-
output_format =
|
|
815
|
+
output_format = self._get_output_format(args)
|
|
407
816
|
dry_run = False # Regular clean is not a dry run
|
|
408
817
|
|
|
409
818
|
formatted = self._formatter.format_cleanup_result(
|
|
@@ -441,7 +850,7 @@ class AgentsCommand(AgentCommand):
|
|
|
441
850
|
f"Could not retrieve details for agent '{agent_name}'"
|
|
442
851
|
)
|
|
443
852
|
|
|
444
|
-
output_format =
|
|
853
|
+
output_format = self._get_output_format(args)
|
|
445
854
|
verbose = getattr(args, "verbose", False)
|
|
446
855
|
|
|
447
856
|
formatted = self._formatter.format_agent_details(
|
|
@@ -463,148 +872,170 @@ class AgentsCommand(AgentCommand):
|
|
|
463
872
|
dry_run = getattr(args, "dry_run", False)
|
|
464
873
|
agent_name = getattr(args, "agent_name", None)
|
|
465
874
|
fix_all = getattr(args, "all", False)
|
|
875
|
+
output_format = self._get_output_format(args)
|
|
466
876
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
# Determine what to fix
|
|
877
|
+
# Route to appropriate handler based on input
|
|
470
878
|
if fix_all:
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
formatted = (
|
|
476
|
-
self._formatter.format_as_json(result)
|
|
477
|
-
if output_format == "json"
|
|
478
|
-
else self._formatter.format_as_yaml(result)
|
|
479
|
-
)
|
|
480
|
-
print(formatted)
|
|
481
|
-
else:
|
|
482
|
-
# Text output
|
|
483
|
-
mode = "DRY RUN" if dry_run else "FIX"
|
|
484
|
-
print(
|
|
485
|
-
f"\nš§ {mode}: Checking {result.get('total_agents', 0)} agent(s) for frontmatter issues...\n"
|
|
486
|
-
)
|
|
487
|
-
|
|
488
|
-
if result.get("results"):
|
|
489
|
-
for agent_result in result["results"]:
|
|
490
|
-
print(f"š {agent_result['agent']}:")
|
|
491
|
-
if agent_result.get("skipped"):
|
|
492
|
-
print(
|
|
493
|
-
f" ā ļø Skipped: {agent_result.get('reason', 'Unknown reason')}"
|
|
494
|
-
)
|
|
495
|
-
elif agent_result.get("was_valid"):
|
|
496
|
-
print(" ā No issues found")
|
|
497
|
-
else:
|
|
498
|
-
if agent_result.get("errors_found", 0) > 0:
|
|
499
|
-
print(
|
|
500
|
-
f" ā Errors found: {agent_result['errors_found']}"
|
|
501
|
-
)
|
|
502
|
-
if agent_result.get("warnings_found", 0) > 0:
|
|
503
|
-
print(
|
|
504
|
-
f" ā ļø Warnings found: {agent_result['warnings_found']}"
|
|
505
|
-
)
|
|
506
|
-
if dry_run:
|
|
507
|
-
if agent_result.get("corrections_available", 0) > 0:
|
|
508
|
-
print(
|
|
509
|
-
f" š§ Would fix: {agent_result['corrections_available']} issues"
|
|
510
|
-
)
|
|
511
|
-
elif agent_result.get("corrections_made", 0) > 0:
|
|
512
|
-
print(
|
|
513
|
-
f" ā Fixed: {agent_result['corrections_made']} issues"
|
|
514
|
-
)
|
|
515
|
-
print()
|
|
516
|
-
|
|
517
|
-
# Summary
|
|
518
|
-
print("=" * 80)
|
|
519
|
-
print("SUMMARY:")
|
|
520
|
-
print(f" Agents checked: {result.get('agents_checked', 0)}")
|
|
521
|
-
print(
|
|
522
|
-
f" Total issues found: {result.get('total_issues_found', 0)}"
|
|
523
|
-
)
|
|
524
|
-
if dry_run:
|
|
525
|
-
print(
|
|
526
|
-
f" Issues that would be fixed: {result.get('total_corrections_available', 0)}"
|
|
527
|
-
)
|
|
528
|
-
print("\nš” Run without --dry-run to apply fixes")
|
|
529
|
-
else:
|
|
530
|
-
print(
|
|
531
|
-
f" Issues fixed: {result.get('total_corrections_made', 0)}"
|
|
532
|
-
)
|
|
533
|
-
if result.get("total_corrections_made", 0) > 0:
|
|
534
|
-
print("\nā Frontmatter issues have been fixed!")
|
|
535
|
-
print("=" * 80 + "\n")
|
|
879
|
+
return self._fix_all_agents(dry_run, output_format)
|
|
880
|
+
if agent_name:
|
|
881
|
+
return self._fix_single_agent(agent_name, dry_run, output_format)
|
|
882
|
+
return self._handle_no_agent_specified(output_format)
|
|
536
883
|
|
|
537
|
-
|
|
538
|
-
|
|
884
|
+
except Exception as e:
|
|
885
|
+
self.logger.error(f"Error fixing agents: {e}", exc_info=True)
|
|
886
|
+
return CommandResult.error_result(f"Error fixing agents: {e}")
|
|
539
887
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
agent_name, dry_run=dry_run
|
|
544
|
-
)
|
|
888
|
+
def _fix_all_agents(self, dry_run: bool, output_format: str) -> CommandResult:
|
|
889
|
+
"""Fix all agents' frontmatter issues."""
|
|
890
|
+
result = self.validation_service.fix_all_agents(dry_run=dry_run)
|
|
545
891
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
892
|
+
if self._is_structured_format(output_format):
|
|
893
|
+
self._print_structured_output(result, output_format)
|
|
894
|
+
else:
|
|
895
|
+
self._print_all_agents_text_output(result, dry_run)
|
|
550
896
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
self._formatter.format_as_json(result)
|
|
554
|
-
if output_format == "json"
|
|
555
|
-
else self._formatter.format_as_yaml(result)
|
|
556
|
-
)
|
|
557
|
-
print(formatted)
|
|
558
|
-
else:
|
|
559
|
-
# Text output
|
|
560
|
-
mode = "DRY RUN" if dry_run else "FIX"
|
|
561
|
-
print(
|
|
562
|
-
f"\nš§ {mode}: Checking agent '{agent_name}' for frontmatter issues...\n"
|
|
563
|
-
)
|
|
897
|
+
msg = f"{'Would fix' if dry_run else 'Fixed'} {result.get('total_corrections_available' if dry_run else 'total_corrections_made', 0)} issues"
|
|
898
|
+
return CommandResult.success_result(msg, data=result)
|
|
564
899
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
print(f" - {error}")
|
|
573
|
-
if result.get("warnings_found"):
|
|
574
|
-
print(" ā ļø Warnings:")
|
|
575
|
-
for warning in result["warnings_found"]:
|
|
576
|
-
print(f" - {warning}")
|
|
577
|
-
if dry_run:
|
|
578
|
-
if result.get("corrections_available"):
|
|
579
|
-
print(" š§ Would fix:")
|
|
580
|
-
for correction in result["corrections_available"]:
|
|
581
|
-
print(f" - {correction}")
|
|
582
|
-
elif result.get("corrections_made"):
|
|
583
|
-
print(" ā Fixed:")
|
|
584
|
-
for correction in result["corrections_made"]:
|
|
585
|
-
print(f" - {correction}")
|
|
586
|
-
print()
|
|
900
|
+
def _fix_single_agent(
|
|
901
|
+
self, agent_name: str, dry_run: bool, output_format: str
|
|
902
|
+
) -> CommandResult:
|
|
903
|
+
"""Fix a single agent's frontmatter issues."""
|
|
904
|
+
result = self.validation_service.fix_agent_frontmatter(
|
|
905
|
+
agent_name, dry_run=dry_run
|
|
906
|
+
)
|
|
587
907
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
908
|
+
if not result.get("success"):
|
|
909
|
+
return CommandResult.error_result(
|
|
910
|
+
result.get("error", "Failed to fix agent")
|
|
911
|
+
)
|
|
592
912
|
|
|
593
|
-
|
|
594
|
-
|
|
913
|
+
if self._is_structured_format(output_format):
|
|
914
|
+
self._print_structured_output(result, output_format)
|
|
915
|
+
else:
|
|
916
|
+
self._print_single_agent_text_output(agent_name, result, dry_run)
|
|
595
917
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
if output_format in ["json", "yaml"]:
|
|
599
|
-
return CommandResult.error_result(
|
|
600
|
-
"No agent specified", data={"usage": usage_msg}
|
|
601
|
-
)
|
|
602
|
-
print(f"ā {usage_msg}")
|
|
603
|
-
return CommandResult.error_result("No agent specified")
|
|
918
|
+
msg = f"{'Would fix' if dry_run else 'Fixed'} agent '{agent_name}'"
|
|
919
|
+
return CommandResult.success_result(msg, data=result)
|
|
604
920
|
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
921
|
+
def _handle_no_agent_specified(self, output_format: str) -> CommandResult:
|
|
922
|
+
"""Handle case where no agent is specified."""
|
|
923
|
+
usage_msg = "Please specify an agent name or use --all to fix all agents\nUsage: claude-mpm agents fix [agent_name] [--dry-run] [--all]"
|
|
924
|
+
if self._is_structured_format(output_format):
|
|
925
|
+
return CommandResult.error_result(
|
|
926
|
+
"No agent specified", data={"usage": usage_msg}
|
|
927
|
+
)
|
|
928
|
+
print(f"ā {usage_msg}")
|
|
929
|
+
return CommandResult.error_result("No agent specified")
|
|
930
|
+
|
|
931
|
+
def _print_structured_output(self, result: dict, output_format: str) -> None:
|
|
932
|
+
"""Print result in JSON or YAML format."""
|
|
933
|
+
formatted = (
|
|
934
|
+
self._formatter.format_as_json(result)
|
|
935
|
+
if str(output_format).lower() == OutputFormat.JSON
|
|
936
|
+
else self._formatter.format_as_yaml(result)
|
|
937
|
+
)
|
|
938
|
+
print(formatted)
|
|
939
|
+
|
|
940
|
+
def _print_all_agents_text_output(self, result: dict, dry_run: bool) -> None:
|
|
941
|
+
"""Print text output for all agents fix operation."""
|
|
942
|
+
mode = "DRY RUN" if dry_run else "FIX"
|
|
943
|
+
print(
|
|
944
|
+
f"\nš§ {mode}: Checking {result.get('total_agents', 0)} agent(s) for frontmatter issues...\n"
|
|
945
|
+
)
|
|
946
|
+
|
|
947
|
+
if result.get("results"):
|
|
948
|
+
for agent_result in result["results"]:
|
|
949
|
+
self._print_agent_result(agent_result, dry_run)
|
|
950
|
+
|
|
951
|
+
self._print_all_agents_summary(result, dry_run)
|
|
952
|
+
|
|
953
|
+
def _print_agent_result(self, agent_result: dict, dry_run: bool) -> None:
|
|
954
|
+
"""Print result for a single agent."""
|
|
955
|
+
print(f"š {agent_result['agent']}:")
|
|
956
|
+
if agent_result.get("skipped"):
|
|
957
|
+
print(f" ā ļø Skipped: {agent_result.get('reason', 'Unknown reason')}")
|
|
958
|
+
elif agent_result.get("was_valid"):
|
|
959
|
+
print(" ā No issues found")
|
|
960
|
+
else:
|
|
961
|
+
self._print_agent_issues(agent_result, dry_run)
|
|
962
|
+
print()
|
|
963
|
+
|
|
964
|
+
def _print_agent_issues(self, agent_result: dict, dry_run: bool) -> None:
|
|
965
|
+
"""Print issues found for an agent."""
|
|
966
|
+
if agent_result.get("errors_found", 0) > 0:
|
|
967
|
+
print(f" ā Errors found: {agent_result['errors_found']}")
|
|
968
|
+
if agent_result.get("warnings_found", 0) > 0:
|
|
969
|
+
print(f" ā ļø Warnings found: {agent_result['warnings_found']}")
|
|
970
|
+
|
|
971
|
+
if dry_run:
|
|
972
|
+
if agent_result.get("corrections_available", 0) > 0:
|
|
973
|
+
print(f" š§ Would fix: {agent_result['corrections_available']} issues")
|
|
974
|
+
elif agent_result.get("corrections_made", 0) > 0:
|
|
975
|
+
print(f" ā Fixed: {agent_result['corrections_made']} issues")
|
|
976
|
+
|
|
977
|
+
def _print_all_agents_summary(self, result: dict, dry_run: bool) -> None:
|
|
978
|
+
"""Print summary for all agents fix operation."""
|
|
979
|
+
print("=" * 80)
|
|
980
|
+
print("SUMMARY:")
|
|
981
|
+
print(f" Agents checked: {result.get('agents_checked', 0)}")
|
|
982
|
+
print(f" Total issues found: {result.get('total_issues_found', 0)}")
|
|
983
|
+
|
|
984
|
+
if dry_run:
|
|
985
|
+
print(
|
|
986
|
+
f" Issues that would be fixed: {result.get('total_corrections_available', 0)}"
|
|
987
|
+
)
|
|
988
|
+
print("\nš” Run without --dry-run to apply fixes")
|
|
989
|
+
else:
|
|
990
|
+
print(f" Issues fixed: {result.get('total_corrections_made', 0)}")
|
|
991
|
+
if result.get("total_corrections_made", 0) > 0:
|
|
992
|
+
print("\nā Frontmatter issues have been fixed!")
|
|
993
|
+
print("=" * 80 + "\n")
|
|
994
|
+
|
|
995
|
+
def _print_single_agent_text_output(
|
|
996
|
+
self, agent_name: str, result: dict, dry_run: bool
|
|
997
|
+
) -> None:
|
|
998
|
+
"""Print text output for single agent fix operation."""
|
|
999
|
+
mode = "DRY RUN" if dry_run else "FIX"
|
|
1000
|
+
print(f"\nš§ {mode}: Checking agent '{agent_name}' for frontmatter issues...\n")
|
|
1001
|
+
|
|
1002
|
+
print(f"š {agent_name}:")
|
|
1003
|
+
if result.get("was_valid"):
|
|
1004
|
+
print(" ā No issues found")
|
|
1005
|
+
else:
|
|
1006
|
+
self._print_single_agent_issues(result, dry_run)
|
|
1007
|
+
print()
|
|
1008
|
+
|
|
1009
|
+
self._print_single_agent_footer(result, dry_run)
|
|
1010
|
+
|
|
1011
|
+
def _print_single_agent_issues(self, result: dict, dry_run: bool) -> None:
|
|
1012
|
+
"""Print issues for a single agent."""
|
|
1013
|
+
if result.get("errors_found"):
|
|
1014
|
+
print(" ā Errors:")
|
|
1015
|
+
for error in result["errors_found"]:
|
|
1016
|
+
print(f" - {error}")
|
|
1017
|
+
|
|
1018
|
+
if result.get("warnings_found"):
|
|
1019
|
+
print(" ā ļø Warnings:")
|
|
1020
|
+
for warning in result["warnings_found"]:
|
|
1021
|
+
print(f" - {warning}")
|
|
1022
|
+
|
|
1023
|
+
if dry_run:
|
|
1024
|
+
if result.get("corrections_available"):
|
|
1025
|
+
print(" š§ Would fix:")
|
|
1026
|
+
for correction in result["corrections_available"]:
|
|
1027
|
+
print(f" - {correction}")
|
|
1028
|
+
elif result.get("corrections_made"):
|
|
1029
|
+
print(" ā Fixed:")
|
|
1030
|
+
for correction in result["corrections_made"]:
|
|
1031
|
+
print(f" - {correction}")
|
|
1032
|
+
|
|
1033
|
+
def _print_single_agent_footer(self, result: dict, dry_run: bool) -> None:
|
|
1034
|
+
"""Print footer message for single agent fix."""
|
|
1035
|
+
if dry_run and result.get("corrections_available"):
|
|
1036
|
+
print("š” Run without --dry-run to apply fixes\n")
|
|
1037
|
+
elif not dry_run and result.get("corrections_made"):
|
|
1038
|
+
print("ā Frontmatter issues have been fixed!\n")
|
|
608
1039
|
|
|
609
1040
|
def _check_agent_dependencies(self, args) -> CommandResult:
|
|
610
1041
|
"""Check agent dependencies."""
|
|
@@ -684,7 +1115,7 @@ class AgentsCommand(AgentCommand):
|
|
|
684
1115
|
def _list_agent_dependencies(self, args) -> CommandResult:
|
|
685
1116
|
"""List agent dependencies."""
|
|
686
1117
|
try:
|
|
687
|
-
output_format =
|
|
1118
|
+
output_format = self._get_output_format(args)
|
|
688
1119
|
result = self.dependency_service.list_dependencies(
|
|
689
1120
|
format_type=output_format
|
|
690
1121
|
)
|
|
@@ -696,7 +1127,7 @@ class AgentsCommand(AgentCommand):
|
|
|
696
1127
|
if output_format == "pip":
|
|
697
1128
|
for dep in result["dependencies"]:
|
|
698
1129
|
print(dep)
|
|
699
|
-
elif output_format ==
|
|
1130
|
+
elif str(output_format).lower() == OutputFormat.JSON:
|
|
700
1131
|
print(json.dumps(result["data"], indent=2))
|
|
701
1132
|
else: # text format
|
|
702
1133
|
print("=" * 60)
|
|
@@ -836,6 +1267,16 @@ class AgentsCommand(AgentCommand):
|
|
|
836
1267
|
self.logger.error(f"Error fixing dependencies: {e}", exc_info=True)
|
|
837
1268
|
return CommandResult.error_result(f"Error fixing dependencies: {e}")
|
|
838
1269
|
|
|
1270
|
+
def _handle_cleanup_command(self, args) -> CommandResult:
|
|
1271
|
+
"""Handle cleanup command with proper result wrapping."""
|
|
1272
|
+
exit_code = handle_agents_cleanup(args)
|
|
1273
|
+
return CommandResult(
|
|
1274
|
+
success=exit_code == 0,
|
|
1275
|
+
message=(
|
|
1276
|
+
"Agent cleanup complete" if exit_code == 0 else "Agent cleanup failed"
|
|
1277
|
+
),
|
|
1278
|
+
)
|
|
1279
|
+
|
|
839
1280
|
def _cleanup_orphaned_agents(self, args) -> CommandResult:
|
|
840
1281
|
"""Clean up orphaned agents that don't have templates."""
|
|
841
1282
|
try:
|
|
@@ -854,7 +1295,7 @@ class AgentsCommand(AgentCommand):
|
|
|
854
1295
|
agents_dir=agents_dir, dry_run=dry_run
|
|
855
1296
|
)
|
|
856
1297
|
|
|
857
|
-
output_format =
|
|
1298
|
+
output_format = self._get_output_format(args)
|
|
858
1299
|
|
|
859
1300
|
formatted = self._formatter.format_cleanup_result(
|
|
860
1301
|
results, output_format=output_format, dry_run=dry_run
|
|
@@ -876,6 +1317,1060 @@ class AgentsCommand(AgentCommand):
|
|
|
876
1317
|
self.logger.error(f"Error during cleanup: {e}", exc_info=True)
|
|
877
1318
|
return CommandResult.error_result(f"Error during cleanup: {e}")
|
|
878
1319
|
|
|
1320
|
+
def _create_local_agent(self, args) -> CommandResult:
|
|
1321
|
+
"""Create a new local agent template."""
|
|
1322
|
+
try:
|
|
1323
|
+
if getattr(args, "interactive", False):
|
|
1324
|
+
# Launch interactive wizard
|
|
1325
|
+
from ..interactive.agent_wizard import run_interactive_agent_wizard
|
|
1326
|
+
|
|
1327
|
+
exit_code = run_interactive_agent_wizard()
|
|
1328
|
+
if exit_code == 0:
|
|
1329
|
+
return CommandResult.success_result("Agent created successfully")
|
|
1330
|
+
return CommandResult.error_result("Agent creation cancelled or failed")
|
|
1331
|
+
|
|
1332
|
+
# Non-interactive creation
|
|
1333
|
+
from ...services.agents.local_template_manager import (
|
|
1334
|
+
LocalAgentTemplateManager,
|
|
1335
|
+
)
|
|
1336
|
+
|
|
1337
|
+
agent_id = getattr(args, "agent_id", None)
|
|
1338
|
+
if not agent_id:
|
|
1339
|
+
return CommandResult.error_result(
|
|
1340
|
+
"--agent-id is required for non-interactive creation"
|
|
1341
|
+
)
|
|
1342
|
+
|
|
1343
|
+
manager = LocalAgentTemplateManager()
|
|
1344
|
+
name = getattr(args, "name", agent_id.replace("-", " ").title())
|
|
1345
|
+
model = getattr(args, "model", "sonnet")
|
|
1346
|
+
inherit_from = getattr(args, "inherit_from", None)
|
|
1347
|
+
|
|
1348
|
+
# Create basic template
|
|
1349
|
+
template = manager.create_local_template(
|
|
1350
|
+
agent_id=agent_id,
|
|
1351
|
+
name=name,
|
|
1352
|
+
description=f"Local agent: {name}",
|
|
1353
|
+
instructions="# Agent Instructions\n\nCustomize this agent's behavior here.",
|
|
1354
|
+
model=model,
|
|
1355
|
+
parent_agent=inherit_from,
|
|
1356
|
+
tier="project",
|
|
1357
|
+
)
|
|
1358
|
+
|
|
1359
|
+
if template:
|
|
1360
|
+
return CommandResult.success_result(
|
|
1361
|
+
f"Created local agent '{agent_id}' in .claude-mpm/agents/",
|
|
1362
|
+
data={
|
|
1363
|
+
"agent_id": agent_id,
|
|
1364
|
+
"path": f".claude-mpm/agents/{agent_id}.json",
|
|
1365
|
+
},
|
|
1366
|
+
)
|
|
1367
|
+
return CommandResult.error_result("Failed to create agent template")
|
|
1368
|
+
|
|
1369
|
+
except Exception as e:
|
|
1370
|
+
self.logger.error(f"Error creating local agent: {e}", exc_info=True)
|
|
1371
|
+
return CommandResult.error_result(f"Error creating local agent: {e}")
|
|
1372
|
+
|
|
1373
|
+
def _edit_local_agent(self, args) -> CommandResult:
|
|
1374
|
+
"""Edit a local agent template."""
|
|
1375
|
+
try:
|
|
1376
|
+
agent_id = getattr(args, "agent_id", None)
|
|
1377
|
+
if not agent_id:
|
|
1378
|
+
return CommandResult.error_result("agent_id is required")
|
|
1379
|
+
|
|
1380
|
+
import os
|
|
1381
|
+
import subprocess
|
|
1382
|
+
|
|
1383
|
+
from ...services.agents.local_template_manager import (
|
|
1384
|
+
LocalAgentTemplateManager,
|
|
1385
|
+
)
|
|
1386
|
+
|
|
1387
|
+
manager = LocalAgentTemplateManager()
|
|
1388
|
+
template = manager.get_local_template(agent_id)
|
|
1389
|
+
|
|
1390
|
+
if not template:
|
|
1391
|
+
return CommandResult.error_result(f"Local agent '{agent_id}' not found")
|
|
1392
|
+
|
|
1393
|
+
# Get template file path
|
|
1394
|
+
template_file = None
|
|
1395
|
+
if template.tier == "project":
|
|
1396
|
+
template_file = manager.project_agents_dir / f"{agent_id}.json"
|
|
1397
|
+
else:
|
|
1398
|
+
template_file = manager.user_agents_dir / f"{agent_id}.json"
|
|
1399
|
+
|
|
1400
|
+
if not template_file or not template_file.exists():
|
|
1401
|
+
return CommandResult.error_result(
|
|
1402
|
+
f"Template file not found for '{agent_id}'"
|
|
1403
|
+
)
|
|
1404
|
+
|
|
1405
|
+
if getattr(args, "interactive", False):
|
|
1406
|
+
# Launch interactive editor
|
|
1407
|
+
from ..interactive.agent_wizard import AgentWizard
|
|
1408
|
+
|
|
1409
|
+
wizard = AgentWizard()
|
|
1410
|
+
success, message = wizard._edit_agent_config(template)
|
|
1411
|
+
if success:
|
|
1412
|
+
return CommandResult.success_result(message)
|
|
1413
|
+
return CommandResult.error_result(message)
|
|
1414
|
+
|
|
1415
|
+
# Use system editor
|
|
1416
|
+
editor = getattr(args, "editor", None) or os.environ.get("EDITOR", "nano")
|
|
1417
|
+
subprocess.run([editor, str(template_file)], check=True)
|
|
1418
|
+
return CommandResult.success_result(
|
|
1419
|
+
f"Agent '{agent_id}' edited successfully"
|
|
1420
|
+
)
|
|
1421
|
+
|
|
1422
|
+
except subprocess.CalledProcessError:
|
|
1423
|
+
return CommandResult.error_result("Editor exited with error")
|
|
1424
|
+
except Exception as e:
|
|
1425
|
+
self.logger.error(f"Error editing local agent: {e}", exc_info=True)
|
|
1426
|
+
return CommandResult.error_result(f"Error editing local agent: {e}")
|
|
1427
|
+
|
|
1428
|
+
def _delete_local_agent(self, args) -> CommandResult:
|
|
1429
|
+
"""Delete local agent templates."""
|
|
1430
|
+
try:
|
|
1431
|
+
agent_ids = getattr(args, "agent_ids", [])
|
|
1432
|
+
if not agent_ids:
|
|
1433
|
+
return CommandResult.error_result("No agent IDs specified")
|
|
1434
|
+
|
|
1435
|
+
from ...services.agents.local_template_manager import (
|
|
1436
|
+
LocalAgentTemplateManager,
|
|
1437
|
+
)
|
|
1438
|
+
|
|
1439
|
+
manager = LocalAgentTemplateManager()
|
|
1440
|
+
force = getattr(args, "force", False)
|
|
1441
|
+
keep_deployment = getattr(args, "keep_deployment", False)
|
|
1442
|
+
backup = getattr(args, "backup", False)
|
|
1443
|
+
|
|
1444
|
+
# Confirmation if not forced
|
|
1445
|
+
if not force:
|
|
1446
|
+
print(f"\nā ļø This will delete {len(agent_ids)} agent(s):")
|
|
1447
|
+
for agent_id in agent_ids:
|
|
1448
|
+
print(f" - {agent_id}")
|
|
1449
|
+
confirm = input("\nAre you sure? [y/N]: ").strip().lower()
|
|
1450
|
+
if confirm not in ["y", "yes"]:
|
|
1451
|
+
return CommandResult.error_result("Deletion cancelled")
|
|
1452
|
+
|
|
1453
|
+
# Delete agents
|
|
1454
|
+
if len(agent_ids) == 1:
|
|
1455
|
+
result = manager.delete_local_template(
|
|
1456
|
+
agent_id=agent_ids[0],
|
|
1457
|
+
tier="all",
|
|
1458
|
+
delete_deployment=not keep_deployment,
|
|
1459
|
+
backup_first=backup,
|
|
1460
|
+
)
|
|
1461
|
+
if result["success"]:
|
|
1462
|
+
message = f"Successfully deleted agent '{agent_ids[0]}'"
|
|
1463
|
+
if result["backup_location"]:
|
|
1464
|
+
message += f"\nBackup saved to: {result['backup_location']}"
|
|
1465
|
+
return CommandResult.success_result(message, data=result)
|
|
1466
|
+
return CommandResult.error_result(
|
|
1467
|
+
f"Failed to delete agent: {', '.join(result['errors'])}"
|
|
1468
|
+
)
|
|
1469
|
+
results = manager.delete_multiple_templates(
|
|
1470
|
+
agent_ids=agent_ids,
|
|
1471
|
+
tier="all",
|
|
1472
|
+
delete_deployment=not keep_deployment,
|
|
1473
|
+
backup_first=backup,
|
|
1474
|
+
)
|
|
1475
|
+
|
|
1476
|
+
message = ""
|
|
1477
|
+
if results["successful"]:
|
|
1478
|
+
message = (
|
|
1479
|
+
f"Successfully deleted {len(results['successful'])} agent(s):\n"
|
|
1480
|
+
)
|
|
1481
|
+
for agent_id in results["successful"]:
|
|
1482
|
+
message += f" - {agent_id}\n"
|
|
1483
|
+
|
|
1484
|
+
if results["failed"]:
|
|
1485
|
+
if message:
|
|
1486
|
+
message += "\n"
|
|
1487
|
+
message += f"Failed to delete {len(results['failed'])} agent(s):\n"
|
|
1488
|
+
for agent_id in results["failed"]:
|
|
1489
|
+
errors = results["details"][agent_id]["errors"]
|
|
1490
|
+
message += f" - {agent_id}: {', '.join(errors)}\n"
|
|
1491
|
+
|
|
1492
|
+
if results["successful"]:
|
|
1493
|
+
return CommandResult.success_result(message.strip(), data=results)
|
|
1494
|
+
return CommandResult.error_result(message.strip(), data=results)
|
|
1495
|
+
|
|
1496
|
+
except Exception as e:
|
|
1497
|
+
self.logger.error(f"Error deleting local agents: {e}", exc_info=True)
|
|
1498
|
+
return CommandResult.error_result(f"Error deleting local agents: {e}")
|
|
1499
|
+
|
|
1500
|
+
def _manage_local_agents(self, args) -> CommandResult:
|
|
1501
|
+
"""Redirect to main configuration interface (DEPRECATED)."""
|
|
1502
|
+
try:
|
|
1503
|
+
from rich.console import Console
|
|
1504
|
+
from rich.prompt import Confirm
|
|
1505
|
+
|
|
1506
|
+
console = Console()
|
|
1507
|
+
|
|
1508
|
+
console.print(
|
|
1509
|
+
"\n[bold cyan]āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā®[/bold cyan]"
|
|
1510
|
+
)
|
|
1511
|
+
console.print(
|
|
1512
|
+
"[bold cyan]ā Agent Management Has Moved! ā[/bold cyan]"
|
|
1513
|
+
)
|
|
1514
|
+
console.print(
|
|
1515
|
+
"[bold cyan]ā°āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāÆ[/bold cyan]\n"
|
|
1516
|
+
)
|
|
1517
|
+
|
|
1518
|
+
console.print("For a better experience with integrated configuration:")
|
|
1519
|
+
console.print(" ⢠Agent management")
|
|
1520
|
+
console.print(" ⢠Skills management")
|
|
1521
|
+
console.print(" ⢠Template editing")
|
|
1522
|
+
console.print(" ⢠Behavior configuration")
|
|
1523
|
+
console.print(" ⢠Startup settings\n")
|
|
1524
|
+
|
|
1525
|
+
console.print("Please use: [bold green]claude-mpm config[/bold green]\n")
|
|
1526
|
+
|
|
1527
|
+
if Confirm.ask("Launch configuration interface now?", default=True):
|
|
1528
|
+
# Import and run config command directly
|
|
1529
|
+
from claude_mpm.cli.commands.configure import ConfigureCommand
|
|
1530
|
+
|
|
1531
|
+
config_cmd = ConfigureCommand()
|
|
1532
|
+
return config_cmd.execute(args)
|
|
1533
|
+
console.print(
|
|
1534
|
+
"\n[dim]Run 'claude-mpm config' anytime to access agent management[/dim]"
|
|
1535
|
+
)
|
|
1536
|
+
return CommandResult.success_result("Redirected to config interface")
|
|
1537
|
+
|
|
1538
|
+
except Exception as e:
|
|
1539
|
+
self.logger.error(f"Error redirecting to config: {e}", exc_info=True)
|
|
1540
|
+
return CommandResult.error_result(f"Error redirecting to config: {e}")
|
|
1541
|
+
|
|
1542
|
+
def _configure_deployment(self, args) -> CommandResult:
|
|
1543
|
+
"""Configure agent deployment settings."""
|
|
1544
|
+
try:
|
|
1545
|
+
from pathlib import Path
|
|
1546
|
+
|
|
1547
|
+
import yaml
|
|
1548
|
+
|
|
1549
|
+
from claude_mpm.core.config import Config
|
|
1550
|
+
|
|
1551
|
+
config = Config()
|
|
1552
|
+
config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
|
|
1553
|
+
|
|
1554
|
+
# Handle show command
|
|
1555
|
+
if getattr(args, "show", False):
|
|
1556
|
+
from ...services.agents.deployment.deployment_config_loader import (
|
|
1557
|
+
DeploymentConfigLoader,
|
|
1558
|
+
)
|
|
1559
|
+
|
|
1560
|
+
loader = DeploymentConfigLoader(self.logger)
|
|
1561
|
+
settings = loader.get_deployment_settings(config)
|
|
1562
|
+
|
|
1563
|
+
print("\nš Agent Deployment Configuration")
|
|
1564
|
+
print("=" * 50)
|
|
1565
|
+
print(f"Configuration file: {config_path}")
|
|
1566
|
+
print("\nš§ Deployment Settings:")
|
|
1567
|
+
print(f" Deploy system agents: {settings['deploy_system_agents']}")
|
|
1568
|
+
print(f" Deploy local agents: {settings['deploy_local_agents']}")
|
|
1569
|
+
print(f" Deploy user agents: {settings['deploy_user_agents']}")
|
|
1570
|
+
print(
|
|
1571
|
+
f" Prefer local over system: {settings['prefer_local_over_system']}"
|
|
1572
|
+
)
|
|
1573
|
+
print(f" Version comparison: {settings['version_comparison']}")
|
|
1574
|
+
|
|
1575
|
+
if settings["enabled_agents"]:
|
|
1576
|
+
print(
|
|
1577
|
+
f"\nā
Enabled agents: {', '.join(settings['enabled_agents'])}"
|
|
1578
|
+
)
|
|
1579
|
+
else:
|
|
1580
|
+
print("\nā
Enabled agents: All (no restrictions)")
|
|
1581
|
+
|
|
1582
|
+
if settings["disabled_agents"]:
|
|
1583
|
+
print(
|
|
1584
|
+
f"ā Disabled agents: {', '.join(settings['disabled_agents'])}"
|
|
1585
|
+
)
|
|
1586
|
+
else:
|
|
1587
|
+
print("ā Disabled agents: None")
|
|
1588
|
+
|
|
1589
|
+
print("\n" + "=" * 50)
|
|
1590
|
+
return CommandResult.success_result(
|
|
1591
|
+
"Displayed deployment configuration"
|
|
1592
|
+
)
|
|
1593
|
+
|
|
1594
|
+
# Handle interactive mode
|
|
1595
|
+
if getattr(args, "interactive", False):
|
|
1596
|
+
return self._configure_deployment_interactive(config_path)
|
|
1597
|
+
|
|
1598
|
+
# Load current configuration
|
|
1599
|
+
if not config_path.exists():
|
|
1600
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1601
|
+
config_data = {}
|
|
1602
|
+
else:
|
|
1603
|
+
with config_path.open() as f:
|
|
1604
|
+
config_data = yaml.safe_load(f) or {}
|
|
1605
|
+
|
|
1606
|
+
# Ensure agent_deployment section exists
|
|
1607
|
+
if "agent_deployment" not in config_data:
|
|
1608
|
+
config_data["agent_deployment"] = {}
|
|
1609
|
+
|
|
1610
|
+
modified = False
|
|
1611
|
+
|
|
1612
|
+
# Handle enable/disable operations
|
|
1613
|
+
if getattr(args, "enable_all", False):
|
|
1614
|
+
config_data["agent_deployment"]["enabled_agents"] = []
|
|
1615
|
+
config_data["agent_deployment"]["disabled_agents"] = []
|
|
1616
|
+
print("ā
Enabled all agents for deployment")
|
|
1617
|
+
modified = True
|
|
1618
|
+
|
|
1619
|
+
if getattr(args, "enable_system", False):
|
|
1620
|
+
config_data["agent_deployment"]["deploy_system_agents"] = True
|
|
1621
|
+
print("ā
Enabled system agents for deployment")
|
|
1622
|
+
modified = True
|
|
1623
|
+
|
|
1624
|
+
if getattr(args, "disable_system", False):
|
|
1625
|
+
config_data["agent_deployment"]["deploy_system_agents"] = False
|
|
1626
|
+
print("ā Disabled system agents from deployment")
|
|
1627
|
+
modified = True
|
|
1628
|
+
|
|
1629
|
+
if getattr(args, "enable_local", False):
|
|
1630
|
+
config_data["agent_deployment"]["deploy_local_agents"] = True
|
|
1631
|
+
print("ā
Enabled local agents for deployment")
|
|
1632
|
+
modified = True
|
|
1633
|
+
|
|
1634
|
+
if getattr(args, "disable_local", False):
|
|
1635
|
+
config_data["agent_deployment"]["deploy_local_agents"] = False
|
|
1636
|
+
print("ā Disabled local agents from deployment")
|
|
1637
|
+
modified = True
|
|
1638
|
+
|
|
1639
|
+
if getattr(args, "enable", None):
|
|
1640
|
+
enabled = config_data["agent_deployment"].get("enabled_agents", [])
|
|
1641
|
+
disabled = config_data["agent_deployment"].get("disabled_agents", [])
|
|
1642
|
+
|
|
1643
|
+
for agent_id in args.enable:
|
|
1644
|
+
if agent_id not in enabled:
|
|
1645
|
+
enabled.append(agent_id)
|
|
1646
|
+
if agent_id in disabled:
|
|
1647
|
+
disabled.remove(agent_id)
|
|
1648
|
+
|
|
1649
|
+
config_data["agent_deployment"]["enabled_agents"] = enabled
|
|
1650
|
+
config_data["agent_deployment"]["disabled_agents"] = disabled
|
|
1651
|
+
print(f"ā
Enabled agents: {', '.join(args.enable)}")
|
|
1652
|
+
modified = True
|
|
1653
|
+
|
|
1654
|
+
if getattr(args, "disable", None):
|
|
1655
|
+
disabled = config_data["agent_deployment"].get("disabled_agents", [])
|
|
1656
|
+
|
|
1657
|
+
for agent_id in args.disable:
|
|
1658
|
+
if agent_id not in disabled:
|
|
1659
|
+
disabled.append(agent_id)
|
|
1660
|
+
|
|
1661
|
+
config_data["agent_deployment"]["disabled_agents"] = disabled
|
|
1662
|
+
print(f"ā Disabled agents: {', '.join(args.disable)}")
|
|
1663
|
+
modified = True
|
|
1664
|
+
|
|
1665
|
+
# Save configuration if modified
|
|
1666
|
+
if modified:
|
|
1667
|
+
with config_path.open("w") as f:
|
|
1668
|
+
yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
|
|
1669
|
+
print(f"\nš¾ Configuration saved to {config_path}")
|
|
1670
|
+
return CommandResult.success_result("Deployment configuration updated")
|
|
1671
|
+
|
|
1672
|
+
# If no modifications were made and not showing, display help
|
|
1673
|
+
if not getattr(args, "show", False):
|
|
1674
|
+
print("No configuration changes specified. Use --help for options.")
|
|
1675
|
+
return CommandResult.success_result("No changes made")
|
|
1676
|
+
|
|
1677
|
+
except Exception as e:
|
|
1678
|
+
self.logger.error(f"Error configuring deployment: {e}", exc_info=True)
|
|
1679
|
+
return CommandResult.error_result(f"Error configuring deployment: {e}")
|
|
1680
|
+
|
|
1681
|
+
def _configure_deployment_interactive(self, config_path: Path) -> CommandResult:
|
|
1682
|
+
"""Interactive mode for configuring agent deployment."""
|
|
1683
|
+
try:
|
|
1684
|
+
import yaml
|
|
1685
|
+
|
|
1686
|
+
from ...utils.ui_helpers import (
|
|
1687
|
+
prompt_choice,
|
|
1688
|
+
prompt_multiselect,
|
|
1689
|
+
prompt_yes_no,
|
|
1690
|
+
)
|
|
1691
|
+
|
|
1692
|
+
# Load current configuration
|
|
1693
|
+
if config_path.exists():
|
|
1694
|
+
with config_path.open() as f:
|
|
1695
|
+
config_data = yaml.safe_load(f) or {}
|
|
1696
|
+
else:
|
|
1697
|
+
config_data = {}
|
|
1698
|
+
|
|
1699
|
+
if "agent_deployment" not in config_data:
|
|
1700
|
+
config_data["agent_deployment"] = {}
|
|
1701
|
+
|
|
1702
|
+
settings = config_data["agent_deployment"]
|
|
1703
|
+
|
|
1704
|
+
print("\nš® Interactive Agent Deployment Configuration")
|
|
1705
|
+
print("=" * 50)
|
|
1706
|
+
|
|
1707
|
+
# Configure source types
|
|
1708
|
+
settings["deploy_system_agents"] = prompt_yes_no(
|
|
1709
|
+
"Deploy system agents?",
|
|
1710
|
+
default=settings.get("deploy_system_agents", True),
|
|
1711
|
+
)
|
|
1712
|
+
|
|
1713
|
+
settings["deploy_local_agents"] = prompt_yes_no(
|
|
1714
|
+
"Deploy local project agents?",
|
|
1715
|
+
default=settings.get("deploy_local_agents", True),
|
|
1716
|
+
)
|
|
1717
|
+
|
|
1718
|
+
settings["deploy_user_agents"] = prompt_yes_no(
|
|
1719
|
+
"Deploy user-level agents?",
|
|
1720
|
+
default=settings.get("deploy_user_agents", True),
|
|
1721
|
+
)
|
|
1722
|
+
|
|
1723
|
+
# Configure version behavior
|
|
1724
|
+
settings["prefer_local_over_system"] = prompt_yes_no(
|
|
1725
|
+
"Should local agents override system agents with same ID?",
|
|
1726
|
+
default=settings.get("prefer_local_over_system", True),
|
|
1727
|
+
)
|
|
1728
|
+
|
|
1729
|
+
settings["version_comparison"] = prompt_yes_no(
|
|
1730
|
+
"Compare versions across sources and deploy highest?",
|
|
1731
|
+
default=settings.get("version_comparison", True),
|
|
1732
|
+
)
|
|
1733
|
+
|
|
1734
|
+
# Configure specific agents
|
|
1735
|
+
choice = prompt_choice(
|
|
1736
|
+
"How would you like to configure specific agents?",
|
|
1737
|
+
[
|
|
1738
|
+
"No restrictions (all agents enabled)",
|
|
1739
|
+
"Specify disabled agents",
|
|
1740
|
+
"Specify enabled agents only",
|
|
1741
|
+
],
|
|
1742
|
+
)
|
|
1743
|
+
|
|
1744
|
+
if choice == "No restrictions (all agents enabled)":
|
|
1745
|
+
settings["enabled_agents"] = []
|
|
1746
|
+
settings["disabled_agents"] = []
|
|
1747
|
+
elif choice == "Specify disabled agents":
|
|
1748
|
+
# Get list of available agents
|
|
1749
|
+
from ...services.agents.listing_service import AgentListingService
|
|
1750
|
+
|
|
1751
|
+
listing_service = AgentListingService()
|
|
1752
|
+
agents, _ = listing_service.list_all_agents()
|
|
1753
|
+
agent_ids = sorted({agent.name for agent in agents})
|
|
1754
|
+
|
|
1755
|
+
if agent_ids:
|
|
1756
|
+
disabled = prompt_multiselect(
|
|
1757
|
+
"Select agents to disable:",
|
|
1758
|
+
agent_ids,
|
|
1759
|
+
default=settings.get("disabled_agents", []),
|
|
1760
|
+
)
|
|
1761
|
+
settings["disabled_agents"] = disabled
|
|
1762
|
+
settings["enabled_agents"] = []
|
|
1763
|
+
else:
|
|
1764
|
+
print("No agents found to configure")
|
|
1765
|
+
else: # Specify enabled agents only
|
|
1766
|
+
from ...services.agents.listing_service import AgentListingService
|
|
1767
|
+
|
|
1768
|
+
listing_service = AgentListingService()
|
|
1769
|
+
agents, _ = listing_service.list_all_agents()
|
|
1770
|
+
agent_ids = sorted({agent.name for agent in agents})
|
|
1771
|
+
|
|
1772
|
+
if agent_ids:
|
|
1773
|
+
enabled = prompt_multiselect(
|
|
1774
|
+
"Select agents to enable (others will be disabled):",
|
|
1775
|
+
agent_ids,
|
|
1776
|
+
default=settings.get("enabled_agents", []),
|
|
1777
|
+
)
|
|
1778
|
+
settings["enabled_agents"] = enabled
|
|
1779
|
+
settings["disabled_agents"] = []
|
|
1780
|
+
else:
|
|
1781
|
+
print("No agents found to configure")
|
|
1782
|
+
|
|
1783
|
+
# Save configuration
|
|
1784
|
+
config_data["agent_deployment"] = settings
|
|
1785
|
+
|
|
1786
|
+
# Ensure parent directory exists
|
|
1787
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
1788
|
+
|
|
1789
|
+
with config_path.open("w") as f:
|
|
1790
|
+
yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
|
|
1791
|
+
|
|
1792
|
+
print(f"\nā
Configuration saved to {config_path}")
|
|
1793
|
+
|
|
1794
|
+
# Show summary
|
|
1795
|
+
print("\nš New Configuration Summary:")
|
|
1796
|
+
print(
|
|
1797
|
+
f" System agents: {'Enabled' if settings.get('deploy_system_agents', True) else 'Disabled'}"
|
|
1798
|
+
)
|
|
1799
|
+
print(
|
|
1800
|
+
f" Local agents: {'Enabled' if settings.get('deploy_local_agents', True) else 'Disabled'}"
|
|
1801
|
+
)
|
|
1802
|
+
print(
|
|
1803
|
+
f" User agents: {'Enabled' if settings.get('deploy_user_agents', True) else 'Disabled'}"
|
|
1804
|
+
)
|
|
1805
|
+
|
|
1806
|
+
if settings.get("enabled_agents"):
|
|
1807
|
+
print(f" Enabled specific: {', '.join(settings['enabled_agents'])}")
|
|
1808
|
+
elif settings.get("disabled_agents"):
|
|
1809
|
+
print(f" Disabled specific: {', '.join(settings['disabled_agents'])}")
|
|
1810
|
+
else:
|
|
1811
|
+
print(" All agents enabled")
|
|
1812
|
+
|
|
1813
|
+
return CommandResult.success_result("Interactive configuration completed")
|
|
1814
|
+
|
|
1815
|
+
except KeyboardInterrupt:
|
|
1816
|
+
print("\n\nConfiguration cancelled.")
|
|
1817
|
+
return CommandResult.error_result("Configuration cancelled by user")
|
|
1818
|
+
except Exception as e:
|
|
1819
|
+
self.logger.error(f"Error in interactive configuration: {e}", exc_info=True)
|
|
1820
|
+
return CommandResult.error_result(
|
|
1821
|
+
f"Error in interactive configuration: {e}"
|
|
1822
|
+
)
|
|
1823
|
+
|
|
1824
|
+
def _detect_toolchain(self, args) -> CommandResult:
|
|
1825
|
+
"""Detect project toolchain without deploying agents.
|
|
1826
|
+
|
|
1827
|
+
Part of TSK-0054 Phase 5: Auto-configuration CLI integration.
|
|
1828
|
+
"""
|
|
1829
|
+
try:
|
|
1830
|
+
from .agents_detect import AgentsDetectCommand
|
|
1831
|
+
|
|
1832
|
+
cmd = AgentsDetectCommand()
|
|
1833
|
+
return cmd.run(args)
|
|
1834
|
+
except Exception as e:
|
|
1835
|
+
self.logger.error(f"Error detecting toolchain: {e}", exc_info=True)
|
|
1836
|
+
return CommandResult.error_result(f"Error detecting toolchain: {e}")
|
|
1837
|
+
|
|
1838
|
+
def _recommend_agents(self, args) -> CommandResult:
|
|
1839
|
+
"""Recommend agents based on project toolchain.
|
|
1840
|
+
|
|
1841
|
+
Part of TSK-0054 Phase 5: Auto-configuration CLI integration.
|
|
1842
|
+
"""
|
|
1843
|
+
try:
|
|
1844
|
+
from .agents_recommend import AgentsRecommendCommand
|
|
1845
|
+
|
|
1846
|
+
cmd = AgentsRecommendCommand()
|
|
1847
|
+
return cmd.run(args)
|
|
1848
|
+
except Exception as e:
|
|
1849
|
+
self.logger.error(f"Error recommending agents: {e}", exc_info=True)
|
|
1850
|
+
return CommandResult.error_result(f"Error recommending agents: {e}")
|
|
1851
|
+
|
|
1852
|
+
def _migrate_to_project(self, args) -> CommandResult:
|
|
1853
|
+
"""Migrate user-level agents to project-level.
|
|
1854
|
+
|
|
1855
|
+
DEPRECATION: User-level agents (~/.claude-mpm/agents/) are deprecated and
|
|
1856
|
+
will be removed in v5.0.0. This command migrates them to project-level
|
|
1857
|
+
(.claude-mpm/agents/) where they belong.
|
|
1858
|
+
|
|
1859
|
+
Args:
|
|
1860
|
+
args: Command arguments with dry_run and force flags
|
|
1861
|
+
|
|
1862
|
+
Returns:
|
|
1863
|
+
CommandResult with migration status
|
|
1864
|
+
"""
|
|
1865
|
+
import shutil
|
|
1866
|
+
|
|
1867
|
+
try:
|
|
1868
|
+
user_agents_dir = Path.home() / ".claude-mpm" / "agents"
|
|
1869
|
+
project_agents_dir = Path.cwd() / ".claude-mpm" / "agents"
|
|
1870
|
+
|
|
1871
|
+
dry_run = getattr(args, "dry_run", False)
|
|
1872
|
+
force = getattr(args, "force", False)
|
|
1873
|
+
|
|
1874
|
+
# Check if user agents directory exists
|
|
1875
|
+
if not user_agents_dir.exists():
|
|
1876
|
+
print("ā
No user-level agents found. Nothing to migrate.")
|
|
1877
|
+
return CommandResult.success_result("No user-level agents to migrate")
|
|
1878
|
+
|
|
1879
|
+
# Find all user agent files
|
|
1880
|
+
user_agent_files = list(user_agents_dir.glob("*.json")) + list(
|
|
1881
|
+
user_agents_dir.glob("*.md")
|
|
1882
|
+
)
|
|
1883
|
+
|
|
1884
|
+
if not user_agent_files:
|
|
1885
|
+
print("ā
No user-level agents found. Nothing to migrate.")
|
|
1886
|
+
return CommandResult.success_result("No user-level agents to migrate")
|
|
1887
|
+
|
|
1888
|
+
# Display what we found
|
|
1889
|
+
print(f"\nš¦ Found {len(user_agent_files)} user-level agent(s) to migrate:")
|
|
1890
|
+
for agent_file in user_agent_files:
|
|
1891
|
+
print(f" - {agent_file.name}")
|
|
1892
|
+
|
|
1893
|
+
if dry_run:
|
|
1894
|
+
print("\nš DRY RUN: Would migrate to:")
|
|
1895
|
+
print(f" ā {project_agents_dir}")
|
|
1896
|
+
print("\nRun without --dry-run to perform the migration.")
|
|
1897
|
+
return CommandResult.success_result(
|
|
1898
|
+
"Dry run completed",
|
|
1899
|
+
data={
|
|
1900
|
+
"user_agents_found": len(user_agent_files),
|
|
1901
|
+
"target_directory": str(project_agents_dir),
|
|
1902
|
+
},
|
|
1903
|
+
)
|
|
1904
|
+
|
|
1905
|
+
# Create project agents directory
|
|
1906
|
+
project_agents_dir.mkdir(parents=True, exist_ok=True)
|
|
1907
|
+
|
|
1908
|
+
# Migrate agents
|
|
1909
|
+
migrated = 0
|
|
1910
|
+
skipped = 0
|
|
1911
|
+
errors = []
|
|
1912
|
+
|
|
1913
|
+
for agent_file in user_agent_files:
|
|
1914
|
+
target_file = project_agents_dir / agent_file.name
|
|
1915
|
+
|
|
1916
|
+
# Check for conflicts
|
|
1917
|
+
if target_file.exists() and not force:
|
|
1918
|
+
print(f"ā ļø Skipping {agent_file.name} (already exists in project)")
|
|
1919
|
+
print(" Use --force to overwrite existing agents")
|
|
1920
|
+
skipped += 1
|
|
1921
|
+
continue
|
|
1922
|
+
|
|
1923
|
+
try:
|
|
1924
|
+
# Copy agent to project directory
|
|
1925
|
+
shutil.copy2(agent_file, target_file)
|
|
1926
|
+
migrated += 1
|
|
1927
|
+
print(f"ā
Migrated {agent_file.name}")
|
|
1928
|
+
except Exception as e:
|
|
1929
|
+
error_msg = f"Failed to migrate {agent_file.name}: {e}"
|
|
1930
|
+
errors.append(error_msg)
|
|
1931
|
+
print(f"ā {error_msg}")
|
|
1932
|
+
|
|
1933
|
+
# Summary
|
|
1934
|
+
print("\nš Migration Summary:")
|
|
1935
|
+
print(f" ā
Migrated: {migrated}/{len(user_agent_files)}")
|
|
1936
|
+
if skipped > 0:
|
|
1937
|
+
print(f" āļø Skipped: {skipped} (already exist)")
|
|
1938
|
+
if errors:
|
|
1939
|
+
print(f" ā Errors: {len(errors)}")
|
|
1940
|
+
|
|
1941
|
+
if migrated > 0:
|
|
1942
|
+
print(f"\nā
Successfully migrated {migrated} agent(s) to:")
|
|
1943
|
+
print(f" {project_agents_dir}")
|
|
1944
|
+
print(
|
|
1945
|
+
"\nā ļø IMPORTANT: Verify agents work correctly, then remove user-level agents:"
|
|
1946
|
+
)
|
|
1947
|
+
print(f" rm -rf {user_agents_dir}")
|
|
1948
|
+
print("\nš” Why this change?")
|
|
1949
|
+
print(" - Project isolation: Each project has its own agents")
|
|
1950
|
+
print(" - Version control: Agents can be versioned with your code")
|
|
1951
|
+
print(" - Team consistency: Everyone uses the same agents")
|
|
1952
|
+
|
|
1953
|
+
return CommandResult.success_result(
|
|
1954
|
+
f"Migrated {migrated} agents",
|
|
1955
|
+
data={
|
|
1956
|
+
"migrated": migrated,
|
|
1957
|
+
"skipped": skipped,
|
|
1958
|
+
"errors": errors,
|
|
1959
|
+
"total": len(user_agent_files),
|
|
1960
|
+
},
|
|
1961
|
+
)
|
|
1962
|
+
|
|
1963
|
+
except Exception as e:
|
|
1964
|
+
self.logger.error(f"Error migrating agents: {e}", exc_info=True)
|
|
1965
|
+
return CommandResult.error_result(f"Error migrating agents: {e}")
|
|
1966
|
+
|
|
1967
|
+
def _deploy_minimal_configuration(self, args) -> CommandResult:
|
|
1968
|
+
"""Deploy minimal configuration (6 core agents).
|
|
1969
|
+
|
|
1970
|
+
Part of Phase 3 (1M-382): Agent Selection Modes.
|
|
1971
|
+
Deploy exactly 6 agents for basic Claude MPM workflow:
|
|
1972
|
+
engineer, documentation, qa, research, ops, ticketing.
|
|
1973
|
+
"""
|
|
1974
|
+
try:
|
|
1975
|
+
from ...config.agent_sources import AgentSourceConfiguration
|
|
1976
|
+
from ...services.agents.agent_selection_service import AgentSelectionService
|
|
1977
|
+
from ...services.agents.single_tier_deployment_service import (
|
|
1978
|
+
SingleTierDeploymentService,
|
|
1979
|
+
)
|
|
1980
|
+
|
|
1981
|
+
# Initialize services
|
|
1982
|
+
config = AgentSourceConfiguration.load()
|
|
1983
|
+
deployment_dir = Path.home() / ".claude" / "agents"
|
|
1984
|
+
deployment_service = SingleTierDeploymentService(config, deployment_dir)
|
|
1985
|
+
selection_service = AgentSelectionService(deployment_service)
|
|
1986
|
+
|
|
1987
|
+
# Get dry_run flag
|
|
1988
|
+
dry_run = getattr(args, "dry_run", False)
|
|
1989
|
+
|
|
1990
|
+
# Deploy minimal configuration
|
|
1991
|
+
print("šÆ Deploying minimal configuration (6 core agents)...")
|
|
1992
|
+
if dry_run:
|
|
1993
|
+
print("š DRY RUN MODE - No agents will be deployed\n")
|
|
1994
|
+
|
|
1995
|
+
result = selection_service.deploy_minimal_configuration(dry_run=dry_run)
|
|
1996
|
+
|
|
1997
|
+
# Format output
|
|
1998
|
+
output_format = self._get_output_format(args)
|
|
1999
|
+
if self._is_structured_format(output_format):
|
|
2000
|
+
formatted = (
|
|
2001
|
+
self._formatter.format_as_json(result)
|
|
2002
|
+
if str(output_format).lower() == OutputFormat.JSON
|
|
2003
|
+
else self._formatter.format_as_yaml(result)
|
|
2004
|
+
)
|
|
2005
|
+
print(formatted)
|
|
2006
|
+
return CommandResult.success_result(
|
|
2007
|
+
f"Minimal configuration {result['status']}", data=result
|
|
2008
|
+
)
|
|
2009
|
+
|
|
2010
|
+
# Text output
|
|
2011
|
+
print(f"\n{'=' * 60}")
|
|
2012
|
+
print(f"Status: {result['status'].upper()}")
|
|
2013
|
+
print(f"Mode: {result['mode']}")
|
|
2014
|
+
print(f"{'=' * 60}")
|
|
2015
|
+
print(
|
|
2016
|
+
f"\nš Summary: {result['deployed_count']} deployed, "
|
|
2017
|
+
f"{result['failed_count']} failed, {result['missing_count']} missing"
|
|
2018
|
+
)
|
|
2019
|
+
|
|
2020
|
+
if result["deployed_agents"]:
|
|
2021
|
+
print(f"\nā
Deployed agents ({len(result['deployed_agents'])}):")
|
|
2022
|
+
for agent in result["deployed_agents"]:
|
|
2023
|
+
print(f" ⢠{agent}")
|
|
2024
|
+
|
|
2025
|
+
if result["failed_agents"]:
|
|
2026
|
+
print(f"\nā Failed agents ({len(result['failed_agents'])}):")
|
|
2027
|
+
for agent in result["failed_agents"]:
|
|
2028
|
+
print(f" ⢠{agent}")
|
|
2029
|
+
|
|
2030
|
+
if result["missing_agents"]:
|
|
2031
|
+
print(f"\nā ļø Missing agents ({len(result['missing_agents'])}):")
|
|
2032
|
+
for agent in result["missing_agents"]:
|
|
2033
|
+
print(f" ⢠{agent}")
|
|
2034
|
+
print("\nThese agents are not available in configured sources.")
|
|
2035
|
+
|
|
2036
|
+
if dry_run:
|
|
2037
|
+
print(
|
|
2038
|
+
"\nš” This was a dry run. Run without --dry-run to deploy agents."
|
|
2039
|
+
)
|
|
2040
|
+
|
|
2041
|
+
return CommandResult.success_result(
|
|
2042
|
+
f"Minimal configuration {result['status']}", data=result
|
|
2043
|
+
)
|
|
2044
|
+
|
|
2045
|
+
except Exception as e:
|
|
2046
|
+
self.logger.error(
|
|
2047
|
+
f"Error deploying minimal configuration: {e}", exc_info=True
|
|
2048
|
+
)
|
|
2049
|
+
return CommandResult.error_result(
|
|
2050
|
+
f"Error deploying minimal configuration: {e}"
|
|
2051
|
+
)
|
|
2052
|
+
|
|
2053
|
+
def _deploy_auto_configure(self, args) -> CommandResult:
|
|
2054
|
+
"""Auto-detect toolchain and deploy matching agents.
|
|
2055
|
+
|
|
2056
|
+
Part of Phase 3 (1M-382): Agent Selection Modes.
|
|
2057
|
+
Detect project toolchain (languages, frameworks, build tools) and
|
|
2058
|
+
deploy matching specialized agents.
|
|
2059
|
+
"""
|
|
2060
|
+
try:
|
|
2061
|
+
from ...config.agent_sources import AgentSourceConfiguration
|
|
2062
|
+
from ...services.agents.agent_selection_service import AgentSelectionService
|
|
2063
|
+
from ...services.agents.single_tier_deployment_service import (
|
|
2064
|
+
SingleTierDeploymentService,
|
|
2065
|
+
)
|
|
2066
|
+
|
|
2067
|
+
# Initialize services
|
|
2068
|
+
config = AgentSourceConfiguration.load()
|
|
2069
|
+
deployment_dir = Path.home() / ".claude" / "agents"
|
|
2070
|
+
deployment_service = SingleTierDeploymentService(config, deployment_dir)
|
|
2071
|
+
selection_service = AgentSelectionService(deployment_service)
|
|
2072
|
+
|
|
2073
|
+
# Get arguments
|
|
2074
|
+
project_path = getattr(args, "path", Path.cwd())
|
|
2075
|
+
dry_run = getattr(args, "dry_run", False)
|
|
2076
|
+
|
|
2077
|
+
# Deploy auto-configure
|
|
2078
|
+
print(f"š Auto-detecting toolchain in {project_path}...")
|
|
2079
|
+
if dry_run:
|
|
2080
|
+
print("š DRY RUN MODE - No agents will be deployed\n")
|
|
2081
|
+
|
|
2082
|
+
result = selection_service.deploy_auto_configure(
|
|
2083
|
+
project_path=project_path, dry_run=dry_run
|
|
2084
|
+
)
|
|
2085
|
+
|
|
2086
|
+
# Format output
|
|
2087
|
+
output_format = self._get_output_format(args)
|
|
2088
|
+
if self._is_structured_format(output_format):
|
|
2089
|
+
formatted = (
|
|
2090
|
+
self._formatter.format_as_json(result)
|
|
2091
|
+
if str(output_format).lower() == OutputFormat.JSON
|
|
2092
|
+
else self._formatter.format_as_yaml(result)
|
|
2093
|
+
)
|
|
2094
|
+
print(formatted)
|
|
2095
|
+
return CommandResult.success_result(
|
|
2096
|
+
f"Auto-configure {result['status']}", data=result
|
|
2097
|
+
)
|
|
2098
|
+
|
|
2099
|
+
# Text output
|
|
2100
|
+
print(f"\n{'=' * 60}")
|
|
2101
|
+
print(f"Status: {result['status'].upper()}")
|
|
2102
|
+
print(f"Mode: {result['mode']}")
|
|
2103
|
+
print(f"{'=' * 60}")
|
|
2104
|
+
|
|
2105
|
+
# Show detected toolchain
|
|
2106
|
+
toolchain = result.get("toolchain", {})
|
|
2107
|
+
print("\nš§ Detected Toolchain:")
|
|
2108
|
+
if toolchain.get("languages"):
|
|
2109
|
+
print(f" Languages: {', '.join(toolchain['languages'])}")
|
|
2110
|
+
if toolchain.get("frameworks"):
|
|
2111
|
+
print(f" Frameworks: {', '.join(toolchain['frameworks'])}")
|
|
2112
|
+
if toolchain.get("build_tools"):
|
|
2113
|
+
print(f" Build Tools: {', '.join(toolchain['build_tools'])}")
|
|
2114
|
+
|
|
2115
|
+
if not any(toolchain.values()):
|
|
2116
|
+
print(" (No toolchain detected)")
|
|
2117
|
+
|
|
2118
|
+
# Show recommended agents
|
|
2119
|
+
recommended = result.get("recommended_agents", [])
|
|
2120
|
+
if recommended:
|
|
2121
|
+
print(f"\nšÆ Recommended agents ({len(recommended)}):")
|
|
2122
|
+
for agent in recommended:
|
|
2123
|
+
print(f" ⢠{agent}")
|
|
2124
|
+
|
|
2125
|
+
# Show deployment summary
|
|
2126
|
+
print(
|
|
2127
|
+
f"\nš Summary: {result['deployed_count']} deployed, "
|
|
2128
|
+
f"{result['failed_count']} failed, {result['missing_count']} missing"
|
|
2129
|
+
)
|
|
2130
|
+
|
|
2131
|
+
if result.get("deployed_agents"):
|
|
2132
|
+
print(f"\nā
Deployed agents ({len(result['deployed_agents'])}):")
|
|
2133
|
+
for agent in result["deployed_agents"]:
|
|
2134
|
+
print(f" ⢠{agent}")
|
|
2135
|
+
|
|
2136
|
+
if result.get("failed_agents"):
|
|
2137
|
+
print(f"\nā Failed agents ({len(result['failed_agents'])}):")
|
|
2138
|
+
for agent in result["failed_agents"]:
|
|
2139
|
+
print(f" ⢠{agent}")
|
|
2140
|
+
|
|
2141
|
+
if result.get("missing_agents"):
|
|
2142
|
+
print(f"\nā ļø Missing agents ({len(result['missing_agents'])}):")
|
|
2143
|
+
for agent in result["missing_agents"]:
|
|
2144
|
+
print(f" ⢠{agent}")
|
|
2145
|
+
print("\nThese agents are not available in configured sources.")
|
|
2146
|
+
|
|
2147
|
+
if dry_run:
|
|
2148
|
+
print(
|
|
2149
|
+
"\nš” This was a dry run. Run without --dry-run to deploy agents."
|
|
2150
|
+
)
|
|
2151
|
+
|
|
2152
|
+
return CommandResult.success_result(
|
|
2153
|
+
f"Auto-configure {result['status']}", data=result
|
|
2154
|
+
)
|
|
2155
|
+
|
|
2156
|
+
except Exception as e:
|
|
2157
|
+
self.logger.error(f"Error in auto-configure: {e}", exc_info=True)
|
|
2158
|
+
return CommandResult.error_result(f"Error in auto-configure: {e}")
|
|
2159
|
+
|
|
2160
|
+
def _cache_status(self, args) -> CommandResult:
|
|
2161
|
+
"""Show git status of agent cache.
|
|
2162
|
+
|
|
2163
|
+
Displays current branch, uncommitted changes, unpushed commits, and
|
|
2164
|
+
remote URL for the agent cache repository.
|
|
2165
|
+
"""
|
|
2166
|
+
try:
|
|
2167
|
+
from ...services.agents.cache_git_manager import CacheGitManager
|
|
2168
|
+
|
|
2169
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
|
|
2170
|
+
manager = CacheGitManager(cache_dir)
|
|
2171
|
+
|
|
2172
|
+
if not manager.is_git_repo():
|
|
2173
|
+
print("ā Cache is not a git repository")
|
|
2174
|
+
print(f"\nCache location: {cache_dir}")
|
|
2175
|
+
print(
|
|
2176
|
+
"\nš” This is expected if you haven't cloned the agents repository."
|
|
2177
|
+
)
|
|
2178
|
+
print(" The cache will be managed via HTTP sync instead.")
|
|
2179
|
+
return CommandResult.error_result("Cache is not a git repository")
|
|
2180
|
+
|
|
2181
|
+
status = manager.get_status()
|
|
2182
|
+
output_format = self._get_output_format(args)
|
|
2183
|
+
|
|
2184
|
+
if self._is_structured_format(output_format):
|
|
2185
|
+
formatted = (
|
|
2186
|
+
self._formatter.format_as_json(status)
|
|
2187
|
+
if str(output_format).lower() == OutputFormat.JSON
|
|
2188
|
+
else self._formatter.format_as_yaml(status)
|
|
2189
|
+
)
|
|
2190
|
+
print(formatted)
|
|
2191
|
+
return CommandResult.success_result(
|
|
2192
|
+
"Cache status retrieved", data=status
|
|
2193
|
+
)
|
|
2194
|
+
|
|
2195
|
+
# Text output
|
|
2196
|
+
print(f"\nš Cache: {manager.repo_path}")
|
|
2197
|
+
print(f"šæ Branch: {status.get('branch', 'unknown')}")
|
|
2198
|
+
|
|
2199
|
+
if status.get("remote_url"):
|
|
2200
|
+
print(f"š Remote: {status['remote_url']}")
|
|
2201
|
+
|
|
2202
|
+
# Show sync status
|
|
2203
|
+
ahead = status.get("ahead", 0)
|
|
2204
|
+
behind = status.get("behind", 0)
|
|
2205
|
+
|
|
2206
|
+
if ahead > 0:
|
|
2207
|
+
print(f"š¤ Ahead of remote: {ahead} commit(s)")
|
|
2208
|
+
if behind > 0:
|
|
2209
|
+
print(f"š„ Behind remote: {behind} commit(s)")
|
|
2210
|
+
|
|
2211
|
+
if ahead == 0 and behind == 0:
|
|
2212
|
+
print("ā
In sync with remote")
|
|
2213
|
+
|
|
2214
|
+
# Show uncommitted changes
|
|
2215
|
+
uncommitted = status.get("uncommitted", [])
|
|
2216
|
+
if uncommitted:
|
|
2217
|
+
print(f"\nā ļø Uncommitted changes: {len(uncommitted)}")
|
|
2218
|
+
for file in uncommitted[:10]: # Show max 10 files
|
|
2219
|
+
print(f" - {file}")
|
|
2220
|
+
if len(uncommitted) > 10:
|
|
2221
|
+
print(f" ... and {len(uncommitted) - 10} more")
|
|
2222
|
+
else:
|
|
2223
|
+
print("\nā
No uncommitted changes")
|
|
2224
|
+
|
|
2225
|
+
# Overall status
|
|
2226
|
+
if status.get("is_clean"):
|
|
2227
|
+
print("\n⨠Cache is clean and up-to-date")
|
|
2228
|
+
else:
|
|
2229
|
+
print("\nš” Run 'claude-mpm agents cache-sync' to sync with remote")
|
|
2230
|
+
|
|
2231
|
+
return CommandResult.success_result("Cache status displayed", data=status)
|
|
2232
|
+
|
|
2233
|
+
except Exception as e:
|
|
2234
|
+
self.logger.error(f"Error getting cache status: {e}", exc_info=True)
|
|
2235
|
+
return CommandResult.error_result(f"Error getting cache status: {e}")
|
|
2236
|
+
|
|
2237
|
+
def _cache_pull(self, args) -> CommandResult:
|
|
2238
|
+
"""Pull latest agents from remote repository."""
|
|
2239
|
+
try:
|
|
2240
|
+
from ...services.agents.cache_git_manager import CacheGitManager
|
|
2241
|
+
|
|
2242
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
|
|
2243
|
+
manager = CacheGitManager(cache_dir)
|
|
2244
|
+
|
|
2245
|
+
if not manager.is_git_repo():
|
|
2246
|
+
print("ā Cache is not a git repository")
|
|
2247
|
+
return CommandResult.error_result("Cache is not a git repository")
|
|
2248
|
+
|
|
2249
|
+
branch = getattr(args, "branch", "main")
|
|
2250
|
+
print(f"š Pulling latest changes from {branch}...")
|
|
2251
|
+
|
|
2252
|
+
success, msg = manager.pull_latest(branch)
|
|
2253
|
+
|
|
2254
|
+
if success:
|
|
2255
|
+
print(f"ā
{msg}")
|
|
2256
|
+
return CommandResult.success_result(msg)
|
|
2257
|
+
print(f"ā {msg}")
|
|
2258
|
+
return CommandResult.error_result(msg)
|
|
2259
|
+
|
|
2260
|
+
except Exception as e:
|
|
2261
|
+
self.logger.error(f"Error pulling cache: {e}", exc_info=True)
|
|
2262
|
+
return CommandResult.error_result(f"Error pulling cache: {e}")
|
|
2263
|
+
|
|
2264
|
+
def _cache_commit(self, args) -> CommandResult:
|
|
2265
|
+
"""Commit changes to cache repository."""
|
|
2266
|
+
try:
|
|
2267
|
+
from ...services.agents.cache_git_manager import CacheGitManager
|
|
2268
|
+
|
|
2269
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
|
|
2270
|
+
manager = CacheGitManager(cache_dir)
|
|
2271
|
+
|
|
2272
|
+
if not manager.is_git_repo():
|
|
2273
|
+
print("ā Cache is not a git repository")
|
|
2274
|
+
return CommandResult.error_result("Cache is not a git repository")
|
|
2275
|
+
|
|
2276
|
+
# Get commit message from args
|
|
2277
|
+
message = getattr(args, "message", None)
|
|
2278
|
+
if not message:
|
|
2279
|
+
# Default message
|
|
2280
|
+
message = "feat: update agents from local development"
|
|
2281
|
+
|
|
2282
|
+
print("š¾ Committing changes...")
|
|
2283
|
+
success, msg = manager.commit_changes(message)
|
|
2284
|
+
|
|
2285
|
+
if success:
|
|
2286
|
+
print(f"ā
{msg}")
|
|
2287
|
+
print(f"\nš” Commit message: {message}")
|
|
2288
|
+
return CommandResult.success_result(msg)
|
|
2289
|
+
print(f"ā {msg}")
|
|
2290
|
+
return CommandResult.error_result(msg)
|
|
2291
|
+
|
|
2292
|
+
except Exception as e:
|
|
2293
|
+
self.logger.error(f"Error committing cache changes: {e}", exc_info=True)
|
|
2294
|
+
return CommandResult.error_result(f"Error committing cache changes: {e}")
|
|
2295
|
+
|
|
2296
|
+
def _cache_push(self, args) -> CommandResult:
|
|
2297
|
+
"""Push local agent changes to remote."""
|
|
2298
|
+
try:
|
|
2299
|
+
from ...services.agents.cache_git_manager import CacheGitManager
|
|
2300
|
+
|
|
2301
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
|
|
2302
|
+
manager = CacheGitManager(cache_dir)
|
|
2303
|
+
|
|
2304
|
+
if not manager.is_git_repo():
|
|
2305
|
+
print("ā Cache is not a git repository")
|
|
2306
|
+
return CommandResult.error_result("Cache is not a git repository")
|
|
2307
|
+
|
|
2308
|
+
# Check for uncommitted changes
|
|
2309
|
+
if manager.has_uncommitted_changes():
|
|
2310
|
+
print("ā ļø You have uncommitted changes.")
|
|
2311
|
+
print("\nš” Commit changes first with:")
|
|
2312
|
+
print(" claude-mpm agents cache-commit --message 'your message'")
|
|
2313
|
+
|
|
2314
|
+
# Ask if user wants to commit first
|
|
2315
|
+
auto_commit = getattr(args, "auto_commit", False)
|
|
2316
|
+
if auto_commit:
|
|
2317
|
+
print("\nš Auto-committing changes...")
|
|
2318
|
+
success, msg = manager.commit_changes("feat: update agents")
|
|
2319
|
+
if not success:
|
|
2320
|
+
print(f"ā Commit failed: {msg}")
|
|
2321
|
+
return CommandResult.error_result(f"Commit failed: {msg}")
|
|
2322
|
+
print(f"ā
{msg}")
|
|
2323
|
+
else:
|
|
2324
|
+
return CommandResult.error_result(
|
|
2325
|
+
"Uncommitted changes detected. Commit first or use --auto-commit"
|
|
2326
|
+
)
|
|
2327
|
+
|
|
2328
|
+
# Push changes
|
|
2329
|
+
branch = getattr(args, "branch", "main")
|
|
2330
|
+
print(f"š¤ Pushing changes to {branch}...")
|
|
2331
|
+
|
|
2332
|
+
success, msg = manager.push_changes(branch)
|
|
2333
|
+
|
|
2334
|
+
if success:
|
|
2335
|
+
print(f"ā
{msg}")
|
|
2336
|
+
return CommandResult.success_result(msg)
|
|
2337
|
+
print(f"ā {msg}")
|
|
2338
|
+
return CommandResult.error_result(msg)
|
|
2339
|
+
|
|
2340
|
+
except Exception as e:
|
|
2341
|
+
self.logger.error(f"Error pushing cache: {e}", exc_info=True)
|
|
2342
|
+
return CommandResult.error_result(f"Error pushing cache: {e}")
|
|
2343
|
+
|
|
2344
|
+
def _cache_sync(self, args) -> CommandResult:
|
|
2345
|
+
"""Full cache sync: pull, commit (if needed), push."""
|
|
2346
|
+
try:
|
|
2347
|
+
from ...services.agents.cache_git_manager import CacheGitManager
|
|
2348
|
+
|
|
2349
|
+
cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
|
|
2350
|
+
manager = CacheGitManager(cache_dir)
|
|
2351
|
+
|
|
2352
|
+
if not manager.is_git_repo():
|
|
2353
|
+
print("ā Cache is not a git repository")
|
|
2354
|
+
return CommandResult.error_result("Cache is not a git repository")
|
|
2355
|
+
|
|
2356
|
+
print("š Syncing cache with remote...\n")
|
|
2357
|
+
|
|
2358
|
+
success, msg = manager.sync_with_remote()
|
|
2359
|
+
|
|
2360
|
+
# Print detailed sync message
|
|
2361
|
+
print(msg)
|
|
2362
|
+
|
|
2363
|
+
if success:
|
|
2364
|
+
print("\n⨠Cache sync complete!")
|
|
2365
|
+
return CommandResult.success_result("Cache synced successfully")
|
|
2366
|
+
|
|
2367
|
+
print("\nā Cache sync failed. See details above.")
|
|
2368
|
+
return CommandResult.error_result("Cache sync failed")
|
|
2369
|
+
|
|
2370
|
+
except Exception as e:
|
|
2371
|
+
self.logger.error(f"Error syncing cache: {e}", exc_info=True)
|
|
2372
|
+
return CommandResult.error_result(f"Error syncing cache: {e}")
|
|
2373
|
+
|
|
879
2374
|
|
|
880
2375
|
def manage_agents(args):
|
|
881
2376
|
"""
|
|
@@ -887,7 +2382,7 @@ def manage_agents(args):
|
|
|
887
2382
|
result = command.execute(args)
|
|
888
2383
|
|
|
889
2384
|
# Print result if structured output format is requested
|
|
890
|
-
if
|
|
2385
|
+
if _is_structured_output(args):
|
|
891
2386
|
command.print_result(result, args)
|
|
892
2387
|
|
|
893
2388
|
return result.exit_code
|