claude-mpm 4.21.3__py3-none-any.whl → 5.1.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/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +12 -0
- claude_mpm/agents/{OUTPUT_STYLE.md → CLAUDE_MPM_OUTPUT_STYLE.md} +3 -48
- claude_mpm/agents/CLAUDE_MPM_TEACHER_OUTPUT_STYLE.md +2002 -0
- claude_mpm/agents/PM_INSTRUCTIONS.md +1239 -674
- claude_mpm/agents/WORKFLOW.md +75 -2
- claude_mpm/agents/__init__.py +6 -0
- claude_mpm/agents/agent_loader.py +1 -4
- claude_mpm/agents/base_agent.json +6 -3
- claude_mpm/agents/base_agent_loader.py +10 -35
- claude_mpm/agents/frontmatter_validator.py +69 -1
- claude_mpm/agents/templates/circuit-breakers.md +1254 -0
- claude_mpm/agents/templates/context-management-examples.md +544 -0
- claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +89 -19
- claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
- claude_mpm/agents/templates/research-gate-examples.md +669 -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/cli/__init__.py +37 -2
- claude_mpm/cli/commands/__init__.py +2 -0
- claude_mpm/cli/commands/agent_source.py +774 -0
- claude_mpm/cli/commands/agent_state_manager.py +188 -30
- claude_mpm/cli/commands/agents.py +1128 -36
- claude_mpm/cli/commands/agents_cleanup.py +210 -0
- claude_mpm/cli/commands/agents_discover.py +338 -0
- claude_mpm/cli/commands/aggregate.py +1 -1
- claude_mpm/cli/commands/analyze.py +3 -3
- claude_mpm/cli/commands/auto_configure.py +537 -239
- claude_mpm/cli/commands/cleanup.py +1 -1
- claude_mpm/cli/commands/config.py +7 -4
- claude_mpm/cli/commands/configure.py +935 -45
- claude_mpm/cli/commands/configure_agent_display.py +4 -4
- claude_mpm/cli/commands/configure_navigation.py +63 -46
- claude_mpm/cli/commands/debug.py +12 -12
- claude_mpm/cli/commands/doctor.py +10 -2
- claude_mpm/cli/commands/hook_errors.py +277 -0
- claude_mpm/cli/commands/local_deploy.py +1 -4
- claude_mpm/cli/commands/mcp_install_commands.py +1 -1
- claude_mpm/cli/commands/mpm_init/core.py +50 -2
- claude_mpm/cli/commands/mpm_init/git_activity.py +10 -10
- claude_mpm/cli/commands/mpm_init/prompts.py +6 -6
- claude_mpm/cli/commands/postmortem.py +401 -0
- claude_mpm/cli/commands/run.py +125 -167
- claude_mpm/cli/commands/skill_source.py +694 -0
- claude_mpm/cli/commands/skills.py +757 -20
- claude_mpm/cli/executor.py +78 -3
- claude_mpm/cli/interactive/agent_wizard.py +1032 -47
- claude_mpm/cli/parsers/agent_source_parser.py +171 -0
- claude_mpm/cli/parsers/agents_parser.py +310 -4
- claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
- claude_mpm/cli/parsers/base_parser.py +53 -0
- claude_mpm/cli/parsers/config_parser.py +96 -43
- claude_mpm/cli/parsers/skill_source_parser.py +169 -0
- claude_mpm/cli/parsers/skills_parser.py +145 -0
- claude_mpm/cli/parsers/source_parser.py +138 -0
- claude_mpm/cli/startup.py +564 -108
- claude_mpm/cli/startup_display.py +480 -0
- claude_mpm/cli/utils.py +1 -1
- claude_mpm/cli_module/commands.py +1 -1
- claude_mpm/commands/{mpm-auto-configure.md → mpm-agents-auto-configure.md} +9 -0
- claude_mpm/commands/mpm-agents-detect.md +9 -0
- claude_mpm/commands/{mpm-agents.md → mpm-agents-list.md} +9 -0
- claude_mpm/commands/mpm-agents-recommend.md +9 -0
- claude_mpm/commands/{mpm-config.md → mpm-config-view.md} +9 -0
- claude_mpm/commands/mpm-doctor.md +9 -0
- claude_mpm/commands/mpm-help.md +14 -2
- claude_mpm/commands/mpm-init.md +27 -2
- claude_mpm/commands/mpm-monitor.md +9 -0
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/{mpm-resume.md → mpm-session-resume.md} +9 -0
- claude_mpm/commands/mpm-status.md +9 -0
- claude_mpm/commands/{mpm-organize.md → mpm-ticket-organize.md} +9 -0
- claude_mpm/commands/mpm-ticket-view.md +552 -0
- claude_mpm/commands/mpm-version.md +9 -0
- claude_mpm/commands/mpm.md +10 -0
- claude_mpm/config/agent_presets.py +488 -0
- claude_mpm/config/agent_sources.py +325 -0
- claude_mpm/config/skill_presets.py +392 -0
- claude_mpm/config/skill_sources.py +590 -0
- claude_mpm/constants.py +13 -0
- claude_mpm/core/api_validator.py +1 -1
- claude_mpm/core/claude_runner.py +19 -35
- claude_mpm/core/config.py +24 -0
- claude_mpm/core/constants.py +1 -1
- claude_mpm/core/framework/__init__.py +3 -16
- claude_mpm/core/framework/loaders/file_loader.py +54 -101
- claude_mpm/core/framework/loaders/instruction_loader.py +25 -5
- claude_mpm/core/framework/processors/metadata_processor.py +1 -1
- claude_mpm/core/hook_error_memory.py +381 -0
- claude_mpm/core/hook_manager.py +41 -2
- claude_mpm/core/interactive_session.py +131 -10
- claude_mpm/core/logger.py +3 -1
- claude_mpm/core/oneshot_session.py +110 -8
- claude_mpm/core/output_style_manager.py +173 -43
- 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/shared/singleton_manager.py +11 -4
- claude_mpm/core/system_context.py +38 -0
- claude_mpm/core/unified_agent_registry.py +129 -1
- claude_mpm/core/unified_config.py +22 -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 +15 -15
- claude_mpm/dashboard/static/js/components/activity-tree.js +178 -178
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +101 -101
- claude_mpm/dashboard/static/js/components/agent-inference.js +31 -31
- claude_mpm/dashboard/static/js/components/build-tracker.js +59 -59
- claude_mpm/dashboard/static/js/components/code-simple.js +107 -107
- claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
- claude_mpm/dashboard/static/js/components/diff-viewer.js +113 -113
- claude_mpm/dashboard/static/js/components/event-viewer.js +12 -12
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +57 -57
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +74 -74
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +6 -6
- claude_mpm/dashboard/static/js/components/file-viewer.js +42 -42
- claude_mpm/dashboard/static/js/components/module-viewer.js +27 -27
- claude_mpm/dashboard/static/js/components/session-manager.js +14 -14
- claude_mpm/dashboard/static/js/components/socket-manager.js +1 -1
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +14 -14
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +110 -110
- claude_mpm/dashboard/static/js/components/working-directory.js +8 -8
- claude_mpm/dashboard/static/js/connection-manager.js +76 -76
- claude_mpm/dashboard/static/js/dashboard.js +76 -58
- claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
- claude_mpm/dashboard/static/js/socket-client.js +138 -121
- claude_mpm/dashboard/templates/code_simple.html +23 -23
- claude_mpm/dashboard/templates/index.html +18 -18
- claude_mpm/experimental/cli_enhancements.py +1 -5
- claude_mpm/hooks/claude_hooks/event_handlers.py +3 -1
- claude_mpm/hooks/claude_hooks/hook_handler.py +24 -7
- claude_mpm/hooks/claude_hooks/installer.py +45 -0
- claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
- claude_mpm/hooks/failure_learning/__init__.py +2 -8
- claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
- claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
- claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
- claude_mpm/hooks/kuzu_response_hook.py +1 -5
- claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
- claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
- claude_mpm/models/agent_definition.py +7 -0
- claude_mpm/models/git_repository.py +198 -0
- claude_mpm/scripts/claude-hook-handler.sh +3 -3
- claude_mpm/scripts/start_activity_logging.py +3 -1
- claude_mpm/services/agents/agent_builder.py +45 -9
- 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_deploy_index_parser.py +569 -0
- claude_mpm/services/agents/cache_git_manager.py +621 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +126 -2
- claude_mpm/services/agents/deployment/agent_discovery_service.py +105 -73
- claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
- claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
- claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
- claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
- claude_mpm/services/agents/deployment/agent_template_builder.py +236 -15
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
- claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
- claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +225 -18
- claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
- claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
- claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +557 -0
- claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
- claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
- claude_mpm/services/agents/git_source_manager.py +629 -0
- claude_mpm/services/agents/loading/framework_agent_loader.py +9 -12
- claude_mpm/services/agents/local_template_manager.py +50 -10
- 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/cli/session_pause_manager.py +1 -1
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/command_deployment_service.py +200 -6
- claude_mpm/services/core/base.py +7 -2
- claude_mpm/services/core/interfaces/__init__.py +1 -3
- claude_mpm/services/core/interfaces/health.py +1 -4
- claude_mpm/services/core/models/__init__.py +2 -11
- claude_mpm/services/diagnostics/checks/__init__.py +4 -0
- claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
- claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
- claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
- claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
- claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
- claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
- claude_mpm/services/diagnostics/doctor_reporter.py +40 -10
- claude_mpm/services/event_bus/direct_relay.py +3 -3
- claude_mpm/services/event_bus/event_bus.py +36 -3
- claude_mpm/services/events/consumers/logging.py +1 -2
- 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/infrastructure/monitoring/__init__.py +1 -5
- claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
- claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
- 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 +3 -13
- claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
- claude_mpm/services/local_ops/health_manager.py +1 -4
- claude_mpm/services/local_ops/process_manager.py +1 -1
- claude_mpm/services/local_ops/resource_monitor.py +2 -2
- claude_mpm/services/mcp_config_manager.py +75 -145
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/process_pool.py +22 -16
- claude_mpm/services/mcp_gateway/server/mcp_gateway.py +1 -6
- claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -2
- claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
- claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
- claude_mpm/services/mcp_service_verifier.py +6 -3
- claude_mpm/services/memory/optimizer.py +1 -1
- claude_mpm/services/model/model_router.py +8 -9
- claude_mpm/services/monitor/daemon.py +29 -9
- claude_mpm/services/monitor/daemon_manager.py +96 -19
- claude_mpm/services/monitor/server.py +2 -2
- claude_mpm/services/native_agent_converter.py +356 -0
- claude_mpm/services/port_manager.py +1 -1
- claude_mpm/services/pr/__init__.py +14 -0
- claude_mpm/services/pr/pr_template_service.py +329 -0
- claude_mpm/services/project/documentation_manager.py +2 -1
- claude_mpm/services/project/project_organizer.py +4 -0
- claude_mpm/services/project/toolchain_analyzer.py +3 -1
- claude_mpm/services/runner_configuration_service.py +17 -3
- claude_mpm/services/self_upgrade_service.py +165 -7
- claude_mpm/services/session_management_service.py +16 -4
- 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/handlers/connection.py +1 -1
- claude_mpm/services/socketio/handlers/git.py +2 -2
- claude_mpm/services/socketio/server/core.py +1 -4
- claude_mpm/services/socketio/server/main.py +1 -3
- claude_mpm/services/system_instructions_service.py +1 -3
- claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
- claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
- claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +1 -1
- claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
- claude_mpm/services/unified/unified_deployment.py +1 -5
- claude_mpm/services/version_control/conflict_resolution.py +6 -4
- claude_mpm/services/visualization/__init__.py +1 -5
- claude_mpm/services/visualization/mermaid_generator.py +2 -3
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/performance-profiling.md +6 -0
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +2 -2
- claude_mpm/skills/skills_registry.py +0 -1
- 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 +8 -8
- claude_mpm/tools/code_tree_analyzer/analysis.py +1 -1
- claude_mpm/utils/agent_dependency_loader.py +80 -13
- claude_mpm/utils/agent_filters.py +288 -0
- claude_mpm/utils/dependency_cache.py +3 -1
- claude_mpm/utils/gitignore.py +244 -0
- claude_mpm/utils/log_cleanup.py +3 -3
- claude_mpm/utils/migration.py +372 -0
- claude_mpm/utils/progress.py +387 -0
- claude_mpm/utils/robust_installer.py +3 -5
- claude_mpm/utils/structured_questions.py +619 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.1.9.dist-info}/METADATA +496 -65
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.1.9.dist-info}/RECORD +284 -443
- 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 -273
- claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
- claude_mpm/agents/templates/api_qa.json +0 -180
- claude_mpm/agents/templates/circuit_breakers.md +0 -638
- claude_mpm/agents/templates/clerk-ops.json +0 -235
- claude_mpm/agents/templates/code_analyzer.json +0 -101
- claude_mpm/agents/templates/content-agent.json +0 -358
- claude_mpm/agents/templates/dart_engineer.json +0 -307
- claude_mpm/agents/templates/data_engineer.json +0 -225
- claude_mpm/agents/templates/documentation.json +0 -211
- claude_mpm/agents/templates/engineer.json +0 -210
- claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
- claude_mpm/agents/templates/golang_engineer.json +0 -270
- claude_mpm/agents/templates/imagemagick.json +0 -264
- claude_mpm/agents/templates/java_engineer.json +0 -346
- claude_mpm/agents/templates/local_ops_agent.json +0 -1840
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
- claude_mpm/agents/templates/memory_manager.json +0 -158
- claude_mpm/agents/templates/nextjs_engineer.json +0 -285
- claude_mpm/agents/templates/ops.json +0 -185
- claude_mpm/agents/templates/php-engineer.json +0 -287
- claude_mpm/agents/templates/product_owner.json +0 -338
- claude_mpm/agents/templates/project_organizer.json +0 -140
- claude_mpm/agents/templates/prompt-engineer.json +0 -737
- claude_mpm/agents/templates/python_engineer.json +0 -387
- claude_mpm/agents/templates/qa.json +0 -242
- claude_mpm/agents/templates/react_engineer.json +0 -238
- claude_mpm/agents/templates/refactoring_engineer.json +0 -276
- claude_mpm/agents/templates/research.json +0 -188
- claude_mpm/agents/templates/ruby-engineer.json +0 -280
- claude_mpm/agents/templates/rust_engineer.json +0 -275
- claude_mpm/agents/templates/security.json +0 -202
- claude_mpm/agents/templates/svelte-engineer.json +0 -225
- claude_mpm/agents/templates/ticketing.json +0 -177
- claude_mpm/agents/templates/typescript_engineer.json +0 -285
- claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
- claude_mpm/agents/templates/version_control.json +0 -157
- claude_mpm/agents/templates/web_qa.json +0 -399
- claude_mpm/agents/templates/web_ui.json +0 -189
- claude_mpm/commands/mpm-tickets.md +0 -102
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
- claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
- claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
- claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
- claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
- claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
- claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
- claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
- claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
- claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
- claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
- claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
- claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
- claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
- claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
- claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
- claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
- claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
- claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
- claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
- claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
- claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
- 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/connection-debug.js +0 -654
- claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
- 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-change-tracker.js +0 -443
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
- claude_mpm/dashboard/static/built/components/file-viewer.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/nav-bar.js +0 -145
- claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
- 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/connection-manager.js +0 -536
- claude_mpm/dashboard/static/built/dashboard.js +0 -2
- claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
- claude_mpm/dashboard/static/built/react/events.js +0 -30
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
- claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
- claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
- claude_mpm/dashboard/static/built/shared/logger.js +0 -385
- claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
- claude_mpm/dashboard/static/built/socket-client.js +0 -2
- claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
- claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
- 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/file-viewer.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/react/events.js +0 -30
- claude_mpm/dashboard/static/dist/socket-client.js +0 -2
- claude_mpm/dashboard/static/events.html +0 -607
- claude_mpm/dashboard/static/index.html +0 -635
- claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
- claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
- claude_mpm/dashboard/static/js/shared/logger.js +0 -385
- claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
- claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
- claude_mpm/dashboard/static/legacy/activity.html +0 -736
- claude_mpm/dashboard/static/legacy/agents.html +0 -786
- claude_mpm/dashboard/static/legacy/files.html +0 -747
- claude_mpm/dashboard/static/legacy/tools.html +0 -831
- claude_mpm/dashboard/static/monitors.html +0 -431
- claude_mpm/dashboard/static/production/events.html +0 -659
- claude_mpm/dashboard/static/production/main.html +0 -698
- claude_mpm/dashboard/static/production/monitors.html +0 -483
- claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
- claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
- claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
- claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
- claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
- claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -79
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -178
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/agent-prompts.md +0 -577
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/coordination-patterns.md +0 -467
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/examples.md +0 -537
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/references/troubleshooting.md +0 -730
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -112
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/code-reviewer-template.md +0 -146
- claude_mpm/skills/bundled/collaboration/requesting-code-review/references/review-examples.md +0 -412
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -81
- claude_mpm/skills/bundled/collaboration/writing-plans/references/best-practices.md +0 -362
- claude_mpm/skills/bundled/collaboration/writing-plans/references/plan-structure-templates.md +0 -312
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -152
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/advanced-techniques.md +0 -668
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/examples.md +0 -587
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/integration.md +0 -438
- claude_mpm/skills/bundled/debugging/root-cause-tracing/references/tracing-techniques.md +0 -391
- claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
- claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
- claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
- claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
- claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -131
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -325
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/integration-and-workflows.md +0 -490
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/red-flags-and-failures.md +0 -425
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -499
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -86
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -43
- claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
- claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
- claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
- claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
- claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -160
- claude_mpm/skills/bundled/main/mcp-builder/reference/design_principles.md +0 -412
- claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
- claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
- claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
- claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
- claude_mpm/skills/bundled/main/mcp-builder/reference/workflow.md +0 -1237
- claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -189
- claude_mpm/skills/bundled/main/skill-creator/references/best-practices.md +0 -500
- claude_mpm/skills/bundled/main/skill-creator/references/creation-workflow.md +0 -464
- claude_mpm/skills/bundled/main/skill-creator/references/examples.md +0 -619
- claude_mpm/skills/bundled/main/skill-creator/references/progressive-disclosure.md +0 -437
- claude_mpm/skills/bundled/main/skill-creator/references/skill-structure.md +0 -231
- claude_mpm/skills/bundled/php/espocrm-development/SKILL.md +0 -170
- claude_mpm/skills/bundled/php/espocrm-development/references/architecture.md +0 -602
- claude_mpm/skills/bundled/php/espocrm-development/references/common-tasks.md +0 -821
- claude_mpm/skills/bundled/php/espocrm-development/references/development-workflow.md +0 -742
- claude_mpm/skills/bundled/php/espocrm-development/references/frontend-customization.md +0 -726
- claude_mpm/skills/bundled/php/espocrm-development/references/hooks-and-services.md +0 -764
- claude_mpm/skills/bundled/php/espocrm-development/references/testing-debugging.md +0 -831
- claude_mpm/skills/bundled/rust/desktop-applications/SKILL.md +0 -226
- claude_mpm/skills/bundled/rust/desktop-applications/references/architecture-patterns.md +0 -901
- claude_mpm/skills/bundled/rust/desktop-applications/references/native-gui-frameworks.md +0 -901
- claude_mpm/skills/bundled/rust/desktop-applications/references/platform-integration.md +0 -775
- claude_mpm/skills/bundled/rust/desktop-applications/references/state-management.md +0 -937
- claude_mpm/skills/bundled/rust/desktop-applications/references/tauri-framework.md +0 -770
- claude_mpm/skills/bundled/rust/desktop-applications/references/testing-deployment.md +0 -961
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -119
- claude_mpm/skills/bundled/testing/condition-based-waiting/references/patterns-and-implementation.md +0 -253
- claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
- claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
- claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
- claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
- claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
- claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
- claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -140
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/completeness-anti-patterns.md +0 -572
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/core-anti-patterns.md +0 -411
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/detection-guide.md +0 -569
- claude_mpm/skills/bundled/testing/testing-anti-patterns/references/tdd-connection.md +0 -695
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -184
- claude_mpm/skills/bundled/testing/webapp-testing/decision-tree.md +0 -459
- claude_mpm/skills/bundled/testing/webapp-testing/playwright-patterns.md +0 -479
- claude_mpm/skills/bundled/testing/webapp-testing/reconnaissance-pattern.md +0 -687
- claude_mpm/skills/bundled/testing/webapp-testing/server-management.md +0 -758
- claude_mpm/skills/bundled/testing/webapp-testing/troubleshooting.md +0 -868
- /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
- /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
- /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
- /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.1.9.dist-info}/WHEEL +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.1.9.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.1.9.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.21.3.dist-info → claude_mpm-5.1.9.dist-info}/top_level.txt +0 -0
|
@@ -12,15 +12,21 @@ DESIGN DECISIONS:
|
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
import json
|
|
15
|
+
import shutil
|
|
15
16
|
from pathlib import Path
|
|
16
17
|
from typing import Dict, List, Optional
|
|
17
18
|
|
|
19
|
+
import questionary
|
|
20
|
+
import questionary.constants
|
|
21
|
+
import questionary.prompts.common # For checkbox symbol customization
|
|
22
|
+
from questionary import Style
|
|
18
23
|
from rich.console import Console
|
|
19
24
|
from rich.prompt import Confirm, Prompt
|
|
20
25
|
from rich.text import Text
|
|
21
26
|
|
|
22
27
|
from ...core.config import Config
|
|
23
28
|
from ...services.version_service import VersionService
|
|
29
|
+
from ...utils.agent_filters import apply_all_filters, get_deployed_agent_ids
|
|
24
30
|
from ...utils.console import console as default_console
|
|
25
31
|
from ..shared import BaseCommand, CommandResult
|
|
26
32
|
from .agent_state_manager import SimpleAgentManager
|
|
@@ -41,6 +47,21 @@ from .configure_validators import (
|
|
|
41
47
|
class ConfigureCommand(BaseCommand):
|
|
42
48
|
"""Interactive configuration management command."""
|
|
43
49
|
|
|
50
|
+
# Questionary style optimized for dark terminals (WCAG AAA compliant)
|
|
51
|
+
QUESTIONARY_STYLE = Style(
|
|
52
|
+
[
|
|
53
|
+
("selected", "fg:#e0e0e0 bold"), # Light gray - excellent readability
|
|
54
|
+
("pointer", "fg:#ffd700 bold"), # Gold/yellow - highly visible pointer
|
|
55
|
+
("highlighted", "fg:#e0e0e0"), # Light gray - clear hover state
|
|
56
|
+
("question", "fg:#e0e0e0 bold"), # Light gray bold - prominent questions
|
|
57
|
+
("checkbox", "fg:#00ff00"), # Green - for checked boxes
|
|
58
|
+
(
|
|
59
|
+
"checkbox-selected",
|
|
60
|
+
"fg:#00ff00 bold",
|
|
61
|
+
), # Green bold - for checked selected boxes
|
|
62
|
+
]
|
|
63
|
+
)
|
|
64
|
+
|
|
44
65
|
def __init__(self):
|
|
45
66
|
super().__init__("configure")
|
|
46
67
|
self.console = default_console
|
|
@@ -284,61 +305,140 @@ class ConfigureCommand(BaseCommand):
|
|
|
284
305
|
return self.navigation.show_main_menu()
|
|
285
306
|
|
|
286
307
|
def _manage_agents(self) -> None:
|
|
287
|
-
"""
|
|
308
|
+
"""Enhanced agent management with remote agent discovery and installation."""
|
|
288
309
|
while True:
|
|
289
310
|
self.console.clear()
|
|
290
|
-
self.
|
|
311
|
+
self.navigation.display_header()
|
|
312
|
+
self.console.print("\n[bold blue]═══ Agent Management ═══[/bold blue]\n")
|
|
313
|
+
|
|
314
|
+
# Step 1: Show configured sources
|
|
315
|
+
self.console.print("[bold white]═══ Agent Sources ═══[/bold white]\n")
|
|
316
|
+
|
|
317
|
+
sources = self._get_configured_sources()
|
|
318
|
+
if sources:
|
|
319
|
+
from rich.table import Table
|
|
320
|
+
|
|
321
|
+
sources_table = Table(show_header=True, header_style="bold white")
|
|
322
|
+
sources_table.add_column(
|
|
323
|
+
"Source",
|
|
324
|
+
style="bright_yellow",
|
|
325
|
+
width=40,
|
|
326
|
+
no_wrap=True,
|
|
327
|
+
overflow="ellipsis",
|
|
328
|
+
)
|
|
329
|
+
sources_table.add_column(
|
|
330
|
+
"Status", style="green", width=15, no_wrap=True
|
|
331
|
+
)
|
|
332
|
+
sources_table.add_column(
|
|
333
|
+
"Agents", style="yellow", width=10, no_wrap=True
|
|
334
|
+
)
|
|
291
335
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
336
|
+
for source in sources:
|
|
337
|
+
status = "✓ Active" if source.get("enabled", True) else "Disabled"
|
|
338
|
+
agent_count = source.get("agent_count", "?")
|
|
339
|
+
sources_table.add_row(
|
|
340
|
+
source["identifier"], status, str(agent_count)
|
|
341
|
+
)
|
|
295
342
|
|
|
296
|
-
|
|
297
|
-
|
|
343
|
+
self.console.print(sources_table)
|
|
344
|
+
else:
|
|
345
|
+
self.console.print("[yellow]No agent sources configured[/yellow]")
|
|
346
|
+
self.console.print(
|
|
347
|
+
"[dim]Default source 'bobmatnyc/claude-mpm-agents' will be used[/dim]\n"
|
|
348
|
+
)
|
|
298
349
|
|
|
299
|
-
#
|
|
300
|
-
|
|
301
|
-
text_t.append("[t]", style="bold blue")
|
|
302
|
-
text_t.append(" Toggle agents (enable/disable multiple)")
|
|
303
|
-
self.console.print(text_t)
|
|
350
|
+
# Step 2: Discover and display available agents
|
|
351
|
+
self.console.print("\n[bold white]═══ Available Agents ═══[/bold white]\n")
|
|
304
352
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
self.console.print(text_c)
|
|
353
|
+
try:
|
|
354
|
+
# Discover agents (includes both local and remote)
|
|
355
|
+
agents = self.agent_manager.discover_agents(include_remote=True)
|
|
309
356
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
357
|
+
# Set deployment status on each agent for display
|
|
358
|
+
deployed_ids = get_deployed_agent_ids()
|
|
359
|
+
for agent in agents:
|
|
360
|
+
# Extract leaf name for comparison
|
|
361
|
+
agent_leaf_name = agent.name.split("/")[-1]
|
|
362
|
+
agent.is_deployed = agent_leaf_name in deployed_ids
|
|
314
363
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
text_r.append(" Reset agent to defaults")
|
|
318
|
-
self.console.print(text_r)
|
|
364
|
+
# Filter BASE_AGENT from display (1M-502 Phase 1)
|
|
365
|
+
agents = self._filter_agent_configs(agents, filter_deployed=False)
|
|
319
366
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
367
|
+
if not agents:
|
|
368
|
+
self.console.print("[yellow]No agents found[/yellow]")
|
|
369
|
+
self.console.print(
|
|
370
|
+
"[dim]Configure sources with 'claude-mpm agent-source add'[/dim]\n"
|
|
371
|
+
)
|
|
372
|
+
else:
|
|
373
|
+
# Display agents in a table (already filtered at line 339)
|
|
374
|
+
self._display_agents_with_source_info(agents)
|
|
324
375
|
|
|
325
|
-
|
|
376
|
+
except Exception as e:
|
|
377
|
+
self.console.print(f"[red]Error discovering agents: {e}[/red]")
|
|
378
|
+
self.logger.error(f"Agent discovery failed: {e}", exc_info=True)
|
|
326
379
|
|
|
327
|
-
|
|
380
|
+
# Step 3: Menu options with arrow-key navigation
|
|
381
|
+
self.console.print()
|
|
382
|
+
self.logger.debug("About to show agent management menu")
|
|
383
|
+
try:
|
|
384
|
+
choice = questionary.select(
|
|
385
|
+
"Agent Management:",
|
|
386
|
+
choices=[
|
|
387
|
+
"Manage sources (add/remove repositories)",
|
|
388
|
+
"Select Agents",
|
|
389
|
+
"Install preset (predefined sets)",
|
|
390
|
+
"Remove agents",
|
|
391
|
+
"View agent details",
|
|
392
|
+
"Toggle agents (legacy enable/disable)",
|
|
393
|
+
questionary.Separator(),
|
|
394
|
+
"← Back to main menu",
|
|
395
|
+
],
|
|
396
|
+
style=self.QUESTIONARY_STYLE,
|
|
397
|
+
).ask()
|
|
398
|
+
|
|
399
|
+
if choice is None or choice == "← Back to main menu":
|
|
400
|
+
break
|
|
328
401
|
|
|
329
|
-
|
|
402
|
+
agents_var = agents if "agents" in locals() else []
|
|
403
|
+
|
|
404
|
+
# Map selection to action
|
|
405
|
+
if choice == "Manage sources (add/remove repositories)":
|
|
406
|
+
self._manage_sources()
|
|
407
|
+
elif choice == "Select Agents":
|
|
408
|
+
self.logger.debug("User selected 'Select Agents' from menu")
|
|
409
|
+
self._deploy_agents_individual(agents_var)
|
|
410
|
+
elif choice == "Install preset (predefined sets)":
|
|
411
|
+
self._deploy_agents_preset()
|
|
412
|
+
elif choice == "Remove agents":
|
|
413
|
+
self._remove_agents(agents_var)
|
|
414
|
+
elif choice == "View agent details":
|
|
415
|
+
self._view_agent_details_enhanced(agents_var)
|
|
416
|
+
elif choice == "Toggle agents (legacy enable/disable)":
|
|
417
|
+
self._toggle_agents_interactive(agents_var)
|
|
418
|
+
|
|
419
|
+
except KeyboardInterrupt:
|
|
420
|
+
self.console.print("\n[yellow]Operation cancelled[/yellow]")
|
|
421
|
+
break
|
|
422
|
+
except Exception as e:
|
|
423
|
+
# Handle questionary menu failure
|
|
424
|
+
import sys
|
|
425
|
+
|
|
426
|
+
self.logger.error(f"Agent management menu failed: {e}", exc_info=True)
|
|
427
|
+
self.console.print("[red]Error: Interactive menu failed[/red]")
|
|
428
|
+
self.console.print(f"[dim]Reason: {e}[/dim]")
|
|
429
|
+
if not sys.stdin.isatty():
|
|
430
|
+
self.console.print(
|
|
431
|
+
"[dim]Interactive terminal required for this operation[/dim]"
|
|
432
|
+
)
|
|
433
|
+
self.console.print("[dim]Use command-line options instead:[/dim]")
|
|
434
|
+
self.console.print(
|
|
435
|
+
"[dim] claude-mpm configure --list-agents[/dim]"
|
|
436
|
+
)
|
|
437
|
+
self.console.print(
|
|
438
|
+
"[dim] claude-mpm configure --enable-agent <id>[/dim]"
|
|
439
|
+
)
|
|
440
|
+
Prompt.ask("\nPress Enter to continue")
|
|
330
441
|
break
|
|
331
|
-
if choice == "t":
|
|
332
|
-
self._toggle_agents_interactive(agents)
|
|
333
|
-
elif choice == "c":
|
|
334
|
-
self._customize_agent_template(agents)
|
|
335
|
-
elif choice == "v":
|
|
336
|
-
self._view_agent_details(agents)
|
|
337
|
-
elif choice == "r":
|
|
338
|
-
self._reset_agent_defaults(agents)
|
|
339
|
-
else:
|
|
340
|
-
self.console.print("[red]Invalid choice.[/red]")
|
|
341
|
-
Prompt.ask("Press Enter to continue")
|
|
342
442
|
|
|
343
443
|
def _display_agents_table(self, agents: List[AgentConfig]) -> None:
|
|
344
444
|
"""Display a table of available agents."""
|
|
@@ -511,6 +611,8 @@ class ConfigureCommand(BaseCommand):
|
|
|
511
611
|
|
|
512
612
|
# Get list of enabled agents
|
|
513
613
|
agents = self.agent_manager.discover_agents()
|
|
614
|
+
# Filter BASE_AGENT from all agent operations (1M-502 Phase 1)
|
|
615
|
+
agents = self._filter_agent_configs(agents, filter_deployed=False)
|
|
514
616
|
enabled_agents = [
|
|
515
617
|
a.name
|
|
516
618
|
for a in agents
|
|
@@ -554,9 +656,9 @@ class ConfigureCommand(BaseCommand):
|
|
|
554
656
|
else:
|
|
555
657
|
from rich.table import Table
|
|
556
658
|
|
|
557
|
-
table = Table(show_header=True, header_style="bold
|
|
558
|
-
table.add_column("Agent", style="
|
|
559
|
-
table.add_column("Skills", style="green")
|
|
659
|
+
table = Table(show_header=True, header_style="bold white")
|
|
660
|
+
table.add_column("Agent", style="white", no_wrap=True)
|
|
661
|
+
table.add_column("Skills", style="green", no_wrap=True)
|
|
560
662
|
|
|
561
663
|
for agent_id, skills in mappings.items():
|
|
562
664
|
skills_str = (
|
|
@@ -577,6 +679,8 @@ class ConfigureCommand(BaseCommand):
|
|
|
577
679
|
|
|
578
680
|
# Get enabled agents
|
|
579
681
|
agents = self.agent_manager.discover_agents()
|
|
682
|
+
# Filter BASE_AGENT from all agent operations (1M-502 Phase 1)
|
|
683
|
+
agents = self._filter_agent_configs(agents, filter_deployed=False)
|
|
580
684
|
enabled_agents = [
|
|
581
685
|
a.name
|
|
582
686
|
for a in agents
|
|
@@ -708,6 +812,8 @@ class ConfigureCommand(BaseCommand):
|
|
|
708
812
|
def _list_agents_non_interactive(self) -> CommandResult:
|
|
709
813
|
"""List agents in non-interactive mode."""
|
|
710
814
|
agents = self.agent_manager.discover_agents()
|
|
815
|
+
# Filter BASE_AGENT from all agent lists (1M-502 Phase 1)
|
|
816
|
+
agents = self._filter_agent_configs(agents, filter_deployed=False)
|
|
711
817
|
|
|
712
818
|
data = []
|
|
713
819
|
for agent in agents:
|
|
@@ -809,6 +915,790 @@ class ConfigureCommand(BaseCommand):
|
|
|
809
915
|
except Exception as e:
|
|
810
916
|
return CommandResult.error_result(f"Startup configuration failed: {e}")
|
|
811
917
|
|
|
918
|
+
# ========================================================================
|
|
919
|
+
# Enhanced Agent Management Methods (Remote Agent Discovery Integration)
|
|
920
|
+
# ========================================================================
|
|
921
|
+
|
|
922
|
+
def _get_configured_sources(self) -> List[Dict]:
|
|
923
|
+
"""Get list of configured agent sources with agent counts."""
|
|
924
|
+
try:
|
|
925
|
+
from claude_mpm.config.agent_sources import AgentSourceConfiguration
|
|
926
|
+
|
|
927
|
+
config = AgentSourceConfiguration.load()
|
|
928
|
+
|
|
929
|
+
# Convert repositories to source dictionaries
|
|
930
|
+
sources = []
|
|
931
|
+
for repo in config.repositories:
|
|
932
|
+
# Extract identifier from repository
|
|
933
|
+
identifier = repo.identifier
|
|
934
|
+
|
|
935
|
+
# Count agents in cache
|
|
936
|
+
cache_dir = (
|
|
937
|
+
Path.home() / ".claude-mpm" / "cache" / "remote-agents" / identifier
|
|
938
|
+
)
|
|
939
|
+
agent_count = 0
|
|
940
|
+
if cache_dir.exists():
|
|
941
|
+
agents_dir = cache_dir / "agents"
|
|
942
|
+
if agents_dir.exists():
|
|
943
|
+
agent_count = len(list(agents_dir.rglob("*.md")))
|
|
944
|
+
|
|
945
|
+
sources.append(
|
|
946
|
+
{
|
|
947
|
+
"identifier": identifier,
|
|
948
|
+
"url": repo.url,
|
|
949
|
+
"enabled": repo.enabled,
|
|
950
|
+
"priority": repo.priority,
|
|
951
|
+
"agent_count": agent_count,
|
|
952
|
+
}
|
|
953
|
+
)
|
|
954
|
+
|
|
955
|
+
return sources
|
|
956
|
+
except Exception as e:
|
|
957
|
+
self.logger.warning(f"Failed to get configured sources: {e}")
|
|
958
|
+
return []
|
|
959
|
+
|
|
960
|
+
def _filter_agent_configs(
|
|
961
|
+
self, agents: List[AgentConfig], filter_deployed: bool = False
|
|
962
|
+
) -> List[AgentConfig]:
|
|
963
|
+
"""Filter AgentConfig objects using agent_filters utilities.
|
|
964
|
+
|
|
965
|
+
Converts AgentConfig objects to dictionaries for filtering,
|
|
966
|
+
then back to AgentConfig. Always filters BASE_AGENT.
|
|
967
|
+
Optionally filters deployed agents.
|
|
968
|
+
|
|
969
|
+
Args:
|
|
970
|
+
agents: List of AgentConfig objects
|
|
971
|
+
filter_deployed: Whether to filter out deployed agents (default: False)
|
|
972
|
+
|
|
973
|
+
Returns:
|
|
974
|
+
Filtered list of AgentConfig objects
|
|
975
|
+
"""
|
|
976
|
+
# Convert AgentConfig to dict format for filtering
|
|
977
|
+
agent_dicts = []
|
|
978
|
+
for agent in agents:
|
|
979
|
+
agent_dicts.append(
|
|
980
|
+
{
|
|
981
|
+
"agent_id": agent.name,
|
|
982
|
+
"name": agent.name,
|
|
983
|
+
"description": agent.description,
|
|
984
|
+
"deployed": getattr(agent, "is_deployed", False),
|
|
985
|
+
}
|
|
986
|
+
)
|
|
987
|
+
|
|
988
|
+
# Apply filters (always filter BASE_AGENT)
|
|
989
|
+
filtered_dicts = apply_all_filters(
|
|
990
|
+
agent_dicts, filter_base=True, filter_deployed=filter_deployed
|
|
991
|
+
)
|
|
992
|
+
|
|
993
|
+
# Convert back to AgentConfig objects
|
|
994
|
+
filtered_names = {d["agent_id"] for d in filtered_dicts}
|
|
995
|
+
return [a for a in agents if a.name in filtered_names]
|
|
996
|
+
|
|
997
|
+
@staticmethod
|
|
998
|
+
def _calculate_column_widths(
|
|
999
|
+
terminal_width: int, columns: Dict[str, int]
|
|
1000
|
+
) -> Dict[str, int]:
|
|
1001
|
+
"""Calculate dynamic column widths based on terminal size.
|
|
1002
|
+
|
|
1003
|
+
Args:
|
|
1004
|
+
terminal_width: Current terminal width in characters
|
|
1005
|
+
columns: Dict mapping column names to minimum widths
|
|
1006
|
+
|
|
1007
|
+
Returns:
|
|
1008
|
+
Dict mapping column names to calculated widths
|
|
1009
|
+
|
|
1010
|
+
Design:
|
|
1011
|
+
- Ensures minimum widths are respected
|
|
1012
|
+
- Distributes extra space proportionally
|
|
1013
|
+
- Handles narrow terminals gracefully (minimum 80 chars)
|
|
1014
|
+
"""
|
|
1015
|
+
# Ensure minimum terminal width
|
|
1016
|
+
min_terminal_width = 80
|
|
1017
|
+
terminal_width = max(terminal_width, min_terminal_width)
|
|
1018
|
+
|
|
1019
|
+
# Calculate total minimum width needed
|
|
1020
|
+
total_min_width = sum(columns.values())
|
|
1021
|
+
|
|
1022
|
+
# Account for table borders and padding (2 chars per column + 2 for edges)
|
|
1023
|
+
overhead = (len(columns) * 2) + 2
|
|
1024
|
+
available_width = terminal_width - overhead
|
|
1025
|
+
|
|
1026
|
+
# If we have extra space, distribute proportionally
|
|
1027
|
+
if available_width > total_min_width:
|
|
1028
|
+
extra_space = available_width - total_min_width
|
|
1029
|
+
total_weight = sum(columns.values())
|
|
1030
|
+
|
|
1031
|
+
result = {}
|
|
1032
|
+
for col_name, min_width in columns.items():
|
|
1033
|
+
# Distribute extra space based on minimum width proportion
|
|
1034
|
+
proportion = min_width / total_weight
|
|
1035
|
+
extra = int(extra_space * proportion)
|
|
1036
|
+
result[col_name] = min_width + extra
|
|
1037
|
+
return result
|
|
1038
|
+
# Terminal too narrow, use minimum widths
|
|
1039
|
+
return columns.copy()
|
|
1040
|
+
|
|
1041
|
+
def _display_agents_with_source_info(self, agents: List[AgentConfig]) -> None:
|
|
1042
|
+
"""Display agents table with source information and installation status."""
|
|
1043
|
+
from rich.table import Table
|
|
1044
|
+
|
|
1045
|
+
# Get terminal width and calculate dynamic column widths
|
|
1046
|
+
terminal_width = shutil.get_terminal_size().columns
|
|
1047
|
+
min_widths = {
|
|
1048
|
+
"#": 4,
|
|
1049
|
+
"Agent ID": 30,
|
|
1050
|
+
"Name": 20,
|
|
1051
|
+
"Source": 15,
|
|
1052
|
+
"Status": 10,
|
|
1053
|
+
}
|
|
1054
|
+
widths = self._calculate_column_widths(terminal_width, min_widths)
|
|
1055
|
+
|
|
1056
|
+
agents_table = Table(show_header=True, header_style="bold white")
|
|
1057
|
+
agents_table.add_column("#", style="dim", width=widths["#"], no_wrap=True)
|
|
1058
|
+
agents_table.add_column(
|
|
1059
|
+
"Agent ID",
|
|
1060
|
+
style="white",
|
|
1061
|
+
width=widths["Agent ID"],
|
|
1062
|
+
no_wrap=True,
|
|
1063
|
+
overflow="ellipsis",
|
|
1064
|
+
)
|
|
1065
|
+
agents_table.add_column(
|
|
1066
|
+
"Name",
|
|
1067
|
+
style="white",
|
|
1068
|
+
width=widths["Name"],
|
|
1069
|
+
no_wrap=True,
|
|
1070
|
+
overflow="ellipsis",
|
|
1071
|
+
)
|
|
1072
|
+
agents_table.add_column(
|
|
1073
|
+
"Source",
|
|
1074
|
+
style="bright_yellow",
|
|
1075
|
+
width=widths["Source"],
|
|
1076
|
+
no_wrap=True,
|
|
1077
|
+
)
|
|
1078
|
+
agents_table.add_column(
|
|
1079
|
+
"Status", style="white", width=widths["Status"], no_wrap=True
|
|
1080
|
+
)
|
|
1081
|
+
|
|
1082
|
+
for idx, agent in enumerate(agents, 1):
|
|
1083
|
+
# Determine source with repo name
|
|
1084
|
+
source_type = getattr(agent, "source_type", "local")
|
|
1085
|
+
|
|
1086
|
+
if source_type == "remote":
|
|
1087
|
+
# Get repo name from agent metadata
|
|
1088
|
+
source_dict = getattr(agent, "source_dict", {})
|
|
1089
|
+
repo_url = source_dict.get("source", "")
|
|
1090
|
+
|
|
1091
|
+
# Extract repo name from URL
|
|
1092
|
+
if (
|
|
1093
|
+
"bobmatnyc/claude-mpm" in repo_url
|
|
1094
|
+
or "claude-mpm" in repo_url.lower()
|
|
1095
|
+
):
|
|
1096
|
+
source_label = "MPM Agents"
|
|
1097
|
+
elif "/" in repo_url:
|
|
1098
|
+
# Extract last part of org/repo
|
|
1099
|
+
parts = repo_url.rstrip("/").split("/")
|
|
1100
|
+
if len(parts) >= 2:
|
|
1101
|
+
source_label = f"{parts[-2]}/{parts[-1]}"
|
|
1102
|
+
else:
|
|
1103
|
+
source_label = "Community"
|
|
1104
|
+
else:
|
|
1105
|
+
source_label = "Community"
|
|
1106
|
+
else:
|
|
1107
|
+
source_label = "Local"
|
|
1108
|
+
|
|
1109
|
+
# Determine installation status (removed symbols for cleaner look)
|
|
1110
|
+
is_installed = getattr(agent, "is_deployed", False)
|
|
1111
|
+
if is_installed:
|
|
1112
|
+
status = "[green]Installed[/green]"
|
|
1113
|
+
else:
|
|
1114
|
+
status = "Available"
|
|
1115
|
+
|
|
1116
|
+
# Get display name (for remote agents, use display_name instead of agent_id)
|
|
1117
|
+
display_name = getattr(agent, "display_name", agent.name)
|
|
1118
|
+
# Let overflow="ellipsis" handle truncation automatically
|
|
1119
|
+
|
|
1120
|
+
agents_table.add_row(
|
|
1121
|
+
str(idx), agent.name, display_name, source_label, status
|
|
1122
|
+
)
|
|
1123
|
+
|
|
1124
|
+
self.console.print(agents_table)
|
|
1125
|
+
|
|
1126
|
+
# Show installed vs available count
|
|
1127
|
+
installed_count = sum(1 for a in agents if getattr(a, "is_deployed", False))
|
|
1128
|
+
available_count = len(agents) - installed_count
|
|
1129
|
+
self.console.print(
|
|
1130
|
+
f"\n[green]✓ {installed_count} installed[/green] | "
|
|
1131
|
+
f"[dim]{available_count} available[/dim] | "
|
|
1132
|
+
f"[dim]Total: {len(agents)}[/dim]"
|
|
1133
|
+
)
|
|
1134
|
+
|
|
1135
|
+
def _manage_sources(self) -> None:
|
|
1136
|
+
"""Interactive source management."""
|
|
1137
|
+
self.console.print("\n[bold white]═══ Manage Agent Sources ═══[/bold white]\n")
|
|
1138
|
+
self.console.print(
|
|
1139
|
+
"[dim]Use 'claude-mpm agent-source' command to add/remove sources[/dim]"
|
|
1140
|
+
)
|
|
1141
|
+
self.console.print("\nExamples:")
|
|
1142
|
+
self.console.print(" claude-mpm agent-source add <git-url>")
|
|
1143
|
+
self.console.print(" claude-mpm agent-source remove <identifier>")
|
|
1144
|
+
self.console.print(" claude-mpm agent-source list")
|
|
1145
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1146
|
+
|
|
1147
|
+
def _deploy_agents_individual(self, agents: List[AgentConfig]) -> None:
|
|
1148
|
+
"""Manage agent installation state (unified install/remove interface)."""
|
|
1149
|
+
if not agents:
|
|
1150
|
+
self.console.print("[yellow]No agents available[/yellow]")
|
|
1151
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1152
|
+
return
|
|
1153
|
+
|
|
1154
|
+
# Get ALL agents (filter BASE_AGENT but keep deployed agents visible)
|
|
1155
|
+
from claude_mpm.utils.agent_filters import (
|
|
1156
|
+
filter_base_agents,
|
|
1157
|
+
get_deployed_agent_ids,
|
|
1158
|
+
)
|
|
1159
|
+
|
|
1160
|
+
# Filter BASE_AGENT but keep deployed agents visible
|
|
1161
|
+
all_agents = filter_base_agents(
|
|
1162
|
+
[
|
|
1163
|
+
{
|
|
1164
|
+
"agent_id": a.name,
|
|
1165
|
+
"name": a.name,
|
|
1166
|
+
"description": a.description,
|
|
1167
|
+
"deployed": getattr(a, "is_deployed", False),
|
|
1168
|
+
}
|
|
1169
|
+
for a in agents
|
|
1170
|
+
]
|
|
1171
|
+
)
|
|
1172
|
+
|
|
1173
|
+
# Get deployed agent IDs (original state - for calculating final changes)
|
|
1174
|
+
# NOTE: deployed_ids contains LEAF NAMES (e.g., "python-engineer")
|
|
1175
|
+
deployed_ids = get_deployed_agent_ids()
|
|
1176
|
+
|
|
1177
|
+
if not all_agents:
|
|
1178
|
+
self.console.print("[yellow]No agents available[/yellow]")
|
|
1179
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1180
|
+
return
|
|
1181
|
+
|
|
1182
|
+
# Build mapping: leaf name -> full path for deployed agents
|
|
1183
|
+
# This allows comparing deployed_ids (leaf names) with agent.name (full paths)
|
|
1184
|
+
deployed_full_paths = set()
|
|
1185
|
+
for agent in agents:
|
|
1186
|
+
agent_leaf_name = agent.name.split("/")[-1]
|
|
1187
|
+
if agent_leaf_name in deployed_ids:
|
|
1188
|
+
deployed_full_paths.add(agent.name)
|
|
1189
|
+
|
|
1190
|
+
# Track current selection state (starts with deployed full paths, updated after each iteration)
|
|
1191
|
+
current_selection = deployed_full_paths.copy()
|
|
1192
|
+
|
|
1193
|
+
# Loop to allow adjusting selection
|
|
1194
|
+
while True:
|
|
1195
|
+
# Build checkbox choices with pre-selection based on current_selection
|
|
1196
|
+
agent_choices = []
|
|
1197
|
+
agent_map = {} # For lookup after selection
|
|
1198
|
+
|
|
1199
|
+
for agent in agents:
|
|
1200
|
+
if agent.name in {a["agent_id"] for a in all_agents}:
|
|
1201
|
+
display_name = getattr(agent, "display_name", agent.name)
|
|
1202
|
+
|
|
1203
|
+
# Pre-check based on current_selection (full paths)
|
|
1204
|
+
# current_selection contains full paths like "engineer/backend/python-engineer"
|
|
1205
|
+
is_selected = agent.name in current_selection
|
|
1206
|
+
|
|
1207
|
+
# Simple format: "agent/path - Display Name"
|
|
1208
|
+
# Checkbox state (checked/unchecked) indicates installed status
|
|
1209
|
+
choice_text = f"{agent.name}"
|
|
1210
|
+
if display_name and display_name != agent.name:
|
|
1211
|
+
choice_text += f" - {display_name}"
|
|
1212
|
+
|
|
1213
|
+
# Create choice with checked based on current_selection
|
|
1214
|
+
choice = questionary.Choice(
|
|
1215
|
+
title=choice_text, value=agent.name, checked=is_selected
|
|
1216
|
+
)
|
|
1217
|
+
|
|
1218
|
+
agent_choices.append(choice)
|
|
1219
|
+
agent_map[agent.name] = agent
|
|
1220
|
+
|
|
1221
|
+
# Multi-select with pre-selection
|
|
1222
|
+
self.console.print("\n[bold cyan]Manage Agent Installation[/bold cyan]")
|
|
1223
|
+
self.console.print("[dim][✓] Checked = Installed (uncheck to remove)[/dim]")
|
|
1224
|
+
self.console.print(
|
|
1225
|
+
"[dim][ ] Unchecked = Available (check to install)[/dim]"
|
|
1226
|
+
)
|
|
1227
|
+
self.console.print(
|
|
1228
|
+
"[dim]Use arrow keys to navigate, space to toggle, "
|
|
1229
|
+
"Enter to apply changes[/dim]\n"
|
|
1230
|
+
)
|
|
1231
|
+
|
|
1232
|
+
# Monkey-patch questionary symbols for better visibility
|
|
1233
|
+
# Must patch common module directly since it imports constants at load time
|
|
1234
|
+
questionary.prompts.common.INDICATOR_SELECTED = "[✓]"
|
|
1235
|
+
questionary.prompts.common.INDICATOR_UNSELECTED = "[ ]"
|
|
1236
|
+
|
|
1237
|
+
# Pre-selection via checked=True on Choice objects
|
|
1238
|
+
self.logger.debug(
|
|
1239
|
+
"About to show checkbox selection with %d agents", len(agent_choices)
|
|
1240
|
+
)
|
|
1241
|
+
|
|
1242
|
+
try:
|
|
1243
|
+
selected_agent_ids = questionary.checkbox(
|
|
1244
|
+
"Agents:", choices=agent_choices, style=self.QUESTIONARY_STYLE
|
|
1245
|
+
).ask()
|
|
1246
|
+
except Exception as e:
|
|
1247
|
+
# Handle questionary failure (non-TTY, broken pipe, keyboard interrupt, etc.)
|
|
1248
|
+
import sys
|
|
1249
|
+
|
|
1250
|
+
self.logger.error(f"Questionary checkbox failed: {e}", exc_info=True)
|
|
1251
|
+
self.console.print(
|
|
1252
|
+
"[red]Error: Could not display interactive menu[/red]"
|
|
1253
|
+
)
|
|
1254
|
+
self.console.print(f"[dim]Reason: {e}[/dim]")
|
|
1255
|
+
if not sys.stdin.isatty():
|
|
1256
|
+
self.console.print("[dim]Interactive terminal required. Use:[/dim]")
|
|
1257
|
+
self.console.print(
|
|
1258
|
+
"[dim] --list-agents to see available agents[/dim]"
|
|
1259
|
+
)
|
|
1260
|
+
self.console.print(
|
|
1261
|
+
"[dim] --enable-agent/--disable-agent for scripting[/dim]"
|
|
1262
|
+
)
|
|
1263
|
+
else:
|
|
1264
|
+
self.console.print(
|
|
1265
|
+
"[dim]This might be a terminal compatibility issue.[/dim]"
|
|
1266
|
+
)
|
|
1267
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1268
|
+
return
|
|
1269
|
+
|
|
1270
|
+
# Handle Esc OR non-interactive terminal
|
|
1271
|
+
if selected_agent_ids is None:
|
|
1272
|
+
# Check if we're in a non-interactive environment
|
|
1273
|
+
import sys
|
|
1274
|
+
|
|
1275
|
+
if not sys.stdin.isatty():
|
|
1276
|
+
self.console.print(
|
|
1277
|
+
"[red]Error: Interactive terminal required for agent selection[/red]"
|
|
1278
|
+
)
|
|
1279
|
+
self.console.print(
|
|
1280
|
+
"[dim]Use --list-agents to see available agents[/dim]"
|
|
1281
|
+
)
|
|
1282
|
+
self.console.print(
|
|
1283
|
+
"[dim]Use --enable-agent/--disable-agent for non-interactive mode[/dim]"
|
|
1284
|
+
)
|
|
1285
|
+
else:
|
|
1286
|
+
self.console.print("[yellow]No changes made[/yellow]")
|
|
1287
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1288
|
+
return
|
|
1289
|
+
|
|
1290
|
+
# Update current_selection based on user's choices (full paths)
|
|
1291
|
+
current_selection = set(selected_agent_ids)
|
|
1292
|
+
|
|
1293
|
+
# Determine actions based on ORIGINAL deployed state
|
|
1294
|
+
# Compare full paths to full paths (deployed_full_paths was built from deployed_ids)
|
|
1295
|
+
to_deploy = (
|
|
1296
|
+
current_selection - deployed_full_paths
|
|
1297
|
+
) # Selected but not originally deployed
|
|
1298
|
+
to_remove = (
|
|
1299
|
+
deployed_full_paths - current_selection
|
|
1300
|
+
) # Originally deployed but not selected
|
|
1301
|
+
|
|
1302
|
+
if not to_deploy and not to_remove:
|
|
1303
|
+
self.console.print(
|
|
1304
|
+
"[yellow]No changes needed - all selected agents are already installed[/yellow]"
|
|
1305
|
+
)
|
|
1306
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1307
|
+
return
|
|
1308
|
+
|
|
1309
|
+
# Show what will happen
|
|
1310
|
+
self.console.print("\n[bold]Changes to apply:[/bold]")
|
|
1311
|
+
if to_deploy:
|
|
1312
|
+
self.console.print(f"[green]Install {len(to_deploy)} agent(s)[/green]")
|
|
1313
|
+
for agent_id in to_deploy:
|
|
1314
|
+
self.console.print(f" + {agent_id}")
|
|
1315
|
+
if to_remove:
|
|
1316
|
+
self.console.print(f"[red]Remove {len(to_remove)} agent(s)[/red]")
|
|
1317
|
+
for agent_id in to_remove:
|
|
1318
|
+
self.console.print(f" - {agent_id}")
|
|
1319
|
+
|
|
1320
|
+
# Ask user to confirm, adjust, or cancel
|
|
1321
|
+
action = questionary.select(
|
|
1322
|
+
"\nWhat would you like to do?",
|
|
1323
|
+
choices=[
|
|
1324
|
+
questionary.Choice("Apply these changes", value="apply"),
|
|
1325
|
+
questionary.Choice("Adjust selection", value="adjust"),
|
|
1326
|
+
questionary.Choice("Cancel", value="cancel"),
|
|
1327
|
+
],
|
|
1328
|
+
default="apply",
|
|
1329
|
+
style=self.QUESTIONARY_STYLE,
|
|
1330
|
+
).ask()
|
|
1331
|
+
|
|
1332
|
+
if action == "cancel":
|
|
1333
|
+
self.console.print("[yellow]Changes cancelled[/yellow]")
|
|
1334
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1335
|
+
return
|
|
1336
|
+
if action == "adjust":
|
|
1337
|
+
# current_selection is already updated, loop will use it
|
|
1338
|
+
continue
|
|
1339
|
+
|
|
1340
|
+
# Execute changes
|
|
1341
|
+
deploy_success = 0
|
|
1342
|
+
deploy_fail = 0
|
|
1343
|
+
remove_success = 0
|
|
1344
|
+
remove_fail = 0
|
|
1345
|
+
|
|
1346
|
+
# Install new agents
|
|
1347
|
+
for agent_id in to_deploy:
|
|
1348
|
+
agent = agent_map.get(agent_id)
|
|
1349
|
+
if agent and self._deploy_single_agent(agent, show_feedback=False):
|
|
1350
|
+
deploy_success += 1
|
|
1351
|
+
self.console.print(f"[green]✓ Installed: {agent_id}[/green]")
|
|
1352
|
+
else:
|
|
1353
|
+
deploy_fail += 1
|
|
1354
|
+
self.console.print(f"[red]✗ Failed to install: {agent_id}[/red]")
|
|
1355
|
+
|
|
1356
|
+
# Remove agents
|
|
1357
|
+
for agent_id in to_remove:
|
|
1358
|
+
try:
|
|
1359
|
+
import json
|
|
1360
|
+
from pathlib import Path
|
|
1361
|
+
|
|
1362
|
+
# Remove from project, legacy, and user locations
|
|
1363
|
+
project_path = (
|
|
1364
|
+
Path.cwd() / ".claude-mpm" / "agents" / f"{agent_id}.md"
|
|
1365
|
+
)
|
|
1366
|
+
legacy_path = Path.cwd() / ".claude" / "agents" / f"{agent_id}.md"
|
|
1367
|
+
user_path = Path.home() / ".claude" / "agents" / f"{agent_id}.md"
|
|
1368
|
+
|
|
1369
|
+
removed = False
|
|
1370
|
+
for path in [project_path, legacy_path, user_path]:
|
|
1371
|
+
if path.exists():
|
|
1372
|
+
path.unlink()
|
|
1373
|
+
removed = True
|
|
1374
|
+
|
|
1375
|
+
# Also remove from virtual deployment state
|
|
1376
|
+
deployment_state_paths = [
|
|
1377
|
+
Path.cwd() / ".claude" / "agents" / ".mpm_deployment_state",
|
|
1378
|
+
Path.home() / ".claude" / "agents" / ".mpm_deployment_state",
|
|
1379
|
+
]
|
|
1380
|
+
|
|
1381
|
+
for state_path in deployment_state_paths:
|
|
1382
|
+
if state_path.exists():
|
|
1383
|
+
try:
|
|
1384
|
+
with state_path.open() as f:
|
|
1385
|
+
state = json.load(f)
|
|
1386
|
+
|
|
1387
|
+
# Remove agent from deployment state
|
|
1388
|
+
agents = state.get("last_check_results", {}).get(
|
|
1389
|
+
"agents", {}
|
|
1390
|
+
)
|
|
1391
|
+
if agent_id in agents:
|
|
1392
|
+
del agents[agent_id]
|
|
1393
|
+
removed = True
|
|
1394
|
+
|
|
1395
|
+
# Save updated state
|
|
1396
|
+
with state_path.open("w") as f:
|
|
1397
|
+
json.dump(state, f, indent=2)
|
|
1398
|
+
except (json.JSONDecodeError, KeyError) as e:
|
|
1399
|
+
# Log but don't fail - physical removal still counts
|
|
1400
|
+
self.logger.debug(
|
|
1401
|
+
f"Failed to update deployment state at {state_path}: {e}"
|
|
1402
|
+
)
|
|
1403
|
+
|
|
1404
|
+
if removed:
|
|
1405
|
+
remove_success += 1
|
|
1406
|
+
self.console.print(f"[green]✓ Removed: {agent_id}[/green]")
|
|
1407
|
+
else:
|
|
1408
|
+
remove_fail += 1
|
|
1409
|
+
self.console.print(f"[yellow]⚠ Not found: {agent_id}[/yellow]")
|
|
1410
|
+
except Exception as e:
|
|
1411
|
+
remove_fail += 1
|
|
1412
|
+
self.console.print(f"[red]✗ Failed to remove {agent_id}: {e}[/red]")
|
|
1413
|
+
|
|
1414
|
+
# Show summary
|
|
1415
|
+
self.console.print()
|
|
1416
|
+
if deploy_success > 0:
|
|
1417
|
+
self.console.print(
|
|
1418
|
+
f"[green]✓ Installed {deploy_success} agent(s)[/green]"
|
|
1419
|
+
)
|
|
1420
|
+
if deploy_fail > 0:
|
|
1421
|
+
self.console.print(
|
|
1422
|
+
f"[red]✗ Failed to install {deploy_fail} agent(s)[/red]"
|
|
1423
|
+
)
|
|
1424
|
+
if remove_success > 0:
|
|
1425
|
+
self.console.print(
|
|
1426
|
+
f"[green]✓ Removed {remove_success} agent(s)[/green]"
|
|
1427
|
+
)
|
|
1428
|
+
if remove_fail > 0:
|
|
1429
|
+
self.console.print(
|
|
1430
|
+
f"[red]✗ Failed to remove {remove_fail} agent(s)[/red]"
|
|
1431
|
+
)
|
|
1432
|
+
|
|
1433
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1434
|
+
# Exit the loop after successful execution
|
|
1435
|
+
break
|
|
1436
|
+
|
|
1437
|
+
def _deploy_agents_preset(self) -> None:
|
|
1438
|
+
"""Install agents using preset configuration."""
|
|
1439
|
+
try:
|
|
1440
|
+
from claude_mpm.services.agents.agent_preset_service import (
|
|
1441
|
+
AgentPresetService,
|
|
1442
|
+
)
|
|
1443
|
+
from claude_mpm.services.agents.git_source_manager import GitSourceManager
|
|
1444
|
+
|
|
1445
|
+
source_manager = GitSourceManager()
|
|
1446
|
+
preset_service = AgentPresetService(source_manager)
|
|
1447
|
+
|
|
1448
|
+
presets = preset_service.list_presets()
|
|
1449
|
+
|
|
1450
|
+
if not presets:
|
|
1451
|
+
self.console.print("[yellow]No presets available[/yellow]")
|
|
1452
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1453
|
+
return
|
|
1454
|
+
|
|
1455
|
+
self.console.print("\n[bold white]═══ Available Presets ═══[/bold white]\n")
|
|
1456
|
+
for idx, preset in enumerate(presets, 1):
|
|
1457
|
+
self.console.print(f" {idx}. [white]{preset['name']}[/white]")
|
|
1458
|
+
self.console.print(f" {preset['description']}")
|
|
1459
|
+
self.console.print(f" [dim]Agents: {len(preset['agents'])}[/dim]\n")
|
|
1460
|
+
|
|
1461
|
+
selection = Prompt.ask("\nEnter preset number (or 'c' to cancel)")
|
|
1462
|
+
if selection.lower() == "c":
|
|
1463
|
+
return
|
|
1464
|
+
|
|
1465
|
+
idx = int(selection) - 1
|
|
1466
|
+
if 0 <= idx < len(presets):
|
|
1467
|
+
preset_name = presets[idx]["name"]
|
|
1468
|
+
|
|
1469
|
+
# Resolve and deploy preset
|
|
1470
|
+
resolution = preset_service.resolve_agents(preset_name)
|
|
1471
|
+
|
|
1472
|
+
if resolution.get("missing_agents"):
|
|
1473
|
+
self.console.print(
|
|
1474
|
+
f"[red]Missing agents: {len(resolution['missing_agents'])}[/red]"
|
|
1475
|
+
)
|
|
1476
|
+
for agent_id in resolution["missing_agents"]:
|
|
1477
|
+
self.console.print(f" • {agent_id}")
|
|
1478
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1479
|
+
return
|
|
1480
|
+
|
|
1481
|
+
# Confirm installation
|
|
1482
|
+
self.console.print(
|
|
1483
|
+
f"\n[bold]Preset '{preset_name}' includes {len(resolution['agents'])} agents[/bold]"
|
|
1484
|
+
)
|
|
1485
|
+
if Confirm.ask("Install all agents?", default=True):
|
|
1486
|
+
installed = 0
|
|
1487
|
+
for agent in resolution["agents"]:
|
|
1488
|
+
# Convert dict to AgentConfig-like object for installation
|
|
1489
|
+
agent_config = AgentConfig(
|
|
1490
|
+
name=agent.get("agent_id", "unknown"),
|
|
1491
|
+
description=agent.get("metadata", {}).get(
|
|
1492
|
+
"description", ""
|
|
1493
|
+
),
|
|
1494
|
+
dependencies=[],
|
|
1495
|
+
)
|
|
1496
|
+
agent_config.source_dict = agent
|
|
1497
|
+
agent_config.full_agent_id = agent.get("agent_id", "unknown")
|
|
1498
|
+
|
|
1499
|
+
if self._deploy_single_agent(agent_config, show_feedback=False):
|
|
1500
|
+
installed += 1
|
|
1501
|
+
|
|
1502
|
+
self.console.print(
|
|
1503
|
+
f"\n[green]✓ Installed {installed}/{len(resolution['agents'])} agents[/green]"
|
|
1504
|
+
)
|
|
1505
|
+
|
|
1506
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1507
|
+
else:
|
|
1508
|
+
self.console.print("[red]Invalid selection[/red]")
|
|
1509
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1510
|
+
|
|
1511
|
+
except Exception as e:
|
|
1512
|
+
self.console.print(f"[red]Error installing preset: {e}[/red]")
|
|
1513
|
+
self.logger.error(f"Preset installation failed: {e}", exc_info=True)
|
|
1514
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1515
|
+
|
|
1516
|
+
def _deploy_single_agent(
|
|
1517
|
+
self, agent: AgentConfig, show_feedback: bool = True
|
|
1518
|
+
) -> bool:
|
|
1519
|
+
"""Install a single agent to the appropriate location."""
|
|
1520
|
+
try:
|
|
1521
|
+
# Check if this is a remote agent with source_dict
|
|
1522
|
+
source_dict = getattr(agent, "source_dict", None)
|
|
1523
|
+
full_agent_id = getattr(agent, "full_agent_id", agent.name)
|
|
1524
|
+
|
|
1525
|
+
if source_dict:
|
|
1526
|
+
# Deploy remote agent using its source file
|
|
1527
|
+
source_file = Path(source_dict.get("source_file", ""))
|
|
1528
|
+
if not source_file.exists():
|
|
1529
|
+
if show_feedback:
|
|
1530
|
+
self.console.print(
|
|
1531
|
+
f"[red]✗ Source file not found: {source_file}[/red]"
|
|
1532
|
+
)
|
|
1533
|
+
return False
|
|
1534
|
+
|
|
1535
|
+
# Determine target file name (use leaf name from hierarchical ID)
|
|
1536
|
+
if "/" in full_agent_id:
|
|
1537
|
+
target_name = full_agent_id.split("/")[-1] + ".md"
|
|
1538
|
+
else:
|
|
1539
|
+
target_name = full_agent_id + ".md"
|
|
1540
|
+
|
|
1541
|
+
# Deploy to user-level agents directory
|
|
1542
|
+
target_dir = Path.home() / ".claude" / "agents"
|
|
1543
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
1544
|
+
target_file = target_dir / target_name
|
|
1545
|
+
|
|
1546
|
+
if show_feedback:
|
|
1547
|
+
self.console.print(
|
|
1548
|
+
f"\n[white]Installing {full_agent_id}...[/white]"
|
|
1549
|
+
)
|
|
1550
|
+
|
|
1551
|
+
# Copy the agent file
|
|
1552
|
+
import shutil
|
|
1553
|
+
|
|
1554
|
+
shutil.copy2(source_file, target_file)
|
|
1555
|
+
|
|
1556
|
+
if show_feedback:
|
|
1557
|
+
self.console.print(
|
|
1558
|
+
f"[green]✓ Successfully installed {full_agent_id} to {target_file}[/green]"
|
|
1559
|
+
)
|
|
1560
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1561
|
+
|
|
1562
|
+
return True
|
|
1563
|
+
# Legacy local template installation (not implemented here)
|
|
1564
|
+
if show_feedback:
|
|
1565
|
+
self.console.print(
|
|
1566
|
+
"[yellow]Local template installation not yet implemented[/yellow]"
|
|
1567
|
+
)
|
|
1568
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1569
|
+
return False
|
|
1570
|
+
|
|
1571
|
+
except Exception as e:
|
|
1572
|
+
if show_feedback:
|
|
1573
|
+
self.console.print(f"[red]Error installing agent: {e}[/red]")
|
|
1574
|
+
self.logger.error(f"Agent installation failed: {e}", exc_info=True)
|
|
1575
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1576
|
+
return False
|
|
1577
|
+
|
|
1578
|
+
def _remove_agents(self, agents: List[AgentConfig]) -> None:
|
|
1579
|
+
"""Remove installed agents."""
|
|
1580
|
+
# Filter to installed agents only
|
|
1581
|
+
installed = [a for a in agents if getattr(a, "is_deployed", False)]
|
|
1582
|
+
|
|
1583
|
+
if not installed:
|
|
1584
|
+
self.console.print("[yellow]No agents are currently installed[/yellow]")
|
|
1585
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1586
|
+
return
|
|
1587
|
+
|
|
1588
|
+
self.console.print(f"\n[bold]Installed agents ({len(installed)}):[/bold]")
|
|
1589
|
+
for idx, agent in enumerate(installed, 1):
|
|
1590
|
+
display_name = getattr(agent, "display_name", agent.name)
|
|
1591
|
+
self.console.print(f" {idx}. {agent.name} - {display_name}")
|
|
1592
|
+
|
|
1593
|
+
selection = Prompt.ask("\nEnter agent number to remove (or 'c' to cancel)")
|
|
1594
|
+
if selection.lower() == "c":
|
|
1595
|
+
return
|
|
1596
|
+
|
|
1597
|
+
try:
|
|
1598
|
+
idx = int(selection) - 1
|
|
1599
|
+
if 0 <= idx < len(installed):
|
|
1600
|
+
agent = installed[idx]
|
|
1601
|
+
full_agent_id = getattr(agent, "full_agent_id", agent.name)
|
|
1602
|
+
|
|
1603
|
+
# Determine possible file names (hierarchical and leaf)
|
|
1604
|
+
file_names = [f"{full_agent_id}.md"]
|
|
1605
|
+
if "/" in full_agent_id:
|
|
1606
|
+
leaf_name = full_agent_id.split("/")[-1]
|
|
1607
|
+
file_names.append(f"{leaf_name}.md")
|
|
1608
|
+
|
|
1609
|
+
# Remove from both project and user directories
|
|
1610
|
+
removed = False
|
|
1611
|
+
project_agent_dir = Path.cwd() / ".claude-mpm" / "agents"
|
|
1612
|
+
user_agent_dir = Path.home() / ".claude" / "agents"
|
|
1613
|
+
|
|
1614
|
+
for file_name in file_names:
|
|
1615
|
+
project_file = project_agent_dir / file_name
|
|
1616
|
+
user_file = user_agent_dir / file_name
|
|
1617
|
+
|
|
1618
|
+
if project_file.exists():
|
|
1619
|
+
project_file.unlink()
|
|
1620
|
+
removed = True
|
|
1621
|
+
self.console.print(f"[green]✓ Removed {project_file}[/green]")
|
|
1622
|
+
|
|
1623
|
+
if user_file.exists():
|
|
1624
|
+
user_file.unlink()
|
|
1625
|
+
removed = True
|
|
1626
|
+
self.console.print(f"[green]✓ Removed {user_file}[/green]")
|
|
1627
|
+
|
|
1628
|
+
if removed:
|
|
1629
|
+
self.console.print(
|
|
1630
|
+
f"[green]✓ Successfully removed {full_agent_id}[/green]"
|
|
1631
|
+
)
|
|
1632
|
+
else:
|
|
1633
|
+
self.console.print("[yellow]Agent files not found[/yellow]")
|
|
1634
|
+
|
|
1635
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1636
|
+
else:
|
|
1637
|
+
self.console.print("[red]Invalid selection[/red]")
|
|
1638
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1639
|
+
|
|
1640
|
+
except (ValueError, IndexError):
|
|
1641
|
+
self.console.print("[red]Invalid selection[/red]")
|
|
1642
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1643
|
+
|
|
1644
|
+
def _view_agent_details_enhanced(self, agents: List[AgentConfig]) -> None:
|
|
1645
|
+
"""View detailed agent information with enhanced remote agent details."""
|
|
1646
|
+
if not agents:
|
|
1647
|
+
self.console.print("[yellow]No agents available[/yellow]")
|
|
1648
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1649
|
+
return
|
|
1650
|
+
|
|
1651
|
+
self.console.print(f"\n[bold]Available agents ({len(agents)}):[/bold]")
|
|
1652
|
+
for idx, agent in enumerate(agents, 1):
|
|
1653
|
+
display_name = getattr(agent, "display_name", agent.name)
|
|
1654
|
+
self.console.print(f" {idx}. {agent.name} - {display_name}")
|
|
1655
|
+
|
|
1656
|
+
selection = Prompt.ask("\nEnter agent number to view (or 'c' to cancel)")
|
|
1657
|
+
if selection.lower() == "c":
|
|
1658
|
+
return
|
|
1659
|
+
|
|
1660
|
+
try:
|
|
1661
|
+
idx = int(selection) - 1
|
|
1662
|
+
if 0 <= idx < len(agents):
|
|
1663
|
+
agent = agents[idx]
|
|
1664
|
+
|
|
1665
|
+
self.console.clear()
|
|
1666
|
+
self.console.print("\n[bold white]═══ Agent Details ═══[/bold white]\n")
|
|
1667
|
+
|
|
1668
|
+
# Basic info
|
|
1669
|
+
self.console.print(f"[bold]ID:[/bold] {agent.name}")
|
|
1670
|
+
display_name = getattr(agent, "display_name", "N/A")
|
|
1671
|
+
self.console.print(f"[bold]Name:[/bold] {display_name}")
|
|
1672
|
+
self.console.print(f"[bold]Description:[/bold] {agent.description}")
|
|
1673
|
+
|
|
1674
|
+
# Source info
|
|
1675
|
+
source_type = getattr(agent, "source_type", "local")
|
|
1676
|
+
self.console.print(f"[bold]Source Type:[/bold] {source_type}")
|
|
1677
|
+
|
|
1678
|
+
if source_type == "remote":
|
|
1679
|
+
source_dict = getattr(agent, "source_dict", {})
|
|
1680
|
+
category = source_dict.get("category", "N/A")
|
|
1681
|
+
source = source_dict.get("source", "N/A")
|
|
1682
|
+
version = source_dict.get("version", "N/A")
|
|
1683
|
+
|
|
1684
|
+
self.console.print(f"[bold]Category:[/bold] {category}")
|
|
1685
|
+
self.console.print(f"[bold]Source:[/bold] {source}")
|
|
1686
|
+
self.console.print(f"[bold]Version:[/bold] {version[:16]}...")
|
|
1687
|
+
|
|
1688
|
+
# Installation status
|
|
1689
|
+
is_installed = getattr(agent, "is_deployed", False)
|
|
1690
|
+
status = "Installed" if is_installed else "Available"
|
|
1691
|
+
self.console.print(f"[bold]Status:[/bold] {status}")
|
|
1692
|
+
|
|
1693
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1694
|
+
else:
|
|
1695
|
+
self.console.print("[red]Invalid selection[/red]")
|
|
1696
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1697
|
+
|
|
1698
|
+
except (ValueError, IndexError):
|
|
1699
|
+
self.console.print("[red]Invalid selection[/red]")
|
|
1700
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1701
|
+
|
|
812
1702
|
|
|
813
1703
|
def manage_configure(args) -> int:
|
|
814
1704
|
"""Main entry point for configuration management command.
|