claude-mpm 4.20.3__py3-none-any.whl → 5.1.8__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 +35 -6
- claude_mpm/agents/OUTPUT_STYLE.md +3 -48
- claude_mpm/agents/PM_INSTRUCTIONS.md +1241 -667
- claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
- 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 +1 -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 +959 -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 +924 -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/__init__.py +73 -0
- claude_mpm/cli/commands/mpm_init/core.py +573 -0
- claude_mpm/cli/commands/mpm_init/display.py +341 -0
- claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
- claude_mpm/cli/commands/mpm_init/modes.py +397 -0
- claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
- claude_mpm/cli/commands/mpm_init_cli.py +396 -0
- claude_mpm/cli/commands/mpm_init_handler.py +67 -1
- 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 +835 -44
- 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 +256 -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/mpm_init_parser.py +42 -0
- 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 +17 -2
- claude_mpm/commands/mpm-init.md +28 -3
- claude_mpm/commands/mpm-monitor.md +9 -0
- claude_mpm/commands/mpm-postmortem.md +123 -0
- claude_mpm/commands/mpm-session-resume.md +381 -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 +11 -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/interfaces.py +56 -1
- claude_mpm/core/logger.py +3 -1
- claude_mpm/core/oneshot_session.py +110 -8
- 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_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/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/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/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
- claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
- claude_mpm/hooks/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/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 +115 -15
- 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 +363 -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 +504 -0
- claude_mpm/services/cli/session_resume_helper.py +36 -16
- 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 +31 -11
- claude_mpm/services/core/interfaces/__init__.py +1 -3
- claude_mpm/services/core/interfaces/health.py +1 -4
- claude_mpm/services/core/interfaces.py +56 -1
- claude_mpm/services/core/models/__init__.py +2 -11
- claude_mpm/services/core/models/agent_config.py +3 -0
- claude_mpm/services/core/models/process.py +4 -0
- 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/diagnostics/models.py +21 -0
- claude_mpm/services/event_bus/direct_relay.py +3 -3
- claude_mpm/services/event_bus/event_bus.py +36 -3
- claude_mpm/services/event_bus/relay.py +23 -7
- 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 +5 -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/auto_configure.py +31 -25
- claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
- claude_mpm/services/mcp_gateway/core/process_pool.py +41 -26
- 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/external_mcp_services.py +26 -21
- 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/failure_tracker.py +19 -4
- 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/__init__.py +3 -3
- claude_mpm/skills/agent_skills_injector.py +42 -49
- claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
- claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +17 -10
- claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +92 -39
- claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +13 -12
- claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +5 -3
- claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +19 -12
- claude_mpm/skills/bundled/performance-profiling.md +6 -0
- claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +6 -6
- claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +13 -9
- claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +8 -8
- claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +37 -15
- claude_mpm/skills/skills_registry.py +44 -48
- claude_mpm/skills/skills_service.py +117 -108
- 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/__init__.py +45 -0
- claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
- claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
- claude_mpm/tools/code_tree_analyzer/core.py +380 -0
- claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
- claude_mpm/tools/code_tree_analyzer/events.py +168 -0
- claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
- claude_mpm/tools/code_tree_analyzer/models.py +39 -0
- claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
- claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
- claude_mpm/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.20.3.dist-info → claude_mpm-5.1.8.dist-info}/METADATA +496 -65
- {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/RECORD +328 -416
- 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 -281
- 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/cli/commands/mpm_init.py +0 -2093
- 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 -75
- claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -184
- claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -107
- claude_mpm/skills/bundled/collaboration/requesting-code-review/code-reviewer.md +0 -146
- claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -118
- claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -177
- 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 -175
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +0 -213
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -314
- claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -227
- claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -74
- claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -32
- 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 -328
- 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/skill-creator/SKILL.md +0 -209
- claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -123
- 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 -304
- claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -96
- claude_mpm/tools/code_tree_analyzer.py +0 -1825
- /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.20.3.dist-info → claude_mpm-5.1.8.dist-info}/WHEEL +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/top_level.txt +0 -0
|
@@ -3,13 +3,18 @@ Skills command implementation for claude-mpm.
|
|
|
3
3
|
|
|
4
4
|
WHY: This module provides CLI commands for managing Claude Code skills,
|
|
5
5
|
exposing SkillsService functionality for skill discovery, deployment, validation,
|
|
6
|
-
updates, and configuration.
|
|
6
|
+
updates, and configuration. Also provides GitHub skills deployment via SkillsDeployer.
|
|
7
7
|
|
|
8
8
|
DESIGN DECISIONS:
|
|
9
9
|
- Use BaseCommand pattern for consistency with other CLI commands
|
|
10
10
|
- Rich output formatting for user-friendly display
|
|
11
11
|
- Graceful error handling with informative messages
|
|
12
12
|
- Support for verbose output and structured formats
|
|
13
|
+
- Dual service approach: SkillsService for bundled, SkillsDeployer for GitHub
|
|
14
|
+
|
|
15
|
+
ARCHITECTURE:
|
|
16
|
+
- SkillsService: Manages bundled skills (in project .claude/skills/)
|
|
17
|
+
- SkillsDeployer: Downloads from GitHub to ~/.claude/skills/ for Claude Code
|
|
13
18
|
"""
|
|
14
19
|
|
|
15
20
|
import os
|
|
@@ -19,8 +24,10 @@ from typing import Optional
|
|
|
19
24
|
from rich.console import Console
|
|
20
25
|
from rich.markdown import Markdown
|
|
21
26
|
from rich.panel import Panel
|
|
27
|
+
from rich.table import Table
|
|
22
28
|
|
|
23
29
|
from ...constants import SkillsCommands
|
|
30
|
+
from ...services.skills_deployer import SkillsDeployerService
|
|
24
31
|
from ...skills.skills_service import SkillsService
|
|
25
32
|
from ..shared import BaseCommand, CommandResult
|
|
26
33
|
|
|
@@ -33,6 +40,7 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
33
40
|
def __init__(self):
|
|
34
41
|
super().__init__("skills")
|
|
35
42
|
self._skills_service = None
|
|
43
|
+
self._skills_deployer = None
|
|
36
44
|
|
|
37
45
|
@property
|
|
38
46
|
def skills_service(self) -> SkillsService:
|
|
@@ -41,6 +49,13 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
41
49
|
self._skills_service = SkillsService()
|
|
42
50
|
return self._skills_service
|
|
43
51
|
|
|
52
|
+
@property
|
|
53
|
+
def skills_deployer(self) -> SkillsDeployerService:
|
|
54
|
+
"""Get skills deployer instance (lazy loaded)."""
|
|
55
|
+
if self._skills_deployer is None:
|
|
56
|
+
self._skills_deployer = SkillsDeployerService()
|
|
57
|
+
return self._skills_deployer
|
|
58
|
+
|
|
44
59
|
def validate_args(self, args) -> Optional[str]:
|
|
45
60
|
"""Validate command arguments."""
|
|
46
61
|
# Most skills commands are optional, basic validation
|
|
@@ -68,6 +83,19 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
68
83
|
SkillsCommands.UPDATE.value: self._update_skills,
|
|
69
84
|
SkillsCommands.INFO.value: self._show_skill_info,
|
|
70
85
|
SkillsCommands.CONFIG.value: self._manage_config,
|
|
86
|
+
SkillsCommands.CONFIGURE.value: self._configure_skills,
|
|
87
|
+
# GitHub deployment commands
|
|
88
|
+
SkillsCommands.DEPLOY_FROM_GITHUB.value: self._deploy_from_github,
|
|
89
|
+
SkillsCommands.LIST_AVAILABLE.value: self._list_available_github_skills,
|
|
90
|
+
SkillsCommands.CHECK_DEPLOYED.value: self._check_deployed_skills,
|
|
91
|
+
SkillsCommands.REMOVE.value: self._remove_skills,
|
|
92
|
+
# Collection management commands
|
|
93
|
+
SkillsCommands.COLLECTION_LIST.value: self._collection_list,
|
|
94
|
+
SkillsCommands.COLLECTION_ADD.value: self._collection_add,
|
|
95
|
+
SkillsCommands.COLLECTION_REMOVE.value: self._collection_remove,
|
|
96
|
+
SkillsCommands.COLLECTION_ENABLE.value: self._collection_enable,
|
|
97
|
+
SkillsCommands.COLLECTION_DISABLE.value: self._collection_disable,
|
|
98
|
+
SkillsCommands.COLLECTION_SET_DEFAULT.value: self._collection_set_default,
|
|
71
99
|
}
|
|
72
100
|
|
|
73
101
|
handler = command_map.get(args.skills_command)
|
|
@@ -83,6 +111,7 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
83
111
|
self.logger.error(f"Skills command failed: {e}")
|
|
84
112
|
if hasattr(args, "debug") and args.debug:
|
|
85
113
|
import traceback
|
|
114
|
+
|
|
86
115
|
traceback.print_exc()
|
|
87
116
|
return CommandResult(
|
|
88
117
|
success=False, message=f"Skills command failed: {e}", exit_code=1
|
|
@@ -94,10 +123,14 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
94
123
|
# Get skills based on filter
|
|
95
124
|
if hasattr(args, "agent") and args.agent:
|
|
96
125
|
skills = self.skills_service.get_skills_for_agent(args.agent)
|
|
97
|
-
console.print(
|
|
126
|
+
console.print(
|
|
127
|
+
f"\n[bold cyan]Skills for agent '{args.agent}':[/bold cyan]\n"
|
|
128
|
+
)
|
|
98
129
|
|
|
99
130
|
if not skills:
|
|
100
|
-
console.print(
|
|
131
|
+
console.print(
|
|
132
|
+
f"[yellow]No skills found for agent '{args.agent}'[/yellow]"
|
|
133
|
+
)
|
|
101
134
|
return CommandResult(success=True, exit_code=0)
|
|
102
135
|
|
|
103
136
|
for skill_name in skills:
|
|
@@ -105,7 +138,11 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
105
138
|
skill_info = self._get_skill_metadata(skill_name)
|
|
106
139
|
if skill_info:
|
|
107
140
|
console.print(f" [green]•[/green] {skill_name}")
|
|
108
|
-
if
|
|
141
|
+
if (
|
|
142
|
+
hasattr(args, "verbose")
|
|
143
|
+
and args.verbose
|
|
144
|
+
and skill_info.get("description")
|
|
145
|
+
):
|
|
109
146
|
console.print(f" {skill_info['description']}")
|
|
110
147
|
else:
|
|
111
148
|
console.print(f" [green]•[/green] {skill_name}")
|
|
@@ -117,7 +154,9 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
117
154
|
# Filter by category if specified
|
|
118
155
|
if hasattr(args, "category") and args.category:
|
|
119
156
|
skills = [s for s in skills if s.get("category") == args.category]
|
|
120
|
-
console.print(
|
|
157
|
+
console.print(
|
|
158
|
+
f"\n[bold cyan]Skills in category '{args.category}':[/bold cyan]\n"
|
|
159
|
+
)
|
|
121
160
|
else:
|
|
122
161
|
console.print("\n[bold cyan]Available Skills:[/bold cyan]\n")
|
|
123
162
|
|
|
@@ -136,7 +175,9 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
136
175
|
# Display by category
|
|
137
176
|
for category, category_skills in sorted(by_category.items()):
|
|
138
177
|
console.print(f"[bold yellow]{category}[/bold yellow]")
|
|
139
|
-
for skill in sorted(
|
|
178
|
+
for skill in sorted(
|
|
179
|
+
category_skills, key=lambda s: s.get("name", "")
|
|
180
|
+
):
|
|
140
181
|
name = skill.get("name", "unknown")
|
|
141
182
|
console.print(f" [green]•[/green] {name}")
|
|
142
183
|
|
|
@@ -155,46 +196,109 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
155
196
|
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
156
197
|
|
|
157
198
|
def _deploy_skills(self, args) -> CommandResult:
|
|
158
|
-
"""Deploy
|
|
199
|
+
"""Deploy skills using two-phase sync: cache → deploy.
|
|
200
|
+
|
|
201
|
+
Phase 3 Integration (1M-486): Uses Git skill source manager for deployment.
|
|
202
|
+
- Phase 1: Sync skills to ~/.claude-mpm/cache/skills/ (if needed)
|
|
203
|
+
- Phase 2: Deploy from cache to project .claude-mpm/skills/
|
|
204
|
+
|
|
205
|
+
This replaces bundled skill deployment with a multi-project
|
|
206
|
+
architecture where one cache serves multiple project deployments.
|
|
207
|
+
"""
|
|
159
208
|
try:
|
|
209
|
+
from pathlib import Path
|
|
210
|
+
|
|
211
|
+
from ...config.skill_sources import SkillSourceConfiguration
|
|
212
|
+
from ...services.skills.git_skill_source_manager import (
|
|
213
|
+
GitSkillSourceManager,
|
|
214
|
+
)
|
|
215
|
+
|
|
160
216
|
force = getattr(args, "force", False)
|
|
161
217
|
specific_skills = getattr(args, "skills", None)
|
|
162
218
|
|
|
163
219
|
console.print("\n[bold cyan]Deploying skills...[/bold cyan]\n")
|
|
164
220
|
|
|
165
|
-
|
|
221
|
+
# Initialize git skill source manager
|
|
222
|
+
config = SkillSourceConfiguration.load()
|
|
223
|
+
git_skill_manager = GitSkillSourceManager(config)
|
|
224
|
+
project_dir = Path.cwd()
|
|
225
|
+
|
|
226
|
+
# Phase 1: Sync skills to cache
|
|
227
|
+
console.print("[dim]Phase 1: Syncing skills to cache...[/dim]")
|
|
228
|
+
sync_results = git_skill_manager.sync_all_sources(force=force)
|
|
229
|
+
|
|
230
|
+
synced_count = sum(
|
|
231
|
+
1 for result in sync_results.values() if result.get("synced")
|
|
232
|
+
)
|
|
233
|
+
console.print(f"[dim]Synced {synced_count} skill source(s)[/dim]\n")
|
|
234
|
+
|
|
235
|
+
# Phase 2: Deploy from cache to project
|
|
236
|
+
console.print("[dim]Phase 2: Deploying from cache to project...[/dim]\n")
|
|
237
|
+
deploy_result = git_skill_manager.deploy_skills_to_project(
|
|
238
|
+
project_dir=project_dir,
|
|
239
|
+
skill_list=specific_skills,
|
|
166
240
|
force=force,
|
|
167
|
-
skill_names=specific_skills
|
|
168
241
|
)
|
|
169
242
|
|
|
170
243
|
# Display results
|
|
171
|
-
if
|
|
172
|
-
console.print(
|
|
173
|
-
|
|
244
|
+
if deploy_result["deployed"]:
|
|
245
|
+
console.print(
|
|
246
|
+
f"[green]✓ Deployed {len(deploy_result['deployed'])} skill(s):[/green]"
|
|
247
|
+
)
|
|
248
|
+
for skill in deploy_result["deployed"]:
|
|
249
|
+
console.print(f" • {skill}")
|
|
250
|
+
console.print()
|
|
251
|
+
|
|
252
|
+
if deploy_result["updated"]:
|
|
253
|
+
console.print(
|
|
254
|
+
f"[green]⟳ Updated {len(deploy_result['updated'])} skill(s):[/green]"
|
|
255
|
+
)
|
|
256
|
+
for skill in deploy_result["updated"]:
|
|
174
257
|
console.print(f" • {skill}")
|
|
175
258
|
console.print()
|
|
176
259
|
|
|
177
|
-
if
|
|
178
|
-
console.print(
|
|
179
|
-
|
|
260
|
+
if deploy_result["skipped"]:
|
|
261
|
+
console.print(
|
|
262
|
+
f"[yellow]⊘ Skipped {len(deploy_result['skipped'])} skill(s) (already up-to-date):[/yellow]"
|
|
263
|
+
)
|
|
264
|
+
for skill in deploy_result["skipped"]:
|
|
180
265
|
console.print(f" • {skill}")
|
|
181
266
|
console.print("[dim]Use --force to redeploy[/dim]\n")
|
|
182
267
|
|
|
183
|
-
if
|
|
184
|
-
console.print(
|
|
185
|
-
|
|
186
|
-
|
|
268
|
+
if deploy_result["failed"]:
|
|
269
|
+
console.print(
|
|
270
|
+
f"[red]✗ Failed to deploy {len(deploy_result['failed'])} skill(s):[/red]"
|
|
271
|
+
)
|
|
272
|
+
for skill in deploy_result["failed"]:
|
|
273
|
+
console.print(f" • {skill}")
|
|
187
274
|
console.print()
|
|
188
275
|
|
|
189
276
|
# Summary
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
277
|
+
success_count = len(deploy_result["deployed"]) + len(
|
|
278
|
+
deploy_result["updated"]
|
|
279
|
+
)
|
|
280
|
+
total = (
|
|
281
|
+
success_count
|
|
282
|
+
+ len(deploy_result["skipped"])
|
|
283
|
+
+ len(deploy_result["failed"])
|
|
284
|
+
)
|
|
285
|
+
console.print(
|
|
286
|
+
f"[bold]Summary:[/bold] {success_count} deployed/updated, "
|
|
287
|
+
f"{len(deploy_result['skipped'])} skipped, "
|
|
288
|
+
f"{len(deploy_result['failed'])} errors (Total: {total})\n"
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
console.print(
|
|
292
|
+
f"[dim]Deployment directory: {deploy_result['deployment_dir']}[/dim]\n"
|
|
293
|
+
)
|
|
194
294
|
|
|
195
295
|
# Exit with error if any deployments failed
|
|
196
|
-
exit_code = 1 if
|
|
197
|
-
return CommandResult(
|
|
296
|
+
exit_code = 1 if deploy_result["failed"] else 0
|
|
297
|
+
return CommandResult(
|
|
298
|
+
success=not deploy_result["failed"],
|
|
299
|
+
message=f"Deployed {success_count} skills from cache",
|
|
300
|
+
exit_code=exit_code,
|
|
301
|
+
)
|
|
198
302
|
|
|
199
303
|
except Exception as e:
|
|
200
304
|
console.print(f"[red]Error deploying skills: {e}[/red]")
|
|
@@ -206,7 +310,9 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
206
310
|
skill_name = args.skill_name
|
|
207
311
|
strict = getattr(args, "strict", False)
|
|
208
312
|
|
|
209
|
-
console.print(
|
|
313
|
+
console.print(
|
|
314
|
+
f"\n[bold cyan]Validating skill '{skill_name}'...[/bold cyan]\n"
|
|
315
|
+
)
|
|
210
316
|
|
|
211
317
|
result = self.skills_service.validate_skill(skill_name)
|
|
212
318
|
|
|
@@ -214,14 +320,18 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
214
320
|
console.print(f"[green]✓ {skill_name} is valid[/green]\n")
|
|
215
321
|
|
|
216
322
|
if result.get("warnings"):
|
|
217
|
-
console.print(
|
|
323
|
+
console.print(
|
|
324
|
+
f"[yellow]Warnings ({len(result['warnings'])}):[/yellow]"
|
|
325
|
+
)
|
|
218
326
|
for warning in result["warnings"]:
|
|
219
327
|
console.print(f" • {warning}")
|
|
220
328
|
console.print()
|
|
221
329
|
|
|
222
330
|
# Treat warnings as errors in strict mode
|
|
223
331
|
if strict:
|
|
224
|
-
console.print(
|
|
332
|
+
console.print(
|
|
333
|
+
"[red]Strict mode: treating warnings as errors[/red]"
|
|
334
|
+
)
|
|
225
335
|
return CommandResult(success=False, exit_code=1)
|
|
226
336
|
|
|
227
337
|
return CommandResult(success=True, exit_code=0)
|
|
@@ -259,7 +369,9 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
259
369
|
return CommandResult(success=True, exit_code=0)
|
|
260
370
|
|
|
261
371
|
# Display available updates
|
|
262
|
-
console.print(
|
|
372
|
+
console.print(
|
|
373
|
+
f"[yellow]Updates available for {len(result['updates_available'])} skill(s):[/yellow]"
|
|
374
|
+
)
|
|
263
375
|
for update_info in result["updates_available"]:
|
|
264
376
|
skill_name = update_info["skill"]
|
|
265
377
|
current = update_info["current_version"]
|
|
@@ -268,7 +380,9 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
268
380
|
console.print()
|
|
269
381
|
|
|
270
382
|
if check_only:
|
|
271
|
-
console.print(
|
|
383
|
+
console.print(
|
|
384
|
+
"[dim]Run without --check-only to install updates[/dim]\n"
|
|
385
|
+
)
|
|
272
386
|
return CommandResult(success=True, exit_code=0)
|
|
273
387
|
|
|
274
388
|
# Install updates
|
|
@@ -278,16 +392,22 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
278
392
|
)
|
|
279
393
|
|
|
280
394
|
if install_result["updated"]:
|
|
281
|
-
console.print(
|
|
395
|
+
console.print(
|
|
396
|
+
f"[green]✓ Updated {len(install_result['updated'])} skill(s)[/green]\n"
|
|
397
|
+
)
|
|
282
398
|
|
|
283
399
|
if install_result.get("errors"):
|
|
284
|
-
console.print(
|
|
400
|
+
console.print(
|
|
401
|
+
f"[red]✗ Failed to update {len(install_result['errors'])} skill(s)[/red]"
|
|
402
|
+
)
|
|
285
403
|
for skill, error in install_result["errors"].items():
|
|
286
404
|
console.print(f" • {skill}: {error}")
|
|
287
405
|
console.print()
|
|
288
406
|
|
|
289
407
|
exit_code = 1 if install_result.get("errors") else 0
|
|
290
|
-
return CommandResult(
|
|
408
|
+
return CommandResult(
|
|
409
|
+
success=not install_result.get("errors"), exit_code=exit_code
|
|
410
|
+
)
|
|
291
411
|
|
|
292
412
|
except Exception as e:
|
|
293
413
|
console.print(f"[red]Error updating skills: {e}[/red]")
|
|
@@ -323,9 +443,13 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
323
443
|
# Show agents using this skill
|
|
324
444
|
agents_using = self.skills_service.get_agents_for_skill(skill_name)
|
|
325
445
|
if agents_using:
|
|
326
|
-
info_text +=
|
|
446
|
+
info_text += (
|
|
447
|
+
f"\n[bold]Used by agents:[/bold] {', '.join(agents_using)}\n"
|
|
448
|
+
)
|
|
327
449
|
|
|
328
|
-
console.print(
|
|
450
|
+
console.print(
|
|
451
|
+
Panel(info_text, title="Skill Information", border_style="cyan")
|
|
452
|
+
)
|
|
329
453
|
|
|
330
454
|
# Show content if requested
|
|
331
455
|
if show_content:
|
|
@@ -337,7 +461,9 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
337
461
|
content = skill_md.read_text()
|
|
338
462
|
console.print(Markdown(content))
|
|
339
463
|
else:
|
|
340
|
-
console.print(
|
|
464
|
+
console.print(
|
|
465
|
+
f"\n[yellow]SKILL.md not found at {skill_md}[/yellow]"
|
|
466
|
+
)
|
|
341
467
|
|
|
342
468
|
return CommandResult(success=True, exit_code=0)
|
|
343
469
|
|
|
@@ -355,16 +481,22 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
355
481
|
config_path = self.skills_service.get_config_path(scope)
|
|
356
482
|
|
|
357
483
|
if show_path:
|
|
358
|
-
console.print(
|
|
484
|
+
console.print(
|
|
485
|
+
f"\n[cyan]Configuration path ({scope}):[/cyan] {config_path}\n"
|
|
486
|
+
)
|
|
359
487
|
return CommandResult(success=True, exit_code=0)
|
|
360
488
|
|
|
361
489
|
if not config_path.exists():
|
|
362
|
-
console.print(
|
|
490
|
+
console.print(
|
|
491
|
+
f"\n[yellow]Configuration file does not exist: {config_path}[/yellow]"
|
|
492
|
+
)
|
|
363
493
|
console.print("[dim]Would you like to create it? (y/n):[/dim] ", end="")
|
|
364
494
|
|
|
365
|
-
if input().lower() ==
|
|
495
|
+
if input().lower() == "y":
|
|
366
496
|
self.skills_service.create_default_config(scope)
|
|
367
|
-
console.print(
|
|
497
|
+
console.print(
|
|
498
|
+
f"[green]Created default configuration at {config_path}[/green]\n"
|
|
499
|
+
)
|
|
368
500
|
else:
|
|
369
501
|
return CommandResult(success=False, exit_code=1)
|
|
370
502
|
|
|
@@ -373,17 +505,22 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
373
505
|
editor = os.environ.get("EDITOR", "nano")
|
|
374
506
|
try:
|
|
375
507
|
subprocess.run([editor, str(config_path)], check=True)
|
|
376
|
-
console.print(
|
|
508
|
+
console.print(
|
|
509
|
+
f"\n[green]Configuration saved to {config_path}[/green]\n"
|
|
510
|
+
)
|
|
377
511
|
return CommandResult(success=True, exit_code=0)
|
|
378
512
|
except subprocess.CalledProcessError as e:
|
|
379
513
|
console.print(f"[red]Error opening editor: {e}[/red]")
|
|
380
514
|
return CommandResult(success=False, exit_code=1)
|
|
381
515
|
else:
|
|
382
516
|
# Display config
|
|
383
|
-
console.print(
|
|
517
|
+
console.print(
|
|
518
|
+
f"\n[bold cyan]Skills Configuration ({scope}):[/bold cyan]\n"
|
|
519
|
+
)
|
|
384
520
|
console.print(f"[dim]Path: {config_path}[/dim]\n")
|
|
385
521
|
|
|
386
522
|
import yaml
|
|
523
|
+
|
|
387
524
|
config = yaml.safe_load(config_path.read_text())
|
|
388
525
|
console.print(yaml.dump(config, default_flow_style=False))
|
|
389
526
|
|
|
@@ -393,6 +530,209 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
393
530
|
console.print(f"[red]Error managing configuration: {e}[/red]")
|
|
394
531
|
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
395
532
|
|
|
533
|
+
def _deploy_from_github(self, args) -> CommandResult:
|
|
534
|
+
"""Deploy skills from GitHub repository."""
|
|
535
|
+
try:
|
|
536
|
+
collection = getattr(args, "collection", None)
|
|
537
|
+
toolchain = getattr(args, "toolchain", None)
|
|
538
|
+
categories = getattr(args, "categories", None)
|
|
539
|
+
force = getattr(args, "force", False)
|
|
540
|
+
all_skills = getattr(args, "all", False)
|
|
541
|
+
|
|
542
|
+
if collection:
|
|
543
|
+
console.print(
|
|
544
|
+
f"\n[bold cyan]Deploying skills from collection '{collection}'...[/bold cyan]\n"
|
|
545
|
+
)
|
|
546
|
+
else:
|
|
547
|
+
console.print(
|
|
548
|
+
"\n[bold cyan]Deploying skills from default collection...[/bold cyan]\n"
|
|
549
|
+
)
|
|
550
|
+
|
|
551
|
+
# Auto-detect toolchain if not specified and not deploying all
|
|
552
|
+
if not toolchain and not all_skills:
|
|
553
|
+
console.print(
|
|
554
|
+
"[yellow]No toolchain specified. Use --toolchain to filter by language,[/yellow]"
|
|
555
|
+
)
|
|
556
|
+
console.print(
|
|
557
|
+
"[yellow]or --all to deploy all available skills.[/yellow]\n"
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
result = self.skills_deployer.deploy_skills(
|
|
561
|
+
collection=collection,
|
|
562
|
+
toolchain=toolchain,
|
|
563
|
+
categories=categories,
|
|
564
|
+
force=force,
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
# Display results
|
|
568
|
+
if result["deployed_count"] > 0:
|
|
569
|
+
console.print(
|
|
570
|
+
f"[green]✓ Deployed {result['deployed_count']} skill(s):[/green]"
|
|
571
|
+
)
|
|
572
|
+
for skill in result["deployed_skills"]:
|
|
573
|
+
console.print(f" • {skill}")
|
|
574
|
+
console.print()
|
|
575
|
+
|
|
576
|
+
if result["skipped_count"] > 0:
|
|
577
|
+
console.print(
|
|
578
|
+
f"[yellow]⊘ Skipped {result['skipped_count']} skill(s) (already deployed):[/yellow]"
|
|
579
|
+
)
|
|
580
|
+
for skill in result["skipped_skills"]:
|
|
581
|
+
console.print(f" • {skill}")
|
|
582
|
+
console.print("[dim]Use --force to redeploy[/dim]\n")
|
|
583
|
+
|
|
584
|
+
if result["errors"]:
|
|
585
|
+
console.print(f"[red]✗ {len(result['errors'])} error(s):[/red]")
|
|
586
|
+
for error in result["errors"]:
|
|
587
|
+
console.print(f" • {error}")
|
|
588
|
+
console.print()
|
|
589
|
+
|
|
590
|
+
# Show restart instructions
|
|
591
|
+
if result["restart_instructions"]:
|
|
592
|
+
console.print(
|
|
593
|
+
Panel(
|
|
594
|
+
result["restart_instructions"],
|
|
595
|
+
title="⚠️ Important",
|
|
596
|
+
border_style="yellow",
|
|
597
|
+
)
|
|
598
|
+
)
|
|
599
|
+
console.print()
|
|
600
|
+
|
|
601
|
+
exit_code = 1 if result["errors"] else 0
|
|
602
|
+
return CommandResult(success=not result["errors"], exit_code=exit_code)
|
|
603
|
+
|
|
604
|
+
except Exception as e:
|
|
605
|
+
console.print(f"[red]Error deploying from GitHub: {e}[/red]")
|
|
606
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
607
|
+
|
|
608
|
+
def _list_available_github_skills(self, args) -> CommandResult:
|
|
609
|
+
"""List available skills from GitHub repository."""
|
|
610
|
+
try:
|
|
611
|
+
collection = getattr(args, "collection", None)
|
|
612
|
+
|
|
613
|
+
if collection:
|
|
614
|
+
console.print(
|
|
615
|
+
f"\n[bold cyan]Fetching skills from collection '{collection}'...[/bold cyan]\n"
|
|
616
|
+
)
|
|
617
|
+
else:
|
|
618
|
+
console.print(
|
|
619
|
+
"\n[bold cyan]Fetching skills from default collection...[/bold cyan]\n"
|
|
620
|
+
)
|
|
621
|
+
|
|
622
|
+
result = self.skills_deployer.list_available_skills(collection=collection)
|
|
623
|
+
|
|
624
|
+
if result.get("error"):
|
|
625
|
+
console.print(f"[red]Error: {result['error']}[/red]")
|
|
626
|
+
return CommandResult(
|
|
627
|
+
success=False, message=result["error"], exit_code=1
|
|
628
|
+
)
|
|
629
|
+
|
|
630
|
+
console.print(
|
|
631
|
+
f"[green]Found {result['total_skills']} available skills[/green]\n"
|
|
632
|
+
)
|
|
633
|
+
|
|
634
|
+
# Display by category
|
|
635
|
+
console.print("[bold yellow]By Category:[/bold yellow]\n")
|
|
636
|
+
for category, skills in sorted(result["by_category"].items()):
|
|
637
|
+
console.print(f" [cyan]{category}[/cyan] ({len(skills)} skills)")
|
|
638
|
+
if hasattr(args, "verbose") and args.verbose:
|
|
639
|
+
for skill in sorted(skills, key=lambda s: s.get("name", "")):
|
|
640
|
+
console.print(f" • {skill.get('name', 'unknown')}")
|
|
641
|
+
console.print()
|
|
642
|
+
|
|
643
|
+
# Display by toolchain
|
|
644
|
+
console.print("[bold yellow]By Toolchain:[/bold yellow]\n")
|
|
645
|
+
for toolchain, skills in sorted(result["by_toolchain"].items()):
|
|
646
|
+
console.print(f" [cyan]{toolchain}[/cyan] ({len(skills)} skills)")
|
|
647
|
+
if hasattr(args, "verbose") and args.verbose:
|
|
648
|
+
for skill in sorted(skills, key=lambda s: s.get("name", "")):
|
|
649
|
+
console.print(f" • {skill.get('name', 'unknown')}")
|
|
650
|
+
console.print()
|
|
651
|
+
|
|
652
|
+
return CommandResult(success=True, exit_code=0)
|
|
653
|
+
|
|
654
|
+
except Exception as e:
|
|
655
|
+
console.print(f"[red]Error listing available skills: {e}[/red]")
|
|
656
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
657
|
+
|
|
658
|
+
def _check_deployed_skills(self, args) -> CommandResult:
|
|
659
|
+
"""Check currently deployed skills in ~/.claude/skills/."""
|
|
660
|
+
try:
|
|
661
|
+
result = self.skills_deployer.check_deployed_skills()
|
|
662
|
+
|
|
663
|
+
console.print("\n[bold cyan]Claude Code Skills Status:[/bold cyan]\n")
|
|
664
|
+
console.print(f"[dim]Directory: {result['claude_skills_dir']}[/dim]\n")
|
|
665
|
+
|
|
666
|
+
if result["deployed_count"] == 0:
|
|
667
|
+
console.print("[yellow]No skills currently deployed.[/yellow]")
|
|
668
|
+
console.print(
|
|
669
|
+
"[dim]Use 'claude-mpm skills deploy-github' to deploy skills.[/dim]\n"
|
|
670
|
+
)
|
|
671
|
+
return CommandResult(success=True, exit_code=0)
|
|
672
|
+
|
|
673
|
+
console.print(
|
|
674
|
+
f"[green]{result['deployed_count']} skill(s) deployed:[/green]\n"
|
|
675
|
+
)
|
|
676
|
+
|
|
677
|
+
# Create table for deployed skills
|
|
678
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
679
|
+
table.add_column("Skill Name", style="green")
|
|
680
|
+
table.add_column("Path", style="dim")
|
|
681
|
+
|
|
682
|
+
for skill in sorted(result["skills"], key=lambda s: s["name"]):
|
|
683
|
+
table.add_row(skill["name"], skill["path"])
|
|
684
|
+
|
|
685
|
+
console.print(table)
|
|
686
|
+
console.print()
|
|
687
|
+
|
|
688
|
+
return CommandResult(success=True, exit_code=0)
|
|
689
|
+
|
|
690
|
+
except Exception as e:
|
|
691
|
+
console.print(f"[red]Error checking deployed skills: {e}[/red]")
|
|
692
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
693
|
+
|
|
694
|
+
def _remove_skills(self, args) -> CommandResult:
|
|
695
|
+
"""Remove deployed skills."""
|
|
696
|
+
try:
|
|
697
|
+
skill_names = getattr(args, "skill_names", None)
|
|
698
|
+
remove_all = getattr(args, "all", False)
|
|
699
|
+
|
|
700
|
+
if remove_all:
|
|
701
|
+
skill_names = None
|
|
702
|
+
console.print(
|
|
703
|
+
"\n[bold yellow]Removing ALL deployed skills...[/bold yellow]\n"
|
|
704
|
+
)
|
|
705
|
+
elif skill_names:
|
|
706
|
+
console.print(
|
|
707
|
+
f"\n[bold cyan]Removing {len(skill_names)} skill(s)...[/bold cyan]\n"
|
|
708
|
+
)
|
|
709
|
+
else:
|
|
710
|
+
console.print("[red]Error: Specify skill names or use --all[/red]")
|
|
711
|
+
return CommandResult(success=False, exit_code=1)
|
|
712
|
+
|
|
713
|
+
result = self.skills_deployer.remove_skills(skill_names)
|
|
714
|
+
|
|
715
|
+
if result["removed_count"] > 0:
|
|
716
|
+
console.print(
|
|
717
|
+
f"[green]✓ Removed {result['removed_count']} skill(s):[/green]"
|
|
718
|
+
)
|
|
719
|
+
for skill in result["removed_skills"]:
|
|
720
|
+
console.print(f" • {skill}")
|
|
721
|
+
console.print()
|
|
722
|
+
|
|
723
|
+
if result["errors"]:
|
|
724
|
+
console.print(f"[red]✗ {len(result['errors'])} error(s):[/red]")
|
|
725
|
+
for error in result["errors"]:
|
|
726
|
+
console.print(f" • {error}")
|
|
727
|
+
console.print()
|
|
728
|
+
|
|
729
|
+
exit_code = 1 if result["errors"] else 0
|
|
730
|
+
return CommandResult(success=not result["errors"], exit_code=exit_code)
|
|
731
|
+
|
|
732
|
+
except Exception as e:
|
|
733
|
+
console.print(f"[red]Error removing skills: {e}[/red]")
|
|
734
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
735
|
+
|
|
396
736
|
def _get_skill_metadata(self, skill_name: str) -> Optional[dict]:
|
|
397
737
|
"""Get skill metadata from SKILL.md file."""
|
|
398
738
|
try:
|
|
@@ -404,12 +744,463 @@ class SkillsManagementCommand(BaseCommand):
|
|
|
404
744
|
|
|
405
745
|
# Parse SKILL.md metadata
|
|
406
746
|
content = skill_md.read_text()
|
|
407
|
-
|
|
408
|
-
return metadata
|
|
747
|
+
return self.skills_service.parse_skill_metadata(content)
|
|
409
748
|
|
|
410
749
|
except Exception:
|
|
411
750
|
return None
|
|
412
751
|
|
|
752
|
+
# === Collection Management Commands ===
|
|
753
|
+
|
|
754
|
+
def _collection_list(self, args) -> CommandResult:
|
|
755
|
+
"""List all configured skill collections."""
|
|
756
|
+
try:
|
|
757
|
+
result = self.skills_deployer.list_collections()
|
|
758
|
+
|
|
759
|
+
console.print("\n[bold cyan]Skill Collections:[/bold cyan]\n")
|
|
760
|
+
console.print(
|
|
761
|
+
f"[dim]Default collection: {result['default_collection']}[/dim]"
|
|
762
|
+
)
|
|
763
|
+
console.print(
|
|
764
|
+
f"[dim]Enabled: {result['enabled_count']} / {result['total_count']}[/dim]\n"
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
if not result["collections"]:
|
|
768
|
+
console.print("[yellow]No collections configured.[/yellow]")
|
|
769
|
+
console.print(
|
|
770
|
+
"[dim]Use 'claude-mpm skills collection-add' to add a collection.[/dim]\n"
|
|
771
|
+
)
|
|
772
|
+
return CommandResult(success=True, exit_code=0)
|
|
773
|
+
|
|
774
|
+
# Create table for collections
|
|
775
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
776
|
+
table.add_column("Name", style="green")
|
|
777
|
+
table.add_column("URL", style="white")
|
|
778
|
+
table.add_column("Priority", justify="center")
|
|
779
|
+
table.add_column("Enabled", justify="center")
|
|
780
|
+
table.add_column("Last Update", style="dim")
|
|
781
|
+
table.add_column("Default", justify="center")
|
|
782
|
+
|
|
783
|
+
# Sort by priority
|
|
784
|
+
sorted_collections = sorted(
|
|
785
|
+
result["collections"].items(), key=lambda x: x[1].get("priority", 999)
|
|
786
|
+
)
|
|
787
|
+
|
|
788
|
+
for name, config in sorted_collections:
|
|
789
|
+
enabled_icon = "✓" if config.get("enabled", True) else "✗"
|
|
790
|
+
default_icon = "⭐" if name == result["default_collection"] else ""
|
|
791
|
+
last_update = config.get("last_update") or "Never"
|
|
792
|
+
|
|
793
|
+
table.add_row(
|
|
794
|
+
name,
|
|
795
|
+
config["url"],
|
|
796
|
+
str(config.get("priority", "N/A")),
|
|
797
|
+
enabled_icon,
|
|
798
|
+
last_update,
|
|
799
|
+
default_icon,
|
|
800
|
+
)
|
|
801
|
+
|
|
802
|
+
console.print(table)
|
|
803
|
+
console.print()
|
|
804
|
+
|
|
805
|
+
return CommandResult(success=True, exit_code=0)
|
|
806
|
+
|
|
807
|
+
except Exception as e:
|
|
808
|
+
console.print(f"[red]Error listing collections: {e}[/red]")
|
|
809
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
810
|
+
|
|
811
|
+
def _collection_add(self, args) -> CommandResult:
|
|
812
|
+
"""Add a new skill collection."""
|
|
813
|
+
try:
|
|
814
|
+
name = getattr(args, "collection_name", None)
|
|
815
|
+
url = getattr(args, "collection_url", None)
|
|
816
|
+
priority = getattr(args, "priority", 99)
|
|
817
|
+
|
|
818
|
+
if not name or not url:
|
|
819
|
+
console.print("[red]Error: Collection name and URL are required[/red]")
|
|
820
|
+
console.print(
|
|
821
|
+
"[dim]Usage: claude-mpm skills collection-add NAME URL [--priority N][/dim]"
|
|
822
|
+
)
|
|
823
|
+
return CommandResult(success=False, exit_code=1)
|
|
824
|
+
|
|
825
|
+
console.print(f"\n[bold cyan]Adding collection '{name}'...[/bold cyan]\n")
|
|
826
|
+
|
|
827
|
+
result = self.skills_deployer.add_collection(name, url, priority)
|
|
828
|
+
|
|
829
|
+
console.print(f"[green]✓ {result['message']}[/green]")
|
|
830
|
+
console.print(f" [dim]URL: {url}[/dim]")
|
|
831
|
+
console.print(f" [dim]Priority: {priority}[/dim]\n")
|
|
832
|
+
|
|
833
|
+
return CommandResult(success=True, exit_code=0)
|
|
834
|
+
|
|
835
|
+
except ValueError as e:
|
|
836
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
837
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
838
|
+
except Exception as e:
|
|
839
|
+
console.print(f"[red]Unexpected error: {e}[/red]")
|
|
840
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
841
|
+
|
|
842
|
+
def _collection_remove(self, args) -> CommandResult:
|
|
843
|
+
"""Remove a skill collection."""
|
|
844
|
+
try:
|
|
845
|
+
name = getattr(args, "collection_name", None)
|
|
846
|
+
|
|
847
|
+
if not name:
|
|
848
|
+
console.print("[red]Error: Collection name is required[/red]")
|
|
849
|
+
console.print(
|
|
850
|
+
"[dim]Usage: claude-mpm skills collection-remove NAME[/dim]"
|
|
851
|
+
)
|
|
852
|
+
return CommandResult(success=False, exit_code=1)
|
|
853
|
+
|
|
854
|
+
console.print(
|
|
855
|
+
f"\n[bold yellow]Removing collection '{name}'...[/bold yellow]\n"
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
result = self.skills_deployer.remove_collection(name)
|
|
859
|
+
|
|
860
|
+
console.print(f"[green]✓ {result['message']}[/green]")
|
|
861
|
+
if result.get("directory_removed"):
|
|
862
|
+
console.print(" [dim]Collection directory removed[/dim]")
|
|
863
|
+
elif result.get("directory_error"):
|
|
864
|
+
console.print(
|
|
865
|
+
f" [yellow]Warning: {result['directory_error']}[/yellow]"
|
|
866
|
+
)
|
|
867
|
+
console.print()
|
|
868
|
+
|
|
869
|
+
return CommandResult(success=True, exit_code=0)
|
|
870
|
+
|
|
871
|
+
except ValueError as e:
|
|
872
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
873
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
874
|
+
except Exception as e:
|
|
875
|
+
console.print(f"[red]Unexpected error: {e}[/red]")
|
|
876
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
877
|
+
|
|
878
|
+
def _collection_enable(self, args) -> CommandResult:
|
|
879
|
+
"""Enable a disabled collection."""
|
|
880
|
+
try:
|
|
881
|
+
name = getattr(args, "collection_name", None)
|
|
882
|
+
|
|
883
|
+
if not name:
|
|
884
|
+
console.print("[red]Error: Collection name is required[/red]")
|
|
885
|
+
console.print(
|
|
886
|
+
"[dim]Usage: claude-mpm skills collection-enable NAME[/dim]"
|
|
887
|
+
)
|
|
888
|
+
return CommandResult(success=False, exit_code=1)
|
|
889
|
+
|
|
890
|
+
result = self.skills_deployer.enable_collection(name)
|
|
891
|
+
|
|
892
|
+
console.print(f"\n[green]✓ {result['message']}[/green]\n")
|
|
893
|
+
|
|
894
|
+
return CommandResult(success=True, exit_code=0)
|
|
895
|
+
|
|
896
|
+
except ValueError as e:
|
|
897
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
898
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
899
|
+
except Exception as e:
|
|
900
|
+
console.print(f"[red]Unexpected error: {e}[/red]")
|
|
901
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
902
|
+
|
|
903
|
+
def _collection_disable(self, args) -> CommandResult:
|
|
904
|
+
"""Disable a collection."""
|
|
905
|
+
try:
|
|
906
|
+
name = getattr(args, "collection_name", None)
|
|
907
|
+
|
|
908
|
+
if not name:
|
|
909
|
+
console.print("[red]Error: Collection name is required[/red]")
|
|
910
|
+
console.print(
|
|
911
|
+
"[dim]Usage: claude-mpm skills collection-disable NAME[/dim]"
|
|
912
|
+
)
|
|
913
|
+
return CommandResult(success=False, exit_code=1)
|
|
914
|
+
|
|
915
|
+
result = self.skills_deployer.disable_collection(name)
|
|
916
|
+
|
|
917
|
+
console.print(f"\n[green]✓ {result['message']}[/green]\n")
|
|
918
|
+
|
|
919
|
+
return CommandResult(success=True, exit_code=0)
|
|
920
|
+
|
|
921
|
+
except ValueError as e:
|
|
922
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
923
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
924
|
+
except Exception as e:
|
|
925
|
+
console.print(f"[red]Unexpected error: {e}[/red]")
|
|
926
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
927
|
+
|
|
928
|
+
def _collection_set_default(self, args) -> CommandResult:
|
|
929
|
+
"""Set the default collection."""
|
|
930
|
+
try:
|
|
931
|
+
name = getattr(args, "collection_name", None)
|
|
932
|
+
|
|
933
|
+
if not name:
|
|
934
|
+
console.print("[red]Error: Collection name is required[/red]")
|
|
935
|
+
console.print(
|
|
936
|
+
"[dim]Usage: claude-mpm skills collection-set-default NAME[/dim]"
|
|
937
|
+
)
|
|
938
|
+
return CommandResult(success=False, exit_code=1)
|
|
939
|
+
|
|
940
|
+
result = self.skills_deployer.set_default_collection(name)
|
|
941
|
+
|
|
942
|
+
console.print(f"\n[green]✓ {result['message']}[/green]")
|
|
943
|
+
if result.get("previous_default"):
|
|
944
|
+
console.print(f" [dim]Previous: {result['previous_default']}[/dim]")
|
|
945
|
+
console.print()
|
|
946
|
+
|
|
947
|
+
return CommandResult(success=True, exit_code=0)
|
|
948
|
+
|
|
949
|
+
except ValueError as e:
|
|
950
|
+
console.print(f"[red]Error: {e}[/red]")
|
|
951
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
952
|
+
except Exception as e:
|
|
953
|
+
console.print(f"[red]Unexpected error: {e}[/red]")
|
|
954
|
+
|
|
955
|
+
def _configure_skills(self, args) -> CommandResult:
|
|
956
|
+
"""Interactive skills configuration with checkbox selection.
|
|
957
|
+
|
|
958
|
+
Provides checkbox-based selection interface matching agents configure UX:
|
|
959
|
+
- Status column showing Installed/Available
|
|
960
|
+
- Pre-selection for installed skills
|
|
961
|
+
- Apply/Adjust/Cancel menu
|
|
962
|
+
- While loop for adjustment
|
|
963
|
+
- Simplified labels (checkbox state only)
|
|
964
|
+
|
|
965
|
+
This is Option 3 (Hybrid approach): Separate command for interactive mode
|
|
966
|
+
while keeping deploy-github for CLI automation.
|
|
967
|
+
"""
|
|
968
|
+
try:
|
|
969
|
+
import questionary
|
|
970
|
+
from questionary import Choice, Style
|
|
971
|
+
from rich.prompt import Prompt
|
|
972
|
+
|
|
973
|
+
# Questionary style (matching agents configure)
|
|
974
|
+
QUESTIONARY_STYLE = Style(
|
|
975
|
+
[
|
|
976
|
+
(
|
|
977
|
+
"selected",
|
|
978
|
+
"fg:#e0e0e0 bold",
|
|
979
|
+
), # Light gray - excellent readability
|
|
980
|
+
(
|
|
981
|
+
"pointer",
|
|
982
|
+
"fg:#ffd700 bold",
|
|
983
|
+
), # Gold/yellow - highly visible pointer
|
|
984
|
+
("highlighted", "fg:#e0e0e0"), # Light gray - clear hover state
|
|
985
|
+
(
|
|
986
|
+
"question",
|
|
987
|
+
"fg:#e0e0e0 bold",
|
|
988
|
+
), # Light gray bold - prominent questions
|
|
989
|
+
("checkbox", "fg:#00ff00"), # Green - for checked boxes
|
|
990
|
+
(
|
|
991
|
+
"checkbox-selected",
|
|
992
|
+
"fg:#00ff00 bold",
|
|
993
|
+
), # Green bold - for checked selected boxes
|
|
994
|
+
]
|
|
995
|
+
)
|
|
996
|
+
|
|
997
|
+
console.print("\n[bold cyan]Interactive Skills Configuration[/bold cyan]\n")
|
|
998
|
+
console.print(
|
|
999
|
+
"[dim]Select skills to install/uninstall using checkboxes[/dim]"
|
|
1000
|
+
)
|
|
1001
|
+
console.print("[dim]● = Installed, ○ = Available[/dim]\n")
|
|
1002
|
+
|
|
1003
|
+
# Get deployed skills for status detection
|
|
1004
|
+
deployed_result = self.skills_deployer.check_deployed_skills()
|
|
1005
|
+
deployed_skills = {
|
|
1006
|
+
skill["name"] for skill in deployed_result.get("skills", [])
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
# Get available skills from GitHub
|
|
1010
|
+
console.print("[dim]Fetching available skills from GitHub...[/dim]\n")
|
|
1011
|
+
available_result = self.skills_deployer.list_available_skills()
|
|
1012
|
+
|
|
1013
|
+
if available_result.get("error"):
|
|
1014
|
+
console.print(f"[red]Error: {available_result['error']}[/red]")
|
|
1015
|
+
return CommandResult(
|
|
1016
|
+
success=False, message=available_result["error"], exit_code=1
|
|
1017
|
+
)
|
|
1018
|
+
|
|
1019
|
+
# Flatten skills by category
|
|
1020
|
+
all_skills = []
|
|
1021
|
+
for category, skills in available_result.get("by_category", {}).items():
|
|
1022
|
+
for skill in skills:
|
|
1023
|
+
skill_info = {
|
|
1024
|
+
"name": skill.get("name", "unknown"),
|
|
1025
|
+
"category": category,
|
|
1026
|
+
"is_deployed": skill.get("name", "unknown") in deployed_skills,
|
|
1027
|
+
}
|
|
1028
|
+
all_skills.append(skill_info)
|
|
1029
|
+
|
|
1030
|
+
# Sort by deployed status (deployed first), then by name
|
|
1031
|
+
all_skills.sort(key=lambda s: (not s["is_deployed"], s["name"]))
|
|
1032
|
+
|
|
1033
|
+
# Build checkbox choices with pre-selection
|
|
1034
|
+
# Loop to allow adjusting selection
|
|
1035
|
+
while True:
|
|
1036
|
+
skill_choices = []
|
|
1037
|
+
skill_map = {} # For lookup after selection
|
|
1038
|
+
|
|
1039
|
+
for skill in all_skills:
|
|
1040
|
+
skill_name = skill["name"]
|
|
1041
|
+
category = skill["category"]
|
|
1042
|
+
is_deployed = skill["is_deployed"]
|
|
1043
|
+
|
|
1044
|
+
# Simple format: "skill-name (category)"
|
|
1045
|
+
# Checkbox state (checked/unchecked) indicates installed status
|
|
1046
|
+
choice_text = f"{skill_name} ({category})"
|
|
1047
|
+
|
|
1048
|
+
# Pre-select if deployed
|
|
1049
|
+
choice = Choice(
|
|
1050
|
+
title=choice_text, value=skill_name, checked=is_deployed
|
|
1051
|
+
)
|
|
1052
|
+
|
|
1053
|
+
skill_choices.append(choice)
|
|
1054
|
+
skill_map[skill_name] = skill
|
|
1055
|
+
|
|
1056
|
+
# Display checkbox selection
|
|
1057
|
+
selected_skills = questionary.checkbox(
|
|
1058
|
+
"Select skills (Space to toggle, Enter to confirm):",
|
|
1059
|
+
choices=skill_choices,
|
|
1060
|
+
style=QUESTIONARY_STYLE,
|
|
1061
|
+
).ask()
|
|
1062
|
+
|
|
1063
|
+
if selected_skills is None:
|
|
1064
|
+
# User cancelled (Ctrl+C)
|
|
1065
|
+
console.print("[yellow]Skills configuration cancelled[/yellow]")
|
|
1066
|
+
return CommandResult(success=True, exit_code=0)
|
|
1067
|
+
|
|
1068
|
+
# Determine changes
|
|
1069
|
+
to_install = []
|
|
1070
|
+
to_remove = []
|
|
1071
|
+
|
|
1072
|
+
for skill in all_skills:
|
|
1073
|
+
skill_name = skill["name"]
|
|
1074
|
+
is_deployed = skill["is_deployed"]
|
|
1075
|
+
is_selected = skill_name in selected_skills
|
|
1076
|
+
|
|
1077
|
+
if is_selected and not is_deployed:
|
|
1078
|
+
to_install.append(skill_name)
|
|
1079
|
+
elif not is_selected and is_deployed:
|
|
1080
|
+
to_remove.append(skill_name)
|
|
1081
|
+
|
|
1082
|
+
# Show summary of changes
|
|
1083
|
+
console.print("\n[bold]Changes to apply:[/bold]")
|
|
1084
|
+
if to_install:
|
|
1085
|
+
console.print(
|
|
1086
|
+
f"\n[green]✓ Install ({len(to_install)} skills):[/green]"
|
|
1087
|
+
)
|
|
1088
|
+
for skill in to_install:
|
|
1089
|
+
console.print(f" • {skill}")
|
|
1090
|
+
|
|
1091
|
+
if to_remove:
|
|
1092
|
+
console.print(
|
|
1093
|
+
f"\n[yellow]✗ Remove ({len(to_remove)} skills):[/yellow]"
|
|
1094
|
+
)
|
|
1095
|
+
for skill in to_remove:
|
|
1096
|
+
console.print(f" • {skill}")
|
|
1097
|
+
|
|
1098
|
+
if not to_install and not to_remove:
|
|
1099
|
+
console.print(
|
|
1100
|
+
"\n[dim]No changes (selection matches current deployment)[/dim]"
|
|
1101
|
+
)
|
|
1102
|
+
|
|
1103
|
+
console.print()
|
|
1104
|
+
|
|
1105
|
+
# Ask user to confirm, adjust, or cancel
|
|
1106
|
+
action = questionary.select(
|
|
1107
|
+
"\nWhat would you like to do?",
|
|
1108
|
+
choices=[
|
|
1109
|
+
Choice("Apply these changes", value="apply"),
|
|
1110
|
+
Choice("Adjust selection", value="adjust"),
|
|
1111
|
+
Choice("Cancel", value="cancel"),
|
|
1112
|
+
],
|
|
1113
|
+
default="apply",
|
|
1114
|
+
style=QUESTIONARY_STYLE,
|
|
1115
|
+
).ask()
|
|
1116
|
+
|
|
1117
|
+
if action == "cancel":
|
|
1118
|
+
console.print("[yellow]Changes cancelled[/yellow]")
|
|
1119
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1120
|
+
return CommandResult(success=True, exit_code=0)
|
|
1121
|
+
if action == "adjust":
|
|
1122
|
+
# Loop back to skill selection
|
|
1123
|
+
console.print("\n[dim]Adjusting selection...[/dim]\n")
|
|
1124
|
+
continue
|
|
1125
|
+
|
|
1126
|
+
# Apply changes
|
|
1127
|
+
success = True
|
|
1128
|
+
errors = []
|
|
1129
|
+
|
|
1130
|
+
# Install skills
|
|
1131
|
+
if to_install:
|
|
1132
|
+
console.print("\n[bold cyan]Installing skills...[/bold cyan]\n")
|
|
1133
|
+
for skill_name in to_install:
|
|
1134
|
+
try:
|
|
1135
|
+
# Deploy single skill
|
|
1136
|
+
result = self.skills_deployer.deploy_skills(
|
|
1137
|
+
skill_names=[skill_name], force=False
|
|
1138
|
+
)
|
|
1139
|
+
|
|
1140
|
+
if result.get("errors"):
|
|
1141
|
+
errors.extend(result["errors"])
|
|
1142
|
+
success = False
|
|
1143
|
+
else:
|
|
1144
|
+
console.print(
|
|
1145
|
+
f"[green]✓ Installed: {skill_name}[/green]"
|
|
1146
|
+
)
|
|
1147
|
+
except Exception as e:
|
|
1148
|
+
errors.append(f"Failed to install {skill_name}: {e}")
|
|
1149
|
+
success = False
|
|
1150
|
+
|
|
1151
|
+
# Remove skills
|
|
1152
|
+
if to_remove:
|
|
1153
|
+
console.print("\n[bold yellow]Removing skills...[/bold yellow]\n")
|
|
1154
|
+
for skill_name in to_remove:
|
|
1155
|
+
try:
|
|
1156
|
+
# Remove single skill
|
|
1157
|
+
result = self.skills_deployer.remove_skills(
|
|
1158
|
+
skill_names=[skill_name]
|
|
1159
|
+
)
|
|
1160
|
+
|
|
1161
|
+
if result.get("errors"):
|
|
1162
|
+
errors.extend(result["errors"])
|
|
1163
|
+
success = False
|
|
1164
|
+
else:
|
|
1165
|
+
console.print(
|
|
1166
|
+
f"[yellow]✗ Removed: {skill_name}[/yellow]"
|
|
1167
|
+
)
|
|
1168
|
+
except Exception as e:
|
|
1169
|
+
errors.append(f"Failed to remove {skill_name}: {e}")
|
|
1170
|
+
success = False
|
|
1171
|
+
|
|
1172
|
+
# Show errors if any
|
|
1173
|
+
if errors:
|
|
1174
|
+
console.print(f"\n[red]✗ {len(errors)} error(s):[/red]")
|
|
1175
|
+
for error in errors:
|
|
1176
|
+
console.print(f" • {error}")
|
|
1177
|
+
|
|
1178
|
+
# Show restart instructions
|
|
1179
|
+
if success and (to_install or to_remove):
|
|
1180
|
+
console.print(
|
|
1181
|
+
"\n[bold green]✓ Changes applied successfully![/bold green]"
|
|
1182
|
+
)
|
|
1183
|
+
console.print("\n[yellow]⚠️ Important:[/yellow]")
|
|
1184
|
+
console.print(" Restart Claude Code for changes to take effect")
|
|
1185
|
+
|
|
1186
|
+
console.print()
|
|
1187
|
+
Prompt.ask("\nPress Enter to continue")
|
|
1188
|
+
|
|
1189
|
+
# Exit the loop after successful execution
|
|
1190
|
+
break
|
|
1191
|
+
|
|
1192
|
+
exit_code = 0 if success else 1
|
|
1193
|
+
return CommandResult(success=success, exit_code=exit_code)
|
|
1194
|
+
|
|
1195
|
+
except Exception as e:
|
|
1196
|
+
console.print(f"[red]Error in skills configuration: {e}[/red]")
|
|
1197
|
+
import traceback
|
|
1198
|
+
|
|
1199
|
+
console.print(f"[dim]{traceback.format_exc()}[/dim]")
|
|
1200
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
1201
|
+
|
|
1202
|
+
return CommandResult(success=False, message=str(e), exit_code=1)
|
|
1203
|
+
|
|
413
1204
|
|
|
414
1205
|
def manage_skills(args) -> int:
|
|
415
1206
|
"""
|