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
@@ -12,18 +12,26 @@ DESIGN DECISIONS:
12
12
  """
13
13
 
14
14
  import json
15
+ from pathlib import Path
15
16
 
16
17
  from ...constants import AgentCommands
18
+ from ...core.enums import OutputFormat
17
19
  from ...services.cli.agent_cleanup_service import AgentCleanupService
18
20
  from ...services.cli.agent_dependency_service import AgentDependencyService
19
21
  from ...services.cli.agent_listing_service import AgentListingService
20
22
  from ...services.cli.agent_output_formatter import AgentOutputFormatter
21
23
  from ...services.cli.agent_validation_service import AgentValidationService
22
- from ..shared import (
23
- AgentCommand,
24
- CommandResult,
25
- )
24
+ from ..shared import AgentCommand, CommandResult
26
25
  from ..utils import get_agent_versions_display
26
+ from .agents_cleanup import handle_agents_cleanup
27
+
28
+
29
+ def _is_structured_output(args) -> bool:
30
+ """Check if args specify structured output format (JSON/YAML)."""
31
+ if hasattr(args, "format"):
32
+ fmt = str(args.format).lower()
33
+ return fmt in (OutputFormat.JSON, OutputFormat.YAML)
34
+ return False
27
35
 
28
36
 
29
37
  class AgentsCommand(AgentCommand):
@@ -50,8 +58,8 @@ class AgentsCommand(AgentCommand):
50
58
 
51
59
  base_service = AgentDeploymentService()
52
60
  self._deployment_service = DeploymentServiceWrapper(base_service)
53
- except ImportError:
54
- raise ImportError("Agent deployment service not available")
61
+ except ImportError as e:
62
+ raise ImportError("Agent deployment service not available") from e
55
63
  return self._deployment_service
56
64
 
57
65
  @property
@@ -86,6 +94,31 @@ class AgentsCommand(AgentCommand):
86
94
  )
87
95
  return self._cleanup_service
88
96
 
97
+ def _get_output_format(self, args) -> str:
98
+ """
99
+ Get output format from args with enum default.
100
+
101
+ Args:
102
+ args: Command arguments
103
+
104
+ Returns:
105
+ Output format string (compatible with both enum and string usage)
106
+ """
107
+ return getattr(args, "format", OutputFormat.TEXT)
108
+
109
+ def _is_structured_format(self, format_str: str) -> bool:
110
+ """
111
+ Check if format is structured (JSON/YAML).
112
+
113
+ Args:
114
+ format_str: Format string to check
115
+
116
+ Returns:
117
+ True if format is JSON or YAML
118
+ """
119
+ fmt = str(format_str).lower()
120
+ return fmt in (OutputFormat.JSON, OutputFormat.YAML)
121
+
89
122
  def validate_args(self, args) -> str:
90
123
  """Validate command arguments."""
91
124
  # Most agent commands are optional, so basic validation
@@ -114,7 +147,32 @@ class AgentsCommand(AgentCommand):
114
147
  "deps-install": self._install_agent_dependencies,
115
148
  "deps-list": self._list_agent_dependencies,
116
149
  "deps-fix": self._fix_agent_dependencies,
150
+ "cleanup": lambda a: self._handle_cleanup_command(a),
117
151
  "cleanup-orphaned": self._cleanup_orphaned_agents,
152
+ # Local agent management commands
153
+ "create": self._create_local_agent,
154
+ "edit": self._edit_local_agent,
155
+ "delete": self._delete_local_agent,
156
+ "manage": self._manage_local_agents,
157
+ "configure": self._configure_deployment,
158
+ # Migration command (DEPRECATION support)
159
+ "migrate-to-project": self._migrate_to_project,
160
+ # Auto-configuration commands (TSK-0054 Phase 5)
161
+ "detect": self._detect_toolchain,
162
+ "recommend": self._recommend_agents,
163
+ # Agent selection modes (Phase 3: 1M-382)
164
+ "deploy-minimal": self._deploy_minimal_configuration,
165
+ "deploy-auto": self._deploy_auto_configure,
166
+ # Agent source management (Phase 2: 1M-442)
167
+ "available": self._list_available_from_sources,
168
+ # Agent discovery with rich filtering (Phase 1: Discovery & Browsing)
169
+ "discover": self._discover_agents,
170
+ # Cache git management commands
171
+ "cache-status": self._cache_status,
172
+ "cache-pull": self._cache_pull,
173
+ "cache-push": self._cache_push,
174
+ "cache-sync": self._cache_sync,
175
+ "cache-commit": self._cache_commit,
118
176
  }
119
177
 
120
178
  if args.agents_command in command_map:
@@ -135,14 +193,14 @@ class AgentsCommand(AgentCommand):
135
193
  try:
136
194
  agent_versions = get_agent_versions_display()
137
195
 
138
- output_format = getattr(args, "format", "text")
139
- if output_format in ["json", "yaml"]:
196
+ output_format = self._get_output_format(args)
197
+ if self._is_structured_format(output_format):
140
198
  # Parse the agent versions display into structured data
141
199
  if agent_versions:
142
200
  data = {"agent_versions": agent_versions, "has_agents": True}
143
201
  formatted = (
144
202
  self._formatter.format_as_json(data)
145
- if output_format == "json"
203
+ if str(output_format).lower() == OutputFormat.JSON
146
204
  else self._formatter.format_as_yaml(data)
147
205
  )
148
206
  print(formatted)
@@ -156,7 +214,7 @@ class AgentsCommand(AgentCommand):
156
214
  }
157
215
  formatted = (
158
216
  self._formatter.format_as_json(data)
159
- if output_format == "json"
217
+ if str(output_format).lower() == OutputFormat.JSON
160
218
  else self._formatter.format_as_yaml(data)
161
219
  )
162
220
  print(formatted)
@@ -178,7 +236,7 @@ class AgentsCommand(AgentCommand):
178
236
  def _list_agents(self, args) -> CommandResult:
179
237
  """List available or deployed agents."""
180
238
  try:
181
- output_format = getattr(args, "format", "text")
239
+ output_format = self._get_output_format(args)
182
240
 
183
241
  if hasattr(args, "by_tier") and args.by_tier:
184
242
  return self._list_agents_by_tier(args)
@@ -189,7 +247,7 @@ class AgentsCommand(AgentCommand):
189
247
  # Default: show usage
190
248
  usage_msg = "Use --system to list system agents, --deployed to list deployed agents, or --by-tier to group by precedence"
191
249
 
192
- if output_format in ["json", "yaml"]:
250
+ if self._is_structured_format(output_format):
193
251
  return CommandResult.error_result(
194
252
  "No list option specified",
195
253
  data={
@@ -210,7 +268,7 @@ class AgentsCommand(AgentCommand):
210
268
  verbose = getattr(args, "verbose", False)
211
269
  agents = self.listing_service.list_system_agents(verbose=verbose)
212
270
 
213
- output_format = getattr(args, "format", "text")
271
+ output_format = self._get_output_format(args)
214
272
  quiet = getattr(args, "quiet", False)
215
273
 
216
274
  # Convert AgentInfo objects to dicts for formatter
@@ -219,6 +277,7 @@ class AgentsCommand(AgentCommand):
219
277
  "name": agent.name,
220
278
  "type": agent.type,
221
279
  "path": agent.path,
280
+ "file": Path(agent.path).name if agent.path else "Unknown",
222
281
  "description": agent.description,
223
282
  "specializations": agent.specializations,
224
283
  "version": agent.version,
@@ -248,7 +307,7 @@ class AgentsCommand(AgentCommand):
248
307
  verbose=verbose
249
308
  )
250
309
 
251
- output_format = getattr(args, "format", "text")
310
+ output_format = self._get_output_format(args)
252
311
  quiet = getattr(args, "quiet", False)
253
312
 
254
313
  # Convert AgentInfo objects to dicts for formatter
@@ -258,6 +317,7 @@ class AgentsCommand(AgentCommand):
258
317
  "type": agent.type,
259
318
  "tier": agent.tier,
260
319
  "path": agent.path,
320
+ "file": Path(agent.path).name if agent.path else "Unknown",
261
321
  "description": agent.description,
262
322
  "specializations": agent.specializations,
263
323
  "version": agent.version,
@@ -272,7 +332,7 @@ class AgentsCommand(AgentCommand):
272
332
  print(formatted)
273
333
 
274
334
  # Add warnings for text output
275
- if output_format == "text" and warnings:
335
+ if str(output_format).lower() == OutputFormat.TEXT and warnings:
276
336
  print("\nWarnings:")
277
337
  for warning in warnings:
278
338
  print(f" āš ļø {warning}")
@@ -294,7 +354,7 @@ class AgentsCommand(AgentCommand):
294
354
  """List agents grouped by tier/precedence."""
295
355
  try:
296
356
  tier_info = self.listing_service.list_agents_by_tier()
297
- output_format = getattr(args, "format", "text")
357
+ output_format = self._get_output_format(args)
298
358
 
299
359
  # Convert to format expected by formatter
300
360
  agents_by_tier = {
@@ -350,34 +410,213 @@ class AgentsCommand(AgentCommand):
350
410
  self.logger.error(f"Error listing agents by tier: {e}", exc_info=True)
351
411
  return CommandResult.error_result(f"Error listing agents by tier: {e}")
352
412
 
413
+ def _list_available_from_sources(self, args) -> CommandResult:
414
+ """List available agents from all configured git sources.
415
+
416
+ This command shows agents discovered from configured agent sources
417
+ (Git repositories) after syncing their cache. Implements Phase 2 of 1M-442.
418
+
419
+ Args:
420
+ args: Command arguments with optional source filter and format
421
+
422
+ Returns:
423
+ CommandResult with agent list or error
424
+ """
425
+ try:
426
+ from ...config.agent_sources import AgentSourceConfiguration
427
+ from ...services.agents.git_source_manager import GitSourceManager
428
+
429
+ # Load agent sources configuration
430
+ config = AgentSourceConfiguration.load()
431
+ enabled_repos = [r for r in config.repositories if r.enabled]
432
+
433
+ if not enabled_repos:
434
+ message = (
435
+ "No agent sources configured.\n\n"
436
+ "Configure sources with:\n"
437
+ " claude-mpm agent-source add <url>\n\n"
438
+ "Example:\n"
439
+ " claude-mpm agent-source add https://github.com/owner/repo/agents"
440
+ )
441
+ print(message)
442
+ return CommandResult.error_result("No agent sources configured")
443
+
444
+ # Initialize git source manager
445
+ manager = GitSourceManager()
446
+
447
+ # Sync all configured sources (with timeout)
448
+ self.logger.info(f"Syncing {len(enabled_repos)} agent sources...")
449
+ sync_results = {}
450
+
451
+ for repo in enabled_repos:
452
+ try:
453
+ result = manager.sync_repository(repo, force=False)
454
+ sync_results[repo.identifier] = result
455
+ except Exception as e:
456
+ self.logger.warning(f"Failed to sync {repo.identifier}: {e}")
457
+ sync_results[repo.identifier] = {"synced": False, "error": str(e)}
458
+
459
+ # Get source filter from args
460
+ source_filter = getattr(args, "source", None)
461
+
462
+ # List all cached agents
463
+ all_agents = manager.list_cached_agents(repo_identifier=source_filter)
464
+
465
+ if not all_agents:
466
+ message = "No agents found in configured sources."
467
+ if sync_results:
468
+ failed_count = sum(
469
+ 1 for r in sync_results.values() if not r.get("synced")
470
+ )
471
+ if failed_count > 0:
472
+ message += f"\n\n{failed_count} source(s) failed to sync. Check logs for details."
473
+ print(message)
474
+ return CommandResult.success_result(message, data={"agents": []})
475
+
476
+ # Format output
477
+ output_format = getattr(args, "format", "table")
478
+
479
+ if output_format == "json":
480
+ import json
481
+
482
+ print(json.dumps(all_agents, indent=2))
483
+ elif output_format == "simple":
484
+ for agent in all_agents:
485
+ name = agent.get("metadata", {}).get(
486
+ "name", agent.get("agent_id", "unknown")
487
+ )
488
+ repo = agent.get("repository", "unknown")
489
+ print(f"{name} (from {repo})")
490
+ else: # table format
491
+ print(f"\n{'Agent Name':<30} {'Repository':<40} {'Version':<15}")
492
+ print("=" * 85)
493
+ for agent in all_agents:
494
+ name = agent.get("metadata", {}).get(
495
+ "name", agent.get("agent_id", "unknown")
496
+ )
497
+ repo = agent.get("repository", "unknown")
498
+ version = agent.get("version", "unknown")[:12]
499
+ print(f"{name:<30} {repo:<40} {version:<15}")
500
+ print(
501
+ f"\nTotal: {len(all_agents)} agents from {len(sync_results)} sources"
502
+ )
503
+
504
+ return CommandResult.success_result(
505
+ f"Listed {len(all_agents)} agents from sources",
506
+ data={"agents": all_agents, "sync_results": sync_results},
507
+ )
508
+
509
+ except Exception as e:
510
+ self.logger.error(f"Error listing available agents: {e}", exc_info=True)
511
+ return CommandResult.error_result(f"Error listing available agents: {e}")
512
+
513
+ def _discover_agents(self, args) -> CommandResult:
514
+ """Discover agents with rich filtering capabilities.
515
+
516
+ This command extends the 'available' command by adding semantic filtering
517
+ based on AUTO-DEPLOY-INDEX.md categories. Users can filter by category,
518
+ language, framework, platform, and specialization.
519
+
520
+ Design Decision: Delegate to agents_discover.py module
521
+
522
+ Rationale: Keep CLI command logic separate from routing logic for better
523
+ testability and maintainability. The discover_command function handles
524
+ all the complex filtering and formatting logic.
525
+
526
+ Args:
527
+ args: Command arguments with filter options:
528
+ - source: Source repository filter
529
+ - category: Category filter (e.g., 'engineer/backend')
530
+ - language: Language filter (e.g., 'python')
531
+ - framework: Framework filter (e.g., 'react')
532
+ - platform: Platform filter (e.g., 'vercel')
533
+ - specialization: Specialization filter (e.g., 'data')
534
+ - format: Output format (table, json, simple)
535
+ - verbose: Show descriptions and metadata
536
+
537
+ Returns:
538
+ CommandResult with filtered agent list or error
539
+
540
+ Example:
541
+ >>> # Called via: claude-mpm agents discover --category engineer/backend
542
+ >>> _discover_agents(args)
543
+ CommandResult(success=True, message="Discovered 8 agents")
544
+ """
545
+ try:
546
+ from .agents_discover import discover_command
547
+
548
+ # Call discover_command and convert exit code to CommandResult
549
+ exit_code = discover_command(args)
550
+
551
+ if exit_code == 0:
552
+ return CommandResult.success_result("Agent discovery complete")
553
+ return CommandResult.error_result("Agent discovery failed")
554
+
555
+ except Exception as e:
556
+ self.logger.error(f"Error discovering agents: {e}", exc_info=True)
557
+ return CommandResult.error_result(f"Error discovering agents: {e}")
558
+
353
559
  def _deploy_agents(self, args, force=False) -> CommandResult:
354
- """Deploy both system and project agents."""
560
+ """Deploy agents using two-phase sync: cache → deploy.
561
+
562
+ Phase 3 Integration (1M-486): Uses Git sync service for deployment.
563
+ - Phase 1: Sync agents to ~/.claude-mpm/cache/remote-agents/ (if needed)
564
+ - Phase 2: Deploy from cache to project .claude-mpm/agents/
565
+
566
+ This replaces the old single-tier deployment with a multi-project
567
+ architecture where one cache serves multiple project deployments.
568
+ """
355
569
  try:
356
- # Deploy system agents
357
- system_result = self.deployment_service.deploy_system_agents(force=force)
570
+ # Handle preset deployment (uses different path)
571
+ if hasattr(args, "preset") and args.preset:
572
+ return self._deploy_preset(args)
573
+
574
+ from ...services.agents.sources.git_source_sync_service import (
575
+ GitSourceSyncService,
576
+ )
577
+
578
+ # Initialize git sync service
579
+ git_sync = GitSourceSyncService()
580
+ project_dir = Path.cwd()
581
+
582
+ self.logger.info("Phase 1: Syncing agents to cache...")
583
+
584
+ # Sync to cache (downloads from GitHub if needed)
585
+ sync_result = git_sync.sync_repository(force=force)
586
+
587
+ if not sync_result.get("synced"):
588
+ error_msg = sync_result.get("error", "Unknown sync error")
589
+ self.logger.error(f"Sync failed: {error_msg}")
590
+ return CommandResult.error_result(f"Sync failed: {error_msg}")
591
+
592
+ self.logger.info(
593
+ f"Phase 1 complete: {sync_result.get('agent_count', 0)} agents in cache"
594
+ )
595
+ self.logger.info(f"Phase 2: Deploying agents to {project_dir}...")
358
596
 
359
- # Deploy project agents if they exist
360
- project_result = self.deployment_service.deploy_project_agents(force=force)
597
+ # Deploy from cache to project directory
598
+ deploy_result = git_sync.deploy_agents_to_project(
599
+ project_dir=project_dir,
600
+ agent_list=None, # Deploy all cached agents
601
+ force=force,
602
+ )
361
603
 
362
- # Combine results
604
+ # Format combined results for output
363
605
  combined_result = {
364
- "deployed_count": system_result.get("deployed_count", 0)
365
- + project_result.get("deployed_count", 0),
366
- "deployed": system_result.get("deployed", [])
367
- + project_result.get("deployed", []),
368
- "updated_count": system_result.get("updated_count", 0)
369
- + project_result.get("updated_count", 0),
370
- "updated": system_result.get("updated", [])
371
- + project_result.get("updated", []),
372
- "skipped": system_result.get("skipped", [])
373
- + project_result.get("skipped", []),
374
- "errors": system_result.get("errors", [])
375
- + project_result.get("errors", []),
376
- "target_dir": system_result.get("target_dir")
377
- or project_result.get("target_dir"),
606
+ "deployed_count": len(deploy_result.get("deployed", []))
607
+ + len(deploy_result.get("updated", [])),
608
+ "deployed": deploy_result.get("deployed", []),
609
+ "updated": deploy_result.get("updated", []),
610
+ "skipped": deploy_result.get("skipped", []),
611
+ "errors": deploy_result.get("failed", []),
612
+ "target_dir": deploy_result.get("deployment_dir", ""),
613
+ "sync_info": {
614
+ "cached_agents": sync_result.get("agent_count", 0),
615
+ "cache_dir": sync_result.get("cache_dir", ""),
616
+ },
378
617
  }
379
618
 
380
- output_format = getattr(args, "format", "text")
619
+ output_format = self._get_output_format(args)
381
620
  verbose = getattr(args, "verbose", False)
382
621
 
383
622
  formatted = self._formatter.format_deployment_result(
@@ -385,12 +624,15 @@ class AgentsCommand(AgentCommand):
385
624
  )
386
625
  print(formatted)
387
626
 
627
+ success_count = len(deploy_result["deployed"]) + len(
628
+ deploy_result["updated"]
629
+ )
388
630
  return CommandResult.success_result(
389
- f"Deployed {combined_result['deployed_count']} agents",
631
+ f"Deployed {success_count} agents from cache",
390
632
  data={
391
- "system_agents": system_result,
392
- "project_agents": project_result,
393
- "total_deployed": combined_result["deployed_count"],
633
+ "sync_result": sync_result,
634
+ "deploy_result": deploy_result,
635
+ "total_deployed": success_count,
394
636
  },
395
637
  )
396
638
 
@@ -398,12 +640,179 @@ class AgentsCommand(AgentCommand):
398
640
  self.logger.error(f"Error deploying agents: {e}", exc_info=True)
399
641
  return CommandResult.error_result(f"Error deploying agents: {e}")
400
642
 
643
+ def _deploy_preset(self, args) -> CommandResult:
644
+ """Deploy agents by preset name.
645
+
646
+ This method implements Phase 2 of the agents/skills CLI redesign,
647
+ enabling preset-based deployment like:
648
+ claude-mpm agents deploy --preset python-dev
649
+
650
+ Args:
651
+ args: Command arguments with preset name and optional flags
652
+
653
+ Returns:
654
+ CommandResult with deployment status
655
+ """
656
+ try:
657
+ from pathlib import Path
658
+
659
+ from ...config.agent_sources import AgentSourceConfiguration
660
+ from ...services.agents.agent_preset_service import AgentPresetService
661
+ from ...services.agents.git_source_manager import GitSourceManager
662
+ from ...services.agents.single_tier_deployment_service import (
663
+ SingleTierDeploymentService,
664
+ )
665
+
666
+ preset_name = args.preset
667
+ dry_run = getattr(args, "dry_run", False)
668
+
669
+ # Initialize services
670
+ config = AgentSourceConfiguration.load()
671
+ deployment_dir = Path.home() / ".claude" / "agents"
672
+ git_source_manager = GitSourceManager()
673
+ preset_service = AgentPresetService(git_source_manager)
674
+ deployment_service = SingleTierDeploymentService(config, deployment_dir)
675
+
676
+ # Validate preset
677
+ if not preset_service.validate_preset(preset_name):
678
+ available = preset_service.list_presets()
679
+ print(f"āŒ Unknown preset: {preset_name}")
680
+ print("\nšŸ“š Available presets:")
681
+ for preset in available:
682
+ print(
683
+ f" • {preset['name']}: {preset['description']} ({preset['agent_count']} agents)"
684
+ )
685
+ print(f" Use cases: {', '.join(preset['use_cases'])}")
686
+ return CommandResult.error_result(f"Unknown preset: {preset_name}")
687
+
688
+ # Resolve preset to agent list
689
+ print(f"\nšŸ” Resolving preset: {preset_name}")
690
+ resolution = preset_service.resolve_agents(
691
+ preset_name, validate_availability=True
692
+ )
693
+
694
+ # Show preset info
695
+ preset_info = resolution["preset_info"]
696
+ print(f"\nšŸŽÆ Preset: {preset_info['description']}")
697
+ print(f" Agents: {preset_info['agent_count']}")
698
+ print(f" Use cases: {', '.join(preset_info['use_cases'])}")
699
+
700
+ # Show warnings for missing agents
701
+ if resolution["missing_agents"]:
702
+ print("\nāš ļø Missing agents (not found in configured sources):")
703
+ for agent_id in resolution["missing_agents"]:
704
+ print(f" • {agent_id}")
705
+ print("\nšŸ’” These agents are not available in your configured sources.")
706
+ print(" Deployment will continue with available agents.")
707
+
708
+ # Show conflicts
709
+ if resolution["conflicts"]:
710
+ print("\nāš ļø Priority conflicts detected:")
711
+ for conflict in resolution["conflicts"]:
712
+ sources = ", ".join(conflict["sources"])
713
+ print(f" • {conflict['agent_id']} (found in: {sources})")
714
+ print(" Using highest priority source for each")
715
+
716
+ # Dry run mode
717
+ if dry_run:
718
+ print("\nšŸ” DRY RUN: Preview agent deployment\n")
719
+ print("Agents to deploy:")
720
+ for agent in resolution["agents"]:
721
+ source = agent.get("source", "unknown")
722
+ print(f" āœ“ {agent['agent_id']} (from {source})")
723
+ print(
724
+ "\nšŸ’” This is a dry run. Run without --dry-run to actually deploy."
725
+ )
726
+ return CommandResult.success_result(
727
+ "Dry run complete",
728
+ data={
729
+ "preset": preset_name,
730
+ "agents": resolution["agents"],
731
+ "missing": resolution["missing_agents"],
732
+ },
733
+ )
734
+
735
+ # Deploy agents
736
+ print(f"\nšŸ“¦ Deploying {len(resolution['agents'])} agents...")
737
+ deployed_count = 0
738
+ failed_count = 0
739
+ skipped_count = len(resolution["missing_agents"])
740
+ deployed_agents = []
741
+ failed_agents = []
742
+
743
+ for agent in resolution["agents"]:
744
+ agent_id = agent["agent_id"]
745
+ try:
746
+ # Deploy using single-tier deployment service
747
+ result = deployment_service.deploy_agent(
748
+ agent_id, source_repo=agent.get("source"), dry_run=False
749
+ )
750
+
751
+ if result.get("deployed"):
752
+ deployed_count += 1
753
+ deployed_agents.append(agent_id)
754
+ print(f" āœ“ {agent_id}")
755
+ else:
756
+ failed_count += 1
757
+ failed_agents.append(
758
+ {
759
+ "agent_id": agent_id,
760
+ "error": result.get("error", "Unknown"),
761
+ }
762
+ )
763
+ print(f" āœ— {agent_id}: {result.get('error', 'Failed')}")
764
+
765
+ except Exception as e:
766
+ failed_count += 1
767
+ failed_agents.append({"agent_id": agent_id, "error": str(e)})
768
+ print(f" āœ— {agent_id}: {e}")
769
+
770
+ # Summary
771
+ print(f"\n{'=' * 60}")
772
+ print("šŸ“Š Deployment Summary")
773
+ print(f"{'=' * 60}")
774
+ print(f" āœ… Deployed: {deployed_count}")
775
+ print(f" āŒ Failed: {failed_count}")
776
+ print(f" ā­ļø Skipped: {skipped_count} (missing from sources)")
777
+ print(f"{'=' * 60}\n")
778
+
779
+ if failed_agents:
780
+ print("āŒ Failed agents:")
781
+ for failure in failed_agents:
782
+ print(f" • {failure['agent_id']}: {failure['error']}")
783
+ print()
784
+
785
+ if deployed_count > 0:
786
+ print(f"āœ… Successfully deployed {deployed_count} agents!")
787
+ return CommandResult.success_result(
788
+ f"Deployed {deployed_count} agents from preset '{preset_name}'",
789
+ data={
790
+ "preset": preset_name,
791
+ "deployed": deployed_agents,
792
+ "failed": failed_agents,
793
+ "skipped": resolution["missing_agents"],
794
+ },
795
+ )
796
+ return CommandResult.error_result(
797
+ f"No agents deployed from preset '{preset_name}'",
798
+ data={
799
+ "preset": preset_name,
800
+ "failed": failed_agents,
801
+ "skipped": resolution["missing_agents"],
802
+ },
803
+ )
804
+
805
+ except Exception as e:
806
+ self.logger.error(f"Error deploying preset: {e}", exc_info=True)
807
+ print(f"\nāŒ Error deploying preset: {e}")
808
+ return CommandResult.error_result(f"Error deploying preset: {e}")
809
+
401
810
  def _clean_agents(self, args) -> CommandResult:
402
811
  """Clean deployed agents."""
403
812
  try:
404
813
  result = self.cleanup_service.clean_deployed_agents()
405
814
 
406
- output_format = getattr(args, "format", "text")
815
+ output_format = self._get_output_format(args)
407
816
  dry_run = False # Regular clean is not a dry run
408
817
 
409
818
  formatted = self._formatter.format_cleanup_result(
@@ -441,7 +850,7 @@ class AgentsCommand(AgentCommand):
441
850
  f"Could not retrieve details for agent '{agent_name}'"
442
851
  )
443
852
 
444
- output_format = getattr(args, "format", "text")
853
+ output_format = self._get_output_format(args)
445
854
  verbose = getattr(args, "verbose", False)
446
855
 
447
856
  formatted = self._formatter.format_agent_details(
@@ -463,148 +872,170 @@ class AgentsCommand(AgentCommand):
463
872
  dry_run = getattr(args, "dry_run", False)
464
873
  agent_name = getattr(args, "agent_name", None)
465
874
  fix_all = getattr(args, "all", False)
875
+ output_format = self._get_output_format(args)
466
876
 
467
- output_format = getattr(args, "format", "text")
468
-
469
- # Determine what to fix
877
+ # Route to appropriate handler based on input
470
878
  if fix_all:
471
- # Fix all agents
472
- result = self.validation_service.fix_all_agents(dry_run=dry_run)
473
-
474
- if output_format in ["json", "yaml"]:
475
- formatted = (
476
- self._formatter.format_as_json(result)
477
- if output_format == "json"
478
- else self._formatter.format_as_yaml(result)
479
- )
480
- print(formatted)
481
- else:
482
- # Text output
483
- mode = "DRY RUN" if dry_run else "FIX"
484
- print(
485
- f"\nšŸ”§ {mode}: Checking {result.get('total_agents', 0)} agent(s) for frontmatter issues...\n"
486
- )
487
-
488
- if result.get("results"):
489
- for agent_result in result["results"]:
490
- print(f"šŸ“„ {agent_result['agent']}:")
491
- if agent_result.get("skipped"):
492
- print(
493
- f" āš ļø Skipped: {agent_result.get('reason', 'Unknown reason')}"
494
- )
495
- elif agent_result.get("was_valid"):
496
- print(" āœ“ No issues found")
497
- else:
498
- if agent_result.get("errors_found", 0) > 0:
499
- print(
500
- f" āŒ Errors found: {agent_result['errors_found']}"
501
- )
502
- if agent_result.get("warnings_found", 0) > 0:
503
- print(
504
- f" āš ļø Warnings found: {agent_result['warnings_found']}"
505
- )
506
- if dry_run:
507
- if agent_result.get("corrections_available", 0) > 0:
508
- print(
509
- f" šŸ”§ Would fix: {agent_result['corrections_available']} issues"
510
- )
511
- elif agent_result.get("corrections_made", 0) > 0:
512
- print(
513
- f" āœ“ Fixed: {agent_result['corrections_made']} issues"
514
- )
515
- print()
516
-
517
- # Summary
518
- print("=" * 80)
519
- print("SUMMARY:")
520
- print(f" Agents checked: {result.get('agents_checked', 0)}")
521
- print(
522
- f" Total issues found: {result.get('total_issues_found', 0)}"
523
- )
524
- if dry_run:
525
- print(
526
- f" Issues that would be fixed: {result.get('total_corrections_available', 0)}"
527
- )
528
- print("\nšŸ’” Run without --dry-run to apply fixes")
529
- else:
530
- print(
531
- f" Issues fixed: {result.get('total_corrections_made', 0)}"
532
- )
533
- if result.get("total_corrections_made", 0) > 0:
534
- print("\nāœ“ Frontmatter issues have been fixed!")
535
- print("=" * 80 + "\n")
879
+ return self._fix_all_agents(dry_run, output_format)
880
+ if agent_name:
881
+ return self._fix_single_agent(agent_name, dry_run, output_format)
882
+ return self._handle_no_agent_specified(output_format)
536
883
 
537
- msg = f"{'Would fix' if dry_run else 'Fixed'} {result.get('total_corrections_available' if dry_run else 'total_corrections_made', 0)} issues"
538
- return CommandResult.success_result(msg, data=result)
884
+ except Exception as e:
885
+ self.logger.error(f"Error fixing agents: {e}", exc_info=True)
886
+ return CommandResult.error_result(f"Error fixing agents: {e}")
539
887
 
540
- if agent_name:
541
- # Fix specific agent
542
- result = self.validation_service.fix_agent_frontmatter(
543
- agent_name, dry_run=dry_run
544
- )
888
+ def _fix_all_agents(self, dry_run: bool, output_format: str) -> CommandResult:
889
+ """Fix all agents' frontmatter issues."""
890
+ result = self.validation_service.fix_all_agents(dry_run=dry_run)
545
891
 
