claude-mpm 4.1.26__py3-none-any.whl → 5.0.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of claude-mpm might be problematic. Click here for more details.

Files changed (792) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__init__.py +20 -5
  4. claude_mpm/agents/BASE_AGENT_TEMPLATE.md +118 -0
  5. claude_mpm/agents/BASE_DOCUMENTATION.md +53 -0
  6. claude_mpm/agents/BASE_ENGINEER.md +658 -0
  7. claude_mpm/agents/BASE_OPS.md +219 -0
  8. claude_mpm/agents/BASE_PM.md +432 -158
  9. claude_mpm/agents/BASE_PROMPT_ENGINEER.md +787 -0
  10. claude_mpm/agents/BASE_QA.md +167 -0
  11. claude_mpm/agents/BASE_RESEARCH.md +53 -0
  12. claude_mpm/agents/OUTPUT_STYLE.md +254 -29
  13. claude_mpm/agents/PM_INSTRUCTIONS.md +969 -0
  14. claude_mpm/agents/PM_INSTRUCTIONS_TEACH.md +1322 -0
  15. claude_mpm/agents/WORKFLOW.md +355 -191
  16. claude_mpm/agents/__init__.py +6 -0
  17. claude_mpm/agents/agent_loader.py +41 -14
  18. claude_mpm/agents/agent_loader_integration.py +3 -2
  19. claude_mpm/agents/async_agent_loader.py +3 -3
  20. claude_mpm/agents/base_agent.json +6 -3
  21. claude_mpm/agents/base_agent_loader.py +21 -44
  22. claude_mpm/agents/frontmatter_validator.py +292 -252
  23. claude_mpm/agents/system_agent_config.py +3 -2
  24. claude_mpm/agents/templates/README.md +465 -0
  25. claude_mpm/agents/templates/circuit-breakers.md +1005 -0
  26. claude_mpm/agents/templates/context-management-examples.md +544 -0
  27. claude_mpm/agents/templates/git-file-tracking.md +584 -0
  28. claude_mpm/agents/templates/pm-examples.md +474 -0
  29. claude_mpm/agents/templates/pm-red-flags.md +310 -0
  30. claude_mpm/agents/templates/pr-workflow-examples.md +427 -0
  31. claude_mpm/agents/templates/research-gate-examples.md +669 -0
  32. claude_mpm/agents/templates/response-format.md +583 -0
  33. claude_mpm/agents/templates/structured-questions-examples.md +615 -0
  34. claude_mpm/agents/templates/ticket-completeness-examples.md +139 -0
  35. claude_mpm/agents/templates/ticketing-examples.md +277 -0
  36. claude_mpm/agents/templates/validation-templates.md +312 -0
  37. claude_mpm/cli/__init__.py +72 -376
  38. claude_mpm/cli/commands/__init__.py +4 -0
  39. claude_mpm/cli/commands/agent_manager.py +675 -20
  40. claude_mpm/cli/commands/agent_source.py +774 -0
  41. claude_mpm/cli/commands/agent_state_manager.py +344 -0
  42. claude_mpm/cli/commands/agents.py +1673 -178
  43. claude_mpm/cli/commands/agents_cleanup.py +210 -0
  44. claude_mpm/cli/commands/agents_detect.py +380 -0
  45. claude_mpm/cli/commands/agents_discover.py +338 -0
  46. claude_mpm/cli/commands/agents_recommend.py +309 -0
  47. claude_mpm/cli/commands/aggregate.py +11 -7
  48. claude_mpm/cli/commands/analyze.py +18 -13
  49. claude_mpm/cli/commands/analyze_code.py +8 -4
  50. claude_mpm/cli/commands/auto_configure.py +566 -0
  51. claude_mpm/cli/commands/cleanup.py +12 -12
  52. claude_mpm/cli/commands/config.py +54 -17
  53. claude_mpm/cli/commands/configure.py +1184 -1055
  54. claude_mpm/cli/commands/configure_agent_display.py +261 -0
  55. claude_mpm/cli/commands/configure_behavior_manager.py +204 -0
  56. claude_mpm/cli/commands/configure_hook_manager.py +225 -0
  57. claude_mpm/cli/commands/configure_models.py +18 -0
  58. claude_mpm/cli/commands/configure_navigation.py +184 -0
  59. claude_mpm/cli/commands/configure_paths.py +104 -0
  60. claude_mpm/cli/commands/configure_persistence.py +254 -0
  61. claude_mpm/cli/commands/configure_startup_manager.py +646 -0
  62. claude_mpm/cli/commands/configure_template_editor.py +497 -0
  63. claude_mpm/cli/commands/configure_validators.py +73 -0
  64. claude_mpm/cli/commands/dashboard.py +50 -52
  65. claude_mpm/cli/commands/debug.py +19 -19
  66. claude_mpm/cli/commands/doctor.py +51 -7
  67. claude_mpm/cli/commands/hook_errors.py +277 -0
  68. claude_mpm/cli/commands/info.py +3 -4
  69. claude_mpm/cli/commands/local_deploy.py +534 -0
  70. claude_mpm/cli/commands/mcp.py +17 -10
  71. claude_mpm/cli/commands/mcp_command_router.py +11 -0
  72. claude_mpm/cli/commands/mcp_config.py +154 -0
  73. claude_mpm/cli/commands/mcp_external_commands.py +249 -0
  74. claude_mpm/cli/commands/mcp_install_commands.py +101 -32
  75. claude_mpm/cli/commands/mcp_pipx_config.py +2 -2
  76. claude_mpm/cli/commands/mcp_setup_external.py +868 -0
  77. claude_mpm/cli/commands/memory.py +55 -21
  78. claude_mpm/cli/commands/monitor.py +160 -70
  79. claude_mpm/cli/commands/mpm_init/__init__.py +73 -0
  80. claude_mpm/cli/commands/mpm_init/core.py +573 -0
  81. claude_mpm/cli/commands/mpm_init/display.py +341 -0
  82. claude_mpm/cli/commands/mpm_init/git_activity.py +427 -0
  83. claude_mpm/cli/commands/mpm_init/modes.py +397 -0
  84. claude_mpm/cli/commands/mpm_init/prompts.py +442 -0
  85. claude_mpm/cli/commands/mpm_init_cli.py +396 -0
  86. claude_mpm/cli/commands/mpm_init_handler.py +114 -4
  87. claude_mpm/cli/commands/postmortem.py +401 -0
  88. claude_mpm/cli/commands/run.py +252 -167
  89. claude_mpm/cli/commands/search.py +458 -0
  90. claude_mpm/cli/commands/skill_source.py +694 -0
  91. claude_mpm/cli/commands/skills.py +1225 -0
  92. claude_mpm/cli/commands/uninstall.py +176 -0
  93. claude_mpm/cli/commands/upgrade.py +152 -0
  94. claude_mpm/cli/commands/verify.py +119 -0
  95. claude_mpm/cli/executor.py +279 -0
  96. claude_mpm/cli/helpers.py +105 -0
  97. claude_mpm/cli/interactive/__init__.py +21 -0
  98. claude_mpm/cli/interactive/agent_wizard.py +1872 -0
  99. claude_mpm/cli/interactive/skills_wizard.py +491 -0
  100. claude_mpm/cli/parser.py +79 -2
  101. claude_mpm/cli/parsers/__init__.py +7 -1
  102. claude_mpm/cli/parsers/agent_manager_parser.py +161 -1
  103. claude_mpm/cli/parsers/agent_source_parser.py +171 -0
  104. claude_mpm/cli/parsers/agents_parser.py +369 -1
  105. claude_mpm/cli/parsers/auto_configure_parser.py +245 -0
  106. claude_mpm/cli/parsers/base_parser.py +196 -3
  107. claude_mpm/cli/parsers/config_parser.py +96 -43
  108. claude_mpm/cli/parsers/configure_parser.py +11 -15
  109. claude_mpm/cli/parsers/local_deploy_parser.py +227 -0
  110. claude_mpm/cli/parsers/mcp_parser.py +15 -0
  111. claude_mpm/cli/parsers/monitor_parser.py +12 -2
  112. claude_mpm/cli/parsers/mpm_init_parser.py +179 -9
  113. claude_mpm/cli/parsers/run_parser.py +5 -0
  114. claude_mpm/cli/parsers/search_parser.py +245 -0
  115. claude_mpm/cli/parsers/skill_source_parser.py +169 -0
  116. claude_mpm/cli/parsers/skills_parser.py +282 -0
  117. claude_mpm/cli/parsers/source_parser.py +138 -0
  118. claude_mpm/cli/shared/argument_patterns.py +20 -13
  119. claude_mpm/cli/shared/base_command.py +2 -2
  120. claude_mpm/cli/shared/output_formatters.py +28 -19
  121. claude_mpm/cli/startup.py +994 -0
  122. claude_mpm/cli/startup_display.py +480 -0
  123. claude_mpm/cli/startup_logging.py +179 -13
  124. claude_mpm/cli/utils.py +54 -3
  125. claude_mpm/cli_module/commands.py +1 -1
  126. claude_mpm/commands/mpm-agents-auto-configure.md +278 -0
  127. claude_mpm/commands/mpm-agents-detect.md +177 -0
  128. claude_mpm/commands/mpm-agents-list.md +131 -0
  129. claude_mpm/commands/mpm-agents-recommend.md +223 -0
  130. claude_mpm/commands/mpm-config-view.md +150 -0
  131. claude_mpm/commands/mpm-doctor.md +9 -0
  132. claude_mpm/commands/mpm-help.md +297 -5
  133. claude_mpm/commands/mpm-init.md +401 -17
  134. claude_mpm/commands/mpm-monitor.md +418 -0
  135. claude_mpm/commands/mpm-postmortem.md +123 -0
  136. claude_mpm/commands/mpm-session-resume.md +381 -0
  137. claude_mpm/commands/mpm-status.md +79 -8
  138. claude_mpm/commands/mpm-ticket-organize.md +304 -0
  139. claude_mpm/commands/mpm-ticket-view.md +552 -0
  140. claude_mpm/commands/mpm-version.md +122 -0
  141. claude_mpm/commands/mpm.md +12 -0
  142. claude_mpm/config/agent_config.py +4 -4
  143. claude_mpm/config/agent_presets.py +488 -0
  144. claude_mpm/config/agent_sources.py +325 -0
  145. claude_mpm/config/experimental_features.py +7 -7
  146. claude_mpm/config/model_config.py +428 -0
  147. claude_mpm/config/paths.py +3 -2
  148. claude_mpm/config/skill_presets.py +392 -0
  149. claude_mpm/config/skill_sources.py +590 -0
  150. claude_mpm/config/socketio_config.py +3 -3
  151. claude_mpm/constants.py +28 -1
  152. claude_mpm/core/__init__.py +53 -17
  153. claude_mpm/core/agent_name_normalizer.py +3 -2
  154. claude_mpm/core/agent_registry.py +2 -2
  155. claude_mpm/core/agent_session_manager.py +10 -10
  156. claude_mpm/core/api_validator.py +330 -0
  157. claude_mpm/core/base_service.py +33 -23
  158. claude_mpm/core/cache.py +9 -9
  159. claude_mpm/core/claude_runner.py +24 -42
  160. claude_mpm/core/config.py +101 -8
  161. claude_mpm/core/config_aliases.py +7 -6
  162. claude_mpm/core/constants.py +66 -1
  163. claude_mpm/core/container.py +11 -5
  164. claude_mpm/core/enums.py +452 -0
  165. claude_mpm/core/error_handler.py +623 -0
  166. claude_mpm/core/factories.py +1 -1
  167. claude_mpm/core/file_utils.py +764 -0
  168. claude_mpm/core/framework/__init__.py +25 -0
  169. claude_mpm/core/framework/formatters/__init__.py +11 -0
  170. claude_mpm/core/framework/formatters/capability_generator.py +367 -0
  171. claude_mpm/core/framework/formatters/content_formatter.py +288 -0
  172. claude_mpm/core/framework/formatters/context_generator.py +185 -0
  173. claude_mpm/core/framework/loaders/__init__.py +13 -0
  174. claude_mpm/core/framework/loaders/agent_loader.py +210 -0
  175. claude_mpm/core/framework/loaders/file_loader.py +176 -0
  176. claude_mpm/core/framework/loaders/instruction_loader.py +181 -0
  177. claude_mpm/core/framework/loaders/packaged_loader.py +232 -0
  178. claude_mpm/core/framework/processors/__init__.py +11 -0
  179. claude_mpm/core/framework/processors/memory_processor.py +230 -0
  180. claude_mpm/core/framework/processors/metadata_processor.py +146 -0
  181. claude_mpm/core/framework/processors/template_processor.py +244 -0
  182. claude_mpm/core/framework_loader.py +321 -1631
  183. claude_mpm/core/hook_error_memory.py +381 -0
  184. claude_mpm/core/hook_manager.py +49 -8
  185. claude_mpm/core/injectable_service.py +11 -8
  186. claude_mpm/core/instruction_reinforcement_hook.py +4 -3
  187. claude_mpm/core/interactive_session.py +146 -18
  188. claude_mpm/core/interfaces.py +56 -1
  189. claude_mpm/core/lazy.py +3 -3
  190. claude_mpm/core/log_manager.py +92 -23
  191. claude_mpm/core/logger.py +22 -15
  192. claude_mpm/core/logging_config.py +6 -2
  193. claude_mpm/core/logging_utils.py +520 -0
  194. claude_mpm/core/oneshot_session.py +122 -15
  195. claude_mpm/core/optimized_agent_loader.py +9 -9
  196. claude_mpm/core/optimized_startup.py +1 -1
  197. claude_mpm/core/output_style_manager.py +12 -192
  198. claude_mpm/core/pm_hook_interceptor.py +18 -12
  199. claude_mpm/core/protocols/__init__.py +23 -0
  200. claude_mpm/core/protocols/runner_protocol.py +103 -0
  201. claude_mpm/core/protocols/session_protocol.py +131 -0
  202. claude_mpm/core/service_registry.py +7 -3
  203. claude_mpm/core/session_manager.py +14 -12
  204. claude_mpm/core/shared/config_loader.py +1 -1
  205. claude_mpm/core/shared/singleton_manager.py +11 -4
  206. claude_mpm/core/socketio_pool.py +15 -15
  207. claude_mpm/core/system_context.py +38 -0
  208. claude_mpm/core/tool_access_control.py +3 -2
  209. claude_mpm/core/types.py +4 -11
  210. claude_mpm/core/typing_utils.py +7 -6
  211. claude_mpm/core/unified_agent_registry.py +115 -11
  212. claude_mpm/core/unified_config.py +6 -6
  213. claude_mpm/core/unified_paths.py +23 -20
  214. claude_mpm/dashboard/analysis_runner.py +4 -4
  215. claude_mpm/dashboard/api/simple_directory.py +261 -0
  216. claude_mpm/dashboard/static/css/activity.css +69 -69
  217. claude_mpm/dashboard/static/css/connection-status.css +10 -10
  218. claude_mpm/dashboard/static/css/dashboard.css +600 -18
  219. claude_mpm/dashboard/static/js/components/activity-tree.js +181 -195
  220. claude_mpm/dashboard/static/js/components/agent-hierarchy.js +105 -102
  221. claude_mpm/dashboard/static/js/components/agent-inference.js +34 -31
  222. claude_mpm/dashboard/static/js/components/build-tracker.js +67 -59
  223. claude_mpm/dashboard/static/js/components/code-simple.js +857 -0
  224. claude_mpm/dashboard/static/js/components/connection-debug.js +101 -101
  225. claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
  226. claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
  227. claude_mpm/dashboard/static/js/components/event-viewer.js +50 -13
  228. claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
  229. claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
  230. claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
  231. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +36 -16
  232. claude_mpm/dashboard/static/js/components/file-viewer.js +580 -0
  233. claude_mpm/dashboard/static/js/components/module-viewer.js +49 -23
  234. claude_mpm/dashboard/static/js/components/session-manager.js +19 -19
  235. claude_mpm/dashboard/static/js/components/socket-manager.js +5 -1
  236. claude_mpm/dashboard/static/js/components/ui-state-manager.js +356 -41
  237. claude_mpm/dashboard/static/js/components/unified-data-viewer.js +520 -88
  238. claude_mpm/dashboard/static/js/components/working-directory.js +46 -11
  239. claude_mpm/dashboard/static/js/connection-manager.js +76 -76
  240. claude_mpm/dashboard/static/js/dashboard.js +309 -178
  241. claude_mpm/dashboard/static/js/extension-error-handler.js +22 -22
  242. claude_mpm/dashboard/static/js/socket-client.js +183 -139
  243. claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
  244. claude_mpm/dashboard/static/socket.io.min.js +7 -0
  245. claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
  246. claude_mpm/dashboard/templates/code_simple.html +153 -0
  247. claude_mpm/dashboard/templates/index.html +125 -122
  248. claude_mpm/experimental/cli_enhancements.py +5 -7
  249. claude_mpm/generators/agent_profile_generator.py +5 -3
  250. claude_mpm/hooks/__init__.py +37 -1
  251. claude_mpm/hooks/base_hook.py +5 -4
  252. claude_mpm/hooks/claude_hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  253. claude_mpm/hooks/claude_hooks/__pycache__/event_handlers.cpython-313.pyc +0 -0
  254. claude_mpm/hooks/claude_hooks/__pycache__/hook_handler.cpython-313.pyc +0 -0
  255. claude_mpm/hooks/claude_hooks/__pycache__/memory_integration.cpython-313.pyc +0 -0
  256. claude_mpm/hooks/claude_hooks/__pycache__/response_tracking.cpython-313.pyc +0 -0
  257. claude_mpm/hooks/claude_hooks/__pycache__/tool_analysis.cpython-313.pyc +0 -0
  258. claude_mpm/hooks/claude_hooks/connection_pool.py +4 -4
  259. claude_mpm/hooks/claude_hooks/event_handlers.py +24 -19
  260. claude_mpm/hooks/claude_hooks/hook_handler.py +29 -22
  261. claude_mpm/hooks/claude_hooks/installer.py +67 -22
  262. claude_mpm/hooks/claude_hooks/memory_integration.py +3 -3
  263. claude_mpm/hooks/claude_hooks/response_tracking.py +57 -17
  264. claude_mpm/hooks/claude_hooks/services/__pycache__/__init__.cpython-313.pyc +0 -0
  265. claude_mpm/hooks/claude_hooks/services/__pycache__/connection_manager_http.cpython-313.pyc +0 -0
  266. claude_mpm/hooks/claude_hooks/services/__pycache__/duplicate_detector.cpython-313.pyc +0 -0
  267. claude_mpm/hooks/claude_hooks/services/__pycache__/state_manager.cpython-313.pyc +0 -0
  268. claude_mpm/hooks/claude_hooks/services/__pycache__/subagent_processor.cpython-313.pyc +0 -0
  269. claude_mpm/hooks/claude_hooks/services/connection_manager.py +62 -64
  270. claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +140 -76
  271. claude_mpm/hooks/claude_hooks/services/state_manager.py +11 -9
  272. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +3 -3
  273. claude_mpm/hooks/failure_learning/__init__.py +54 -0
  274. claude_mpm/hooks/failure_learning/failure_detection_hook.py +230 -0
  275. claude_mpm/hooks/failure_learning/fix_detection_hook.py +212 -0
  276. claude_mpm/hooks/failure_learning/learning_extraction_hook.py +281 -0
  277. claude_mpm/hooks/instruction_reinforcement.py +301 -0
  278. claude_mpm/hooks/kuzu_enrichment_hook.py +263 -0
  279. claude_mpm/hooks/kuzu_memory_hook.py +386 -0
  280. claude_mpm/hooks/kuzu_response_hook.py +179 -0
  281. claude_mpm/hooks/memory_integration_hook.py +1 -1
  282. claude_mpm/hooks/session_resume_hook.py +121 -0
  283. claude_mpm/hooks/templates/pre_tool_use_simple.py +78 -0
  284. claude_mpm/hooks/templates/pre_tool_use_template.py +323 -0
  285. claude_mpm/hooks/tool_call_interceptor.py +8 -5
  286. claude_mpm/hooks/validation_hooks.py +3 -3
  287. claude_mpm/init.py +23 -4
  288. claude_mpm/models/agent_session.py +8 -6
  289. claude_mpm/models/git_repository.py +198 -0
  290. claude_mpm/models/resume_log.py +340 -0
  291. claude_mpm/scripts/claude-hook-handler.sh +35 -9
  292. claude_mpm/scripts/launch_monitor.py +85 -0
  293. claude_mpm/scripts/mcp_server.py +3 -5
  294. claude_mpm/scripts/mpm_doctor.py +3 -2
  295. claude_mpm/scripts/socketio_daemon.py +159 -512
  296. claude_mpm/scripts/start_activity_logging.py +3 -1
  297. claude_mpm/services/__init__.py +144 -160
  298. claude_mpm/services/agents/__init__.py +18 -5
  299. claude_mpm/services/agents/agent_builder.py +56 -18
  300. claude_mpm/services/agents/agent_preset_service.py +238 -0
  301. claude_mpm/services/agents/agent_selection_service.py +484 -0
  302. claude_mpm/services/agents/auto_config_manager.py +796 -0
  303. claude_mpm/services/agents/auto_deploy_index_parser.py +569 -0
  304. claude_mpm/services/agents/cache_git_manager.py +621 -0
  305. claude_mpm/services/agents/deployment/agent_configuration_manager.py +1 -1
  306. claude_mpm/services/agents/deployment/agent_deployment.py +164 -17
  307. claude_mpm/services/agents/deployment/agent_discovery_service.py +191 -41
  308. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +5 -5
  309. claude_mpm/services/agents/deployment/agent_format_converter.py +56 -12
  310. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -7
  311. claude_mpm/services/agents/deployment/agent_metrics_collector.py +3 -3
  312. claude_mpm/services/agents/deployment/agent_operation_service.py +2 -2
  313. claude_mpm/services/agents/deployment/agent_record_service.py +4 -4
  314. claude_mpm/services/agents/deployment/agent_restore_handler.py +1 -4
  315. claude_mpm/services/agents/deployment/agent_state_service.py +2 -2
  316. claude_mpm/services/agents/deployment/agent_template_builder.py +939 -50
  317. claude_mpm/services/agents/deployment/agent_validator.py +31 -7
  318. claude_mpm/services/agents/deployment/agent_version_manager.py +8 -5
  319. claude_mpm/services/agents/deployment/agent_versioning.py +1 -1
  320. claude_mpm/services/agents/deployment/agents_directory_resolver.py +101 -15
  321. claude_mpm/services/agents/deployment/async_agent_deployment.py +3 -2
  322. claude_mpm/services/agents/deployment/deployment_config_loader.py +131 -7
  323. claude_mpm/services/agents/deployment/deployment_type_detector.py +10 -14
  324. claude_mpm/services/agents/deployment/deployment_wrapper.py +58 -0
  325. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -3
  326. claude_mpm/services/agents/deployment/interface_adapter.py +3 -2
  327. claude_mpm/services/agents/deployment/local_template_deployment.py +360 -0
  328. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +249 -53
  329. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +2 -2
  330. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +8 -7
  331. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +7 -16
  332. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +4 -3
  333. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +7 -5
  334. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +6 -5
  335. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +10 -10
  336. claude_mpm/services/agents/deployment/remote_agent_discovery_service.py +363 -0
  337. claude_mpm/services/agents/deployment/single_agent_deployer.py +2 -2
  338. claude_mpm/services/agents/deployment/system_instructions_deployer.py +168 -43
  339. claude_mpm/services/agents/deployment/validation/__init__.py +3 -1
  340. claude_mpm/services/agents/deployment/validation/deployment_validator.py +2 -2
  341. claude_mpm/services/agents/deployment/validation/template_validator.py +64 -44
  342. claude_mpm/services/agents/deployment/validation/validation_result.py +1 -9
  343. claude_mpm/services/agents/git_source_manager.py +629 -0
  344. claude_mpm/services/agents/loading/agent_profile_loader.py +10 -9
  345. claude_mpm/services/agents/loading/base_agent_manager.py +16 -6
  346. claude_mpm/services/agents/loading/framework_agent_loader.py +11 -14
  347. claude_mpm/services/agents/local_template_manager.py +784 -0
  348. claude_mpm/services/agents/management/agent_capabilities_generator.py +3 -2
  349. claude_mpm/services/agents/management/agent_management_service.py +5 -5
  350. claude_mpm/services/agents/memory/agent_memory_manager.py +32 -29
  351. claude_mpm/services/agents/memory/content_manager.py +17 -9
  352. claude_mpm/services/agents/memory/memory_categorization_service.py +4 -2
  353. claude_mpm/services/agents/memory/memory_file_service.py +32 -6
  354. claude_mpm/services/agents/memory/memory_format_service.py +6 -4
  355. claude_mpm/services/agents/memory/memory_limits_service.py +4 -2
  356. claude_mpm/services/agents/memory/template_generator.py +3 -3
  357. claude_mpm/services/agents/observers.py +547 -0
  358. claude_mpm/services/agents/recommender.py +615 -0
  359. claude_mpm/services/agents/registry/deployed_agent_discovery.py +3 -3
  360. claude_mpm/services/agents/registry/modification_tracker.py +30 -19
  361. claude_mpm/services/agents/single_tier_deployment_service.py +696 -0
  362. claude_mpm/services/agents/sources/__init__.py +13 -0
  363. claude_mpm/services/agents/sources/agent_sync_state.py +516 -0
  364. claude_mpm/services/agents/sources/git_source_sync_service.py +1087 -0
  365. claude_mpm/services/agents/startup_sync.py +239 -0
  366. claude_mpm/services/agents/toolchain_detector.py +474 -0
  367. claude_mpm/services/analysis/__init__.py +25 -0
  368. claude_mpm/services/analysis/postmortem_reporter.py +474 -0
  369. claude_mpm/services/analysis/postmortem_service.py +765 -0
  370. claude_mpm/services/async_session_logger.py +141 -98
  371. claude_mpm/services/claude_session_logger.py +82 -74
  372. claude_mpm/services/cli/agent_cleanup_service.py +5 -0
  373. claude_mpm/services/cli/agent_listing_service.py +5 -5
  374. claude_mpm/services/cli/agent_validation_service.py +3 -1
  375. claude_mpm/services/cli/memory_crud_service.py +12 -7
  376. claude_mpm/services/cli/memory_output_formatter.py +2 -2
  377. claude_mpm/services/cli/resume_service.py +617 -0
  378. claude_mpm/services/cli/session_manager.py +104 -13
  379. claude_mpm/services/cli/session_pause_manager.py +504 -0
  380. claude_mpm/services/cli/session_resume_helper.py +372 -0
  381. claude_mpm/services/cli/startup_checker.py +13 -10
  382. claude_mpm/services/cli/unified_dashboard_manager.py +439 -0
  383. claude_mpm/services/command_deployment_service.py +209 -13
  384. claude_mpm/services/command_handler_service.py +11 -5
  385. claude_mpm/services/core/__init__.py +33 -1
  386. claude_mpm/services/core/base.py +31 -11
  387. claude_mpm/services/core/interfaces/__init__.py +88 -3
  388. claude_mpm/services/core/interfaces/agent.py +184 -0
  389. claude_mpm/services/core/interfaces/health.py +169 -0
  390. claude_mpm/services/core/interfaces/model.py +281 -0
  391. claude_mpm/services/core/interfaces/process.py +372 -0
  392. claude_mpm/services/core/interfaces/project.py +121 -0
  393. claude_mpm/services/core/interfaces/restart.py +307 -0
  394. claude_mpm/services/core/interfaces/stability.py +260 -0
  395. claude_mpm/services/core/interfaces.py +56 -1
  396. claude_mpm/services/core/memory_manager.py +92 -47
  397. claude_mpm/services/core/models/__init__.py +70 -0
  398. claude_mpm/services/core/models/agent_config.py +384 -0
  399. claude_mpm/services/core/models/health.py +162 -0
  400. claude_mpm/services/core/models/process.py +239 -0
  401. claude_mpm/services/core/models/restart.py +302 -0
  402. claude_mpm/services/core/models/stability.py +264 -0
  403. claude_mpm/services/core/models/toolchain.py +306 -0
  404. claude_mpm/services/core/path_resolver.py +36 -14
  405. claude_mpm/services/diagnostics/__init__.py +2 -2
  406. claude_mpm/services/diagnostics/checks/__init__.py +8 -2
  407. claude_mpm/services/diagnostics/checks/agent_check.py +30 -34
  408. claude_mpm/services/diagnostics/checks/agent_sources_check.py +577 -0
  409. claude_mpm/services/diagnostics/checks/claude_code_check.py +270 -0
  410. claude_mpm/services/diagnostics/checks/common_issues_check.py +28 -27
  411. claude_mpm/services/diagnostics/checks/configuration_check.py +26 -25
  412. claude_mpm/services/diagnostics/checks/filesystem_check.py +18 -17
  413. claude_mpm/services/diagnostics/checks/installation_check.py +165 -60
  414. claude_mpm/services/diagnostics/checks/instructions_check.py +21 -21
  415. claude_mpm/services/diagnostics/checks/mcp_check.py +57 -44
  416. claude_mpm/services/diagnostics/checks/mcp_services_check.py +1058 -0
  417. claude_mpm/services/diagnostics/checks/monitor_check.py +24 -24
  418. claude_mpm/services/diagnostics/checks/skill_sources_check.py +587 -0
  419. claude_mpm/services/diagnostics/checks/startup_log_check.py +14 -11
  420. claude_mpm/services/diagnostics/diagnostic_runner.py +31 -13
  421. claude_mpm/services/diagnostics/doctor_reporter.py +305 -47
  422. claude_mpm/services/diagnostics/models.py +37 -21
  423. claude_mpm/services/event_aggregator.py +5 -3
  424. claude_mpm/services/event_bus/direct_relay.py +11 -7
  425. claude_mpm/services/event_bus/event_bus.py +51 -9
  426. claude_mpm/services/event_bus/relay.py +33 -14
  427. claude_mpm/services/events/consumers/dead_letter.py +7 -5
  428. claude_mpm/services/events/consumers/logging.py +1 -2
  429. claude_mpm/services/events/core.py +5 -6
  430. claude_mpm/services/events/producers/hook.py +6 -6
  431. claude_mpm/services/events/producers/system.py +8 -8
  432. claude_mpm/services/exceptions.py +5 -5
  433. claude_mpm/services/framework_claude_md_generator/__init__.py +1 -1
  434. claude_mpm/services/framework_claude_md_generator/content_assembler.py +5 -5
  435. claude_mpm/services/framework_claude_md_generator/content_validator.py +2 -2
  436. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +3 -3
  437. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +2 -2
  438. claude_mpm/services/framework_claude_md_generator/version_manager.py +1 -1
  439. claude_mpm/services/git/__init__.py +21 -0
  440. claude_mpm/services/git/git_operations_service.py +494 -0
  441. claude_mpm/services/github/__init__.py +21 -0
  442. claude_mpm/services/github/github_cli_service.py +397 -0
  443. claude_mpm/services/hook_installer_service.py +506 -0
  444. claude_mpm/services/hook_service.py +5 -6
  445. claude_mpm/services/infrastructure/context_preservation.py +13 -11
  446. claude_mpm/services/infrastructure/daemon_manager.py +9 -9
  447. claude_mpm/services/infrastructure/logging.py +2 -2
  448. claude_mpm/services/infrastructure/monitoring/__init__.py +2 -6
  449. claude_mpm/services/infrastructure/monitoring/aggregator.py +13 -18
  450. claude_mpm/services/infrastructure/monitoring/base.py +5 -13
  451. claude_mpm/services/infrastructure/monitoring/network.py +7 -6
  452. claude_mpm/services/infrastructure/monitoring/process.py +13 -12
  453. claude_mpm/services/infrastructure/monitoring/resources.py +8 -7
  454. claude_mpm/services/infrastructure/monitoring/service.py +16 -15
  455. claude_mpm/services/infrastructure/resume_log_generator.py +439 -0
  456. claude_mpm/services/instructions/__init__.py +9 -0
  457. claude_mpm/services/instructions/instruction_cache_service.py +374 -0
  458. claude_mpm/services/local_ops/__init__.py +155 -0
  459. claude_mpm/services/local_ops/crash_detector.py +257 -0
  460. claude_mpm/services/local_ops/health_checks/__init__.py +26 -0
  461. claude_mpm/services/local_ops/health_checks/http_check.py +224 -0
  462. claude_mpm/services/local_ops/health_checks/process_check.py +236 -0
  463. claude_mpm/services/local_ops/health_checks/resource_check.py +255 -0
  464. claude_mpm/services/local_ops/health_manager.py +427 -0
  465. claude_mpm/services/local_ops/log_monitor.py +396 -0
  466. claude_mpm/services/local_ops/memory_leak_detector.py +294 -0
  467. claude_mpm/services/local_ops/process_manager.py +595 -0
  468. claude_mpm/services/local_ops/resource_monitor.py +331 -0
  469. claude_mpm/services/local_ops/restart_manager.py +401 -0
  470. claude_mpm/services/local_ops/restart_policy.py +387 -0
  471. claude_mpm/services/local_ops/state_manager.py +372 -0
  472. claude_mpm/services/local_ops/unified_manager.py +600 -0
  473. claude_mpm/services/mcp_config_manager.py +1542 -0
  474. claude_mpm/services/mcp_gateway/__init__.py +97 -93
  475. claude_mpm/services/mcp_gateway/auto_configure.py +43 -38
  476. claude_mpm/services/mcp_gateway/config/config_loader.py +3 -3
  477. claude_mpm/services/mcp_gateway/config/configuration.py +24 -5
  478. claude_mpm/services/mcp_gateway/core/__init__.py +1 -2
  479. claude_mpm/services/mcp_gateway/core/base.py +20 -33
  480. claude_mpm/services/mcp_gateway/core/process_pool.py +591 -31
  481. claude_mpm/services/mcp_gateway/core/singleton_manager.py +2 -2
  482. claude_mpm/services/mcp_gateway/core/startup_verification.py +3 -3
  483. claude_mpm/services/mcp_gateway/main.py +90 -15
  484. claude_mpm/services/mcp_gateway/registry/service_registry.py +4 -2
  485. claude_mpm/services/mcp_gateway/registry/tool_registry.py +12 -9
  486. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +5 -10
  487. claude_mpm/services/mcp_gateway/server/stdio_server.py +9 -17
  488. claude_mpm/services/mcp_gateway/tools/__init__.py +14 -2
  489. claude_mpm/services/mcp_gateway/tools/base_adapter.py +15 -15
  490. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +10 -9
  491. claude_mpm/services/mcp_gateway/tools/external_mcp_services.py +654 -0
  492. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +36 -34
  493. claude_mpm/services/mcp_gateway/tools/hello_world.py +8 -8
  494. claude_mpm/services/mcp_gateway/tools/kuzu_memory_service.py +555 -0
  495. claude_mpm/services/mcp_gateway/utils/__init__.py +14 -0
  496. claude_mpm/services/mcp_gateway/utils/package_version_checker.py +160 -0
  497. claude_mpm/services/mcp_gateway/utils/update_preferences.py +170 -0
  498. claude_mpm/services/mcp_service_verifier.py +732 -0
  499. claude_mpm/services/memory/builder.py +9 -8
  500. claude_mpm/services/memory/cache/shared_prompt_cache.py +2 -1
  501. claude_mpm/services/memory/cache/simple_cache.py +2 -2
  502. claude_mpm/services/memory/failure_tracker.py +578 -0
  503. claude_mpm/services/memory/indexed_memory.py +8 -8
  504. claude_mpm/services/memory/optimizer.py +8 -9
  505. claude_mpm/services/memory/router.py +3 -3
  506. claude_mpm/services/memory_hook_service.py +165 -4
  507. claude_mpm/services/model/__init__.py +147 -0
  508. claude_mpm/services/model/base_provider.py +365 -0
  509. claude_mpm/services/model/claude_provider.py +412 -0
  510. claude_mpm/services/model/model_router.py +452 -0
  511. claude_mpm/services/model/ollama_provider.py +415 -0
  512. claude_mpm/services/monitor/__init__.py +20 -0
  513. claude_mpm/services/monitor/daemon.py +691 -0
  514. claude_mpm/services/monitor/daemon_manager.py +1040 -0
  515. claude_mpm/services/monitor/event_emitter.py +350 -0
  516. claude_mpm/services/monitor/handlers/__init__.py +21 -0
  517. claude_mpm/services/monitor/handlers/code_analysis.py +332 -0
  518. claude_mpm/services/monitor/handlers/dashboard.py +299 -0
  519. claude_mpm/services/monitor/handlers/file.py +264 -0
  520. claude_mpm/services/monitor/handlers/hooks.py +512 -0
  521. claude_mpm/services/monitor/management/__init__.py +18 -0
  522. claude_mpm/services/monitor/management/health.py +124 -0
  523. claude_mpm/services/monitor/management/lifecycle.py +724 -0
  524. claude_mpm/services/monitor/server.py +817 -0
  525. claude_mpm/services/monitor_build_service.py +2 -2
  526. claude_mpm/services/native_agent_converter.py +356 -0
  527. claude_mpm/services/orphan_detection.py +786 -0
  528. claude_mpm/services/port_manager.py +3 -3
  529. claude_mpm/services/pr/__init__.py +14 -0
  530. claude_mpm/services/pr/pr_template_service.py +329 -0
  531. claude_mpm/services/project/__init__.py +23 -0
  532. claude_mpm/services/project/analyzer.py +3 -3
  533. claude_mpm/services/project/architecture_analyzer.py +5 -5
  534. claude_mpm/services/project/archive_manager.py +1045 -0
  535. claude_mpm/services/project/dependency_analyzer.py +4 -4
  536. claude_mpm/services/project/detection_strategies.py +719 -0
  537. claude_mpm/services/project/documentation_manager.py +554 -0
  538. claude_mpm/services/project/enhanced_analyzer.py +572 -0
  539. claude_mpm/services/project/metrics_collector.py +4 -4
  540. claude_mpm/services/project/project_organizer.py +1005 -0
  541. claude_mpm/services/project/registry.py +13 -7
  542. claude_mpm/services/project/toolchain_analyzer.py +583 -0
  543. claude_mpm/services/project_port_allocator.py +596 -0
  544. claude_mpm/services/response_tracker.py +21 -10
  545. claude_mpm/services/runner_configuration_service.py +17 -3
  546. claude_mpm/services/self_upgrade_service.py +500 -0
  547. claude_mpm/services/session_management_service.py +23 -9
  548. claude_mpm/services/session_manager.py +380 -0
  549. claude_mpm/services/shared/__init__.py +2 -1
  550. claude_mpm/services/shared/async_service_base.py +16 -27
  551. claude_mpm/services/shared/config_service_base.py +17 -14
  552. claude_mpm/services/shared/lifecycle_service_base.py +1 -14
  553. claude_mpm/services/shared/service_factory.py +8 -5
  554. claude_mpm/services/skills/__init__.py +18 -0
  555. claude_mpm/services/skills/git_skill_source_manager.py +1169 -0
  556. claude_mpm/services/skills/skill_discovery_service.py +568 -0
  557. claude_mpm/services/skills_config.py +547 -0
  558. claude_mpm/services/skills_deployer.py +955 -0
  559. claude_mpm/services/socketio/client_proxy.py +60 -5
  560. claude_mpm/services/socketio/dashboard_server.py +361 -0
  561. claude_mpm/services/socketio/event_normalizer.py +10 -6
  562. claude_mpm/services/socketio/handlers/__init__.py +5 -2
  563. claude_mpm/services/socketio/handlers/base.py +2 -2
  564. claude_mpm/services/socketio/handlers/code_analysis.py +90 -27
  565. claude_mpm/services/socketio/handlers/connection.py +22 -41
  566. claude_mpm/services/socketio/handlers/connection_handler.py +13 -10
  567. claude_mpm/services/socketio/handlers/file.py +46 -10
  568. claude_mpm/services/socketio/handlers/git.py +9 -9
  569. claude_mpm/services/socketio/handlers/hook.py +29 -17
  570. claude_mpm/services/socketio/handlers/registry.py +4 -2
  571. claude_mpm/services/socketio/monitor_client.py +364 -0
  572. claude_mpm/services/socketio/server/broadcaster.py +9 -7
  573. claude_mpm/services/socketio/server/connection_manager.py +2 -2
  574. claude_mpm/services/socketio/server/core.py +142 -8
  575. claude_mpm/services/socketio/server/eventbus_integration.py +20 -14
  576. claude_mpm/services/socketio/server/main.py +24 -24
  577. claude_mpm/services/socketio_client_manager.py +4 -4
  578. claude_mpm/services/subprocess_launcher_service.py +19 -15
  579. claude_mpm/services/system_instructions_service.py +3 -5
  580. claude_mpm/services/ticket_services/formatter_service.py +1 -1
  581. claude_mpm/services/ticket_services/validation_service.py +5 -5
  582. claude_mpm/services/unified/__init__.py +65 -0
  583. claude_mpm/services/unified/analyzer_strategies/__init__.py +44 -0
  584. claude_mpm/services/unified/analyzer_strategies/code_analyzer.py +518 -0
  585. claude_mpm/services/unified/analyzer_strategies/dependency_analyzer.py +680 -0
  586. claude_mpm/services/unified/analyzer_strategies/performance_analyzer.py +900 -0
  587. claude_mpm/services/unified/analyzer_strategies/security_analyzer.py +745 -0
  588. claude_mpm/services/unified/analyzer_strategies/structure_analyzer.py +733 -0
  589. claude_mpm/services/unified/config_strategies/__init__.py +175 -0
  590. claude_mpm/services/unified/config_strategies/config_schema.py +731 -0
  591. claude_mpm/services/unified/config_strategies/context_strategy.py +747 -0
  592. claude_mpm/services/unified/config_strategies/error_handling_strategy.py +1005 -0
  593. claude_mpm/services/unified/config_strategies/file_loader_strategy.py +881 -0
  594. claude_mpm/services/unified/config_strategies/unified_config_service.py +823 -0
  595. claude_mpm/services/unified/config_strategies/validation_strategy.py +1148 -0
  596. claude_mpm/services/unified/deployment_strategies/__init__.py +97 -0
  597. claude_mpm/services/unified/deployment_strategies/base.py +553 -0
  598. claude_mpm/services/unified/deployment_strategies/cloud_strategies.py +573 -0
  599. claude_mpm/services/unified/deployment_strategies/local.py +607 -0
  600. claude_mpm/services/unified/deployment_strategies/utils.py +667 -0
  601. claude_mpm/services/unified/deployment_strategies/vercel.py +471 -0
  602. claude_mpm/services/unified/interfaces.py +475 -0
  603. claude_mpm/services/unified/migration.py +509 -0
  604. claude_mpm/services/unified/strategies.py +534 -0
  605. claude_mpm/services/unified/unified_analyzer.py +542 -0
  606. claude_mpm/services/unified/unified_config.py +691 -0
  607. claude_mpm/services/unified/unified_deployment.py +466 -0
  608. claude_mpm/services/utility_service.py +6 -3
  609. claude_mpm/services/version_control/branch_strategy.py +2 -2
  610. claude_mpm/services/version_control/conflict_resolution.py +14 -8
  611. claude_mpm/services/version_control/git_operations.py +26 -24
  612. claude_mpm/services/version_control/semantic_versioning.py +14 -14
  613. claude_mpm/services/version_control/version_parser.py +14 -11
  614. claude_mpm/services/version_service.py +104 -1
  615. claude_mpm/services/visualization/__init__.py +1 -5
  616. claude_mpm/services/visualization/mermaid_generator.py +2 -3
  617. claude_mpm/skills/__init__.py +42 -0
  618. claude_mpm/skills/agent_skills_injector.py +324 -0
  619. claude_mpm/skills/bundled/LICENSE_ATTRIBUTIONS.md +79 -0
  620. claude_mpm/skills/bundled/__init__.py +6 -0
  621. claude_mpm/skills/bundled/api-documentation.md +393 -0
  622. claude_mpm/skills/bundled/async-testing.md +571 -0
  623. claude_mpm/skills/bundled/code-review.md +143 -0
  624. claude_mpm/skills/bundled/database-migration.md +199 -0
  625. claude_mpm/skills/bundled/docker-containerization.md +194 -0
  626. claude_mpm/skills/bundled/express-local-dev.md +1429 -0
  627. claude_mpm/skills/bundled/fastapi-local-dev.md +1199 -0
  628. claude_mpm/skills/bundled/git-workflow.md +414 -0
  629. claude_mpm/skills/bundled/imagemagick.md +204 -0
  630. claude_mpm/skills/bundled/infrastructure/env-manager/scripts/validate_env.py +576 -0
  631. claude_mpm/skills/bundled/json-data-handling.md +223 -0
  632. claude_mpm/skills/bundled/main/mcp-builder/scripts/connections.py +157 -0
  633. claude_mpm/skills/bundled/main/mcp-builder/scripts/evaluation.py +425 -0
  634. claude_mpm/skills/bundled/main/skill-creator/scripts/init_skill.py +303 -0
  635. claude_mpm/skills/bundled/main/skill-creator/scripts/package_skill.py +113 -0
  636. claude_mpm/skills/bundled/main/skill-creator/scripts/quick_validate.py +72 -0
  637. claude_mpm/skills/bundled/nextjs-local-dev.md +807 -0
  638. claude_mpm/skills/bundled/pdf.md +141 -0
  639. claude_mpm/skills/bundled/performance-profiling.md +573 -0
  640. claude_mpm/skills/bundled/refactoring-patterns.md +180 -0
  641. claude_mpm/skills/bundled/security-scanning.md +327 -0
  642. claude_mpm/skills/bundled/systematic-debugging.md +473 -0
  643. claude_mpm/skills/bundled/test-driven-development.md +378 -0
  644. claude_mpm/skills/bundled/testing/webapp-testing/examples/console_logging.py +35 -0
  645. claude_mpm/skills/bundled/testing/webapp-testing/examples/element_discovery.py +44 -0
  646. claude_mpm/skills/bundled/testing/webapp-testing/examples/static_html_automation.py +34 -0
  647. claude_mpm/skills/bundled/testing/webapp-testing/scripts/with_server.py +129 -0
  648. claude_mpm/skills/bundled/vite-local-dev.md +1061 -0
  649. claude_mpm/skills/bundled/web-performance-optimization.md +2305 -0
  650. claude_mpm/skills/bundled/xlsx.md +157 -0
  651. claude_mpm/skills/registry.py +286 -0
  652. claude_mpm/skills/skill_manager.py +310 -0
  653. claude_mpm/skills/skills_registry.py +347 -0
  654. claude_mpm/skills/skills_service.py +739 -0
  655. claude_mpm/storage/state_storage.py +31 -31
  656. claude_mpm/templates/questions/__init__.py +38 -0
  657. claude_mpm/templates/questions/base.py +193 -0
  658. claude_mpm/templates/questions/pr_strategy.py +311 -0
  659. claude_mpm/templates/questions/project_init.py +385 -0
  660. claude_mpm/templates/questions/ticket_mgmt.py +394 -0
  661. claude_mpm/tools/__main__.py +9 -9
  662. claude_mpm/tools/code_tree_analyzer/__init__.py +45 -0
  663. claude_mpm/tools/code_tree_analyzer/analysis.py +299 -0
  664. claude_mpm/tools/code_tree_analyzer/cache.py +131 -0
  665. claude_mpm/tools/code_tree_analyzer/core.py +380 -0
  666. claude_mpm/tools/code_tree_analyzer/discovery.py +403 -0
  667. claude_mpm/tools/code_tree_analyzer/events.py +168 -0
  668. claude_mpm/tools/code_tree_analyzer/gitignore.py +308 -0
  669. claude_mpm/tools/code_tree_analyzer/models.py +39 -0
  670. claude_mpm/tools/code_tree_analyzer/multilang_analyzer.py +224 -0
  671. claude_mpm/tools/code_tree_analyzer/python_analyzer.py +284 -0
  672. claude_mpm/tools/code_tree_builder.py +6 -6
  673. claude_mpm/tools/code_tree_events.py +14 -10
  674. claude_mpm/tools/socketio_debug.py +11 -11
  675. claude_mpm/utils/agent_dependency_loader.py +184 -36
  676. claude_mpm/utils/agent_filters.py +288 -0
  677. claude_mpm/utils/common.py +544 -0
  678. claude_mpm/utils/config_manager.py +12 -6
  679. claude_mpm/utils/database_connector.py +298 -0
  680. claude_mpm/utils/dependency_cache.py +5 -3
  681. claude_mpm/utils/dependency_strategies.py +15 -10
  682. claude_mpm/utils/display_helper.py +260 -0
  683. claude_mpm/utils/environment_context.py +4 -3
  684. claude_mpm/utils/error_handler.py +5 -3
  685. claude_mpm/utils/file_utils.py +13 -14
  686. claude_mpm/utils/git_analyzer.py +407 -0
  687. claude_mpm/utils/gitignore.py +241 -0
  688. claude_mpm/utils/log_cleanup.py +627 -0
  689. claude_mpm/utils/migration.py +372 -0
  690. claude_mpm/utils/path_operations.py +7 -4
  691. claude_mpm/utils/progress.py +387 -0
  692. claude_mpm/utils/robust_installer.py +131 -24
  693. claude_mpm/utils/session_logging.py +2 -2
  694. claude_mpm/utils/structured_questions.py +619 -0
  695. claude_mpm/utils/subprocess_utils.py +9 -8
  696. claude_mpm/validation/agent_validator.py +6 -6
  697. claude_mpm/validation/frontmatter_validator.py +6 -6
  698. claude_mpm-5.0.9.dist-info/METADATA +1028 -0
  699. claude_mpm-5.0.9.dist-info/RECORD +864 -0
  700. {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/entry_points.txt +1 -0
  701. claude_mpm/agents/INSTRUCTIONS.md +0 -261
  702. claude_mpm/agents/templates/.claude-mpm/memories/README.md +0 -17
  703. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +0 -3
  704. claude_mpm/agents/templates/agent-manager.json +0 -270
  705. claude_mpm/agents/templates/agent-manager.md +0 -619
  706. claude_mpm/agents/templates/agentic_coder_optimizer.json +0 -222
  707. claude_mpm/agents/templates/api_qa.json +0 -171
  708. claude_mpm/agents/templates/code_analyzer.json +0 -95
  709. claude_mpm/agents/templates/data_engineer.json +0 -152
  710. claude_mpm/agents/templates/documentation.json +0 -175
  711. claude_mpm/agents/templates/engineer.json +0 -176
  712. claude_mpm/agents/templates/imagemagick.json +0 -261
  713. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +0 -39
  714. claude_mpm/agents/templates/memory_manager.json +0 -155
  715. claude_mpm/agents/templates/ops.json +0 -175
  716. claude_mpm/agents/templates/project_organizer.json +0 -130
  717. claude_mpm/agents/templates/qa.json +0 -223
  718. claude_mpm/agents/templates/refactoring_engineer.json +0 -266
  719. claude_mpm/agents/templates/research.json +0 -163
  720. claude_mpm/agents/templates/security.json +0 -153
  721. claude_mpm/agents/templates/ticketing.json +0 -169
  722. claude_mpm/agents/templates/vercel_ops_agent.json +0 -281
  723. claude_mpm/agents/templates/version_control.json +0 -147
  724. claude_mpm/agents/templates/web_qa.json +0 -254
  725. claude_mpm/agents/templates/web_ui.json +0 -176
  726. claude_mpm/cli/commands/configure_tui.py +0 -1927
  727. claude_mpm/cli/commands/mpm_init.py +0 -594
  728. claude_mpm/cli/commands/socketio_monitor.py +0 -233
  729. claude_mpm/commands/mpm-agents.md +0 -12
  730. claude_mpm/commands/mpm-config.md +0 -18
  731. claude_mpm/commands/mpm-tickets.md +0 -102
  732. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +0 -1
  733. claude_mpm/dashboard/static/built/components/activity-tree.js +0 -2
  734. claude_mpm/dashboard/static/built/components/agent-inference.js +0 -2
  735. claude_mpm/dashboard/static/built/components/code-tree.js +0 -2
  736. claude_mpm/dashboard/static/built/components/code-viewer.js +0 -2
  737. claude_mpm/dashboard/static/built/components/event-processor.js +0 -2
  738. claude_mpm/dashboard/static/built/components/event-viewer.js +0 -2
  739. claude_mpm/dashboard/static/built/components/export-manager.js +0 -2
  740. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +0 -2
  741. claude_mpm/dashboard/static/built/components/hud-library-loader.js +0 -2
  742. claude_mpm/dashboard/static/built/components/hud-manager.js +0 -2
  743. claude_mpm/dashboard/static/built/components/hud-visualizer.js +0 -2
  744. claude_mpm/dashboard/static/built/components/module-viewer.js +0 -2
  745. claude_mpm/dashboard/static/built/components/session-manager.js +0 -2
  746. claude_mpm/dashboard/static/built/components/socket-manager.js +0 -2
  747. claude_mpm/dashboard/static/built/components/ui-state-manager.js +0 -2
  748. claude_mpm/dashboard/static/built/components/unified-data-viewer.js +0 -2
  749. claude_mpm/dashboard/static/built/components/working-directory.js +0 -2
  750. claude_mpm/dashboard/static/built/dashboard.js +0 -2
  751. claude_mpm/dashboard/static/built/socket-client.js +0 -2
  752. claude_mpm/dashboard/static/css/code-tree.css +0 -1408
  753. claude_mpm/dashboard/static/dist/components/activity-tree.js +0 -2
  754. claude_mpm/dashboard/static/dist/components/agent-inference.js +0 -2
  755. claude_mpm/dashboard/static/dist/components/code-tree.js +0 -2
  756. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  757. claude_mpm/dashboard/static/dist/components/event-processor.js +0 -2
  758. claude_mpm/dashboard/static/dist/components/event-viewer.js +0 -2
  759. claude_mpm/dashboard/static/dist/components/export-manager.js +0 -2
  760. claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +0 -2
  761. claude_mpm/dashboard/static/dist/components/hud-library-loader.js +0 -2
  762. claude_mpm/dashboard/static/dist/components/hud-manager.js +0 -2
  763. claude_mpm/dashboard/static/dist/components/hud-visualizer.js +0 -2
  764. claude_mpm/dashboard/static/dist/components/module-viewer.js +0 -2
  765. claude_mpm/dashboard/static/dist/components/session-manager.js +0 -2
  766. claude_mpm/dashboard/static/dist/components/socket-manager.js +0 -2
  767. claude_mpm/dashboard/static/dist/components/ui-state-manager.js +0 -2
  768. claude_mpm/dashboard/static/dist/components/unified-data-viewer.js +0 -2
  769. claude_mpm/dashboard/static/dist/components/working-directory.js +0 -2
  770. claude_mpm/dashboard/static/dist/dashboard.js +0 -2
  771. claude_mpm/dashboard/static/dist/socket-client.js +0 -2
  772. claude_mpm/dashboard/static/js/components/code-tree.js +0 -3220
  773. claude_mpm/dashboard/static/js/components/code-viewer.js +0 -480
  774. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +0 -425
  775. claude_mpm/hooks/claude_hooks/hook_handler_original.py +0 -1040
  776. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +0 -347
  777. claude_mpm/scripts/socketio_daemon_hardened.py +0 -937
  778. claude_mpm/scripts/socketio_daemon_wrapper.py +0 -78
  779. claude_mpm/scripts/socketio_server_manager.py +0 -349
  780. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +0 -575
  781. claude_mpm/services/cli/dashboard_launcher.py +0 -423
  782. claude_mpm/services/cli/socketio_manager.py +0 -537
  783. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +0 -286
  784. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +0 -645
  785. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +0 -602
  786. claude_mpm/services/project/analyzer_refactored.py +0 -450
  787. claude_mpm/tools/code_tree_analyzer.py +0 -1693
  788. claude_mpm-4.1.26.dist-info/METADATA +0 -332
  789. claude_mpm-4.1.26.dist-info/RECORD +0 -606
  790. {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/WHEEL +0 -0
  791. {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/licenses/LICENSE +0 -0
  792. {claude_mpm-4.1.26.dist-info → claude_mpm-5.0.9.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1225 @@
1
+ """
2
+ Skills command implementation for claude-mpm.
3
+
4
+ WHY: This module provides CLI commands for managing Claude Code skills,
5
+ exposing SkillsService functionality for skill discovery, deployment, validation,
6
+ updates, and configuration. Also provides GitHub skills deployment via SkillsDeployer.
7
+
8
+ DESIGN DECISIONS:
9
+ - Use BaseCommand pattern for consistency with other CLI commands
10
+ - Rich output formatting for user-friendly display
11
+ - Graceful error handling with informative messages
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
18
+ """
19
+
20
+ import os
21
+ import subprocess
22
+ from typing import Optional
23
+
24
+ from rich.console import Console
25
+ from rich.markdown import Markdown
26
+ from rich.panel import Panel
27
+ from rich.table import Table
28
+
29
+ from ...constants import SkillsCommands
30
+ from ...services.skills_deployer import SkillsDeployerService
31
+ from ...skills.skills_service import SkillsService
32
+ from ..shared import BaseCommand, CommandResult
33
+
34
+ console = Console()
35
+
36
+
37
+ class SkillsManagementCommand(BaseCommand):
38
+ """Skills management command for Claude Code skills."""
39
+
40
+ def __init__(self):
41
+ super().__init__("skills")
42
+ self._skills_service = None
43
+ self._skills_deployer = None
44
+
45
+ @property
46
+ def skills_service(self) -> SkillsService:
47
+ """Get skills service instance (lazy loaded)."""
48
+ if self._skills_service is None:
49
+ self._skills_service = SkillsService()
50
+ return self._skills_service
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
+
59
+ def validate_args(self, args) -> Optional[str]:
60
+ """Validate command arguments."""
61
+ # Most skills commands are optional, basic validation
62
+ if hasattr(args, "skills_command") and args.skills_command:
63
+ if args.skills_command == SkillsCommands.VALIDATE.value:
64
+ if not hasattr(args, "skill_name") or not args.skill_name:
65
+ return "Validate command requires a skill name"
66
+ elif args.skills_command == SkillsCommands.INFO.value:
67
+ if not hasattr(args, "skill_name") or not args.skill_name:
68
+ return "Info command requires a skill name"
69
+ return None
70
+
71
+ def run(self, args) -> CommandResult:
72
+ """Execute the skills command."""
73
+ try:
74
+ # Handle default case (no subcommand) - show list
75
+ if not hasattr(args, "skills_command") or not args.skills_command:
76
+ return self._list_skills(args)
77
+
78
+ # Route to appropriate subcommand
79
+ command_map = {
80
+ SkillsCommands.LIST.value: self._list_skills,
81
+ SkillsCommands.DEPLOY.value: self._deploy_skills,
82
+ SkillsCommands.VALIDATE.value: self._validate_skill,
83
+ SkillsCommands.UPDATE.value: self._update_skills,
84
+ SkillsCommands.INFO.value: self._show_skill_info,
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,
99
+ }
100
+
101
+ handler = command_map.get(args.skills_command)
102
+ if handler:
103
+ return handler(args)
104
+ return CommandResult(
105
+ success=False,
106
+ message=f"Unknown skills command: {args.skills_command}",
107
+ exit_code=1,
108
+ )
109
+
110
+ except Exception as e:
111
+ self.logger.error(f"Skills command failed: {e}")
112
+ if hasattr(args, "debug") and args.debug:
113
+ import traceback
114
+
115
+ traceback.print_exc()
116
+ return CommandResult(
117
+ success=False, message=f"Skills command failed: {e}", exit_code=1
118
+ )
119
+
120
+ def _list_skills(self, args) -> CommandResult:
121
+ """List available skills."""
122
+ try:
123
+ # Get skills based on filter
124
+ if hasattr(args, "agent") and args.agent:
125
+ skills = self.skills_service.get_skills_for_agent(args.agent)
126
+ console.print(
127
+ f"\n[bold cyan]Skills for agent '{args.agent}':[/bold cyan]\n"
128
+ )
129
+
130
+ if not skills:
131
+ console.print(
132
+ f"[yellow]No skills found for agent '{args.agent}'[/yellow]"
133
+ )
134
+ return CommandResult(success=True, exit_code=0)
135
+
136
+ for skill_name in skills:
137
+ # Get skill metadata
138
+ skill_info = self._get_skill_metadata(skill_name)
139
+ if skill_info:
140
+ console.print(f" [green]•[/green] {skill_name}")
141
+ if (
142
+ hasattr(args, "verbose")
143
+ and args.verbose
144
+ and skill_info.get("description")
145
+ ):
146
+ console.print(f" {skill_info['description']}")
147
+ else:
148
+ console.print(f" [green]•[/green] {skill_name}")
149
+
150
+ else:
151
+ # Discover all bundled skills
152
+ skills = self.skills_service.discover_bundled_skills()
153
+
154
+ # Filter by category if specified
155
+ if hasattr(args, "category") and args.category:
156
+ skills = [s for s in skills if s.get("category") == args.category]
157
+ console.print(
158
+ f"\n[bold cyan]Skills in category '{args.category}':[/bold cyan]\n"
159
+ )
160
+ else:
161
+ console.print("\n[bold cyan]Available Skills:[/bold cyan]\n")
162
+
163
+ if not skills:
164
+ console.print("[yellow]No skills found[/yellow]")
165
+ return CommandResult(success=True, exit_code=0)
166
+
167
+ # Group by category
168
+ by_category = {}
169
+ for skill in skills:
170
+ category = skill.get("category", "uncategorized")
171
+ if category not in by_category:
172
+ by_category[category] = []
173
+ by_category[category].append(skill)
174
+
175
+ # Display by category
176
+ for category, category_skills in sorted(by_category.items()):
177
+ console.print(f"[bold yellow]{category}[/bold yellow]")
178
+ for skill in sorted(
179
+ category_skills, key=lambda s: s.get("name", "")
180
+ ):
181
+ name = skill.get("name", "unknown")
182
+ console.print(f" [green]•[/green] {name}")
183
+
184
+ if hasattr(args, "verbose") and args.verbose:
185
+ metadata = skill.get("metadata", {})
186
+ if desc := metadata.get("description"):
187
+ console.print(f" {desc}")
188
+ if version := metadata.get("version"):
189
+ console.print(f" [dim]Version: {version}[/dim]")
190
+ console.print()
191
+
192
+ return CommandResult(success=True, exit_code=0)
193
+
194
+ except Exception as e:
195
+ console.print(f"[red]Error listing skills: {e}[/red]")
196
+ return CommandResult(success=False, message=str(e), exit_code=1)
197
+
198
+ def _deploy_skills(self, args) -> CommandResult:
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
+ """
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
+
216
+ force = getattr(args, "force", False)
217
+ specific_skills = getattr(args, "skills", None)
218
+
219
+ console.print("\n[bold cyan]Deploying skills...[/bold cyan]\n")
220
+
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,
240
+ force=force,
241
+ )
242
+
243
+ # Display results
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"]:
257
+ console.print(f" • {skill}")
258
+ console.print()
259
+
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"]:
265
+ console.print(f" • {skill}")
266
+ console.print("[dim]Use --force to redeploy[/dim]\n")
267
+
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}")
274
+ console.print()
275
+
276
+ # Summary
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
+ )
294
+
295
+ # Exit with error if any deployments failed
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
+ )
302
+
303
+ except Exception as e:
304
+ console.print(f"[red]Error deploying skills: {e}[/red]")
305
+ return CommandResult(success=False, message=str(e), exit_code=1)
306
+
307
+ def _validate_skill(self, args) -> CommandResult:
308
+ """Validate skill structure and metadata."""
309
+ try:
310
+ skill_name = args.skill_name
311
+ strict = getattr(args, "strict", False)
312
+
313
+ console.print(
314
+ f"\n[bold cyan]Validating skill '{skill_name}'...[/bold cyan]\n"
315
+ )
316
+
317
+ result = self.skills_service.validate_skill(skill_name)
318
+
319
+ if result["valid"]:
320
+ console.print(f"[green]✓ {skill_name} is valid[/green]\n")
321
+
322
+ if result.get("warnings"):
323
+ console.print(
324
+ f"[yellow]Warnings ({len(result['warnings'])}):[/yellow]"
325
+ )
326
+ for warning in result["warnings"]:
327
+ console.print(f" • {warning}")
328
+ console.print()
329
+
330
+ # Treat warnings as errors in strict mode
331
+ if strict:
332
+ console.print(
333
+ "[red]Strict mode: treating warnings as errors[/red]"
334
+ )
335
+ return CommandResult(success=False, exit_code=1)
336
+
337
+ return CommandResult(success=True, exit_code=0)
338
+ console.print(f"[red]✗ {skill_name} has validation errors:[/red]")
339
+ for error in result.get("errors", []):
340
+ console.print(f" • {error}")
341
+ console.print()
342
+
343
+ if result.get("warnings"):
344
+ console.print("[yellow]Warnings:[/yellow]")
345
+ for warning in result["warnings"]:
346
+ console.print(f" • {warning}")
347
+ console.print()
348
+
349
+ return CommandResult(success=False, exit_code=1)
350
+
351
+ except Exception as e:
352
+ console.print(f"[red]Error validating skill: {e}[/red]")
353
+ return CommandResult(success=False, message=str(e), exit_code=1)
354
+
355
+ def _update_skills(self, args) -> CommandResult:
356
+ """Check for and install skill updates."""
357
+ try:
358
+ skill_names = getattr(args, "skill_names", [])
359
+ check_only = getattr(args, "check_only", False)
360
+ force = getattr(args, "force", False)
361
+
362
+ action = "Checking" if check_only else "Updating"
363
+ console.print(f"\n[bold cyan]{action} skills...[/bold cyan]\n")
364
+
365
+ result = self.skills_service.check_for_updates(skill_names)
366
+
367
+ if not result.get("updates_available"):
368
+ console.print("[green]All skills are up to date[/green]\n")
369
+ return CommandResult(success=True, exit_code=0)
370
+
371
+ # Display available updates
372
+ console.print(
373
+ f"[yellow]Updates available for {len(result['updates_available'])} skill(s):[/yellow]"
374
+ )
375
+ for update_info in result["updates_available"]:
376
+ skill_name = update_info["skill"]
377
+ current = update_info["current_version"]
378
+ latest = update_info["latest_version"]
379
+ console.print(f" • {skill_name}: {current} → {latest}")
380
+ console.print()
381
+
382
+ if check_only:
383
+ console.print(
384
+ "[dim]Run without --check-only to install updates[/dim]\n"
385
+ )
386
+ return CommandResult(success=True, exit_code=0)
387
+
388
+ # Install updates
389
+ console.print("[bold cyan]Installing updates...[/bold cyan]\n")
390
+ install_result = self.skills_service.install_updates(
391
+ result["updates_available"], force=force
392
+ )
393
+
394
+ if install_result["updated"]:
395
+ console.print(
396
+ f"[green]✓ Updated {len(install_result['updated'])} skill(s)[/green]\n"
397
+ )
398
+
399
+ if install_result.get("errors"):
400
+ console.print(
401
+ f"[red]✗ Failed to update {len(install_result['errors'])} skill(s)[/red]"
402
+ )
403
+ for skill, error in install_result["errors"].items():
404
+ console.print(f" • {skill}: {error}")
405
+ console.print()
406
+
407
+ exit_code = 1 if install_result.get("errors") else 0
408
+ return CommandResult(
409
+ success=not install_result.get("errors"), exit_code=exit_code
410
+ )
411
+
412
+ except Exception as e:
413
+ console.print(f"[red]Error updating skills: {e}[/red]")
414
+ return CommandResult(success=False, message=str(e), exit_code=1)
415
+
416
+ def _show_skill_info(self, args) -> CommandResult:
417
+ """Show detailed skill information."""
418
+ try:
419
+ skill_name = args.skill_name
420
+ show_content = getattr(args, "show_content", False)
421
+
422
+ skill_info = self._get_skill_metadata(skill_name)
423
+
424
+ if not skill_info:
425
+ console.print(f"[red]Skill '{skill_name}' not found[/red]")
426
+ return CommandResult(success=False, exit_code=1)
427
+
428
+ # Display skill info in a panel
429
+ info_text = f"[bold cyan]{skill_name}[/bold cyan]\n\n"
430
+
431
+ if desc := skill_info.get("description"):
432
+ info_text += f"{desc}\n\n"
433
+
434
+ if category := skill_info.get("category"):
435
+ info_text += f"[bold]Category:[/bold] {category}\n"
436
+
437
+ if version := skill_info.get("version"):
438
+ info_text += f"[bold]Version:[/bold] {version}\n"
439
+
440
+ if source := skill_info.get("source"):
441
+ info_text += f"[bold]Source:[/bold] {source}\n"
442
+
443
+ # Show agents using this skill
444
+ agents_using = self.skills_service.get_agents_for_skill(skill_name)
445
+ if agents_using:
446
+ info_text += (
447
+ f"\n[bold]Used by agents:[/bold] {', '.join(agents_using)}\n"
448
+ )
449
+
450
+ console.print(
451
+ Panel(info_text, title="Skill Information", border_style="cyan")
452
+ )
453
+
454
+ # Show content if requested
455
+ if show_content:
456
+ skill_path = self.skills_service.get_skill_path(skill_name)
457
+ skill_md = skill_path / "SKILL.md"
458
+
459
+ if skill_md.exists():
460
+ console.print("\n[bold cyan]Skill Content:[/bold cyan]\n")
461
+ content = skill_md.read_text()
462
+ console.print(Markdown(content))
463
+ else:
464
+ console.print(
465
+ f"\n[yellow]SKILL.md not found at {skill_md}[/yellow]"
466
+ )
467
+
468
+ return CommandResult(success=True, exit_code=0)
469
+
470
+ except Exception as e:
471
+ console.print(f"[red]Error showing skill info: {e}[/red]")
472
+ return CommandResult(success=False, message=str(e), exit_code=1)
473
+
474
+ def _manage_config(self, args) -> CommandResult:
475
+ """View or edit skills configuration."""
476
+ try:
477
+ scope = getattr(args, "scope", "project")
478
+ edit = getattr(args, "edit", False)
479
+ show_path = getattr(args, "path", False)
480
+
481
+ config_path = self.skills_service.get_config_path(scope)
482
+
483
+ if show_path:
484
+ console.print(
485
+ f"\n[cyan]Configuration path ({scope}):[/cyan] {config_path}\n"
486
+ )
487
+ return CommandResult(success=True, exit_code=0)
488
+
489
+ if not config_path.exists():
490
+ console.print(
491
+ f"\n[yellow]Configuration file does not exist: {config_path}[/yellow]"
492
+ )
493
+ console.print("[dim]Would you like to create it? (y/n):[/dim] ", end="")
494
+
495
+ if input().lower() == "y":
496
+ self.skills_service.create_default_config(scope)
497
+ console.print(
498
+ f"[green]Created default configuration at {config_path}[/green]\n"
499
+ )
500
+ else:
501
+ return CommandResult(success=False, exit_code=1)
502
+
503
+ if edit:
504
+ # Open in editor
505
+ editor = os.environ.get("EDITOR", "nano")
506
+ try:
507
+ subprocess.run([editor, str(config_path)], check=True)
508
+ console.print(
509
+ f"\n[green]Configuration saved to {config_path}[/green]\n"
510
+ )
511
+ return CommandResult(success=True, exit_code=0)
512
+ except subprocess.CalledProcessError as e:
513
+ console.print(f"[red]Error opening editor: {e}[/red]")
514
+ return CommandResult(success=False, exit_code=1)
515
+ else:
516
+ # Display config
517
+ console.print(
518
+ f"\n[bold cyan]Skills Configuration ({scope}):[/bold cyan]\n"
519
+ )
520
+ console.print(f"[dim]Path: {config_path}[/dim]\n")
521
+
522
+ import yaml
523
+
524
+ config = yaml.safe_load(config_path.read_text())
525
+ console.print(yaml.dump(config, default_flow_style=False))
526
+
527
+ return CommandResult(success=True, exit_code=0)
528
+
529
+ except Exception as e:
530
+ console.print(f"[red]Error managing configuration: {e}[/red]")
531
+ return CommandResult(success=False, message=str(e), exit_code=1)
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
+
736
+ def _get_skill_metadata(self, skill_name: str) -> Optional[dict]:
737
+ """Get skill metadata from SKILL.md file."""
738
+ try:
739
+ skill_path = self.skills_service.get_skill_path(skill_name)
740
+ skill_md = skill_path / "SKILL.md"
741
+
742
+ if not skill_md.exists():
743
+ return None
744
+
745
+ # Parse SKILL.md metadata
746
+ content = skill_md.read_text()
747
+ return self.skills_service.parse_skill_metadata(content)
748
+
749
+ except Exception:
750
+ return None
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
+
1204
+
1205
+ def manage_skills(args) -> int:
1206
+ """
1207
+ Main entry point for skills command.
1208
+
1209
+ Args:
1210
+ args: Parsed command-line arguments
1211
+
1212
+ Returns:
1213
+ Exit code (0 for success, non-zero for failure)
1214
+ """
1215
+ command = SkillsManagementCommand()
1216
+
1217
+ # Validate arguments
1218
+ error = command.validate_args(args)
1219
+ if error:
1220
+ console.print(f"[red]Error: {error}[/red]")
1221
+ return 1
1222
+
1223
+ # Run command
1224
+ result = command.run(args)
1225
+ return result.exit_code