claude-mpm 4.1.1__py3-none-any.whl ā 4.1.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_mpm/BUILD_NUMBER +1 -1
- claude_mpm/VERSION +1 -1
- claude_mpm/__main__.py +1 -1
- claude_mpm/agents/BASE_PM.md +74 -46
- claude_mpm/agents/INSTRUCTIONS.md +11 -153
- claude_mpm/agents/WORKFLOW.md +61 -321
- claude_mpm/agents/__init__.py +11 -11
- claude_mpm/agents/agent_loader.py +23 -20
- claude_mpm/agents/agent_loader_integration.py +1 -1
- claude_mpm/agents/agents_metadata.py +27 -0
- claude_mpm/agents/async_agent_loader.py +5 -8
- claude_mpm/agents/base_agent_loader.py +36 -25
- claude_mpm/agents/frontmatter_validator.py +6 -6
- claude_mpm/agents/schema/agent_schema.json +1 -1
- claude_mpm/agents/system_agent_config.py +9 -9
- claude_mpm/agents/templates/api_qa.json +47 -2
- claude_mpm/agents/templates/engineer.json +33 -11
- claude_mpm/agents/templates/imagemagick.json +256 -0
- claude_mpm/agents/templates/qa.json +41 -2
- claude_mpm/agents/templates/ticketing.json +5 -5
- claude_mpm/agents/templates/web_qa.json +50 -2
- claude_mpm/cli/__init__.py +51 -46
- claude_mpm/cli/__main__.py +1 -1
- claude_mpm/cli/commands/__init__.py +10 -12
- claude_mpm/cli/commands/agent_manager.py +186 -181
- claude_mpm/cli/commands/agents.py +648 -1098
- claude_mpm/cli/commands/aggregate.py +30 -29
- claude_mpm/cli/commands/cleanup.py +50 -44
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
- claude_mpm/cli/commands/config.py +162 -127
- claude_mpm/cli/commands/doctor.py +52 -62
- claude_mpm/cli/commands/info.py +37 -25
- claude_mpm/cli/commands/mcp.py +3 -7
- claude_mpm/cli/commands/mcp_command_router.py +14 -18
- claude_mpm/cli/commands/mcp_install_commands.py +28 -23
- claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
- claude_mpm/cli/commands/mcp_server_commands.py +23 -17
- claude_mpm/cli/commands/memory.py +339 -967
- claude_mpm/cli/commands/monitor.py +117 -88
- claude_mpm/cli/commands/run.py +233 -542
- claude_mpm/cli/commands/socketio_monitor.py +17 -19
- claude_mpm/cli/commands/tickets.py +92 -92
- claude_mpm/cli/parser.py +1 -5
- claude_mpm/cli/parsers/__init__.py +1 -1
- claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
- claude_mpm/cli/parsers/agents_parser.py +2 -3
- claude_mpm/cli/parsers/base_parser.py +7 -5
- claude_mpm/cli/parsers/mcp_parser.py +4 -2
- claude_mpm/cli/parsers/monitor_parser.py +26 -18
- claude_mpm/cli/shared/__init__.py +10 -10
- claude_mpm/cli/shared/argument_patterns.py +57 -71
- claude_mpm/cli/shared/base_command.py +61 -53
- claude_mpm/cli/shared/error_handling.py +62 -58
- claude_mpm/cli/shared/output_formatters.py +78 -77
- claude_mpm/cli/startup_logging.py +280 -172
- claude_mpm/cli/utils.py +10 -11
- claude_mpm/cli_module/__init__.py +1 -1
- claude_mpm/cli_module/args.py +1 -1
- claude_mpm/cli_module/migration_example.py +5 -5
- claude_mpm/config/__init__.py +9 -9
- claude_mpm/config/agent_config.py +15 -14
- claude_mpm/config/experimental_features.py +4 -4
- claude_mpm/config/paths.py +0 -1
- claude_mpm/config/socketio_config.py +5 -6
- claude_mpm/constants.py +1 -2
- claude_mpm/core/__init__.py +8 -8
- claude_mpm/core/agent_name_normalizer.py +1 -1
- claude_mpm/core/agent_registry.py +22 -29
- claude_mpm/core/agent_session_manager.py +3 -3
- claude_mpm/core/base_service.py +7 -15
- claude_mpm/core/cache.py +4 -6
- claude_mpm/core/claude_runner.py +85 -113
- claude_mpm/core/config.py +43 -28
- claude_mpm/core/config_aliases.py +0 -9
- claude_mpm/core/config_constants.py +52 -30
- claude_mpm/core/constants.py +0 -1
- claude_mpm/core/container.py +18 -27
- claude_mpm/core/exceptions.py +2 -2
- claude_mpm/core/factories.py +10 -12
- claude_mpm/core/framework_loader.py +500 -680
- claude_mpm/core/hook_manager.py +26 -22
- claude_mpm/core/hook_performance_config.py +58 -47
- claude_mpm/core/injectable_service.py +1 -1
- claude_mpm/core/interactive_session.py +61 -152
- claude_mpm/core/interfaces.py +1 -100
- claude_mpm/core/lazy.py +5 -5
- claude_mpm/core/log_manager.py +587 -0
- claude_mpm/core/logger.py +125 -8
- claude_mpm/core/logging_config.py +15 -17
- claude_mpm/core/minimal_framework_loader.py +5 -8
- claude_mpm/core/oneshot_session.py +15 -33
- claude_mpm/core/optimized_agent_loader.py +4 -6
- claude_mpm/core/optimized_startup.py +2 -1
- claude_mpm/core/output_style_manager.py +147 -106
- claude_mpm/core/pm_hook_interceptor.py +0 -1
- claude_mpm/core/service_registry.py +11 -8
- claude_mpm/core/session_manager.py +1 -2
- claude_mpm/core/shared/__init__.py +1 -1
- claude_mpm/core/shared/config_loader.py +101 -97
- claude_mpm/core/shared/path_resolver.py +72 -68
- claude_mpm/core/shared/singleton_manager.py +56 -50
- claude_mpm/core/socketio_pool.py +26 -6
- claude_mpm/core/tool_access_control.py +4 -5
- claude_mpm/core/typing_utils.py +50 -59
- claude_mpm/core/unified_agent_registry.py +14 -19
- claude_mpm/core/unified_config.py +4 -6
- claude_mpm/core/unified_paths.py +197 -109
- claude_mpm/dashboard/open_dashboard.py +2 -4
- claude_mpm/experimental/cli_enhancements.py +51 -36
- claude_mpm/generators/agent_profile_generator.py +2 -4
- claude_mpm/hooks/base_hook.py +1 -2
- claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
- claude_mpm/hooks/claude_hooks/event_handlers.py +99 -154
- claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
- claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
- claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
- claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
- claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
- claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
- claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
- claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
- claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
- claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
- claude_mpm/hooks/memory_integration_hook.py +5 -5
- claude_mpm/hooks/tool_call_interceptor.py +1 -1
- claude_mpm/hooks/validation_hooks.py +4 -4
- claude_mpm/init.py +4 -9
- claude_mpm/models/__init__.py +2 -2
- claude_mpm/models/agent_session.py +11 -14
- claude_mpm/scripts/mcp_server.py +20 -11
- claude_mpm/scripts/mcp_wrapper.py +5 -5
- claude_mpm/scripts/mpm_doctor.py +321 -0
- claude_mpm/scripts/socketio_daemon.py +28 -25
- claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
- claude_mpm/scripts/socketio_server_manager.py +116 -95
- claude_mpm/services/__init__.py +49 -49
- claude_mpm/services/agent_capabilities_service.py +12 -18
- claude_mpm/services/agents/__init__.py +22 -22
- claude_mpm/services/agents/agent_builder.py +140 -119
- claude_mpm/services/agents/deployment/__init__.py +3 -3
- claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
- claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
- claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
- claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
- claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
- claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
- claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
- claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
- claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
- claude_mpm/services/agents/deployment/agent_validator.py +0 -1
- claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
- claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
- claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
- claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
- claude_mpm/services/agents/deployment/config/__init__.py +1 -1
- claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
- claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
- claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
- claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
- claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
- claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
- claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
- claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
- claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
- claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
- claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
- claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
- claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
- claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
- claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
- claude_mpm/services/agents/deployment/results/__init__.py +1 -1
- claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
- claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
- claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
- claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
- claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
- claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
- claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
- claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
- claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
- claude_mpm/services/agents/loading/__init__.py +1 -1
- claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
- claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
- claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
- claude_mpm/services/agents/management/__init__.py +1 -1
- claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
- claude_mpm/services/agents/management/agent_management_service.py +5 -9
- claude_mpm/services/agents/memory/__init__.py +4 -4
- claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
- claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
- claude_mpm/services/agents/memory/content_manager.py +44 -38
- claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
- claude_mpm/services/agents/memory/memory_file_service.py +103 -0
- claude_mpm/services/agents/memory/memory_format_service.py +201 -0
- claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
- claude_mpm/services/agents/memory/template_generator.py +4 -6
- claude_mpm/services/agents/registry/__init__.py +11 -7
- claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
- claude_mpm/services/agents/registry/modification_tracker.py +3 -6
- claude_mpm/services/async_session_logger.py +1 -2
- claude_mpm/services/claude_session_logger.py +1 -2
- claude_mpm/services/cli/__init__.py +18 -0
- claude_mpm/services/cli/agent_cleanup_service.py +407 -0
- claude_mpm/services/cli/agent_dependency_service.py +395 -0
- claude_mpm/services/cli/agent_listing_service.py +463 -0
- claude_mpm/services/cli/agent_output_formatter.py +605 -0
- claude_mpm/services/cli/agent_validation_service.py +589 -0
- claude_mpm/services/cli/dashboard_launcher.py +424 -0
- claude_mpm/services/cli/memory_crud_service.py +617 -0
- claude_mpm/services/cli/memory_output_formatter.py +604 -0
- claude_mpm/services/cli/session_manager.py +513 -0
- claude_mpm/services/cli/socketio_manager.py +498 -0
- claude_mpm/services/cli/startup_checker.py +370 -0
- claude_mpm/services/command_deployment_service.py +173 -0
- claude_mpm/services/command_handler_service.py +20 -22
- claude_mpm/services/core/__init__.py +25 -25
- claude_mpm/services/core/base.py +0 -5
- claude_mpm/services/core/cache_manager.py +311 -0
- claude_mpm/services/core/interfaces/__init__.py +32 -32
- claude_mpm/services/core/interfaces/agent.py +0 -21
- claude_mpm/services/core/interfaces/communication.py +0 -27
- claude_mpm/services/core/interfaces/infrastructure.py +0 -56
- claude_mpm/services/core/interfaces/service.py +0 -29
- claude_mpm/services/core/memory_manager.py +637 -0
- claude_mpm/services/core/path_resolver.py +498 -0
- claude_mpm/services/core/service_container.py +520 -0
- claude_mpm/services/core/service_interfaces.py +436 -0
- claude_mpm/services/diagnostics/__init__.py +1 -1
- claude_mpm/services/diagnostics/checks/__init__.py +6 -6
- claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
- claude_mpm/services/diagnostics/checks/base_check.py +12 -16
- claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
- claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
- claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
- claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
- claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
- claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
- claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
- claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
- claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
- claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
- claude_mpm/services/diagnostics/models.py +21 -19
- claude_mpm/services/event_aggregator.py +10 -17
- claude_mpm/services/event_bus/__init__.py +1 -1
- claude_mpm/services/event_bus/config.py +54 -35
- claude_mpm/services/event_bus/event_bus.py +76 -71
- claude_mpm/services/event_bus/relay.py +74 -64
- claude_mpm/services/events/__init__.py +11 -11
- claude_mpm/services/events/consumers/__init__.py +3 -3
- claude_mpm/services/events/consumers/dead_letter.py +71 -63
- claude_mpm/services/events/consumers/logging.py +39 -37
- claude_mpm/services/events/consumers/metrics.py +56 -57
- claude_mpm/services/events/consumers/socketio.py +82 -81
- claude_mpm/services/events/core.py +110 -99
- claude_mpm/services/events/interfaces.py +56 -72
- claude_mpm/services/events/producers/__init__.py +1 -1
- claude_mpm/services/events/producers/hook.py +38 -38
- claude_mpm/services/events/producers/system.py +46 -44
- claude_mpm/services/exceptions.py +81 -80
- claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
- claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
- claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
- claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
- claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
- claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
- claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
- claude_mpm/services/hook_service.py +6 -9
- claude_mpm/services/infrastructure/__init__.py +1 -1
- claude_mpm/services/infrastructure/context_preservation.py +8 -12
- claude_mpm/services/infrastructure/monitoring.py +21 -23
- claude_mpm/services/mcp_gateway/__init__.py +37 -37
- claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
- claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
- claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
- claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
- claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
- claude_mpm/services/mcp_gateway/core/base.py +0 -3
- claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
- claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
- claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
- claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
- claude_mpm/services/mcp_gateway/main.py +2 -1
- claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
- claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
- claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
- claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
- claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
- claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
- claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
- claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
- claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
- claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
- claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
- claude_mpm/services/memory/__init__.py +3 -3
- claude_mpm/services/memory/builder.py +3 -6
- claude_mpm/services/memory/cache/__init__.py +1 -1
- claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
- claude_mpm/services/memory/cache/simple_cache.py +1 -1
- claude_mpm/services/memory/indexed_memory.py +5 -7
- claude_mpm/services/memory/optimizer.py +7 -10
- claude_mpm/services/memory/router.py +8 -9
- claude_mpm/services/memory_hook_service.py +48 -34
- claude_mpm/services/monitor_build_service.py +77 -73
- claude_mpm/services/port_manager.py +130 -108
- claude_mpm/services/project/analyzer.py +12 -10
- claude_mpm/services/project/registry.py +11 -11
- claude_mpm/services/recovery_manager.py +10 -19
- claude_mpm/services/response_tracker.py +0 -1
- claude_mpm/services/runner_configuration_service.py +19 -20
- claude_mpm/services/session_management_service.py +7 -11
- claude_mpm/services/shared/__init__.py +1 -1
- claude_mpm/services/shared/async_service_base.py +58 -50
- claude_mpm/services/shared/config_service_base.py +73 -67
- claude_mpm/services/shared/lifecycle_service_base.py +82 -78
- claude_mpm/services/shared/manager_base.py +94 -82
- claude_mpm/services/shared/service_factory.py +96 -98
- claude_mpm/services/socketio/__init__.py +3 -3
- claude_mpm/services/socketio/client_proxy.py +5 -5
- claude_mpm/services/socketio/event_normalizer.py +199 -181
- claude_mpm/services/socketio/handlers/__init__.py +3 -3
- claude_mpm/services/socketio/handlers/base.py +5 -4
- claude_mpm/services/socketio/handlers/connection.py +163 -136
- claude_mpm/services/socketio/handlers/file.py +13 -14
- claude_mpm/services/socketio/handlers/git.py +12 -7
- claude_mpm/services/socketio/handlers/hook.py +49 -44
- claude_mpm/services/socketio/handlers/memory.py +0 -1
- claude_mpm/services/socketio/handlers/project.py +0 -1
- claude_mpm/services/socketio/handlers/registry.py +37 -19
- claude_mpm/services/socketio/migration_utils.py +98 -84
- claude_mpm/services/socketio/server/__init__.py +1 -1
- claude_mpm/services/socketio/server/broadcaster.py +81 -87
- claude_mpm/services/socketio/server/core.py +65 -54
- claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
- claude_mpm/services/socketio/server/main.py +64 -38
- claude_mpm/services/socketio_client_manager.py +10 -12
- claude_mpm/services/subprocess_launcher_service.py +4 -7
- claude_mpm/services/system_instructions_service.py +13 -14
- claude_mpm/services/ticket_manager.py +2 -2
- claude_mpm/services/utility_service.py +5 -13
- claude_mpm/services/version_control/__init__.py +16 -16
- claude_mpm/services/version_control/branch_strategy.py +5 -8
- claude_mpm/services/version_control/conflict_resolution.py +9 -23
- claude_mpm/services/version_control/git_operations.py +5 -7
- claude_mpm/services/version_control/semantic_versioning.py +16 -17
- claude_mpm/services/version_control/version_parser.py +13 -18
- claude_mpm/services/version_service.py +10 -11
- claude_mpm/storage/__init__.py +1 -1
- claude_mpm/storage/state_storage.py +22 -28
- claude_mpm/utils/__init__.py +6 -6
- claude_mpm/utils/agent_dependency_loader.py +47 -33
- claude_mpm/utils/config_manager.py +11 -14
- claude_mpm/utils/dependency_cache.py +1 -1
- claude_mpm/utils/dependency_manager.py +13 -17
- claude_mpm/utils/dependency_strategies.py +8 -10
- claude_mpm/utils/environment_context.py +3 -9
- claude_mpm/utils/error_handler.py +3 -13
- claude_mpm/utils/file_utils.py +1 -1
- claude_mpm/utils/path_operations.py +8 -12
- claude_mpm/utils/robust_installer.py +110 -33
- claude_mpm/utils/subprocess_utils.py +5 -6
- claude_mpm/validation/agent_validator.py +3 -6
- claude_mpm/validation/frontmatter_validator.py +1 -1
- {claude_mpm-4.1.1.dist-info ā claude_mpm-4.1.3.dist-info}/METADATA +1 -1
- claude_mpm-4.1.3.dist-info/RECORD +528 -0
- claude_mpm/cli/commands/run_config_checker.py +0 -160
- claude_mpm-4.1.1.dist-info/RECORD +0 -494
- {claude_mpm-4.1.1.dist-info ā claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.1.dist-info ā claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.1.dist-info ā claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.1.dist-info ā claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,605 @@
|
|
|
1
|
+
"""Agent output formatting service for CLI commands.
|
|
2
|
+
|
|
3
|
+
WHY: This service extracts output formatting logic from agents.py to reduce
|
|
4
|
+
duplication, improve maintainability, and provide consistent formatting across
|
|
5
|
+
all agent-related CLI commands. Following SOLID principles, this service has
|
|
6
|
+
a single responsibility: formatting agent data for display.
|
|
7
|
+
|
|
8
|
+
DESIGN DECISIONS:
|
|
9
|
+
- Interface-based design for dependency injection and testability
|
|
10
|
+
- Single responsibility: output formatting only
|
|
11
|
+
- Support for multiple formats (json, yaml, table, text)
|
|
12
|
+
- Quiet and verbose mode handling
|
|
13
|
+
- Reusable across all agent commands
|
|
14
|
+
- Consistent formatting patterns
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
import json
|
|
18
|
+
from abc import ABC, abstractmethod
|
|
19
|
+
from typing import Any, Dict, List
|
|
20
|
+
|
|
21
|
+
import yaml
|
|
22
|
+
|
|
23
|
+
from claude_mpm.core.logger import get_logger
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Interface Definition
|
|
27
|
+
class IAgentOutputFormatter(ABC):
|
|
28
|
+
"""Interface for agent output formatting service."""
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
def format_agent_list(
|
|
32
|
+
self,
|
|
33
|
+
agents: List[Dict[str, Any]],
|
|
34
|
+
output_format: str = "text",
|
|
35
|
+
verbose: bool = False,
|
|
36
|
+
quiet: bool = False,
|
|
37
|
+
) -> str:
|
|
38
|
+
"""Format list of agents for display."""
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def format_agent_details(
|
|
42
|
+
self, agent: Dict[str, Any], output_format: str = "text", verbose: bool = False
|
|
43
|
+
) -> str:
|
|
44
|
+
"""Format single agent details."""
|
|
45
|
+
|
|
46
|
+
@abstractmethod
|
|
47
|
+
def format_dependency_report(
|
|
48
|
+
self,
|
|
49
|
+
dependencies: Dict[str, Any],
|
|
50
|
+
output_format: str = "text",
|
|
51
|
+
show_status: bool = True,
|
|
52
|
+
) -> str:
|
|
53
|
+
"""Format dependency information."""
|
|
54
|
+
|
|
55
|
+
@abstractmethod
|
|
56
|
+
def format_deployment_result(
|
|
57
|
+
self, result: Dict[str, Any], output_format: str = "text", verbose: bool = False
|
|
58
|
+
) -> str:
|
|
59
|
+
"""Format deployment results."""
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
def format_cleanup_result(
|
|
63
|
+
self, result: Dict[str, Any], output_format: str = "text", dry_run: bool = False
|
|
64
|
+
) -> str:
|
|
65
|
+
"""Format cleanup results."""
|
|
66
|
+
|
|
67
|
+
@abstractmethod
|
|
68
|
+
def format_as_json(self, data: Any, pretty: bool = True) -> str:
|
|
69
|
+
"""Format data as JSON."""
|
|
70
|
+
|
|
71
|
+
@abstractmethod
|
|
72
|
+
def format_as_yaml(self, data: Any) -> str:
|
|
73
|
+
"""Format data as YAML."""
|
|
74
|
+
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def format_as_table(
|
|
77
|
+
self, headers: List[str], rows: List[List[str]], min_column_width: int = 10
|
|
78
|
+
) -> str:
|
|
79
|
+
"""Format data as table."""
|
|
80
|
+
|
|
81
|
+
@abstractmethod
|
|
82
|
+
def format_agents_by_tier(
|
|
83
|
+
self, agents_by_tier: Dict[str, List[str]], output_format: str = "text"
|
|
84
|
+
) -> str:
|
|
85
|
+
"""Format agents grouped by tier."""
|
|
86
|
+
|
|
87
|
+
@abstractmethod
|
|
88
|
+
def format_fix_result(
|
|
89
|
+
self, result: Dict[str, Any], output_format: str = "text"
|
|
90
|
+
) -> str:
|
|
91
|
+
"""Format fix operation results."""
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class AgentOutputFormatter(IAgentOutputFormatter):
|
|
95
|
+
"""Implementation of agent output formatting service.
|
|
96
|
+
|
|
97
|
+
WHY: Centralizes all agent output formatting logic to ensure consistency
|
|
98
|
+
and reduce code duplication across agent commands.
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
def __init__(self):
|
|
102
|
+
"""Initialize the formatter."""
|
|
103
|
+
self.logger = get_logger(self.__class__.__name__)
|
|
104
|
+
|
|
105
|
+
def format_agent_list(
|
|
106
|
+
self,
|
|
107
|
+
agents: List[Dict[str, Any]],
|
|
108
|
+
output_format: str = "text",
|
|
109
|
+
verbose: bool = False,
|
|
110
|
+
quiet: bool = False,
|
|
111
|
+
) -> str:
|
|
112
|
+
"""Format list of agents for display.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
agents: List of agent dictionaries
|
|
116
|
+
output_format: Output format (text, json, yaml, table)
|
|
117
|
+
verbose: Include extra details
|
|
118
|
+
quiet: Minimal output
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Formatted string for display
|
|
122
|
+
"""
|
|
123
|
+
if output_format == "json":
|
|
124
|
+
return self.format_as_json({"agents": agents, "count": len(agents)})
|
|
125
|
+
if output_format == "yaml":
|
|
126
|
+
return self.format_as_yaml({"agents": agents, "count": len(agents)})
|
|
127
|
+
if output_format == "table":
|
|
128
|
+
return self._format_agents_as_table(agents, verbose, quiet)
|
|
129
|
+
# text format
|
|
130
|
+
return self._format_agents_as_text(agents, verbose, quiet)
|
|
131
|
+
|
|
132
|
+
def format_agent_details(
|
|
133
|
+
self, agent: Dict[str, Any], output_format: str = "text", verbose: bool = False
|
|
134
|
+
) -> str:
|
|
135
|
+
"""Format single agent details.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
agent: Agent dictionary with details
|
|
139
|
+
output_format: Output format (text, json, yaml)
|
|
140
|
+
verbose: Include extra details
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
Formatted string for display
|
|
144
|
+
"""
|
|
145
|
+
if output_format == "json":
|
|
146
|
+
return self.format_as_json(agent)
|
|
147
|
+
if output_format == "yaml":
|
|
148
|
+
return self.format_as_yaml(agent)
|
|
149
|
+
# text format
|
|
150
|
+
lines = []
|
|
151
|
+
lines.append(f"Agent: {agent.get('name', 'Unknown')}")
|
|
152
|
+
lines.append("-" * 40)
|
|
153
|
+
|
|
154
|
+
# Basic info
|
|
155
|
+
for key in ["file", "path", "version", "description", "tier"]:
|
|
156
|
+
if key in agent:
|
|
157
|
+
lines.append(f"{key.capitalize()}: {agent[key]}")
|
|
158
|
+
|
|
159
|
+
# Specializations
|
|
160
|
+
if agent.get("specializations"):
|
|
161
|
+
lines.append(f"Specializations: {', '.join(agent['specializations'])}")
|
|
162
|
+
|
|
163
|
+
# Verbose mode additions
|
|
164
|
+
if verbose:
|
|
165
|
+
if "dependencies" in agent:
|
|
166
|
+
lines.append("\nDependencies:")
|
|
167
|
+
deps = agent["dependencies"]
|
|
168
|
+
if deps.get("python"):
|
|
169
|
+
lines.append(f" Python: {', '.join(deps['python'])}")
|
|
170
|
+
if deps.get("system"):
|
|
171
|
+
lines.append(f" System: {', '.join(deps['system'])}")
|
|
172
|
+
|
|
173
|
+
if "metadata" in agent:
|
|
174
|
+
lines.append("\nMetadata:")
|
|
175
|
+
for k, v in agent["metadata"].items():
|
|
176
|
+
lines.append(f" {k}: {v}")
|
|
177
|
+
|
|
178
|
+
return "\n".join(lines)
|
|
179
|
+
|
|
180
|
+
def format_dependency_report(
|
|
181
|
+
self,
|
|
182
|
+
dependencies: Dict[str, Any],
|
|
183
|
+
output_format: str = "text",
|
|
184
|
+
show_status: bool = True,
|
|
185
|
+
) -> str:
|
|
186
|
+
"""Format dependency information.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
dependencies: Dictionary with dependency info
|
|
190
|
+
output_format: Output format (text, json, yaml)
|
|
191
|
+
show_status: Show installation status
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Formatted string for display
|
|
195
|
+
"""
|
|
196
|
+
if output_format == "json":
|
|
197
|
+
return self.format_as_json(dependencies)
|
|
198
|
+
if output_format == "yaml":
|
|
199
|
+
return self.format_as_yaml(dependencies)
|
|
200
|
+
# text format
|
|
201
|
+
lines = []
|
|
202
|
+
lines.append("Agent Dependencies:")
|
|
203
|
+
lines.append("-" * 40)
|
|
204
|
+
|
|
205
|
+
# Python dependencies
|
|
206
|
+
if dependencies.get("python"):
|
|
207
|
+
lines.append(f"\nPython Dependencies ({len(dependencies['python'])}):")
|
|
208
|
+
for dep in dependencies["python"]:
|
|
209
|
+
if show_status and isinstance(dep, dict):
|
|
210
|
+
status = "ā" if dep.get("installed") else "ā"
|
|
211
|
+
lines.append(f" {status} {dep.get('name', dep)}")
|
|
212
|
+
else:
|
|
213
|
+
lines.append(f" - {dep}")
|
|
214
|
+
|
|
215
|
+
# System dependencies
|
|
216
|
+
if dependencies.get("system"):
|
|
217
|
+
lines.append(f"\nSystem Dependencies ({len(dependencies['system'])}):")
|
|
218
|
+
for dep in dependencies["system"]:
|
|
219
|
+
if show_status and isinstance(dep, dict):
|
|
220
|
+
status = "ā" if dep.get("installed") else "ā"
|
|
221
|
+
lines.append(f" {status} {dep.get('name', dep)}")
|
|
222
|
+
else:
|
|
223
|
+
lines.append(f" - {dep}")
|
|
224
|
+
|
|
225
|
+
# Missing dependencies
|
|
226
|
+
if "missing" in dependencies:
|
|
227
|
+
if dependencies["missing"].get("python"):
|
|
228
|
+
lines.append(
|
|
229
|
+
f"\nā Missing Python: {len(dependencies['missing']['python'])}"
|
|
230
|
+
)
|
|
231
|
+
for dep in dependencies["missing"]["python"][:5]:
|
|
232
|
+
lines.append(f" - {dep}")
|
|
233
|
+
if len(dependencies["missing"]["python"]) > 5:
|
|
234
|
+
lines.append(
|
|
235
|
+
f" ... and {len(dependencies['missing']['python']) - 5} more"
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
if dependencies["missing"].get("system"):
|
|
239
|
+
lines.append(
|
|
240
|
+
f"\nā Missing System: {len(dependencies['missing']['system'])}"
|
|
241
|
+
)
|
|
242
|
+
for dep in dependencies["missing"]["system"]:
|
|
243
|
+
lines.append(f" - {dep}")
|
|
244
|
+
|
|
245
|
+
return "\n".join(lines)
|
|
246
|
+
|
|
247
|
+
def format_deployment_result(
|
|
248
|
+
self, result: Dict[str, Any], output_format: str = "text", verbose: bool = False
|
|
249
|
+
) -> str:
|
|
250
|
+
"""Format deployment results.
|
|
251
|
+
|
|
252
|
+
Args:
|
|
253
|
+
result: Deployment result dictionary
|
|
254
|
+
output_format: Output format (text, json, yaml)
|
|
255
|
+
verbose: Include extra details
|
|
256
|
+
|
|
257
|
+
Returns:
|
|
258
|
+
Formatted string for display
|
|
259
|
+
"""
|
|
260
|
+
if output_format == "json":
|
|
261
|
+
return self.format_as_json(result)
|
|
262
|
+
if output_format == "yaml":
|
|
263
|
+
return self.format_as_yaml(result)
|
|
264
|
+
# text format
|
|
265
|
+
lines = []
|
|
266
|
+
|
|
267
|
+
# Deployed agents
|
|
268
|
+
deployed_count = result.get("deployed_count", 0)
|
|
269
|
+
if deployed_count > 0:
|
|
270
|
+
lines.append(f"ā Deployed {deployed_count} agents")
|
|
271
|
+
if verbose and "deployed" in result:
|
|
272
|
+
for agent in result["deployed"]:
|
|
273
|
+
lines.append(f" - {agent.get('name', agent)}")
|
|
274
|
+
|
|
275
|
+
# Updated agents
|
|
276
|
+
updated_count = result.get("updated_count", 0)
|
|
277
|
+
if updated_count > 0:
|
|
278
|
+
lines.append(f"ā Updated {updated_count} agents")
|
|
279
|
+
if verbose and "updated" in result:
|
|
280
|
+
for agent in result["updated"]:
|
|
281
|
+
lines.append(f" - {agent.get('name', agent)}")
|
|
282
|
+
|
|
283
|
+
# Skipped agents
|
|
284
|
+
if result.get("skipped"):
|
|
285
|
+
lines.append(f"ā Skipped {len(result['skipped'])} up-to-date agents")
|
|
286
|
+
if verbose:
|
|
287
|
+
for agent in result["skipped"]:
|
|
288
|
+
lines.append(f" - {agent.get('name', agent)}")
|
|
289
|
+
|
|
290
|
+
# Errors
|
|
291
|
+
if result.get("errors"):
|
|
292
|
+
lines.append(f"\nā Encountered {len(result['errors'])} errors:")
|
|
293
|
+
for error in result["errors"]:
|
|
294
|
+
lines.append(f" - {error}")
|
|
295
|
+
|
|
296
|
+
# Target directory
|
|
297
|
+
if "target_dir" in result:
|
|
298
|
+
lines.append(f"\nTarget directory: {result['target_dir']}")
|
|
299
|
+
|
|
300
|
+
if not lines:
|
|
301
|
+
lines.append("No agents were deployed (all up to date)")
|
|
302
|
+
|
|
303
|
+
return "\n".join(lines)
|
|
304
|
+
|
|
305
|
+
def format_cleanup_result(
|
|
306
|
+
self, result: Dict[str, Any], output_format: str = "text", dry_run: bool = False
|
|
307
|
+
) -> str:
|
|
308
|
+
"""Format cleanup results.
|
|
309
|
+
|
|
310
|
+
Args:
|
|
311
|
+
result: Cleanup result dictionary
|
|
312
|
+
output_format: Output format (text, json, yaml)
|
|
313
|
+
dry_run: Whether this was a dry run
|
|
314
|
+
|
|
315
|
+
Returns:
|
|
316
|
+
Formatted string for display
|
|
317
|
+
"""
|
|
318
|
+
if output_format == "json":
|
|
319
|
+
result["dry_run"] = dry_run
|
|
320
|
+
return self.format_as_json(result)
|
|
321
|
+
if output_format == "yaml":
|
|
322
|
+
result["dry_run"] = dry_run
|
|
323
|
+
return self.format_as_yaml(result)
|
|
324
|
+
# text format
|
|
325
|
+
lines = []
|
|
326
|
+
|
|
327
|
+
# Orphaned agents found
|
|
328
|
+
if result.get("orphaned"):
|
|
329
|
+
lines.append(f"Found {len(result['orphaned'])} orphaned agent(s):")
|
|
330
|
+
for orphan in result["orphaned"]:
|
|
331
|
+
name = orphan.get("name", "Unknown")
|
|
332
|
+
version = orphan.get("version", "Unknown")
|
|
333
|
+
lines.append(f" - {name} v{version}")
|
|
334
|
+
|
|
335
|
+
# Dry run vs actual cleanup
|
|
336
|
+
if dry_run:
|
|
337
|
+
if result.get("orphaned"):
|
|
338
|
+
lines.append(
|
|
339
|
+
f"\nš This was a dry run. Use --force to actually remove "
|
|
340
|
+
f"{len(result['orphaned'])} orphaned agent(s)"
|
|
341
|
+
)
|
|
342
|
+
else:
|
|
343
|
+
lines.append("ā
No orphaned agents found")
|
|
344
|
+
else:
|
|
345
|
+
# Removed agents
|
|
346
|
+
if result.get("removed"):
|
|
347
|
+
lines.append(
|
|
348
|
+
f"\nā
Successfully removed {len(result['removed'])} orphaned agent(s)"
|
|
349
|
+
)
|
|
350
|
+
for agent in result["removed"]:
|
|
351
|
+
lines.append(f" - {agent}")
|
|
352
|
+
elif "cleaned_count" in result:
|
|
353
|
+
cleaned_count = result["cleaned_count"]
|
|
354
|
+
if cleaned_count > 0:
|
|
355
|
+
lines.append(f"ā Cleaned {cleaned_count} deployed agents")
|
|
356
|
+
else:
|
|
357
|
+
lines.append("No deployed agents to clean")
|
|
358
|
+
else:
|
|
359
|
+
lines.append("ā
No orphaned agents found")
|
|
360
|
+
|
|
361
|
+
# Errors
|
|
362
|
+
if result.get("errors"):
|
|
363
|
+
lines.append(f"\nā Encountered {len(result['errors'])} error(s):")
|
|
364
|
+
for error in result["errors"]:
|
|
365
|
+
lines.append(f" - {error}")
|
|
366
|
+
|
|
367
|
+
return "\n".join(lines)
|
|
368
|
+
|
|
369
|
+
def format_as_json(self, data: Any, pretty: bool = True) -> str:
|
|
370
|
+
"""Format data as JSON.
|
|
371
|
+
|
|
372
|
+
Args:
|
|
373
|
+
data: Data to format
|
|
374
|
+
pretty: Use pretty printing with indentation
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
JSON string
|
|
378
|
+
"""
|
|
379
|
+
if pretty:
|
|
380
|
+
return json.dumps(data, indent=2, sort_keys=True)
|
|
381
|
+
return json.dumps(data)
|
|
382
|
+
|
|
383
|
+
def format_as_yaml(self, data: Any) -> str:
|
|
384
|
+
"""Format data as YAML.
|
|
385
|
+
|
|
386
|
+
Args:
|
|
387
|
+
data: Data to format
|
|
388
|
+
|
|
389
|
+
Returns:
|
|
390
|
+
YAML string
|
|
391
|
+
"""
|
|
392
|
+
return yaml.dump(data, default_flow_style=False, sort_keys=True)
|
|
393
|
+
|
|
394
|
+
def format_as_table(
|
|
395
|
+
self, headers: List[str], rows: List[List[str]], min_column_width: int = 10
|
|
396
|
+
) -> str:
|
|
397
|
+
"""Format data as table.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
headers: Table headers
|
|
401
|
+
rows: Table rows
|
|
402
|
+
min_column_width: Minimum column width
|
|
403
|
+
|
|
404
|
+
Returns:
|
|
405
|
+
Formatted table string
|
|
406
|
+
"""
|
|
407
|
+
# Calculate column widths
|
|
408
|
+
col_widths = [max(min_column_width, len(h)) for h in headers]
|
|
409
|
+
for row in rows:
|
|
410
|
+
for i, cell in enumerate(row):
|
|
411
|
+
if i < len(col_widths):
|
|
412
|
+
col_widths[i] = max(col_widths[i], len(str(cell)))
|
|
413
|
+
|
|
414
|
+
# Build table
|
|
415
|
+
lines = []
|
|
416
|
+
|
|
417
|
+
# Header
|
|
418
|
+
header_line = " | ".join(h.ljust(col_widths[i]) for i, h in enumerate(headers))
|
|
419
|
+
lines.append(header_line)
|
|
420
|
+
lines.append("-" * len(header_line))
|
|
421
|
+
|
|
422
|
+
# Rows
|
|
423
|
+
for row in rows:
|
|
424
|
+
row_line = " | ".join(
|
|
425
|
+
str(cell).ljust(col_widths[i]) if i < len(row) else " " * col_widths[i]
|
|
426
|
+
for i in range(len(headers))
|
|
427
|
+
for cell in [row[i] if i < len(row) else ""]
|
|
428
|
+
)
|
|
429
|
+
lines.append(row_line)
|
|
430
|
+
|
|
431
|
+
return "\n".join(lines)
|
|
432
|
+
|
|
433
|
+
def _format_agents_as_text(
|
|
434
|
+
self, agents: List[Dict[str, Any]], verbose: bool, quiet: bool
|
|
435
|
+
) -> str:
|
|
436
|
+
"""Format agents as text output.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
agents: List of agent dictionaries
|
|
440
|
+
verbose: Include extra details
|
|
441
|
+
quiet: Minimal output
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
Formatted text string
|
|
445
|
+
"""
|
|
446
|
+
if not agents:
|
|
447
|
+
return "No agents found"
|
|
448
|
+
|
|
449
|
+
lines = []
|
|
450
|
+
|
|
451
|
+
if not quiet:
|
|
452
|
+
lines.append("Available Agents:")
|
|
453
|
+
lines.append("-" * 80)
|
|
454
|
+
|
|
455
|
+
for agent in agents:
|
|
456
|
+
if quiet:
|
|
457
|
+
# Minimal output - just names
|
|
458
|
+
lines.append(agent.get("name", agent.get("file", "Unknown")))
|
|
459
|
+
else:
|
|
460
|
+
# Standard output
|
|
461
|
+
lines.append(f"š {agent.get('file', 'Unknown')}")
|
|
462
|
+
if "name" in agent:
|
|
463
|
+
lines.append(f" Name: {agent['name']}")
|
|
464
|
+
if "description" in agent:
|
|
465
|
+
lines.append(f" Description: {agent['description']}")
|
|
466
|
+
if "version" in agent:
|
|
467
|
+
lines.append(f" Version: {agent['version']}")
|
|
468
|
+
|
|
469
|
+
# Verbose additions
|
|
470
|
+
if verbose:
|
|
471
|
+
if "path" in agent:
|
|
472
|
+
lines.append(f" Path: {agent['path']}")
|
|
473
|
+
if "tier" in agent:
|
|
474
|
+
lines.append(f" Tier: {agent['tier']}")
|
|
475
|
+
if agent.get("specializations"):
|
|
476
|
+
lines.append(
|
|
477
|
+
f" Specializations: {', '.join(agent['specializations'])}"
|
|
478
|
+
)
|
|
479
|
+
|
|
480
|
+
if not quiet:
|
|
481
|
+
lines.append("") # Empty line between agents
|
|
482
|
+
|
|
483
|
+
return "\n".join(lines)
|
|
484
|
+
|
|
485
|
+
def _format_agents_as_table(
|
|
486
|
+
self, agents: List[Dict[str, Any]], verbose: bool, quiet: bool
|
|
487
|
+
) -> str:
|
|
488
|
+
"""Format agents as table output.
|
|
489
|
+
|
|
490
|
+
Args:
|
|
491
|
+
agents: List of agent dictionaries
|
|
492
|
+
verbose: Include extra details
|
|
493
|
+
quiet: Minimal output
|
|
494
|
+
|
|
495
|
+
Returns:
|
|
496
|
+
Formatted table string
|
|
497
|
+
"""
|
|
498
|
+
if not agents:
|
|
499
|
+
return "No agents found"
|
|
500
|
+
|
|
501
|
+
# Define headers based on verbosity
|
|
502
|
+
if quiet:
|
|
503
|
+
headers = ["Name"]
|
|
504
|
+
rows = [
|
|
505
|
+
[agent.get("name", agent.get("file", "Unknown"))] for agent in agents
|
|
506
|
+
]
|
|
507
|
+
elif verbose:
|
|
508
|
+
headers = ["Name", "Version", "Tier", "Description", "Path"]
|
|
509
|
+
rows = []
|
|
510
|
+
for agent in agents:
|
|
511
|
+
rows.append(
|
|
512
|
+
[
|
|
513
|
+
agent.get("name", agent.get("file", "Unknown")),
|
|
514
|
+
agent.get("version", "-"),
|
|
515
|
+
agent.get("tier", "-"),
|
|
516
|
+
agent.get("description", "-")[
|
|
517
|
+
:50
|
|
518
|
+
], # Truncate long descriptions
|
|
519
|
+
str(agent.get("path", "-"))[:40], # Truncate long paths
|
|
520
|
+
]
|
|
521
|
+
)
|
|
522
|
+
else:
|
|
523
|
+
headers = ["Name", "Version", "Description"]
|
|
524
|
+
rows = []
|
|
525
|
+
for agent in agents:
|
|
526
|
+
rows.append(
|
|
527
|
+
[
|
|
528
|
+
agent.get("name", agent.get("file", "Unknown")),
|
|
529
|
+
agent.get("version", "-"),
|
|
530
|
+
agent.get("description", "-")[
|
|
531
|
+
:60
|
|
532
|
+
], # Truncate long descriptions
|
|
533
|
+
]
|
|
534
|
+
)
|
|
535
|
+
|
|
536
|
+
return self.format_as_table(headers, rows)
|
|
537
|
+
|
|
538
|
+
def format_agents_by_tier(
|
|
539
|
+
self, agents_by_tier: Dict[str, List[str]], output_format: str = "text"
|
|
540
|
+
) -> str:
|
|
541
|
+
"""Format agents grouped by tier.
|
|
542
|
+
|
|
543
|
+
Args:
|
|
544
|
+
agents_by_tier: Dictionary mapping tier names to agent lists
|
|
545
|
+
output_format: Output format (text, json, yaml)
|
|
546
|
+
|
|
547
|
+
Returns:
|
|
548
|
+
Formatted string for display
|
|
549
|
+
"""
|
|
550
|
+
if output_format == "json":
|
|
551
|
+
return self.format_as_json(agents_by_tier)
|
|
552
|
+
if output_format == "yaml":
|
|
553
|
+
return self.format_as_yaml(agents_by_tier)
|
|
554
|
+
# text format
|
|
555
|
+
lines = []
|
|
556
|
+
lines.append("Agents by Tier/Precedence:")
|
|
557
|
+
lines.append("=" * 50)
|
|
558
|
+
|
|
559
|
+
for tier, agents in agents_by_tier.items():
|
|
560
|
+
lines.append(f"\n{tier.upper()}:")
|
|
561
|
+
lines.append("-" * 20)
|
|
562
|
+
if agents:
|
|
563
|
+
for agent in agents:
|
|
564
|
+
lines.append(f" ⢠{agent}")
|
|
565
|
+
else:
|
|
566
|
+
lines.append(" (none)")
|
|
567
|
+
|
|
568
|
+
return "\n".join(lines)
|
|
569
|
+
|
|
570
|
+
def format_fix_result(
|
|
571
|
+
self, result: Dict[str, Any], output_format: str = "text"
|
|
572
|
+
) -> str:
|
|
573
|
+
"""Format fix operation results.
|
|
574
|
+
|
|
575
|
+
Args:
|
|
576
|
+
result: Fix operation result dictionary
|
|
577
|
+
output_format: Output format (text, json, yaml)
|
|
578
|
+
|
|
579
|
+
Returns:
|
|
580
|
+
Formatted string for display
|
|
581
|
+
"""
|
|
582
|
+
if output_format == "json":
|
|
583
|
+
return self.format_as_json(result)
|
|
584
|
+
if output_format == "yaml":
|
|
585
|
+
return self.format_as_yaml(result)
|
|
586
|
+
# text format
|
|
587
|
+
lines = []
|
|
588
|
+
lines.append("ā Agent deployment issues fixed")
|
|
589
|
+
|
|
590
|
+
if result.get("fixes_applied"):
|
|
591
|
+
lines.append("\nFixes applied:")
|
|
592
|
+
for fix in result["fixes_applied"]:
|
|
593
|
+
lines.append(f" - {fix}")
|
|
594
|
+
|
|
595
|
+
if result.get("errors"):
|
|
596
|
+
lines.append(f"\nā Encountered {len(result['errors'])} error(s):")
|
|
597
|
+
for error in result["errors"]:
|
|
598
|
+
lines.append(f" - {error}")
|
|
599
|
+
|
|
600
|
+
if result.get("warnings"):
|
|
601
|
+
lines.append("\nā ļø Warnings:")
|
|
602
|
+
for warning in result["warnings"]:
|
|
603
|
+
lines.append(f" - {warning}")
|
|
604
|
+
|
|
605
|
+
return "\n".join(lines)
|