546
- if not result.get("success"):
547
- return CommandResult.error_result(
548
- result.get("error", "Failed to fix agent")
549
- )
892
+ if self._is_structured_format(output_format):
893
+ self._print_structured_output(result, output_format)
894
+ else:
895
+ self._print_all_agents_text_output(result, dry_run)
550
896
 
551
- if output_format in ["json", "yaml"]:
552
- formatted = (
553
- self._formatter.format_as_json(result)
554
- if output_format == "json"
555
- else self._formatter.format_as_yaml(result)
556
- )
557
- print(formatted)
558
- else:
559
- # Text output
560
- mode = "DRY RUN" if dry_run else "FIX"
561
- print(
562
- f"\nšŸ”§ {mode}: Checking agent '{agent_name}' for frontmatter issues...\n"
563
- )
897
+ msg = f"{'Would fix' if dry_run else 'Fixed'} {result.get('total_corrections_available' if dry_run else 'total_corrections_made', 0)} issues"
898
+ return CommandResult.success_result(msg, data=result)
564
899
 
565
- print(f"šŸ“„ {agent_name}:")
566
- if result.get("was_valid"):
567
- print(" āœ“ No issues found")
568
- else:
569
- if result.get("errors_found"):
570
- print(" āŒ Errors:")
571
- for error in result["errors_found"]:
572
- print(f" - {error}")
573
- if result.get("warnings_found"):
574
- print(" āš ļø Warnings:")
575
- for warning in result["warnings_found"]:
576
- print(f" - {warning}")
577
- if dry_run:
578
- if result.get("corrections_available"):
579
- print(" šŸ”§ Would fix:")
580
- for correction in result["corrections_available"]:
581
- print(f" - {correction}")
582
- elif result.get("corrections_made"):
583
- print(" āœ“ Fixed:")
584
- for correction in result["corrections_made"]:
585
- print(f" - {correction}")
586
- print()
900
+ def _fix_single_agent(
901
+ self, agent_name: str, dry_run: bool, output_format: str
902
+ ) -> CommandResult:
903
+ """Fix a single agent's frontmatter issues."""
904
+ result = self.validation_service.fix_agent_frontmatter(
905
+ agent_name, dry_run=dry_run
906
+ )
587
907
 
