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.

Files changed (520) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_PM.md +35 -6
  3. claude_mpm/agents/OUTPUT_STYLE.md +3 -48
  4. claude_mpm/agents/PM_INSTRUCTIONS.md +1241 -667
  5. claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
  6. claude_mpm/agents/WORKFLOW.md +75 -2
  7. claude_mpm/agents/__init__.py +6 -0
  8. claude_mpm/agents/agent_loader.py +1 -4
  9. claude_mpm/agents/base_agent.json +6 -3
  10. claude_mpm/agents/base_agent_loader.py +10 -35
  11. claude_mpm/agents/frontmatter_validator.py +1 -1
  12. claude_mpm/agents/templates/circuit-breakers.md +1254 -0
  13. claude_mpm/agents/templates/context-management-examples.md +544 -0
  14. claude_mpm/agents/templates/{pm_red_flags.md → pm-red-flags.md} +89 -19
  15. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  16. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  17. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  18. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  19. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  20. claude_mpm/cli/__init__.py +37 -2
  21. claude_mpm/cli/commands/__init__.py +2 -0
  22. claude_mpm/cli/commands/agent_source.py +774 -0
  23. claude_mpm/cli/commands/agent_state_manager.py +188 -30
  24. claude_mpm/cli/commands/agents.py +959 -36
  25. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  26. claude_mpm/cli/commands/agents_discover.py +338 -0
  27. claude_mpm/cli/commands/aggregate.py +1 -1
  28. claude_mpm/cli/commands/analyze.py +3 -3
  29. claude_mpm/cli/commands/auto_configure.py +537 -239
  30. claude_mpm/cli/commands/cleanup.py +1 -1
  31. claude_mpm/cli/commands/config.py +7 -4
  32. claude_mpm/cli/commands/configure.py +924 -45
  33. claude_mpm/cli/commands/configure_agent_display.py +4 -4
  34. claude_mpm/cli/commands/configure_navigation.py +63 -46
  35. claude_mpm/cli/commands/debug.py +12 -12
  36. claude_mpm/cli/commands/doctor.py +10 -2
  37. claude_mpm/cli/commands/hook_errors.py +277 -0
  38. claude_mpm/cli/commands/local_deploy.py +1 -4
  39. claude_mpm/cli/commands/mcp_install_commands.py +1 -1
  40. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  41. claude_mpm/cli/commands/mpm_init/core.py +573 -0
  42. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  43. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  44. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  45. claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
  46. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  47. claude_mpm/cli/commands/mpm_init_handler.py +67 -1
  48. claude_mpm/cli/commands/postmortem.py +401 -0
  49. claude_mpm/cli/commands/run.py +125 -167
  50. claude_mpm/cli/commands/skill_source.py +694 -0
  51. claude_mpm/cli/commands/skills.py +835 -44
  52. claude_mpm/cli/executor.py +78 -3
  53. claude_mpm/cli/interactive/agent_wizard.py +1032 -47
  54. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  55. claude_mpm/cli/parsers/agents_parser.py +256 -4
  56. claude_mpm/cli/parsers/auto_configure_parser.py +13 -0
  57. claude_mpm/cli/parsers/base_parser.py +53 -0
  58. claude_mpm/cli/parsers/config_parser.py +96 -43
  59. claude_mpm/cli/parsers/mpm_init_parser.py +42 -0
  60. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  61. claude_mpm/cli/parsers/skills_parser.py +145 -0
  62. claude_mpm/cli/parsers/source_parser.py +138 -0
  63. claude_mpm/cli/startup.py +564 -108
  64. claude_mpm/cli/startup_display.py +480 -0
  65. claude_mpm/cli/utils.py +1 -1
  66. claude_mpm/cli_module/commands.py +1 -1
  67. claude_mpm/commands/{mpm-auto-configure.md → mpm-agents-auto-configure.md} +9 -0
  68. claude_mpm/commands/mpm-agents-detect.md +9 -0
  69. claude_mpm/commands/{mpm-agents.md → mpm-agents-list.md} +9 -0
  70. claude_mpm/commands/mpm-agents-recommend.md +9 -0
  71. claude_mpm/commands/{mpm-config.md → mpm-config-view.md} +9 -0
  72. claude_mpm/commands/mpm-doctor.md +9 -0
  73. claude_mpm/commands/mpm-help.md +17 -2
  74. claude_mpm/commands/mpm-init.md +28 -3
  75. claude_mpm/commands/mpm-monitor.md +9 -0
  76. claude_mpm/commands/mpm-postmortem.md +123 -0
  77. claude_mpm/commands/mpm-session-resume.md +381 -0
  78. claude_mpm/commands/mpm-status.md +9 -0
  79. claude_mpm/commands/{mpm-organize.md → mpm-ticket-organize.md} +9 -0
  80. claude_mpm/commands/mpm-ticket-view.md +552 -0
  81. claude_mpm/commands/mpm-version.md +9 -0
  82. claude_mpm/commands/mpm.md +11 -0
  83. claude_mpm/config/agent_presets.py +488 -0
  84. claude_mpm/config/agent_sources.py +325 -0
  85. claude_mpm/config/skill_presets.py +392 -0
  86. claude_mpm/config/skill_sources.py +590 -0
  87. claude_mpm/constants.py +13 -0
  88. claude_mpm/core/api_validator.py +1 -1
  89. claude_mpm/core/claude_runner.py +19 -35
  90. claude_mpm/core/config.py +24 -0
  91. claude_mpm/core/constants.py +1 -1
  92. claude_mpm/core/framework/__init__.py +3 -16
  93. claude_mpm/core/framework/loaders/file_loader.py +54 -101
  94. claude_mpm/core/framework/loaders/instruction_loader.py +25 -5
  95. claude_mpm/core/framework/processors/metadata_processor.py +1 -1
  96. claude_mpm/core/hook_error_memory.py +381 -0
  97. claude_mpm/core/hook_manager.py +41 -2
  98. claude_mpm/core/interactive_session.py +131 -10
  99. claude_mpm/core/interfaces.py +56 -1
  100. claude_mpm/core/logger.py +3 -1
  101. claude_mpm/core/oneshot_session.py +110 -8
  102. claude_mpm/core/protocols/__init__.py +23 -0
  103. claude_mpm/core/protocols/runner_protocol.py +103 -0
  104. claude_mpm/core/protocols/session_protocol.py +131 -0
  105. claude_mpm/core/shared/singleton_manager.py +11 -4
  106. claude_mpm/core/system_context.py +38 -0
  107. claude_mpm/core/unified_config.py +22 -0
  108. claude_mpm/dashboard/static/css/activity.css +69 -69
  109. claude_mpm/dashboard/static/css/connection-status.css +10 -10
  110. claude_mpm/dashboard/static/css/dashboard.css +15 -15
  111. claude_mpm/dashboard/static/js/components/activity-tree.js +178 -178
  112. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +101 -101
  113. claude_mpm/dashboard/static/js/components/agent-inference.js +31 -31
  114. claude_mpm/dashboard/static/js/components/build-tracker.js +59 -59
  115. claude_mpm/dashboard/static/js/components/code-simple.js +107 -107
  116. claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
  117. claude_mpm/dashboard/static/js/components/diff-viewer.js +113 -113
  118. claude_mpm/dashboard/static/js/components/event-viewer.js +12 -12
  119. claude_mpm/dashboard/static/js/components/file-change-tracker.js +57 -57
  120. claude_mpm/dashboard/static/js/components/file-change-viewer.js +74 -74
  121. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +6 -6
  122. claude_mpm/dashboard/static/js/components/file-viewer.js +42 -42
  123. claude_mpm/dashboard/static/js/components/module-viewer.js +27 -27
  124. claude_mpm/dashboard/static/js/components/session-manager.js +14 -14
  125. claude_mpm/dashboard/static/js/components/socket-manager.js +1 -1
  126. claude_mpm/dashboard/static/js/components/ui-state-manager.js +14 -14
  127. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +110 -110
  128. claude_mpm/dashboard/static/js/components/working-directory.js +8 -8
  129. claude_mpm/dashboard/static/js/connection-manager.js +76 -76
  130. claude_mpm/dashboard/static/js/dashboard.js +76 -58
  131. claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
  132. claude_mpm/dashboard/static/js/socket-client.js +138 -121
  133. claude_mpm/dashboard/templates/code_simple.html +23 -23
  134. claude_mpm/dashboard/templates/index.html +18 -18
  135. claude_mpm/experimental/cli_enhancements.py +1 -5
  136. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  137. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  138. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  139. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  140. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  141. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  142. claude_mpm/hooks/claude_hooks/event_handlers.py +3 -1
  143. claude_mpm/hooks/claude_hooks/hook_handler.py +24 -7
  144. claude_mpm/hooks/claude_hooks/installer.py +45 -0
  145. claude_mpm/hooks/claude_hooks/memory_integration.py +12 -1
  146. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  147. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  148. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  149. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  150. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  151. claude_mpm/hooks/failure_learning/__init__.py +2 -8
  152. claude_mpm/hooks/failure_learning/failure_detection_hook.py +1 -6
  153. claude_mpm/hooks/failure_learning/fix_detection_hook.py +1 -6
  154. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +1 -6
  155. claude_mpm/hooks/kuzu_response_hook.py +1 -5
  156. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  157. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  158. claude_mpm/models/git_repository.py +198 -0
  159. claude_mpm/scripts/claude-hook-handler.sh +3 -3
  160. claude_mpm/scripts/start_activity_logging.py +3 -1
  161. claude_mpm/services/agents/agent_builder.py +45 -9
  162. claude_mpm/services/agents/agent_preset_service.py +238 -0
  163. claude_mpm/services/agents/agent_selection_service.py +484 -0
  164. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  165. claude_mpm/services/agents/cache_git_manager.py +621 -0
  166. claude_mpm/services/agents/deployment/agent_deployment.py +126 -2
  167. claude_mpm/services/agents/deployment/agent_discovery_service.py +105 -73
  168. claude_mpm/services/agents/deployment/agent_format_converter.py +1 -1
  169. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +1 -5
  170. claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
  171. claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
  172. claude_mpm/services/agents/deployment/agent_template_builder.py +236 -15
  173. claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
  174. claude_mpm/services/agents/deployment/async_agent_deployment.py +2 -1
  175. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
  176. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +115 -15
  177. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
  178. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +1 -4
  179. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
  180. claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
  181. claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -46
  182. claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
  183. claude_mpm/services/agents/git_source_manager.py +629 -0
  184. claude_mpm/services/agents/loading/framework_agent_loader.py +9 -12
  185. claude_mpm/services/agents/local_template_manager.py +50 -10
  186. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  187. claude_mpm/services/agents/sources/__init__.py +13 -0
  188. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  189. claude_mpm/services/agents/sources/git_source_sync_service.py +1087 -0
  190. claude_mpm/services/agents/startup_sync.py +239 -0
  191. claude_mpm/services/agents/toolchain_detector.py +474 -0
  192. claude_mpm/services/analysis/__init__.py +25 -0
  193. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  194. claude_mpm/services/analysis/postmortem_service.py +765 -0
  195. claude_mpm/services/cli/session_pause_manager.py +504 -0
  196. claude_mpm/services/cli/session_resume_helper.py +36 -16
  197. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  198. claude_mpm/services/command_deployment_service.py +200 -6
  199. claude_mpm/services/core/base.py +31 -11
  200. claude_mpm/services/core/interfaces/__init__.py +1 -3
  201. claude_mpm/services/core/interfaces/health.py +1 -4
  202. claude_mpm/services/core/interfaces.py +56 -1
  203. claude_mpm/services/core/models/__init__.py +2 -11
  204. claude_mpm/services/core/models/agent_config.py +3 -0
  205. claude_mpm/services/core/models/process.py +4 -0
  206. claude_mpm/services/diagnostics/checks/__init__.py +4 -0
  207. claude_mpm/services/diagnostics/checks/agent_check.py +0 -2
  208. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  209. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  210. claude_mpm/services/diagnostics/checks/mcp_check.py +0 -1
  211. claude_mpm/services/diagnostics/checks/mcp_services_check.py +7 -15
  212. claude_mpm/services/diagnostics/checks/monitor_check.py +0 -1
  213. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  214. claude_mpm/services/diagnostics/diagnostic_runner.py +9 -0
  215. claude_mpm/services/diagnostics/doctor_reporter.py +40 -10
  216. claude_mpm/services/diagnostics/models.py +21 -0
  217. claude_mpm/services/event_bus/direct_relay.py +3 -3
  218. claude_mpm/services/event_bus/event_bus.py +36 -3
  219. claude_mpm/services/event_bus/relay.py +23 -7
  220. claude_mpm/services/events/consumers/logging.py +1 -2
  221. claude_mpm/services/git/__init__.py +21 -0
  222. claude_mpm/services/git/git_operations_service.py +494 -0
  223. claude_mpm/services/github/__init__.py +21 -0
  224. claude_mpm/services/github/github_cli_service.py +397 -0
  225. claude_mpm/services/infrastructure/monitoring/__init__.py +1 -5
  226. claude_mpm/services/infrastructure/monitoring/aggregator.py +1 -6
  227. claude_mpm/services/infrastructure/monitoring/resources.py +1 -1
  228. claude_mpm/services/instructions/__init__.py +9 -0
  229. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  230. claude_mpm/services/local_ops/__init__.py +5 -13
  231. claude_mpm/services/local_ops/health_checks/__init__.py +1 -3
  232. claude_mpm/services/local_ops/health_manager.py +1 -4
  233. claude_mpm/services/local_ops/process_manager.py +1 -1
  234. claude_mpm/services/local_ops/resource_monitor.py +2 -2
  235. claude_mpm/services/mcp_config_manager.py +75 -145
  236. claude_mpm/services/mcp_gateway/auto_configure.py +31 -25
  237. claude_mpm/services/mcp_gateway/config/configuration.py +1 -1
  238. claude_mpm/services/mcp_gateway/core/process_pool.py +41 -26
  239. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +1 -6
  240. claude_mpm/services/mcp_gateway/server/stdio_server.py +0 -2
  241. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +1 -1
  242. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +26 -21
  243. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +6 -2
  244. claude_mpm/services/mcp_service_verifier.py +6 -3
  245. claude_mpm/services/memory/failure_tracker.py +19 -4
  246. claude_mpm/services/memory/optimizer.py +1 -1
  247. claude_mpm/services/model/model_router.py +8 -9
  248. claude_mpm/services/monitor/daemon.py +29 -9
  249. claude_mpm/services/monitor/daemon_manager.py +96 -19
  250. claude_mpm/services/monitor/server.py +2 -2
  251. claude_mpm/services/native_agent_converter.py +356 -0
  252. claude_mpm/services/port_manager.py +1 -1
  253. claude_mpm/services/pr/__init__.py +14 -0
  254. claude_mpm/services/pr/pr_template_service.py +329 -0
  255. claude_mpm/services/project/documentation_manager.py +2 -1
  256. claude_mpm/services/project/project_organizer.py +4 -0
  257. claude_mpm/services/project/toolchain_analyzer.py +3 -1
  258. claude_mpm/services/runner_configuration_service.py +17 -3
  259. claude_mpm/services/self_upgrade_service.py +165 -7
  260. claude_mpm/services/session_management_service.py +16 -4
  261. claude_mpm/services/skills/__init__.py +18 -0
  262. claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
  263. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  264. claude_mpm/services/skills_config.py +547 -0
  265. claude_mpm/services/skills_deployer.py +955 -0
  266. claude_mpm/services/socketio/handlers/connection.py +1 -1
  267. claude_mpm/services/socketio/handlers/git.py +2 -2
  268. claude_mpm/services/socketio/server/core.py +1 -4
  269. claude_mpm/services/socketio/server/main.py +1 -3
  270. claude_mpm/services/system_instructions_service.py +1 -3
  271. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +0 -3
  272. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +0 -1
  273. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +1 -1
  274. claude_mpm/services/unified/deployment_strategies/vercel.py +1 -5
  275. claude_mpm/services/unified/unified_deployment.py +1 -5
  276. claude_mpm/services/version_control/conflict_resolution.py +6 -4
  277. claude_mpm/services/visualization/__init__.py +1 -5
  278. claude_mpm/services/visualization/mermaid_generator.py +2 -3
  279. claude_mpm/skills/__init__.py +3 -3
  280. claude_mpm/skills/agent_skills_injector.py +42 -49
  281. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  282. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +17 -10
  283. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +92 -39
  284. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +13 -12
  285. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +5 -3
  286. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +19 -12
  287. claude_mpm/skills/bundled/performance-profiling.md +6 -0
  288. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +6 -6
  289. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +13 -9
  290. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +8 -8
  291. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +37 -15
  292. claude_mpm/skills/skills_registry.py +44 -48
  293. claude_mpm/skills/skills_service.py +117 -108
  294. claude_mpm/templates/questions/__init__.py +38 -0
  295. claude_mpm/templates/questions/base.py +193 -0
  296. claude_mpm/templates/questions/pr_strategy.py +311 -0
  297. claude_mpm/templates/questions/project_init.py +385 -0
  298. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  299. claude_mpm/tools/__main__.py +8 -8
  300. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  301. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  302. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  303. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  304. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  305. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  306. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  307. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  308. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  309. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  310. claude_mpm/utils/agent_dependency_loader.py +80 -13
  311. claude_mpm/utils/agent_filters.py +288 -0
  312. claude_mpm/utils/dependency_cache.py +3 -1
  313. claude_mpm/utils/gitignore.py +244 -0
  314. claude_mpm/utils/log_cleanup.py +3 -3
  315. claude_mpm/utils/migration.py +372 -0
  316. claude_mpm/utils/progress.py +387 -0
  317. claude_mpm/utils/robust_installer.py +3 -5
  318. claude_mpm/utils/structured_questions.py +619 -0
  319. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/METADATA +496 -65
  320. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/RECORD +328 -416
  321. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
  322. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
  323. claude_mpm/agents/templates/agent-manager.json +0 -273
  324. claude_mpm/agents/templates/agentic-coder-optimizer.json +0 -248
  325. claude_mpm/agents/templates/api_qa.json +0 -180
  326. claude_mpm/agents/templates/circuit_breakers.md +0 -638
  327. claude_mpm/agents/templates/clerk-ops.json +0 -235
  328. claude_mpm/agents/templates/code_analyzer.json +0 -101
  329. claude_mpm/agents/templates/content-agent.json +0 -358
  330. claude_mpm/agents/templates/dart_engineer.json +0 -307
  331. claude_mpm/agents/templates/data_engineer.json +0 -225
  332. claude_mpm/agents/templates/documentation.json +0 -211
  333. claude_mpm/agents/templates/engineer.json +0 -210
  334. claude_mpm/agents/templates/gcp_ops_agent.json +0 -253
  335. claude_mpm/agents/templates/golang_engineer.json +0 -270
  336. claude_mpm/agents/templates/imagemagick.json +0 -264
  337. claude_mpm/agents/templates/java_engineer.json +0 -346
  338. claude_mpm/agents/templates/local_ops_agent.json +0 -1840
  339. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
  340. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250901_010124_142.md +0 -400
  341. claude_mpm/agents/templates/memory_manager.json +0 -158
  342. claude_mpm/agents/templates/nextjs_engineer.json +0 -285
  343. claude_mpm/agents/templates/ops.json +0 -185
  344. claude_mpm/agents/templates/php-engineer.json +0 -281
  345. claude_mpm/agents/templates/product_owner.json +0 -338
  346. claude_mpm/agents/templates/project_organizer.json +0 -140
  347. claude_mpm/agents/templates/prompt-engineer.json +0 -737
  348. claude_mpm/agents/templates/python_engineer.json +0 -387
  349. claude_mpm/agents/templates/qa.json +0 -242
  350. claude_mpm/agents/templates/react_engineer.json +0 -238
  351. claude_mpm/agents/templates/refactoring_engineer.json +0 -276
  352. claude_mpm/agents/templates/research.json +0 -188
  353. claude_mpm/agents/templates/ruby-engineer.json +0 -280
  354. claude_mpm/agents/templates/rust_engineer.json +0 -275
  355. claude_mpm/agents/templates/security.json +0 -202
  356. claude_mpm/agents/templates/svelte-engineer.json +0 -225
  357. claude_mpm/agents/templates/ticketing.json +0 -177
  358. claude_mpm/agents/templates/typescript_engineer.json +0 -285
  359. claude_mpm/agents/templates/vercel_ops_agent.json +0 -412
  360. claude_mpm/agents/templates/version_control.json +0 -157
  361. claude_mpm/agents/templates/web_qa.json +0 -399
  362. claude_mpm/agents/templates/web_ui.json +0 -189
  363. claude_mpm/cli/commands/mpm_init.py +0 -2093
  364. claude_mpm/commands/mpm-tickets.md +0 -102
  365. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
  366. claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +0 -188
  367. claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +0 -156
  368. claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +0 -38
  369. claude_mpm/dashboard/react/components/shared/FilterBar.module.css +0 -92
  370. claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +0 -248
  371. claude_mpm/dashboard/static/archive/activity_dashboard_test.html +0 -61
  372. claude_mpm/dashboard/static/archive/test_activity_connection.html +0 -179
  373. claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +0 -68
  374. claude_mpm/dashboard/static/archive/test_dashboard.html +0 -409
  375. claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +0 -519
  376. claude_mpm/dashboard/static/archive/test_dashboard_verification.html +0 -181
  377. claude_mpm/dashboard/static/archive/test_file_data.html +0 -315
  378. claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +0 -243
  379. claude_mpm/dashboard/static/archive/test_file_tree_fix.html +0 -234
  380. claude_mpm/dashboard/static/archive/test_file_tree_rename.html +0 -117
  381. claude_mpm/dashboard/static/archive/test_file_tree_tab.html +0 -115
  382. claude_mpm/dashboard/static/archive/test_file_viewer.html +0 -224
  383. claude_mpm/dashboard/static/archive/test_final_activity.html +0 -220
  384. claude_mpm/dashboard/static/archive/test_tab_fix.html +0 -139
  385. claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +0 -1
  386. claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
  387. claude_mpm/dashboard/static/built/components/agent-hierarchy.js +0 -777
  388. claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
  389. claude_mpm/dashboard/static/built/components/build-tracker.js +0 -333
  390. claude_mpm/dashboard/static/built/components/code-simple.js +0 -857
  391. claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +0 -353
  392. claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +0 -235
  393. claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +0 -409
  394. claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +0 -435
  395. claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
  396. claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
  397. claude_mpm/dashboard/static/built/components/connection-debug.js +0 -654
  398. claude_mpm/dashboard/static/built/components/diff-viewer.js +0 -891
  399. claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
  400. claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
  401. claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
  402. claude_mpm/dashboard/static/built/components/file-change-tracker.js +0 -443
  403. claude_mpm/dashboard/static/built/components/file-change-viewer.js +0 -690
  404. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
  405. claude_mpm/dashboard/static/built/components/file-viewer.js +0 -2
  406. claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
  407. claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
  408. claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
  409. claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
  410. claude_mpm/dashboard/static/built/components/nav-bar.js +0 -145
  411. claude_mpm/dashboard/static/built/components/page-structure.js +0 -429
  412. claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
  413. claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
  414. claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
  415. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
  416. claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
  417. claude_mpm/dashboard/static/built/connection-manager.js +0 -536
  418. claude_mpm/dashboard/static/built/dashboard.js +0 -2
  419. claude_mpm/dashboard/static/built/extension-error-handler.js +0 -164
  420. claude_mpm/dashboard/static/built/react/events.js +0 -30
  421. claude_mpm/dashboard/static/built/shared/dom-helpers.js +0 -396
  422. claude_mpm/dashboard/static/built/shared/event-bus.js +0 -330
  423. claude_mpm/dashboard/static/built/shared/event-filter-service.js +0 -540
  424. claude_mpm/dashboard/static/built/shared/logger.js +0 -385
  425. claude_mpm/dashboard/static/built/shared/page-structure.js +0 -249
  426. claude_mpm/dashboard/static/built/shared/tooltip-service.js +0 -253
  427. claude_mpm/dashboard/static/built/socket-client.js +0 -2
  428. claude_mpm/dashboard/static/built/tab-isolation-fix.js +0 -185
  429. claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +0 -1
  430. claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
  431. claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
  432. claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
  433. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  434. claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
  435. claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
  436. claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
  437. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
  438. claude_mpm/dashboard/static/dist/components/file-viewer.js +0 -2
  439. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
  440. claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
  441. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
  442. claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
  443. claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
  444. claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
  445. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
  446. claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
  447. claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
  448. claude_mpm/dashboard/static/dist/dashboard.js +0 -2
  449. claude_mpm/dashboard/static/dist/react/events.js +0 -30
  450. claude_mpm/dashboard/static/dist/socket-client.js +0 -2
  451. claude_mpm/dashboard/static/events.html +0 -607
  452. claude_mpm/dashboard/static/index.html +0 -635
  453. claude_mpm/dashboard/static/js/shared/dom-helpers.js +0 -396
  454. claude_mpm/dashboard/static/js/shared/event-bus.js +0 -330
  455. claude_mpm/dashboard/static/js/shared/logger.js +0 -385
  456. claude_mpm/dashboard/static/js/shared/tooltip-service.js +0 -253
  457. claude_mpm/dashboard/static/js/stores/dashboard-store.js +0 -562
  458. claude_mpm/dashboard/static/legacy/activity.html +0 -736
  459. claude_mpm/dashboard/static/legacy/agents.html +0 -786
  460. claude_mpm/dashboard/static/legacy/files.html +0 -747
  461. claude_mpm/dashboard/static/legacy/tools.html +0 -831
  462. claude_mpm/dashboard/static/monitors.html +0 -431
  463. claude_mpm/dashboard/static/production/events.html +0 -659
  464. claude_mpm/dashboard/static/production/main.html +0 -698
  465. claude_mpm/dashboard/static/production/monitors.html +0 -483
  466. claude_mpm/dashboard/static/test-archive/dashboard.html +0 -635
  467. claude_mpm/dashboard/static/test-archive/debug-events.html +0 -147
  468. claude_mpm/dashboard/static/test-archive/test-navigation.html +0 -256
  469. claude_mpm/dashboard/static/test-archive/test-react-exports.html +0 -180
  470. claude_mpm/dashboard/static/test-archive/test_debug.html +0 -25
  471. claude_mpm/skills/bundled/collaboration/brainstorming/SKILL.md +0 -75
  472. claude_mpm/skills/bundled/collaboration/dispatching-parallel-agents/SKILL.md +0 -184
  473. claude_mpm/skills/bundled/collaboration/requesting-code-review/SKILL.md +0 -107
  474. claude_mpm/skills/bundled/collaboration/requesting-code-review/code-reviewer.md +0 -146
  475. claude_mpm/skills/bundled/collaboration/writing-plans/SKILL.md +0 -118
  476. claude_mpm/skills/bundled/debugging/root-cause-tracing/SKILL.md +0 -177
  477. claude_mpm/skills/bundled/debugging/systematic-debugging/CREATION-LOG.md +0 -119
  478. claude_mpm/skills/bundled/debugging/systematic-debugging/SKILL.md +0 -148
  479. claude_mpm/skills/bundled/debugging/systematic-debugging/references/anti-patterns.md +0 -483
  480. claude_mpm/skills/bundled/debugging/systematic-debugging/references/examples.md +0 -452
  481. claude_mpm/skills/bundled/debugging/systematic-debugging/references/troubleshooting.md +0 -449
  482. claude_mpm/skills/bundled/debugging/systematic-debugging/references/workflow.md +0 -411
  483. claude_mpm/skills/bundled/debugging/systematic-debugging/test-academic.md +0 -14
  484. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-1.md +0 -58
  485. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-2.md +0 -68
  486. claude_mpm/skills/bundled/debugging/systematic-debugging/test-pressure-3.md +0 -69
  487. claude_mpm/skills/bundled/debugging/verification-before-completion/SKILL.md +0 -175
  488. claude_mpm/skills/bundled/debugging/verification-before-completion/references/common-failures.md +0 -213
  489. claude_mpm/skills/bundled/debugging/verification-before-completion/references/gate-function.md +0 -314
  490. claude_mpm/skills/bundled/debugging/verification-before-completion/references/verification-patterns.md +0 -227
  491. claude_mpm/skills/bundled/main/artifacts-builder/SKILL.md +0 -74
  492. claude_mpm/skills/bundled/main/internal-comms/SKILL.md +0 -32
  493. claude_mpm/skills/bundled/main/internal-comms/examples/3p-updates.md +0 -47
  494. claude_mpm/skills/bundled/main/internal-comms/examples/company-newsletter.md +0 -65
  495. claude_mpm/skills/bundled/main/internal-comms/examples/faq-answers.md +0 -30
  496. claude_mpm/skills/bundled/main/internal-comms/examples/general-comms.md +0 -16
  497. claude_mpm/skills/bundled/main/mcp-builder/SKILL.md +0 -328
  498. claude_mpm/skills/bundled/main/mcp-builder/reference/evaluation.md +0 -602
  499. claude_mpm/skills/bundled/main/mcp-builder/reference/mcp_best_practices.md +0 -915
  500. claude_mpm/skills/bundled/main/mcp-builder/reference/node_mcp_server.md +0 -916
  501. claude_mpm/skills/bundled/main/mcp-builder/reference/python_mcp_server.md +0 -752
  502. claude_mpm/skills/bundled/main/skill-creator/SKILL.md +0 -209
  503. claude_mpm/skills/bundled/testing/condition-based-waiting/SKILL.md +0 -123
  504. claude_mpm/skills/bundled/testing/test-driven-development/SKILL.md +0 -145
  505. claude_mpm/skills/bundled/testing/test-driven-development/references/anti-patterns.md +0 -543
  506. claude_mpm/skills/bundled/testing/test-driven-development/references/examples.md +0 -741
  507. claude_mpm/skills/bundled/testing/test-driven-development/references/integration.md +0 -470
  508. claude_mpm/skills/bundled/testing/test-driven-development/references/philosophy.md +0 -458
  509. claude_mpm/skills/bundled/testing/test-driven-development/references/workflow.md +0 -639
  510. claude_mpm/skills/bundled/testing/testing-anti-patterns/SKILL.md +0 -304
  511. claude_mpm/skills/bundled/testing/webapp-testing/SKILL.md +0 -96
  512. claude_mpm/tools/code_tree_analyzer.py +0 -1825
  513. /claude_mpm/agents/templates/{git_file_tracking.md → git-file-tracking.md} +0 -0
  514. /claude_mpm/agents/templates/{pm_examples.md → pm-examples.md} +0 -0
  515. /claude_mpm/agents/templates/{response_format.md → response-format.md} +0 -0
  516. /claude_mpm/agents/templates/{validation_templates.md → validation-templates.md} +0 -0
  517. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/WHEEL +0 -0
  518. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/entry_points.txt +0 -0
  519. {claude_mpm-4.20.3.dist-info → claude_mpm-5.1.8.dist-info}/licenses/LICENSE +0 -0
  520. {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(f"\n[bold cyan]Skills for agent '{args.agent}':[/bold cyan]\n")
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(f"[yellow]No skills found for agent '{args.agent}'[/yellow]")
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 hasattr(args, "verbose") and args.verbose and skill_info.get("description"):
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(f"\n[bold cyan]Skills in category '{args.category}':[/bold cyan]\n")
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(category_skills, key=lambda s: s.get("name", "")):
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 bundled skills to project."""
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
- result = self.skills_service.deploy_bundled_skills(
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 result["deployed"]:
172
- console.print(f"[green]✓ Deployed {len(result['deployed'])} skill(s):[/green]")
173
- for skill in result["deployed"]:
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 result["skipped"]:
178
- console.print(f"[yellow]⊘ Skipped {len(result['skipped'])} skill(s) (already deployed):[/yellow]")
179
- for skill in result["skipped"]:
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 result["errors"]:
184
- console.print(f"[red]✗ Failed to deploy {len(result['errors'])} skill(s):[/red]")
185
- for skill, error in result["errors"].items():
186
- console.print(f" • {skill}: {error}")
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
- total = len(result["deployed"]) + len(result["skipped"]) + len(result["errors"])
191
- console.print(f"[bold]Summary:[/bold] {len(result['deployed'])} deployed, "
192
- f"{len(result['skipped'])} skipped, {len(result['errors'])} errors "
193
- f"(Total: {total})\n")
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 result["errors"] else 0
197
- return CommandResult(success=not result["errors"], exit_code=exit_code)
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(f"\n[bold cyan]Validating skill '{skill_name}'...[/bold cyan]\n")
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(f"[yellow]Warnings ({len(result['warnings'])}):[/yellow]")
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("[red]Strict mode: treating warnings as errors[/red]")
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(f"[yellow]Updates available for {len(result['updates_available'])} skill(s):[/yellow]")
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("[dim]Run without --check-only to install updates[/dim]\n")
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(f"[green]✓ Updated {len(install_result['updated'])} skill(s)[/green]\n")
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(f"[red]✗ Failed to update {len(install_result['errors'])} skill(s)[/red]")
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(success=not install_result.get("errors"), exit_code=exit_code)
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 += f"\n[bold]Used by agents:[/bold] {', '.join(agents_using)}\n"
446
+ info_text += (
447
+ f"\n[bold]Used by agents:[/bold] {', '.join(agents_using)}\n"
448
+ )
327
449
 
328
- console.print(Panel(info_text, title="Skill Information", border_style="cyan"))
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(f"\n[yellow]SKILL.md not found at {skill_md}[/yellow]")
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(f"\n[cyan]Configuration path ({scope}):[/cyan] {config_path}\n")
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(f"\n[yellow]Configuration file does not exist: {config_path}[/yellow]")
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() == 'y':
495
+ if input().lower() == "y":
366
496
  self.skills_service.create_default_config(scope)
367
- console.print(f"[green]Created default configuration at {config_path}[/green]\n")
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(f"\n[green]Configuration saved to {config_path}[/green]\n")
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(f"\n[bold cyan]Skills Configuration ({scope}):[/bold cyan]\n")
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
- metadata = self.skills_service.parse_skill_metadata(content)
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
  """