588
- if dry_run and result.get("corrections_available"):
589
- print("šŸ’” Run without --dry-run to apply fixes\n")
590
- elif not dry_run and result.get("corrections_made"):
591
- print("āœ“ Frontmatter issues have been fixed!\n")
908
+ if not result.get("success"):
909
+ return CommandResult.error_result(
910
+ result.get("error", "Failed to fix agent")
911
+ )
592
912
 
593
- msg = f"{'Would fix' if dry_run else 'Fixed'} agent '{agent_name}'"
594
- return CommandResult.success_result(msg, data=result)
913
+ if self._is_structured_format(output_format):
914
+ self._print_structured_output(result, output_format)
915
+ else:
916
+ self._print_single_agent_text_output(agent_name, result, dry_run)
595
917
 
596
- # No agent specified and not --all
597
- usage_msg = "Please specify an agent name or use --all to fix all agents\nUsage: claude-mpm agents fix [agent_name] [--dry-run] [--all]"
598
- if output_format in ["json", "yaml"]:
599
- return CommandResult.error_result(
600
- "No agent specified", data={"usage": usage_msg}
601
- )
602
- print(f"āŒ {usage_msg}")
603
- return CommandResult.error_result("No agent specified")
918
+ msg = f"{'Would fix' if dry_run else 'Fixed'} agent '{agent_name}'"
919
+ return CommandResult.success_result(msg, data=result)
604
920
 
605
- except Exception as e:
606
- self.logger.error(f"Error fixing agents: {e}", exc_info=True)
607
- return CommandResult.error_result(f"Error fixing agents: {e}")
921
+ def _handle_no_agent_specified(self, output_format: str) -> CommandResult:
922
+ """Handle case where no agent is specified."""
923
+ usage_msg = "Please specify an agent name or use --all to fix all agents\nUsage: claude-mpm agents fix [agent_name] [--dry-run] [--all]"
924
+ if self._is_structured_format(output_format):
925
+ return CommandResult.error_result(
926
+ "No agent specified", data={"usage": usage_msg}
927
+ )
928
+ print(f"āŒ {usage_msg}")
929
+ return CommandResult.error_result("No agent specified")
930
+
931
+ def _print_structured_output(self, result: dict, output_format: str) -> None:
932
+ """Print result in JSON or YAML format."""
933
+ formatted = (
934
+ self._formatter.format_as_json(result)
935
+ if str(output_format).lower() == OutputFormat.JSON
936
+ else self._formatter.format_as_yaml(result)
937
+ )
938
+ print(formatted)
939
+
940
+ def _print_all_agents_text_output(self, result: dict, dry_run: bool) -> None:
941
+ """Print text output for all agents fix operation."""
942
+ mode = "DRY RUN" if dry_run else "FIX"
943
+ print(
944
+ f"\nšŸ”§ {mode}: Checking {result.get('total_agents', 0)} agent(s) for frontmatter issues...\n"
945
+ )
946
+
947
+ if result.get("results"):
948
+ for agent_result in result["results"]:
949
+ self._print_agent_result(agent_result, dry_run)
950
+
951
+ self._print_all_agents_summary(result, dry_run)
952
+
953
+ def _print_agent_result(self, agent_result: dict, dry_run: bool) -> None:
954
+ """Print result for a single agent."""
955
+ print(f"šŸ“„ {agent_result['agent']}:")
956
+ if agent_result.get("skipped"):
957
+ print(f" āš ļø Skipped: {agent_result.get('reason', 'Unknown reason')}")
958
+ elif agent_result.get("was_valid"):
959
+ print(" āœ“ No issues found")
960
+ else:
961
+ self._print_agent_issues(agent_result, dry_run)
962
+ print()
963
+
964
+ def _print_agent_issues(self, agent_result: dict, dry_run: bool) -> None:
965
+ """Print issues found for an agent."""
966
+ if agent_result.get("errors_found", 0) > 0:
967
+ print(f" āŒ Errors found: {agent_result['errors_found']}")
968
+ if agent_result.get("warnings_found", 0) > 0:
969
+ print(f" āš ļø Warnings found: {agent_result['warnings_found']}")
970
+
971
+ if dry_run:
972
+ if agent_result.get("corrections_available", 0) > 0:
973
+ print(f" šŸ”§ Would fix: {agent_result['corrections_available']} issues")
974
+ elif agent_result.get("corrections_made", 0) > 0:
975
+ print(f" āœ“ Fixed: {agent_result['corrections_made']} issues")
976
+
977
+ def _print_all_agents_summary(self, result: dict, dry_run: bool) -> None:
978
+ """Print summary for all agents fix operation."""
979
+ print("=" * 80)
980
+ print("SUMMARY:")
981
+ print(f" Agents checked: {result.get('agents_checked', 0)}")
982
+ print(f" Total issues found: {result.get('total_issues_found', 0)}")
983
+
984
+ if dry_run:
985
+ print(
986
+ f" Issues that would be fixed: {result.get('total_corrections_available', 0)}"
987
+ )
988
+ print("\nšŸ’” Run without --dry-run to apply fixes")
989
+ else:
990
+ print(f" Issues fixed: {result.get('total_corrections_made', 0)}")
991
+ if result.get("total_corrections_made", 0) > 0:
992
+ print("\nāœ“ Frontmatter issues have been fixed!")
993
+ print("=" * 80 + "\n")
994
+
995
+ def _print_single_agent_text_output(
996
+ self, agent_name: str, result: dict, dry_run: bool
997
+ ) -> None:
998
+ """Print text output for single agent fix operation."""
999
+ mode = "DRY RUN" if dry_run else "FIX"
1000
+ print(f"\nšŸ”§ {mode}: Checking agent '{agent_name}' for frontmatter issues...\n")
1001
+
1002
+ print(f"šŸ“„ {agent_name}:")
1003
+ if result.get("was_valid"):
1004
+ print(" āœ“ No issues found")
1005
+ else:
1006
+ self._print_single_agent_issues(result, dry_run)
1007
+ print()
1008
+
1009
+ self._print_single_agent_footer(result, dry_run)
1010
+
1011
+ def _print_single_agent_issues(self, result: dict, dry_run: bool) -> None:
1012
+ """Print issues for a single agent."""
1013
+ if result.get("errors_found"):
1014
+ print(" āŒ Errors:")
1015
+ for error in result["errors_found"]:
1016
+ print(f" - {error}")
1017
+
1018
+ if result.get("warnings_found"):
1019
+ print(" āš ļø Warnings:")
1020
+ for warning in result["warnings_found"]:
1021
+ print(f" - {warning}")
1022
+
1023
+ if dry_run:
1024
+ if result.get("corrections_available"):
1025
+ print(" šŸ”§ Would fix:")
1026
+ for correction in result["corrections_available"]:
1027
+ print(f" - {correction}")
1028
+ elif result.get("corrections_made"):
1029
+ print(" āœ“ Fixed:")
1030
+ for correction in result["corrections_made"]:
1031
+ print(f" - {correction}")
1032
+
1033
+ def _print_single_agent_footer(self, result: dict, dry_run: bool) -> None:
1034
+ """Print footer message for single agent fix."""
1035
+ if dry_run and result.get("corrections_available"):
1036
+ print("šŸ’” Run without --dry-run to apply fixes\n")
1037
+ elif not dry_run and result.get("corrections_made"):
1038
+ print("āœ“ Frontmatter issues have been fixed!\n")
608
1039
 
609
1040
  def _check_agent_dependencies(self, args) -> CommandResult:
610
1041
  """Check agent dependencies."""
@@ -684,7 +1115,7 @@ class AgentsCommand(AgentCommand):
684
1115
  def _list_agent_dependencies(self, args) -> CommandResult:
685
1116
  """List agent dependencies."""
686
1117
  try:
687
- output_format = getattr(args, "format", "text")
1118
+ output_format = self._get_output_format(args)
688
1119
  result = self.dependency_service.list_dependencies(
689
1120
  format_type=output_format
690
1121
  )
@@ -696,7 +1127,7 @@ class AgentsCommand(AgentCommand):
696
1127
  if output_format == "pip":
697
1128
  for dep in result["dependencies"]:
698
1129
  print(dep)
699
- elif output_format == "json":
1130
+ elif str(output_format).lower() == OutputFormat.JSON:
700
1131
  print(json.dumps(result["data"], indent=2))
701
1132
  else: # text format
702
1133
  print("=" * 60)
@@ -836,6 +1267,16 @@ class AgentsCommand(AgentCommand):
836
1267
  self.logger.error(f"Error fixing dependencies: {e}", exc_info=True)
837
1268
  return CommandResult.error_result(f"Error fixing dependencies: {e}")
838
1269
 
1270
+ def _handle_cleanup_command(self, args) -> CommandResult:
1271
+ """Handle cleanup command with proper result wrapping."""
1272
+ exit_code = handle_agents_cleanup(args)
1273
+ return CommandResult(
1274
+ success=exit_code == 0,
1275
+ message=(
1276
+ "Agent cleanup complete" if exit_code == 0 else "Agent cleanup failed"
1277
+ ),
1278
+ )
1279
+
839
1280
  def _cleanup_orphaned_agents(self, args) -> CommandResult:
840
1281
  """Clean up orphaned agents that don't have templates."""
841
1282
  try:
@@ -854,7 +1295,7 @@ class AgentsCommand(AgentCommand):
854
1295
  agents_dir=agents_dir, dry_run=dry_run
855
1296
  )
856
1297
 
857
- output_format = getattr(args, "format", "text")
1298
+ output_format = self._get_output_format(args)
858
1299
 
859
1300
  formatted = self._formatter.format_cleanup_result(
860
1301
  results, output_format=output_format, dry_run=dry_run
@@ -876,6 +1317,1060 @@ class AgentsCommand(AgentCommand):
876
1317
  self.logger.error(f"Error during cleanup: {e}", exc_info=True)
877
1318
  return CommandResult.error_result(f"Error during cleanup: {e}")
878
1319
 
1320
+ def _create_local_agent(self, args) -> CommandResult:
1321
+ """Create a new local agent template."""
1322
+ try:
1323
+ if getattr(args, "interactive", False):
1324
+ # Launch interactive wizard
1325
+ from ..interactive.agent_wizard import run_interactive_agent_wizard
1326
+
1327
+ exit_code = run_interactive_agent_wizard()
1328
+ if exit_code == 0:
1329
+ return CommandResult.success_result("Agent created successfully")
1330
+ return CommandResult.error_result("Agent creation cancelled or failed")
1331
+
1332
+ # Non-interactive creation
1333
+ from ...services.agents.local_template_manager import (
1334
+ LocalAgentTemplateManager,
1335
+ )
1336
+
1337
+ agent_id = getattr(args, "agent_id", None)
1338
+ if not agent_id:
1339
+ return CommandResult.error_result(
1340
+ "--agent-id is required for non-interactive creation"
1341
+ )
1342
+
1343
+ manager = LocalAgentTemplateManager()
1344
+ name = getattr(args, "name", agent_id.replace("-", " ").title())
1345
+ model = getattr(args, "model", "sonnet")
1346
+ inherit_from = getattr(args, "inherit_from", None)
1347
+
1348
+ # Create basic template
1349
+ template = manager.create_local_template(
1350
+ agent_id=agent_id,
1351
+ name=name,
1352
+ description=f"Local agent: {name}",
1353
+ instructions="# Agent Instructions\n\nCustomize this agent's behavior here.",
1354
+ model=model,
1355
+ parent_agent=inherit_from,
1356
+ tier="project",
1357
+ )
1358
+
1359
+ if template:
1360
+ return CommandResult.success_result(
1361
+ f"Created local agent '{agent_id}' in .claude-mpm/agents/",
1362
+ data={
1363
+ "agent_id": agent_id,
1364
+ "path": f".claude-mpm/agents/{agent_id}.json",
1365
+ },
1366
+ )
1367
+ return CommandResult.error_result("Failed to create agent template")
1368
+
1369
+ except Exception as e:
1370
+ self.logger.error(f"Error creating local agent: {e}", exc_info=True)
1371
+ return CommandResult.error_result(f"Error creating local agent: {e}")
1372
+
1373
+ def _edit_local_agent(self, args) -> CommandResult:
1374
+ """Edit a local agent template."""
1375
+ try:
1376
+ agent_id = getattr(args, "agent_id", None)
1377
+ if not agent_id:
1378
+ return CommandResult.error_result("agent_id is required")
1379
+
1380
+ import os
1381
+ import subprocess
1382
+
1383
+ from ...services.agents.local_template_manager import (
1384
+ LocalAgentTemplateManager,
1385
+ )
1386
+
1387
+ manager = LocalAgentTemplateManager()
1388
+ template = manager.get_local_template(agent_id)
1389
+
1390
+ if not template:
1391
+ return CommandResult.error_result(f"Local agent '{agent_id}' not found")
1392
+
1393
+ # Get template file path
1394
+ template_file = None
1395
+ if template.tier == "project":
1396
+ template_file = manager.project_agents_dir / f"{agent_id}.json"
1397
+ else:
1398
+ template_file = manager.user_agents_dir / f"{agent_id}.json"
1399
+
1400
+ if not template_file or not template_file.exists():
1401
+ return CommandResult.error_result(
1402
+ f"Template file not found for '{agent_id}'"
1403
+ )
1404
+
1405
+ if getattr(args, "interactive", False):
1406
+ # Launch interactive editor
1407
+ from ..interactive.agent_wizard import AgentWizard
1408
+
1409
+ wizard = AgentWizard()
1410
+ success, message = wizard._edit_agent_config(template)
1411
+ if success:
1412
+ return CommandResult.success_result(message)
1413
+ return CommandResult.error_result(message)
1414
+
1415
+ # Use system editor
1416
+ editor = getattr(args, "editor", None) or os.environ.get("EDITOR", "nano")
1417
+ subprocess.run([editor, str(template_file)], check=True)
1418
+ return CommandResult.success_result(
1419
+ f"Agent '{agent_id}' edited successfully"
1420
+ )
1421
+
1422
+ except subprocess.CalledProcessError:
1423
+ return CommandResult.error_result("Editor exited with error")
1424
+ except Exception as e:
1425
+ self.logger.error(f"Error editing local agent: {e}", exc_info=True)
1426
+ return CommandResult.error_result(f"Error editing local agent: {e}")
1427
+
1428
+ def _delete_local_agent(self, args) -> CommandResult:
1429
+ """Delete local agent templates."""
1430
+ try:
1431
+ agent_ids = getattr(args, "agent_ids", [])
1432
+ if not agent_ids:
1433
+ return CommandResult.error_result("No agent IDs specified")
1434
+
1435
+ from ...services.agents.local_template_manager import (
1436
+ LocalAgentTemplateManager,
1437
+ )
1438
+
1439
+ manager = LocalAgentTemplateManager()
1440
+ force = getattr(args, "force", False)
1441
+ keep_deployment = getattr(args, "keep_deployment", False)
1442
+ backup = getattr(args, "backup", False)
1443
+
1444
+ # Confirmation if not forced
1445
+ if not force:
1446
+ print(f"\nāš ļø This will delete {len(agent_ids)} agent(s):")
1447
+ for agent_id in agent_ids:
1448
+ print(f" - {agent_id}")
1449
+ confirm = input("\nAre you sure? [y/N]: ").strip().lower()
1450
+ if confirm not in ["y", "yes"]:
1451
+ return CommandResult.error_result("Deletion cancelled")
1452
+
1453
+ # Delete agents
1454
+ if len(agent_ids) == 1:
1455
+ result = manager.delete_local_template(
1456
+ agent_id=agent_ids[0],
1457
+ tier="all",
1458
+ delete_deployment=not keep_deployment,
1459
+ backup_first=backup,
1460
+ )
1461
+ if result["success"]:
1462
+ message = f"Successfully deleted agent '{agent_ids[0]}'"
1463
+ if result["backup_location"]:
1464
+ message += f"\nBackup saved to: {result['backup_location']}"
1465
+ return CommandResult.success_result(message, data=result)
1466
+ return CommandResult.error_result(
1467
+ f"Failed to delete agent: {', '.join(result['errors'])}"
1468
+ )
1469
+ results = manager.delete_multiple_templates(
1470
+ agent_ids=agent_ids,
1471
+ tier="all",
1472
+ delete_deployment=not keep_deployment,
1473
+ backup_first=backup,
1474
+ )
1475
+
1476
+ message = ""
1477
+ if results["successful"]:
1478
+ message = (
1479
+ f"Successfully deleted {len(results['successful'])} agent(s):\n"
1480
+ )
1481
+ for agent_id in results["successful"]:
1482
+ message += f" - {agent_id}\n"
1483
+
1484
+ if results["failed"]:
1485
+ if message:
1486
+ message += "\n"
1487
+ message += f"Failed to delete {len(results['failed'])} agent(s):\n"
1488
+ for agent_id in results["failed"]:
1489
+ errors = results["details"][agent_id]["errors"]
1490
+ message += f" - {agent_id}: {', '.join(errors)}\n"
1491
+
1492
+ if results["successful"]:
1493
+ return CommandResult.success_result(message.strip(), data=results)
1494
+ return CommandResult.error_result(message.strip(), data=results)
1495
+
1496
+ except Exception as e:
1497
+ self.logger.error(f"Error deleting local agents: {e}", exc_info=True)
1498
+ return CommandResult.error_result(f"Error deleting local agents: {e}")
1499
+
1500
+ def _manage_local_agents(self, args) -> CommandResult:
1501
+ """Redirect to main configuration interface (DEPRECATED)."""
1502
+ try:
1503
+ from rich.console import Console
1504
+ from rich.prompt import Confirm
1505
+
1506
+ console = Console()
1507
+
1508
+ console.print(
1509
+ "\n[bold cyan]╭─────────────────────────────────────────╮[/bold cyan]"
1510
+ )
1511
+ console.print(
1512
+ "[bold cyan]│ Agent Management Has Moved! │[/bold cyan]"
1513
+ )
1514
+ console.print(
1515
+ "[bold cyan]╰─────────────────────────────────────────╯[/bold cyan]\n"
1516
+ )
1517
+
1518
+ console.print("For a better experience with integrated configuration:")
1519
+ console.print(" • Agent management")
1520
+ console.print(" • Skills management")
1521
+ console.print(" • Template editing")
1522
+ console.print(" • Behavior configuration")
1523
+ console.print(" • Startup settings\n")
1524
+
1525
+ console.print("Please use: [bold green]claude-mpm config[/bold green]\n")
1526
+
1527
+ if Confirm.ask("Launch configuration interface now?", default=True):
1528
+ # Import and run config command directly
1529
+ from claude_mpm.cli.commands.configure import ConfigureCommand
1530
+
1531
+ config_cmd = ConfigureCommand()
1532
+ return config_cmd.execute(args)
1533
+ console.print(
1534
+ "\n[dim]Run 'claude-mpm config' anytime to access agent management[/dim]"
1535
+ )
1536
+ return CommandResult.success_result("Redirected to config interface")
1537
+
1538
+ except Exception as e:
1539
+ self.logger.error(f"Error redirecting to config: {e}", exc_info=True)
1540
+ return CommandResult.error_result(f"Error redirecting to config: {e}")
1541
+
1542
+ def _configure_deployment(self, args) -> CommandResult:
1543
+ """Configure agent deployment settings."""
1544
+ try:
1545
+ from pathlib import Path
1546
+
1547
+ import yaml
1548
+
1549
+ from claude_mpm.core.config import Config
1550
+
1551
+ config = Config()
1552
+ config_path = Path.cwd() / ".claude-mpm" / "configuration.yaml"
1553
+
1554
+ # Handle show command
1555
+ if getattr(args, "show", False):
1556
+ from ...services.agents.deployment.deployment_config_loader import (
1557
+ DeploymentConfigLoader,
1558
+ )
1559
+
1560
+ loader = DeploymentConfigLoader(self.logger)
1561
+ settings = loader.get_deployment_settings(config)
1562
+
1563
+ print("\nšŸ“‹ Agent Deployment Configuration")
1564
+ print("=" * 50)
1565
+ print(f"Configuration file: {config_path}")
1566
+ print("\nšŸ”§ Deployment Settings:")
1567
+ print(f" Deploy system agents: {settings['deploy_system_agents']}")
1568
+ print(f" Deploy local agents: {settings['deploy_local_agents']}")
1569
+ print(f" Deploy user agents: {settings['deploy_user_agents']}")
1570
+ print(
1571
+ f" Prefer local over system: {settings['prefer_local_over_system']}"
1572
+ )
1573
+ print(f" Version comparison: {settings['version_comparison']}")
1574
+
1575
+ if settings["enabled_agents"]:
1576
+ print(
1577
+ f"\nāœ… Enabled agents: {', '.join(settings['enabled_agents'])}"
1578
+ )
1579
+ else:
1580
+ print("\nāœ… Enabled agents: All (no restrictions)")
1581
+
1582
+ if settings["disabled_agents"]:
1583
+ print(
1584
+ f"āŒ Disabled agents: {', '.join(settings['disabled_agents'])}"
1585
+ )
1586
+ else:
1587
+ print("āŒ Disabled agents: None")
1588
+
1589
+ print("\n" + "=" * 50)
1590
+ return CommandResult.success_result(
1591
+ "Displayed deployment configuration"
1592
+ )
1593
+
1594
+ # Handle interactive mode
1595
+ if getattr(args, "interactive", False):
1596
+ return self._configure_deployment_interactive(config_path)
1597
+
1598
+ # Load current configuration
1599
+ if not config_path.exists():
1600
+ config_path.parent.mkdir(parents=True, exist_ok=True)
1601
+ config_data = {}
1602
+ else:
1603
+ with config_path.open() as f:
1604
+ config_data = yaml.safe_load(f) or {}
1605
+
1606
+ # Ensure agent_deployment section exists
1607
+ if "agent_deployment" not in config_data:
1608
+ config_data["agent_deployment"] = {}
1609
+
1610
+ modified = False
1611
+
1612
+ # Handle enable/disable operations
1613
+ if getattr(args, "enable_all", False):
1614
+ config_data["agent_deployment"]["enabled_agents"] = []
1615
+ config_data["agent_deployment"]["disabled_agents"] = []
1616
+ print("āœ… Enabled all agents for deployment")
1617
+ modified = True
1618
+
1619
+ if getattr(args, "enable_system", False):
1620
+ config_data["agent_deployment"]["deploy_system_agents"] = True
1621
+ print("āœ… Enabled system agents for deployment")
1622
+ modified = True
1623
+
1624
+ if getattr(args, "disable_system", False):
1625
+ config_data["agent_deployment"]["deploy_system_agents"] = False
1626
+ print("āŒ Disabled system agents from deployment")
1627
+ modified = True
1628
+
1629
+ if getattr(args, "enable_local", False):
1630
+ config_data["agent_deployment"]["deploy_local_agents"] = True
1631
+ print("āœ… Enabled local agents for deployment")
1632
+ modified = True
1633
+
1634
+ if getattr(args, "disable_local", False):
1635
+ config_data["agent_deployment"]["deploy_local_agents"] = False
1636
+ print("āŒ Disabled local agents from deployment")
1637
+ modified = True
1638
+
1639
+ if getattr(args, "enable", None):
1640
+ enabled = config_data["agent_deployment"].get("enabled_agents", [])
1641
+ disabled = config_data["agent_deployment"].get("disabled_agents", [])
1642
+
1643
+ for agent_id in args.enable:
1644
+ if agent_id not in enabled:
1645
+ enabled.append(agent_id)
1646
+ if agent_id in disabled:
1647
+ disabled.remove(agent_id)
1648
+
1649
+ config_data["agent_deployment"]["enabled_agents"] = enabled
1650
+ config_data["agent_deployment"]["disabled_agents"] = disabled
1651
+ print(f"āœ… Enabled agents: {', '.join(args.enable)}")
1652
+ modified = True
1653
+
1654
+ if getattr(args, "disable", None):
1655
+ disabled = config_data["agent_deployment"].get("disabled_agents", [])
1656
+
1657
+ for agent_id in args.disable:
1658
+ if agent_id not in disabled:
1659
+ disabled.append(agent_id)
1660
+
1661
+ config_data["agent_deployment"]["disabled_agents"] = disabled
1662
+ print(f"āŒ Disabled agents: {', '.join(args.disable)}")
1663
+ modified = True
1664
+
1665
+ # Save configuration if modified
1666
+ if modified:
1667
+ with config_path.open("w") as f:
1668
+ yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
1669
+ print(f"\nšŸ’¾ Configuration saved to {config_path}")
1670
+ return CommandResult.success_result("Deployment configuration updated")
1671
+
1672
+ # If no modifications were made and not showing, display help
1673
+ if not getattr(args, "show", False):
1674
+ print("No configuration changes specified. Use --help for options.")
1675
+ return CommandResult.success_result("No changes made")
1676
+
1677
+ except Exception as e:
1678
+ self.logger.error(f"Error configuring deployment: {e}", exc_info=True)
1679
+ return CommandResult.error_result(f"Error configuring deployment: {e}")
1680
+
1681
+ def _configure_deployment_interactive(self, config_path: Path) -> CommandResult:
1682
+ """Interactive mode for configuring agent deployment."""
1683
+ try:
1684
+ import yaml
1685
+
1686
+ from ...utils.ui_helpers import (
1687
+ prompt_choice,
1688
+ prompt_multiselect,
1689
+ prompt_yes_no,
1690
+ )
1691
+
1692
+ # Load current configuration
1693
+ if config_path.exists():
1694
+ with config_path.open() as f:
1695
+ config_data = yaml.safe_load(f) or {}
1696
+ else:
1697
+ config_data = {}
1698
+
1699
+ if "agent_deployment" not in config_data:
1700
+ config_data["agent_deployment"] = {}
1701
+
1702
+ settings = config_data["agent_deployment"]
1703
+
1704
+ print("\nšŸŽ® Interactive Agent Deployment Configuration")
1705
+ print("=" * 50)
1706
+
1707
+ # Configure source types
1708
+ settings["deploy_system_agents"] = prompt_yes_no(
1709
+ "Deploy system agents?",
1710
+ default=settings.get("deploy_system_agents", True),
1711
+ )
1712
+
1713
+ settings["deploy_local_agents"] = prompt_yes_no(
1714
+ "Deploy local project agents?",
1715
+ default=settings.get("deploy_local_agents", True),
1716
+ )
1717
+
1718
+ settings["deploy_user_agents"] = prompt_yes_no(
1719
+ "Deploy user-level agents?",
1720
+ default=settings.get("deploy_user_agents", True),
1721
+ )
1722
+
1723
+ # Configure version behavior
1724
+ settings["prefer_local_over_system"] = prompt_yes_no(
1725
+ "Should local agents override system agents with same ID?",
1726
+ default=settings.get("prefer_local_over_system", True),
1727
+ )
1728
+
1729
+ settings["version_comparison"] = prompt_yes_no(
1730
+ "Compare versions across sources and deploy highest?",
1731
+ default=settings.get("version_comparison", True),
1732
+ )
1733
+
1734
+ # Configure specific agents
1735
+ choice = prompt_choice(
1736
+ "How would you like to configure specific agents?",
1737
+ [
1738
+ "No restrictions (all agents enabled)",
1739
+ "Specify disabled agents",
1740
+ "Specify enabled agents only",
1741
+ ],
1742
+ )
1743
+
1744
+ if choice == "No restrictions (all agents enabled)":
1745
+ settings["enabled_agents"] = []
1746
+ settings["disabled_agents"] = []
1747
+ elif choice == "Specify disabled agents":
1748
+ # Get list of available agents
1749
+ from ...services.agents.listing_service import AgentListingService
1750
+
1751
+ listing_service = AgentListingService()
1752
+ agents, _ = listing_service.list_all_agents()
1753
+ agent_ids = sorted({agent.name for agent in agents})
1754
+
1755
+ if agent_ids:
1756
+ disabled = prompt_multiselect(
1757
+ "Select agents to disable:",
1758
+ agent_ids,
1759
+ default=settings.get("disabled_agents", []),
1760
+ )
1761
+ settings["disabled_agents"] = disabled
1762
+ settings["enabled_agents"] = []
1763
+ else:
1764
+ print("No agents found to configure")
1765
+ else: # Specify enabled agents only
1766
+ from ...services.agents.listing_service import AgentListingService
1767
+
1768
+ listing_service = AgentListingService()
1769
+ agents, _ = listing_service.list_all_agents()
1770
+ agent_ids = sorted({agent.name for agent in agents})
1771
+
1772
+ if agent_ids:
1773
+ enabled = prompt_multiselect(
1774
+ "Select agents to enable (others will be disabled):",
1775
+ agent_ids,
1776
+ default=settings.get("enabled_agents", []),
1777
+ )
1778
+ settings["enabled_agents"] = enabled
1779
+ settings["disabled_agents"] = []
1780
+ else:
1781
+ print("No agents found to configure")
1782
+
1783
+ # Save configuration
1784
+ config_data["agent_deployment"] = settings
1785
+
1786
+ # Ensure parent directory exists
1787
+ config_path.parent.mkdir(parents=True, exist_ok=True)
1788
+
1789
+ with config_path.open("w") as f:
1790
+ yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
1791
+
1792
+ print(f"\nāœ… Configuration saved to {config_path}")
1793
+
1794
+ # Show summary
1795
+ print("\nšŸ“‹ New Configuration Summary:")
1796
+ print(
1797
+ f" System agents: {'Enabled' if settings.get('deploy_system_agents', True) else 'Disabled'}"
1798
+ )
1799
+ print(
1800
+ f" Local agents: {'Enabled' if settings.get('deploy_local_agents', True) else 'Disabled'}"
1801
+ )
1802
+ print(
1803
+ f" User agents: {'Enabled' if settings.get('deploy_user_agents', True) else 'Disabled'}"
1804
+ )
1805
+
1806
+ if settings.get("enabled_agents"):
1807
+ print(f" Enabled specific: {', '.join(settings['enabled_agents'])}")
1808
+ elif settings.get("disabled_agents"):
1809
+ print(f" Disabled specific: {', '.join(settings['disabled_agents'])}")
1810
+ else:
1811
+ print(" All agents enabled")
1812
+
1813
+ return CommandResult.success_result("Interactive configuration completed")
1814
+
1815
+ except KeyboardInterrupt:
1816
+ print("\n\nConfiguration cancelled.")
1817
+ return CommandResult.error_result("Configuration cancelled by user")
1818
+ except Exception as e:
1819
+ self.logger.error(f"Error in interactive configuration: {e}", exc_info=True)
1820
+ return CommandResult.error_result(
1821
+ f"Error in interactive configuration: {e}"
1822
+ )
1823
+
1824
+ def _detect_toolchain(self, args) -> CommandResult:
1825
+ """Detect project toolchain without deploying agents.
1826
+
1827
+ Part of TSK-0054 Phase 5: Auto-configuration CLI integration.
1828
+ """
1829
+ try:
1830
+ from .agents_detect import AgentsDetectCommand
1831
+
1832
+ cmd = AgentsDetectCommand()
1833
+ return cmd.run(args)
1834
+ except Exception as e:
1835
+ self.logger.error(f"Error detecting toolchain: {e}", exc_info=True)
1836
+ return CommandResult.error_result(f"Error detecting toolchain: {e}")
1837
+
1838
+ def _recommend_agents(self, args) -> CommandResult:
1839
+ """Recommend agents based on project toolchain.
1840
+
1841
+ Part of TSK-0054 Phase 5: Auto-configuration CLI integration.
1842
+ """
1843
+ try:
1844
+ from .agents_recommend import AgentsRecommendCommand
1845
+
1846
+ cmd = AgentsRecommendCommand()
1847
+ return cmd.run(args)
1848
+ except Exception as e:
1849
+ self.logger.error(f"Error recommending agents: {e}", exc_info=True)
1850
+ return CommandResult.error_result(f"Error recommending agents: {e}")
1851
+
1852
+ def _migrate_to_project(self, args) -> CommandResult:
1853
+ """Migrate user-level agents to project-level.
1854
+
1855
+ DEPRECATION: User-level agents (~/.claude-mpm/agents/) are deprecated and
1856
+ will be removed in v5.0.0. This command migrates them to project-level
1857
+ (.claude-mpm/agents/) where they belong.
1858
+
1859
+ Args:
1860
+ args: Command arguments with dry_run and force flags
1861
+
1862
+ Returns:
1863
+ CommandResult with migration status
1864
+ """
1865
+ import shutil
1866
+
1867
+ try:
1868
+ user_agents_dir = Path.home() / ".claude-mpm" / "agents"
1869
+ project_agents_dir = Path.cwd() / ".claude-mpm" / "agents"
1870
+
1871
+ dry_run = getattr(args, "dry_run", False)
1872
+ force = getattr(args, "force", False)
1873
+
1874
+ # Check if user agents directory exists
1875
+ if not user_agents_dir.exists():
1876
+ print("āœ… No user-level agents found. Nothing to migrate.")
1877
+ return CommandResult.success_result("No user-level agents to migrate")
1878
+
1879
+ # Find all user agent files
1880
+ user_agent_files = list(user_agents_dir.glob("*.json")) + list(
1881
+ user_agents_dir.glob("*.md")
1882
+ )
1883
+
1884
+ if not user_agent_files:
1885
+ print("āœ… No user-level agents found. Nothing to migrate.")
1886
+ return CommandResult.success_result("No user-level agents to migrate")
1887
+
1888
+ # Display what we found
1889
+ print(f"\nšŸ“¦ Found {len(user_agent_files)} user-level agent(s) to migrate:")
1890
+ for agent_file in user_agent_files:
1891
+ print(f" - {agent_file.name}")
1892
+
1893
+ if dry_run:
1894
+ print("\nšŸ” DRY RUN: Would migrate to:")
1895
+ print(f" → {project_agents_dir}")
1896
+ print("\nRun without --dry-run to perform the migration.")
1897
+ return CommandResult.success_result(
1898
+ "Dry run completed",
1899
+ data={
1900
+ "user_agents_found": len(user_agent_files),
1901
+ "target_directory": str(project_agents_dir),
1902
+ },
1903
+ )
1904
+
1905
+ # Create project agents directory
1906
+ project_agents_dir.mkdir(parents=True, exist_ok=True)
1907
+
1908
+ # Migrate agents
1909
+ migrated = 0
1910
+ skipped = 0
1911
+ errors = []
1912
+
1913
+ for agent_file in user_agent_files:
1914
+ target_file = project_agents_dir / agent_file.name
1915
+
1916
+ # Check for conflicts
1917
+ if target_file.exists() and not force:
1918
+ print(f"āš ļø Skipping {agent_file.name} (already exists in project)")
1919
+ print(" Use --force to overwrite existing agents")
1920
+ skipped += 1
1921
+ continue
1922
+
1923
+ try:
1924
+ # Copy agent to project directory
1925
+ shutil.copy2(agent_file, target_file)
1926
+ migrated += 1
1927
+ print(f"āœ… Migrated {agent_file.name}")
1928
+ except Exception as e:
1929
+ error_msg = f"Failed to migrate {agent_file.name}: {e}"
1930
+ errors.append(error_msg)
1931
+ print(f"āŒ {error_msg}")
1932
+
1933
+ # Summary
1934
+ print("\nšŸ“Š Migration Summary:")
1935
+ print(f" āœ… Migrated: {migrated}/{len(user_agent_files)}")
1936
+ if skipped > 0:
1937
+ print(f" ā­ļø Skipped: {skipped} (already exist)")
1938
+ if errors:
1939
+ print(f" āŒ Errors: {len(errors)}")
1940
+
1941
+ if migrated > 0:
1942
+ print(f"\nāœ… Successfully migrated {migrated} agent(s) to:")
1943
+ print(f" {project_agents_dir}")
1944
+ print(
1945
+ "\nāš ļø IMPORTANT: Verify agents work correctly, then remove user-level agents:"
1946
+ )
1947
+ print(f" rm -rf {user_agents_dir}")
1948
+ print("\nšŸ’” Why this change?")
1949
+ print(" - Project isolation: Each project has its own agents")
1950
+ print(" - Version control: Agents can be versioned with your code")
1951
+ print(" - Team consistency: Everyone uses the same agents")
1952
+
1953
+ return CommandResult.success_result(
1954
+ f"Migrated {migrated} agents",
1955
+ data={
1956
+ "migrated": migrated,
1957
+ "skipped": skipped,
1958
+ "errors": errors,
1959
+ "total": len(user_agent_files),
1960
+ },
1961
+ )
1962
+
1963
+ except Exception as e:
1964
+ self.logger.error(f"Error migrating agents: {e}", exc_info=True)
1965
+ return CommandResult.error_result(f"Error migrating agents: {e}")
1966
+
1967
+ def _deploy_minimal_configuration(self, args) -> CommandResult:
1968
+ """Deploy minimal configuration (6 core agents).
1969
+
1970
+ Part of Phase 3 (1M-382): Agent Selection Modes.
1971
+ Deploy exactly 6 agents for basic Claude MPM workflow:
1972
+ engineer, documentation, qa, research, ops, ticketing.
1973
+ """
1974
+ try:
1975
+ from ...config.agent_sources import AgentSourceConfiguration
1976
+ from ...services.agents.agent_selection_service import AgentSelectionService
1977
+ from ...services.agents.single_tier_deployment_service import (
1978
+ SingleTierDeploymentService,
1979
+ )
1980
+
1981
+ # Initialize services
1982
+ config = AgentSourceConfiguration.load()
1983
+ deployment_dir = Path.home() / ".claude" / "agents"
1984
+ deployment_service = SingleTierDeploymentService(config, deployment_dir)
1985
+ selection_service = AgentSelectionService(deployment_service)
1986
+
1987
+ # Get dry_run flag
1988
+ dry_run = getattr(args, "dry_run", False)
1989
+
1990
+ # Deploy minimal configuration
1991
+ print("šŸŽÆ Deploying minimal configuration (6 core agents)...")
1992
+ if dry_run:
1993
+ print("šŸ” DRY RUN MODE - No agents will be deployed\n")
1994
+
1995
+ result = selection_service.deploy_minimal_configuration(dry_run=dry_run)
1996
+
1997
+ # Format output
1998
+ output_format = self._get_output_format(args)
1999
+ if self._is_structured_format(output_format):
2000
+ formatted = (
2001
+ self._formatter.format_as_json(result)
2002
+ if str(output_format).lower() == OutputFormat.JSON
2003
+ else self._formatter.format_as_yaml(result)
2004
+ )
2005
+ print(formatted)
2006
+ return CommandResult.success_result(
2007
+ f"Minimal configuration {result['status']}", data=result
2008
+ )
2009
+
2010
+ # Text output
2011
+ print(f"\n{'=' * 60}")
2012
+ print(f"Status: {result['status'].upper()}")
2013
+ print(f"Mode: {result['mode']}")
2014
+ print(f"{'=' * 60}")
2015
+ print(
2016
+ f"\nšŸ“Š Summary: {result['deployed_count']} deployed, "
2017
+ f"{result['failed_count']} failed, {result['missing_count']} missing"
2018
+ )
2019
+
2020
+ if result["deployed_agents"]:
2021
+ print(f"\nāœ… Deployed agents ({len(result['deployed_agents'])}):")
2022
+ for agent in result["deployed_agents"]:
2023
+ print(f" • {agent}")
2024
+
2025
+ if result["failed_agents"]:
2026
+ print(f"\nāŒ Failed agents ({len(result['failed_agents'])}):")
2027
+ for agent in result["failed_agents"]:
2028
+ print(f" • {agent}")
2029
+
2030
+ if result["missing_agents"]:
2031
+ print(f"\nāš ļø Missing agents ({len(result['missing_agents'])}):")
2032
+ for agent in result["missing_agents"]:
2033
+ print(f" • {agent}")
2034
+ print("\nThese agents are not available in configured sources.")
2035
+
2036
+ if dry_run:
2037
+ print(
2038
+ "\nšŸ’” This was a dry run. Run without --dry-run to deploy agents."
2039
+ )
2040
+
2041
+ return CommandResult.success_result(
2042
+ f"Minimal configuration {result['status']}", data=result
2043
+ )
2044
+
2045
+ except Exception as e:
2046
+ self.logger.error(
2047
+ f"Error deploying minimal configuration: {e}", exc_info=True
2048
+ )
2049
+ return CommandResult.error_result(
2050
+ f"Error deploying minimal configuration: {e}"
2051
+ )
2052
+
2053
+ def _deploy_auto_configure(self, args) -> CommandResult:
2054
+ """Auto-detect toolchain and deploy matching agents.
2055
+
2056
+ Part of Phase 3 (1M-382): Agent Selection Modes.
2057
+ Detect project toolchain (languages, frameworks, build tools) and
2058
+ deploy matching specialized agents.
2059
+ """
2060
+ try:
2061
+ from ...config.agent_sources import AgentSourceConfiguration
2062
+ from ...services.agents.agent_selection_service import AgentSelectionService
2063
+ from ...services.agents.single_tier_deployment_service import (
2064
+ SingleTierDeploymentService,
2065
+ )
2066
+
2067
+ # Initialize services
2068
+ config = AgentSourceConfiguration.load()
2069
+ deployment_dir = Path.home() / ".claude" / "agents"
2070
+ deployment_service = SingleTierDeploymentService(config, deployment_dir)
2071
+ selection_service = AgentSelectionService(deployment_service)
2072
+
2073
+ # Get arguments
2074
+ project_path = getattr(args, "path", Path.cwd())
2075
+ dry_run = getattr(args, "dry_run", False)
2076
+
2077
+ # Deploy auto-configure
2078
+ print(f"šŸ” Auto-detecting toolchain in {project_path}...")
2079
+ if dry_run:
2080
+ print("šŸ” DRY RUN MODE - No agents will be deployed\n")
2081
+
2082
+ result = selection_service.deploy_auto_configure(
2083
+ project_path=project_path, dry_run=dry_run
2084
+ )
2085
+
2086
+ # Format output
2087
+ output_format = self._get_output_format(args)
2088
+ if self._is_structured_format(output_format):
2089
+ formatted = (
2090
+ self._formatter.format_as_json(result)
2091
+ if str(output_format).lower() == OutputFormat.JSON
2092
+ else self._formatter.format_as_yaml(result)
2093
+ )
2094
+ print(formatted)
2095
+ return CommandResult.success_result(
2096
+ f"Auto-configure {result['status']}", data=result
2097
+ )
2098
+
2099
+ # Text output
2100
+ print(f"\n{'=' * 60}")
2101
+ print(f"Status: {result['status'].upper()}")
2102
+ print(f"Mode: {result['mode']}")
2103
+ print(f"{'=' * 60}")
2104
+
2105
+ # Show detected toolchain
2106
+ toolchain = result.get("toolchain", {})
2107
+ print("\nšŸ”§ Detected Toolchain:")
2108
+ if toolchain.get("languages"):
2109
+ print(f" Languages: {', '.join(toolchain['languages'])}")
2110
+ if toolchain.get("frameworks"):
2111
+ print(f" Frameworks: {', '.join(toolchain['frameworks'])}")
2112
+ if toolchain.get("build_tools"):
2113
+ print(f" Build Tools: {', '.join(toolchain['build_tools'])}")
2114
+
2115
+ if not any(toolchain.values()):
2116
+ print(" (No toolchain detected)")
2117
+
2118
+ # Show recommended agents
2119
+ recommended = result.get("recommended_agents", [])
2120
+ if recommended:
2121
+ print(f"\nšŸŽÆ Recommended agents ({len(recommended)}):")
2122
+ for agent in recommended:
2123
+ print(f" • {agent}")
2124
+
2125
+ # Show deployment summary
2126
+ print(
2127
+ f"\nšŸ“Š Summary: {result['deployed_count']} deployed, "
2128
+ f"{result['failed_count']} failed, {result['missing_count']} missing"
2129
+ )
2130
+
2131
+ if result.get("deployed_agents"):
2132
+ print(f"\nāœ… Deployed agents ({len(result['deployed_agents'])}):")
2133
+ for agent in result["deployed_agents"]:
2134
+ print(f" • {agent}")
2135
+
2136
+ if result.get("failed_agents"):
2137
+ print(f"\nāŒ Failed agents ({len(result['failed_agents'])}):")
2138
+ for agent in result["failed_agents"]:
2139
+ print(f" • {agent}")
2140
+
2141
+ if result.get("missing_agents"):
2142
+ print(f"\nāš ļø Missing agents ({len(result['missing_agents'])}):")
2143
+ for agent in result["missing_agents"]:
2144
+ print(f" • {agent}")
2145
+ print("\nThese agents are not available in configured sources.")
2146
+
2147
+ if dry_run:
2148
+ print(
2149
+ "\nšŸ’” This was a dry run. Run without --dry-run to deploy agents."
2150
+ )
2151
+
2152
+ return CommandResult.success_result(
2153
+ f"Auto-configure {result['status']}", data=result
2154
+ )
2155
+
2156
+ except Exception as e:
2157
+ self.logger.error(f"Error in auto-configure: {e}", exc_info=True)
2158
+ return CommandResult.error_result(f"Error in auto-configure: {e}")
2159
+
2160
+ def _cache_status(self, args) -> CommandResult:
2161
+ """Show git status of agent cache.
2162
+
2163
+ Displays current branch, uncommitted changes, unpushed commits, and
2164
+ remote URL for the agent cache repository.
2165
+ """
2166
+ try:
2167
+ from ...services.agents.cache_git_manager import CacheGitManager
2168
+
2169
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2170
+ manager = CacheGitManager(cache_dir)
2171
+
2172
+ if not manager.is_git_repo():
2173
+ print("āŒ Cache is not a git repository")
2174
+ print(f"\nCache location: {cache_dir}")
2175
+ print(
2176
+ "\nšŸ’” This is expected if you haven't cloned the agents repository."
2177
+ )
2178
+ print(" The cache will be managed via HTTP sync instead.")
2179
+ return CommandResult.error_result("Cache is not a git repository")
2180
+
2181
+ status = manager.get_status()
2182
+ output_format = self._get_output_format(args)
2183
+
2184
+ if self._is_structured_format(output_format):
2185
+ formatted = (
2186
+ self._formatter.format_as_json(status)
2187
+ if str(output_format).lower() == OutputFormat.JSON
2188
+ else self._formatter.format_as_yaml(status)
2189
+ )
2190
+ print(formatted)
2191
+ return CommandResult.success_result(
2192
+ "Cache status retrieved", data=status
2193
+ )
2194
+
2195
+ # Text output
2196
+ print(f"\nšŸ“ Cache: {manager.repo_path}")
2197
+ print(f"🌿 Branch: {status.get('branch', 'unknown')}")
2198
+
2199
+ if status.get("remote_url"):
2200
+ print(f"šŸ”— Remote: {status['remote_url']}")
2201
+
2202
+ # Show sync status
2203
+ ahead = status.get("ahead", 0)
2204
+ behind = status.get("behind", 0)
2205
+
2206
+ if ahead > 0:
2207
+ print(f"šŸ“¤ Ahead of remote: {ahead} commit(s)")
2208
+ if behind > 0:
2209
+ print(f"šŸ“„ Behind remote: {behind} commit(s)")
2210
+
2211
+ if ahead == 0 and behind == 0:
2212
+ print("āœ… In sync with remote")
2213
+
2214
+ # Show uncommitted changes
2215
+ uncommitted = status.get("uncommitted", [])
2216
+ if uncommitted:
2217
+ print(f"\nāš ļø Uncommitted changes: {len(uncommitted)}")
2218
+ for file in uncommitted[:10]: # Show max 10 files
2219
+ print(f" - {file}")
2220
+ if len(uncommitted) > 10:
2221
+ print(f" ... and {len(uncommitted) - 10} more")
2222
+ else:
2223
+ print("\nāœ… No uncommitted changes")
2224
+
2225
+ # Overall status
2226
+ if status.get("is_clean"):
2227
+ print("\n✨ Cache is clean and up-to-date")
2228
+ else:
2229
+ print("\nšŸ’” Run 'claude-mpm agents cache-sync' to sync with remote")
2230
+
2231
+ return CommandResult.success_result("Cache status displayed", data=status)
2232
+
2233
+ except Exception as e:
2234
+ self.logger.error(f"Error getting cache status: {e}", exc_info=True)
2235
+ return CommandResult.error_result(f"Error getting cache status: {e}")
2236
+
2237
+ def _cache_pull(self, args) -> CommandResult:
2238
+ """Pull latest agents from remote repository."""
2239
+ try:
2240
+ from ...services.agents.cache_git_manager import CacheGitManager
2241
+
2242
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2243
+ manager = CacheGitManager(cache_dir)
2244
+
2245
+ if not manager.is_git_repo():
2246
+ print("āŒ Cache is not a git repository")
2247
+ return CommandResult.error_result("Cache is not a git repository")
2248
+
2249
+ branch = getattr(args, "branch", "main")
2250
+ print(f"šŸ”„ Pulling latest changes from {branch}...")
2251
+
2252
+ success, msg = manager.pull_latest(branch)
2253
+
2254
+ if success:
2255
+ print(f"āœ… {msg}")
2256
+ return CommandResult.success_result(msg)
2257
+ print(f"āŒ {msg}")
2258
+ return CommandResult.error_result(msg)
2259
+
2260
+ except Exception as e:
2261
+ self.logger.error(f"Error pulling cache: {e}", exc_info=True)
2262
+ return CommandResult.error_result(f"Error pulling cache: {e}")
2263
+
2264
+ def _cache_commit(self, args) -> CommandResult:
2265
+ """Commit changes to cache repository."""
2266
+ try:
2267
+ from ...services.agents.cache_git_manager import CacheGitManager
2268
+
2269
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2270
+ manager = CacheGitManager(cache_dir)
2271
+
2272
+ if not manager.is_git_repo():
2273
+ print("āŒ Cache is not a git repository")
2274
+ return CommandResult.error_result("Cache is not a git repository")
2275
+
2276
+ # Get commit message from args
2277
+ message = getattr(args, "message", None)
2278
+ if not message:
2279
+ # Default message
2280
+ message = "feat: update agents from local development"
2281
+
2282
+ print("šŸ’¾ Committing changes...")
2283
+ success, msg = manager.commit_changes(message)
2284
+
2285
+ if success:
2286
+ print(f"āœ… {msg}")
2287
+ print(f"\nšŸ’” Commit message: {message}")
2288
+ return CommandResult.success_result(msg)
2289
+ print(f"āŒ {msg}")
2290
+ return CommandResult.error_result(msg)
2291
+
2292
+ except Exception as e:
2293
+ self.logger.error(f"Error committing cache changes: {e}", exc_info=True)
2294
+ return CommandResult.error_result(f"Error committing cache changes: {e}")
2295
+
2296
+ def _cache_push(self, args) -> CommandResult:
2297
+ """Push local agent changes to remote."""
2298
+ try:
2299
+ from ...services.agents.cache_git_manager import CacheGitManager
2300
+
2301
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2302
+ manager = CacheGitManager(cache_dir)
2303
+
2304
+ if not manager.is_git_repo():
2305
+ print("āŒ Cache is not a git repository")
2306
+ return CommandResult.error_result("Cache is not a git repository")
2307
+
2308
+ # Check for uncommitted changes
2309
+ if manager.has_uncommitted_changes():
2310
+ print("āš ļø You have uncommitted changes.")
2311
+ print("\nšŸ’” Commit changes first with:")
2312
+ print(" claude-mpm agents cache-commit --message 'your message'")
2313
+
2314
+ # Ask if user wants to commit first
2315
+ auto_commit = getattr(args, "auto_commit", False)
2316
+ if auto_commit:
2317
+ print("\nšŸ“ Auto-committing changes...")
2318
+ success, msg = manager.commit_changes("feat: update agents")
2319
+ if not success:
2320
+ print(f"āŒ Commit failed: {msg}")
2321
+ return CommandResult.error_result(f"Commit failed: {msg}")
2322
+ print(f"āœ… {msg}")
2323
+ else:
2324
+ return CommandResult.error_result(
2325
+ "Uncommitted changes detected. Commit first or use --auto-commit"
2326
+ )
2327
+
2328
+ # Push changes
2329
+ branch = getattr(args, "branch", "main")
2330
+ print(f"šŸ“¤ Pushing changes to {branch}...")
2331
+
2332
+ success, msg = manager.push_changes(branch)
2333
+
2334
+ if success:
2335
+ print(f"āœ… {msg}")
2336
+ return CommandResult.success_result(msg)
2337
+ print(f"āŒ {msg}")
2338
+ return CommandResult.error_result(msg)
2339
+
2340
+ except Exception as e:
2341
+ self.logger.error(f"Error pushing cache: {e}", exc_info=True)
2342
+ return CommandResult.error_result(f"Error pushing cache: {e}")
2343
+
2344
+ def _cache_sync(self, args) -> CommandResult:
2345
+ """Full cache sync: pull, commit (if needed), push."""
2346
+ try:
2347
+ from ...services.agents.cache_git_manager import CacheGitManager
2348
+
2349
+ cache_dir = Path.home() / ".claude-mpm" / "cache" / "remote-agents"
2350
+ manager = CacheGitManager(cache_dir)
2351
+
2352
+ if not manager.is_git_repo():
2353
+ print("āŒ Cache is not a git repository")
2354
+ return CommandResult.error_result("Cache is not a git repository")
2355
+
2356
+ print("šŸ”„ Syncing cache with remote...\n")
2357
+
2358
+ success, msg = manager.sync_with_remote()
2359
+
2360
+ # Print detailed sync message
2361
+ print(msg)
2362
+
2363
+ if success:
2364
+ print("\n✨ Cache sync complete!")
2365
+ return CommandResult.success_result("Cache synced successfully")
2366
+
2367
+ print("\nāŒ Cache sync failed. See details above.")
2368
+ return CommandResult.error_result("Cache sync failed")
2369
+
2370
+ except Exception as e:
2371
+ self.logger.error(f"Error syncing cache: {e}", exc_info=True)
2372
+ return CommandResult.error_result(f"Error syncing cache: {e}")
2373
+
879
2374
 
880
2375
  def manage_agents(args):
881
2376
  """
@@ -887,7 +2382,7 @@ def manage_agents(args):
887
2382
  result = command.execute(args)
888
2383
 
889
2384
  # Print result if structured output format is requested
890
- if hasattr(args, "format") and args.format in ["json", "yaml"]:
2385
+ if _is_structured_output(args):
891
2386
  command.print_result(result, args)
892
2387
 
893
2388
  return result.exit_code