claude-mpm 4.1.1__py3-none-any.whl → 4.1.3__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.
Files changed (389) hide show
  1. claude_mpm/BUILD_NUMBER +1 -1
  2. claude_mpm/VERSION +1 -1
  3. claude_mpm/__main__.py +1 -1
  4. claude_mpm/agents/BASE_PM.md +74 -46
  5. claude_mpm/agents/INSTRUCTIONS.md +11 -153
  6. claude_mpm/agents/WORKFLOW.md +61 -321
  7. claude_mpm/agents/__init__.py +11 -11
  8. claude_mpm/agents/agent_loader.py +23 -20
  9. claude_mpm/agents/agent_loader_integration.py +1 -1
  10. claude_mpm/agents/agents_metadata.py +27 -0
  11. claude_mpm/agents/async_agent_loader.py +5 -8
  12. claude_mpm/agents/base_agent_loader.py +36 -25
  13. claude_mpm/agents/frontmatter_validator.py +6 -6
  14. claude_mpm/agents/schema/agent_schema.json +1 -1
  15. claude_mpm/agents/system_agent_config.py +9 -9
  16. claude_mpm/agents/templates/api_qa.json +47 -2
  17. claude_mpm/agents/templates/engineer.json +33 -11
  18. claude_mpm/agents/templates/imagemagick.json +256 -0
  19. claude_mpm/agents/templates/qa.json +41 -2
  20. claude_mpm/agents/templates/ticketing.json +5 -5
  21. claude_mpm/agents/templates/web_qa.json +50 -2
  22. claude_mpm/cli/__init__.py +51 -46
  23. claude_mpm/cli/__main__.py +1 -1
  24. claude_mpm/cli/commands/__init__.py +10 -12
  25. claude_mpm/cli/commands/agent_manager.py +186 -181
  26. claude_mpm/cli/commands/agents.py +648 -1098
  27. claude_mpm/cli/commands/aggregate.py +30 -29
  28. claude_mpm/cli/commands/cleanup.py +50 -44
  29. claude_mpm/cli/commands/cleanup_orphaned_agents.py +25 -25
  30. claude_mpm/cli/commands/config.py +162 -127
  31. claude_mpm/cli/commands/doctor.py +52 -62
  32. claude_mpm/cli/commands/info.py +37 -25
  33. claude_mpm/cli/commands/mcp.py +3 -7
  34. claude_mpm/cli/commands/mcp_command_router.py +14 -18
  35. claude_mpm/cli/commands/mcp_install_commands.py +28 -23
  36. claude_mpm/cli/commands/mcp_pipx_config.py +58 -49
  37. claude_mpm/cli/commands/mcp_server_commands.py +23 -17
  38. claude_mpm/cli/commands/memory.py +339 -967
  39. claude_mpm/cli/commands/monitor.py +117 -88
  40. claude_mpm/cli/commands/run.py +233 -542
  41. claude_mpm/cli/commands/socketio_monitor.py +17 -19
  42. claude_mpm/cli/commands/tickets.py +92 -92
  43. claude_mpm/cli/parser.py +1 -5
  44. claude_mpm/cli/parsers/__init__.py +1 -1
  45. claude_mpm/cli/parsers/agent_manager_parser.py +50 -98
  46. claude_mpm/cli/parsers/agents_parser.py +2 -3
  47. claude_mpm/cli/parsers/base_parser.py +7 -5
  48. claude_mpm/cli/parsers/mcp_parser.py +4 -2
  49. claude_mpm/cli/parsers/monitor_parser.py +26 -18
  50. claude_mpm/cli/shared/__init__.py +10 -10
  51. claude_mpm/cli/shared/argument_patterns.py +57 -71
  52. claude_mpm/cli/shared/base_command.py +61 -53
  53. claude_mpm/cli/shared/error_handling.py +62 -58
  54. claude_mpm/cli/shared/output_formatters.py +78 -77
  55. claude_mpm/cli/startup_logging.py +280 -172
  56. claude_mpm/cli/utils.py +10 -11
  57. claude_mpm/cli_module/__init__.py +1 -1
  58. claude_mpm/cli_module/args.py +1 -1
  59. claude_mpm/cli_module/migration_example.py +5 -5
  60. claude_mpm/config/__init__.py +9 -9
  61. claude_mpm/config/agent_config.py +15 -14
  62. claude_mpm/config/experimental_features.py +4 -4
  63. claude_mpm/config/paths.py +0 -1
  64. claude_mpm/config/socketio_config.py +5 -6
  65. claude_mpm/constants.py +1 -2
  66. claude_mpm/core/__init__.py +8 -8
  67. claude_mpm/core/agent_name_normalizer.py +1 -1
  68. claude_mpm/core/agent_registry.py +22 -29
  69. claude_mpm/core/agent_session_manager.py +3 -3
  70. claude_mpm/core/base_service.py +7 -15
  71. claude_mpm/core/cache.py +4 -6
  72. claude_mpm/core/claude_runner.py +85 -113
  73. claude_mpm/core/config.py +43 -28
  74. claude_mpm/core/config_aliases.py +0 -9
  75. claude_mpm/core/config_constants.py +52 -30
  76. claude_mpm/core/constants.py +0 -1
  77. claude_mpm/core/container.py +18 -27
  78. claude_mpm/core/exceptions.py +2 -2
  79. claude_mpm/core/factories.py +10 -12
  80. claude_mpm/core/framework_loader.py +500 -680
  81. claude_mpm/core/hook_manager.py +26 -22
  82. claude_mpm/core/hook_performance_config.py +58 -47
  83. claude_mpm/core/injectable_service.py +1 -1
  84. claude_mpm/core/interactive_session.py +61 -152
  85. claude_mpm/core/interfaces.py +1 -100
  86. claude_mpm/core/lazy.py +5 -5
  87. claude_mpm/core/log_manager.py +587 -0
  88. claude_mpm/core/logger.py +125 -8
  89. claude_mpm/core/logging_config.py +15 -17
  90. claude_mpm/core/minimal_framework_loader.py +5 -8
  91. claude_mpm/core/oneshot_session.py +15 -33
  92. claude_mpm/core/optimized_agent_loader.py +4 -6
  93. claude_mpm/core/optimized_startup.py +2 -1
  94. claude_mpm/core/output_style_manager.py +147 -106
  95. claude_mpm/core/pm_hook_interceptor.py +0 -1
  96. claude_mpm/core/service_registry.py +11 -8
  97. claude_mpm/core/session_manager.py +1 -2
  98. claude_mpm/core/shared/__init__.py +1 -1
  99. claude_mpm/core/shared/config_loader.py +101 -97
  100. claude_mpm/core/shared/path_resolver.py +72 -68
  101. claude_mpm/core/shared/singleton_manager.py +56 -50
  102. claude_mpm/core/socketio_pool.py +26 -6
  103. claude_mpm/core/tool_access_control.py +4 -5
  104. claude_mpm/core/typing_utils.py +50 -59
  105. claude_mpm/core/unified_agent_registry.py +14 -19
  106. claude_mpm/core/unified_config.py +4 -6
  107. claude_mpm/core/unified_paths.py +197 -109
  108. claude_mpm/dashboard/open_dashboard.py +2 -4
  109. claude_mpm/experimental/cli_enhancements.py +51 -36
  110. claude_mpm/generators/agent_profile_generator.py +2 -4
  111. claude_mpm/hooks/base_hook.py +1 -2
  112. claude_mpm/hooks/claude_hooks/connection_pool.py +72 -26
  113. claude_mpm/hooks/claude_hooks/event_handlers.py +99 -154
  114. claude_mpm/hooks/claude_hooks/hook_handler.py +110 -720
  115. claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +104 -77
  116. claude_mpm/hooks/claude_hooks/hook_handler_original.py +1040 -0
  117. claude_mpm/hooks/claude_hooks/hook_handler_refactored.py +347 -0
  118. claude_mpm/hooks/claude_hooks/memory_integration.py +2 -4
  119. claude_mpm/hooks/claude_hooks/response_tracking.py +15 -11
  120. claude_mpm/hooks/claude_hooks/services/__init__.py +13 -0
  121. claude_mpm/hooks/claude_hooks/services/connection_manager.py +190 -0
  122. claude_mpm/hooks/claude_hooks/services/duplicate_detector.py +106 -0
  123. claude_mpm/hooks/claude_hooks/services/state_manager.py +282 -0
  124. claude_mpm/hooks/claude_hooks/services/subagent_processor.py +374 -0
  125. claude_mpm/hooks/claude_hooks/tool_analysis.py +12 -18
  126. claude_mpm/hooks/memory_integration_hook.py +5 -5
  127. claude_mpm/hooks/tool_call_interceptor.py +1 -1
  128. claude_mpm/hooks/validation_hooks.py +4 -4
  129. claude_mpm/init.py +4 -9
  130. claude_mpm/models/__init__.py +2 -2
  131. claude_mpm/models/agent_session.py +11 -14
  132. claude_mpm/scripts/mcp_server.py +20 -11
  133. claude_mpm/scripts/mcp_wrapper.py +5 -5
  134. claude_mpm/scripts/mpm_doctor.py +321 -0
  135. claude_mpm/scripts/socketio_daemon.py +28 -25
  136. claude_mpm/scripts/socketio_daemon_hardened.py +298 -258
  137. claude_mpm/scripts/socketio_server_manager.py +116 -95
  138. claude_mpm/services/__init__.py +49 -49
  139. claude_mpm/services/agent_capabilities_service.py +12 -18
  140. claude_mpm/services/agents/__init__.py +22 -22
  141. claude_mpm/services/agents/agent_builder.py +140 -119
  142. claude_mpm/services/agents/deployment/__init__.py +3 -3
  143. claude_mpm/services/agents/deployment/agent_config_provider.py +9 -9
  144. claude_mpm/services/agents/deployment/agent_configuration_manager.py +19 -20
  145. claude_mpm/services/agents/deployment/agent_definition_factory.py +1 -5
  146. claude_mpm/services/agents/deployment/agent_deployment.py +129 -511
  147. claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -8
  148. claude_mpm/services/agents/deployment/agent_environment_manager.py +2 -7
  149. claude_mpm/services/agents/deployment/agent_filesystem_manager.py +6 -10
  150. claude_mpm/services/agents/deployment/agent_format_converter.py +11 -15
  151. claude_mpm/services/agents/deployment/agent_frontmatter_validator.py +2 -3
  152. claude_mpm/services/agents/deployment/agent_lifecycle_manager.py +5 -5
  153. claude_mpm/services/agents/deployment/agent_metrics_collector.py +13 -19
  154. claude_mpm/services/agents/deployment/agent_restore_handler.py +0 -1
  155. claude_mpm/services/agents/deployment/agent_template_builder.py +26 -35
  156. claude_mpm/services/agents/deployment/agent_validator.py +0 -1
  157. claude_mpm/services/agents/deployment/agent_version_manager.py +7 -9
  158. claude_mpm/services/agents/deployment/agent_versioning.py +3 -3
  159. claude_mpm/services/agents/deployment/agents_directory_resolver.py +6 -7
  160. claude_mpm/services/agents/deployment/async_agent_deployment.py +51 -38
  161. claude_mpm/services/agents/deployment/base_agent_locator.py +132 -0
  162. claude_mpm/services/agents/deployment/config/__init__.py +1 -1
  163. claude_mpm/services/agents/deployment/config/deployment_config.py +7 -8
  164. claude_mpm/services/agents/deployment/deployment_results_manager.py +185 -0
  165. claude_mpm/services/agents/deployment/deployment_type_detector.py +1 -1
  166. claude_mpm/services/agents/deployment/deployment_wrapper.py +18 -18
  167. claude_mpm/services/agents/deployment/facade/__init__.py +1 -1
  168. claude_mpm/services/agents/deployment/facade/deployment_executor.py +0 -3
  169. claude_mpm/services/agents/deployment/facade/deployment_facade.py +3 -4
  170. claude_mpm/services/agents/deployment/interface_adapter.py +5 -7
  171. claude_mpm/services/agents/deployment/multi_source_deployment_service.py +345 -276
  172. claude_mpm/services/agents/deployment/pipeline/__init__.py +2 -2
  173. claude_mpm/services/agents/deployment/pipeline/pipeline_builder.py +1 -1
  174. claude_mpm/services/agents/deployment/pipeline/pipeline_context.py +6 -4
  175. claude_mpm/services/agents/deployment/pipeline/pipeline_executor.py +3 -3
  176. claude_mpm/services/agents/deployment/pipeline/steps/__init__.py +2 -2
  177. claude_mpm/services/agents/deployment/pipeline/steps/agent_processing_step.py +14 -13
  178. claude_mpm/services/agents/deployment/pipeline/steps/base_step.py +0 -1
  179. claude_mpm/services/agents/deployment/pipeline/steps/configuration_step.py +1 -1
  180. claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +8 -9
  181. claude_mpm/services/agents/deployment/pipeline/steps/validation_step.py +1 -1
  182. claude_mpm/services/agents/deployment/processors/__init__.py +1 -1
  183. claude_mpm/services/agents/deployment/processors/agent_processor.py +20 -16
  184. claude_mpm/services/agents/deployment/refactored_agent_deployment_service.py +5 -12
  185. claude_mpm/services/agents/deployment/results/__init__.py +1 -1
  186. claude_mpm/services/agents/deployment/results/deployment_result_builder.py +1 -1
  187. claude_mpm/services/agents/deployment/single_agent_deployer.py +315 -0
  188. claude_mpm/services/agents/deployment/strategies/__init__.py +2 -2
  189. claude_mpm/services/agents/deployment/strategies/base_strategy.py +1 -7
  190. claude_mpm/services/agents/deployment/strategies/project_strategy.py +1 -4
  191. claude_mpm/services/agents/deployment/strategies/system_strategy.py +2 -3
  192. claude_mpm/services/agents/deployment/strategies/user_strategy.py +3 -7
  193. claude_mpm/services/agents/deployment/validation/__init__.py +1 -1
  194. claude_mpm/services/agents/deployment/validation/agent_validator.py +1 -1
  195. claude_mpm/services/agents/deployment/validation/template_validator.py +2 -2
  196. claude_mpm/services/agents/deployment/validation/validation_result.py +2 -6
  197. claude_mpm/services/agents/loading/__init__.py +1 -1
  198. claude_mpm/services/agents/loading/agent_profile_loader.py +6 -12
  199. claude_mpm/services/agents/loading/base_agent_manager.py +5 -5
  200. claude_mpm/services/agents/loading/framework_agent_loader.py +2 -4
  201. claude_mpm/services/agents/management/__init__.py +1 -1
  202. claude_mpm/services/agents/management/agent_capabilities_generator.py +1 -3
  203. claude_mpm/services/agents/management/agent_management_service.py +5 -9
  204. claude_mpm/services/agents/memory/__init__.py +4 -4
  205. claude_mpm/services/agents/memory/agent_memory_manager.py +157 -503
  206. claude_mpm/services/agents/memory/agent_persistence_service.py +0 -2
  207. claude_mpm/services/agents/memory/content_manager.py +44 -38
  208. claude_mpm/services/agents/memory/memory_categorization_service.py +165 -0
  209. claude_mpm/services/agents/memory/memory_file_service.py +103 -0
  210. claude_mpm/services/agents/memory/memory_format_service.py +201 -0
  211. claude_mpm/services/agents/memory/memory_limits_service.py +99 -0
  212. claude_mpm/services/agents/memory/template_generator.py +4 -6
  213. claude_mpm/services/agents/registry/__init__.py +11 -7
  214. claude_mpm/services/agents/registry/deployed_agent_discovery.py +30 -27
  215. claude_mpm/services/agents/registry/modification_tracker.py +3 -6
  216. claude_mpm/services/async_session_logger.py +1 -2
  217. claude_mpm/services/claude_session_logger.py +1 -2
  218. claude_mpm/services/cli/__init__.py +18 -0
  219. claude_mpm/services/cli/agent_cleanup_service.py +407 -0
  220. claude_mpm/services/cli/agent_dependency_service.py +395 -0
  221. claude_mpm/services/cli/agent_listing_service.py +463 -0
  222. claude_mpm/services/cli/agent_output_formatter.py +605 -0
  223. claude_mpm/services/cli/agent_validation_service.py +589 -0
  224. claude_mpm/services/cli/dashboard_launcher.py +424 -0
  225. claude_mpm/services/cli/memory_crud_service.py +617 -0
  226. claude_mpm/services/cli/memory_output_formatter.py +604 -0
  227. claude_mpm/services/cli/session_manager.py +513 -0
  228. claude_mpm/services/cli/socketio_manager.py +498 -0
  229. claude_mpm/services/cli/startup_checker.py +370 -0
  230. claude_mpm/services/command_deployment_service.py +173 -0
  231. claude_mpm/services/command_handler_service.py +20 -22
  232. claude_mpm/services/core/__init__.py +25 -25
  233. claude_mpm/services/core/base.py +0 -5
  234. claude_mpm/services/core/cache_manager.py +311 -0
  235. claude_mpm/services/core/interfaces/__init__.py +32 -32
  236. claude_mpm/services/core/interfaces/agent.py +0 -21
  237. claude_mpm/services/core/interfaces/communication.py +0 -27
  238. claude_mpm/services/core/interfaces/infrastructure.py +0 -56
  239. claude_mpm/services/core/interfaces/service.py +0 -29
  240. claude_mpm/services/core/memory_manager.py +637 -0
  241. claude_mpm/services/core/path_resolver.py +498 -0
  242. claude_mpm/services/core/service_container.py +520 -0
  243. claude_mpm/services/core/service_interfaces.py +436 -0
  244. claude_mpm/services/diagnostics/__init__.py +1 -1
  245. claude_mpm/services/diagnostics/checks/__init__.py +6 -6
  246. claude_mpm/services/diagnostics/checks/agent_check.py +152 -97
  247. claude_mpm/services/diagnostics/checks/base_check.py +12 -16
  248. claude_mpm/services/diagnostics/checks/claude_desktop_check.py +84 -81
  249. claude_mpm/services/diagnostics/checks/common_issues_check.py +99 -91
  250. claude_mpm/services/diagnostics/checks/configuration_check.py +82 -77
  251. claude_mpm/services/diagnostics/checks/filesystem_check.py +67 -68
  252. claude_mpm/services/diagnostics/checks/installation_check.py +254 -94
  253. claude_mpm/services/diagnostics/checks/mcp_check.py +90 -88
  254. claude_mpm/services/diagnostics/checks/monitor_check.py +75 -76
  255. claude_mpm/services/diagnostics/checks/startup_log_check.py +67 -73
  256. claude_mpm/services/diagnostics/diagnostic_runner.py +67 -59
  257. claude_mpm/services/diagnostics/doctor_reporter.py +107 -70
  258. claude_mpm/services/diagnostics/models.py +21 -19
  259. claude_mpm/services/event_aggregator.py +10 -17
  260. claude_mpm/services/event_bus/__init__.py +1 -1
  261. claude_mpm/services/event_bus/config.py +54 -35
  262. claude_mpm/services/event_bus/event_bus.py +76 -71
  263. claude_mpm/services/event_bus/relay.py +74 -64
  264. claude_mpm/services/events/__init__.py +11 -11
  265. claude_mpm/services/events/consumers/__init__.py +3 -3
  266. claude_mpm/services/events/consumers/dead_letter.py +71 -63
  267. claude_mpm/services/events/consumers/logging.py +39 -37
  268. claude_mpm/services/events/consumers/metrics.py +56 -57
  269. claude_mpm/services/events/consumers/socketio.py +82 -81
  270. claude_mpm/services/events/core.py +110 -99
  271. claude_mpm/services/events/interfaces.py +56 -72
  272. claude_mpm/services/events/producers/__init__.py +1 -1
  273. claude_mpm/services/events/producers/hook.py +38 -38
  274. claude_mpm/services/events/producers/system.py +46 -44
  275. claude_mpm/services/exceptions.py +81 -80
  276. claude_mpm/services/framework_claude_md_generator/__init__.py +2 -4
  277. claude_mpm/services/framework_claude_md_generator/content_assembler.py +3 -5
  278. claude_mpm/services/framework_claude_md_generator/content_validator.py +1 -1
  279. claude_mpm/services/framework_claude_md_generator/deployment_manager.py +4 -4
  280. claude_mpm/services/framework_claude_md_generator/section_generators/__init__.py +0 -1
  281. claude_mpm/services/framework_claude_md_generator/section_generators/agents.py +0 -2
  282. claude_mpm/services/framework_claude_md_generator/version_manager.py +4 -5
  283. claude_mpm/services/hook_service.py +6 -9
  284. claude_mpm/services/infrastructure/__init__.py +1 -1
  285. claude_mpm/services/infrastructure/context_preservation.py +8 -12
  286. claude_mpm/services/infrastructure/monitoring.py +21 -23
  287. claude_mpm/services/mcp_gateway/__init__.py +37 -37
  288. claude_mpm/services/mcp_gateway/auto_configure.py +95 -103
  289. claude_mpm/services/mcp_gateway/config/__init__.py +1 -1
  290. claude_mpm/services/mcp_gateway/config/config_loader.py +23 -25
  291. claude_mpm/services/mcp_gateway/config/config_schema.py +5 -5
  292. claude_mpm/services/mcp_gateway/config/configuration.py +9 -6
  293. claude_mpm/services/mcp_gateway/core/__init__.py +10 -10
  294. claude_mpm/services/mcp_gateway/core/base.py +0 -3
  295. claude_mpm/services/mcp_gateway/core/interfaces.py +1 -38
  296. claude_mpm/services/mcp_gateway/core/process_pool.py +99 -93
  297. claude_mpm/services/mcp_gateway/core/singleton_manager.py +65 -62
  298. claude_mpm/services/mcp_gateway/core/startup_verification.py +75 -74
  299. claude_mpm/services/mcp_gateway/main.py +2 -1
  300. claude_mpm/services/mcp_gateway/registry/service_registry.py +5 -8
  301. claude_mpm/services/mcp_gateway/registry/tool_registry.py +1 -1
  302. claude_mpm/services/mcp_gateway/server/__init__.py +1 -1
  303. claude_mpm/services/mcp_gateway/server/mcp_gateway.py +12 -19
  304. claude_mpm/services/mcp_gateway/server/stdio_handler.py +4 -3
  305. claude_mpm/services/mcp_gateway/server/stdio_server.py +79 -71
  306. claude_mpm/services/mcp_gateway/tools/__init__.py +2 -2
  307. claude_mpm/services/mcp_gateway/tools/base_adapter.py +5 -6
  308. claude_mpm/services/mcp_gateway/tools/document_summarizer.py +13 -22
  309. claude_mpm/services/mcp_gateway/tools/health_check_tool.py +79 -78
  310. claude_mpm/services/mcp_gateway/tools/hello_world.py +12 -14
  311. claude_mpm/services/mcp_gateway/tools/ticket_tools.py +42 -49
  312. claude_mpm/services/mcp_gateway/tools/unified_ticket_tool.py +51 -55
  313. claude_mpm/services/memory/__init__.py +3 -3
  314. claude_mpm/services/memory/builder.py +3 -6
  315. claude_mpm/services/memory/cache/__init__.py +1 -1
  316. claude_mpm/services/memory/cache/shared_prompt_cache.py +3 -5
  317. claude_mpm/services/memory/cache/simple_cache.py +1 -1
  318. claude_mpm/services/memory/indexed_memory.py +5 -7
  319. claude_mpm/services/memory/optimizer.py +7 -10
  320. claude_mpm/services/memory/router.py +8 -9
  321. claude_mpm/services/memory_hook_service.py +48 -34
  322. claude_mpm/services/monitor_build_service.py +77 -73
  323. claude_mpm/services/port_manager.py +130 -108
  324. claude_mpm/services/project/analyzer.py +12 -10
  325. claude_mpm/services/project/registry.py +11 -11
  326. claude_mpm/services/recovery_manager.py +10 -19
  327. claude_mpm/services/response_tracker.py +0 -1
  328. claude_mpm/services/runner_configuration_service.py +19 -20
  329. claude_mpm/services/session_management_service.py +7 -11
  330. claude_mpm/services/shared/__init__.py +1 -1
  331. claude_mpm/services/shared/async_service_base.py +58 -50
  332. claude_mpm/services/shared/config_service_base.py +73 -67
  333. claude_mpm/services/shared/lifecycle_service_base.py +82 -78
  334. claude_mpm/services/shared/manager_base.py +94 -82
  335. claude_mpm/services/shared/service_factory.py +96 -98
  336. claude_mpm/services/socketio/__init__.py +3 -3
  337. claude_mpm/services/socketio/client_proxy.py +5 -5
  338. claude_mpm/services/socketio/event_normalizer.py +199 -181
  339. claude_mpm/services/socketio/handlers/__init__.py +3 -3
  340. claude_mpm/services/socketio/handlers/base.py +5 -4
  341. claude_mpm/services/socketio/handlers/connection.py +163 -136
  342. claude_mpm/services/socketio/handlers/file.py +13 -14
  343. claude_mpm/services/socketio/handlers/git.py +12 -7
  344. claude_mpm/services/socketio/handlers/hook.py +49 -44
  345. claude_mpm/services/socketio/handlers/memory.py +0 -1
  346. claude_mpm/services/socketio/handlers/project.py +0 -1
  347. claude_mpm/services/socketio/handlers/registry.py +37 -19
  348. claude_mpm/services/socketio/migration_utils.py +98 -84
  349. claude_mpm/services/socketio/server/__init__.py +1 -1
  350. claude_mpm/services/socketio/server/broadcaster.py +81 -87
  351. claude_mpm/services/socketio/server/core.py +65 -54
  352. claude_mpm/services/socketio/server/eventbus_integration.py +95 -56
  353. claude_mpm/services/socketio/server/main.py +64 -38
  354. claude_mpm/services/socketio_client_manager.py +10 -12
  355. claude_mpm/services/subprocess_launcher_service.py +4 -7
  356. claude_mpm/services/system_instructions_service.py +13 -14
  357. claude_mpm/services/ticket_manager.py +2 -2
  358. claude_mpm/services/utility_service.py +5 -13
  359. claude_mpm/services/version_control/__init__.py +16 -16
  360. claude_mpm/services/version_control/branch_strategy.py +5 -8
  361. claude_mpm/services/version_control/conflict_resolution.py +9 -23
  362. claude_mpm/services/version_control/git_operations.py +5 -7
  363. claude_mpm/services/version_control/semantic_versioning.py +16 -17
  364. claude_mpm/services/version_control/version_parser.py +13 -18
  365. claude_mpm/services/version_service.py +10 -11
  366. claude_mpm/storage/__init__.py +1 -1
  367. claude_mpm/storage/state_storage.py +22 -28
  368. claude_mpm/utils/__init__.py +6 -6
  369. claude_mpm/utils/agent_dependency_loader.py +47 -33
  370. claude_mpm/utils/config_manager.py +11 -14
  371. claude_mpm/utils/dependency_cache.py +1 -1
  372. claude_mpm/utils/dependency_manager.py +13 -17
  373. claude_mpm/utils/dependency_strategies.py +8 -10
  374. claude_mpm/utils/environment_context.py +3 -9
  375. claude_mpm/utils/error_handler.py +3 -13
  376. claude_mpm/utils/file_utils.py +1 -1
  377. claude_mpm/utils/path_operations.py +8 -12
  378. claude_mpm/utils/robust_installer.py +110 -33
  379. claude_mpm/utils/subprocess_utils.py +5 -6
  380. claude_mpm/validation/agent_validator.py +3 -6
  381. claude_mpm/validation/frontmatter_validator.py +1 -1
  382. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/METADATA +1 -1
  383. claude_mpm-4.1.3.dist-info/RECORD +528 -0
  384. claude_mpm/cli/commands/run_config_checker.py +0 -160
  385. claude_mpm-4.1.1.dist-info/RECORD +0 -494
  386. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/WHEEL +0 -0
  387. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/entry_points.txt +0 -0
  388. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/licenses/LICENSE +0 -0
  389. {claude_mpm-4.1.1.dist-info → claude_mpm-4.1.3.dist-info}/top_level.txt +0 -0
@@ -27,24 +27,15 @@ ROLLBACK PROCEDURES:
27
27
  - Version tracking allows targeted rollbacks
28
28
  """
29
29
 
30
- import logging
31
- import os
32
- import shutil
33
30
  import time
34
31
  from pathlib import Path
35
32
  from typing import Any, Dict, List, Optional, Tuple
36
33
 
37
34
  from claude_mpm.config.paths import paths
38
- from claude_mpm.constants import AgentMetadata, EnvironmentVars, Paths
35
+ from claude_mpm.constants import Paths
39
36
  from claude_mpm.core.config import Config
40
- from claude_mpm.core.constants import ResourceLimits, SystemLimits, TimeoutConfig
41
37
  from claude_mpm.core.exceptions import AgentDeploymentError
42
38
  from claude_mpm.core.interfaces import AgentDeploymentInterface
43
- from claude_mpm.core.logging_config import (
44
- get_logger,
45
- log_operation,
46
- log_performance_context,
47
- )
48
39
  from claude_mpm.services.shared import ConfigServiceBase
49
40
 
50
41
  from .agent_configuration_manager import AgentConfigurationManager
@@ -56,7 +47,10 @@ from .agent_metrics_collector import AgentMetricsCollector
56
47
  from .agent_template_builder import AgentTemplateBuilder
57
48
  from .agent_validator import AgentValidator
58
49
  from .agent_version_manager import AgentVersionManager
50
+ from .base_agent_locator import BaseAgentLocator
51
+ from .deployment_results_manager import DeploymentResultsManager
59
52
  from .multi_source_deployment_service import MultiSourceAgentDeploymentService
53
+ from .single_agent_deployer import SingleAgentDeployer
60
54
 
61
55
 
62
56
  class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
@@ -129,26 +123,29 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
129
123
  # Initialize validator service
130
124
  self.validator = AgentValidator()
131
125
 
126
+ # Initialize base agent locator service
127
+ self.base_agent_locator = BaseAgentLocator(self.logger)
128
+
129
+ # Initialize deployment results manager
130
+ self.results_manager = DeploymentResultsManager(self.logger)
131
+
132
+ # Initialize single agent deployer
133
+ self.single_agent_deployer = SingleAgentDeployer(
134
+ self.template_builder,
135
+ self.version_manager,
136
+ self.results_manager,
137
+ self.logger,
138
+ )
139
+
132
140
  # Initialize filesystem manager service
133
141
  self.filesystem_manager = AgentFileSystemManager()
134
142
 
135
- # Initialize deployment metrics tracking
136
- self._deployment_metrics = {
137
- "total_deployments": 0,
138
- "successful_deployments": 0,
139
- "failed_deployments": 0,
140
- "migrations_performed": 0,
141
- "version_migration_count": 0,
142
- "agent_type_counts": {},
143
- "deployment_errors": {},
144
- }
145
-
146
143
  # Determine the actual working directory using configuration
147
144
  # Priority: param > config > environment > current directory
148
145
  self.working_directory = self.get_config_value(
149
146
  "working_directory",
150
147
  default=working_directory or Path.cwd(),
151
- config_type=Path
148
+ config_type=Path,
152
149
  )
153
150
  self.logger.info(f"Working directory for deployment: {self.working_directory}")
154
151
 
@@ -157,25 +154,29 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
157
154
  self.templates_dir = self.get_config_value(
158
155
  "templates_dir",
159
156
  default=templates_dir or paths.agents_dir / "templates",
160
- config_type=Path
157
+ config_type=Path,
161
158
  )
162
159
 
163
160
  # Initialize discovery service (after templates_dir is set)
164
161
  self.discovery_service = AgentDiscoveryService(self.templates_dir)
165
-
162
+
166
163
  # Initialize multi-source deployment service for version comparison
167
164
  self.multi_source_service = MultiSourceAgentDeploymentService()
168
165
 
169
166
  # Find base agent file using configuration
170
167
  # Priority: param > config > search
171
- configured_base_agent = self.get_config_value("base_agent_path", config_type=Path)
168
+ configured_base_agent = self.get_config_value(
169
+ "base_agent_path", config_type=Path
170
+ )
172
171
  if base_agent_path:
173
172
  self.base_agent_path = Path(base_agent_path)
174
173
  elif configured_base_agent:
175
174
  self.base_agent_path = configured_base_agent
176
175
  else:
177
176
  # Priority-based search for base_agent.json
178
- self.base_agent_path = self._find_base_agent_file()
177
+ self.base_agent_path = self.base_agent_locator.find_base_agent_file(
178
+ paths.agents_dir
179
+ )
179
180
 
180
181
  # Initialize configuration manager (after base_agent_path is set)
181
182
  self.configuration_manager = AgentConfigurationManager(self.base_agent_path)
@@ -185,68 +186,6 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
185
186
 
186
187
  self.logger.info(f"Templates directory: {self.templates_dir}")
187
188
  self.logger.info(f"Base agent path: {self.base_agent_path}")
188
-
189
- def _find_base_agent_file(self) -> Path:
190
- """Find base agent file with priority-based search.
191
-
192
- Priority order:
193
- 1. Environment variable override (CLAUDE_MPM_BASE_AGENT_PATH)
194
- 2. Current working directory (for local development)
195
- 3. Known development locations
196
- 4. User override location (~/.claude/agents/)
197
- 5. Framework agents directory (from paths)
198
- """
199
- # Priority 0: Check environment variable override
200
- env_path = os.environ.get("CLAUDE_MPM_BASE_AGENT_PATH")
201
- if env_path:
202
- env_base_agent = Path(env_path)
203
- if env_base_agent.exists():
204
- self.logger.info(f"Using environment variable base_agent: {env_base_agent}")
205
- return env_base_agent
206
- else:
207
- self.logger.warning(f"CLAUDE_MPM_BASE_AGENT_PATH set but file doesn't exist: {env_base_agent}")
208
-
209
- # Priority 1: Check current working directory for local development
210
- cwd = Path.cwd()
211
- cwd_base_agent = cwd / "src" / "claude_mpm" / "agents" / "base_agent.json"
212
- if cwd_base_agent.exists():
213
- self.logger.info(f"Using local development base_agent from cwd: {cwd_base_agent}")
214
- return cwd_base_agent
215
-
216
- # Priority 2: Check known development locations
217
- known_dev_paths = [
218
- Path("/Users/masa/Projects/claude-mpm/src/claude_mpm/agents/base_agent.json"),
219
- Path.home() / "Projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
220
- Path.home() / "projects" / "claude-mpm" / "src" / "claude_mpm" / "agents" / "base_agent.json",
221
- ]
222
-
223
- for dev_path in known_dev_paths:
224
- if dev_path.exists():
225
- self.logger.info(f"Using development base_agent: {dev_path}")
226
- return dev_path
227
-
228
- # Priority 3: Check user override location
229
- user_base_agent = Path.home() / ".claude" / "agents" / "base_agent.json"
230
- if user_base_agent.exists():
231
- self.logger.info(f"Using user override base_agent: {user_base_agent}")
232
- return user_base_agent
233
-
234
- # Priority 4: Use framework agents directory (fallback)
235
- framework_base_agent = paths.agents_dir / "base_agent.json"
236
- if framework_base_agent.exists():
237
- self.logger.info(f"Using framework base_agent: {framework_base_agent}")
238
- return framework_base_agent
239
-
240
- # If still not found, log all searched locations and raise error
241
- self.logger.error("Base agent file not found in any location:")
242
- self.logger.error(f" 1. CWD: {cwd_base_agent}")
243
- self.logger.error(f" 2. Dev paths: {known_dev_paths}")
244
- self.logger.error(f" 3. User: {user_base_agent}")
245
- self.logger.error(f" 4. Framework: {framework_base_agent}")
246
-
247
- # Final fallback to framework path even if it doesn't exist
248
- # (will fail later with better error message)
249
- return framework_base_agent
250
189
 
251
190
  def deploy_agents(
252
191
  self,
@@ -349,7 +288,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
349
288
  agents_dir = self._determine_agents_directory(target_dir)
350
289
 
351
290
  # Initialize results dictionary
352
- results = self._initialize_deployment_results(agents_dir, deployment_start_time)
291
+ results = self.results_manager.initialize_deployment_results(
292
+ agents_dir, deployment_start_time
293
+ )
353
294
 
354
295
  try:
355
296
  # Create agents directory if needed
@@ -359,7 +300,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
359
300
  self._repair_existing_agents(agents_dir, results)
360
301
 
361
302
  # Log deployment source tier
362
- source_tier = self._determine_source_tier()
303
+ source_tier = self.base_agent_locator.determine_source_tier(
304
+ self.templates_dir
305
+ )
363
306
  self.logger.info(
364
307
  f"Building and deploying {source_tier} agents to: {agents_dir}"
365
308
  )
@@ -382,17 +325,19 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
382
325
 
383
326
  # Check if we should use multi-source deployment
384
327
  use_multi_source = self._should_use_multi_source_deployment(deployment_mode)
385
-
328
+
386
329
  if use_multi_source:
387
330
  # Use multi-source deployment to get highest version agents
388
- template_files, agent_sources, cleanup_results = self._get_multi_source_templates(
389
- excluded_agents, config, agents_dir, force_rebuild
331
+ template_files, agent_sources, cleanup_results = (
332
+ self._get_multi_source_templates(
333
+ excluded_agents, config, agents_dir, force_rebuild
334
+ )
390
335
  )
391
336
  results["total"] = len(template_files)
392
337
  results["multi_source"] = True
393
338
  results["agent_sources"] = agent_sources
394
339
  results["cleanup"] = cleanup_results
395
-
340
+
396
341
  # Log cleanup results if any agents were removed
397
342
  if cleanup_results.get("removed"):
398
343
  self.logger.info(
@@ -410,13 +355,21 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
410
355
 
411
356
  # Deploy each agent template
412
357
  for template_file in template_files:
413
- template_file_path = template_file if isinstance(template_file, Path) else Path(template_file)
358
+ template_file_path = (
359
+ template_file
360
+ if isinstance(template_file, Path)
361
+ else Path(template_file)
362
+ )
414
363
  agent_name = template_file_path.stem
415
-
364
+
416
365
  # Get source info for this agent (agent_sources now uses file stems as keys)
417
- source_info = agent_sources.get(agent_name, "unknown") if agent_sources else "single"
418
-
419
- self._deploy_single_agent(
366
+ source_info = (
367
+ agent_sources.get(agent_name, "unknown")
368
+ if agent_sources
369
+ else "single"
370
+ )
371
+
372
+ self.single_agent_deployer.deploy_single_agent(
420
373
  template_file=template_file_path,
421
374
  agents_dir=agents_dir,
422
375
  base_agent_data=base_agent_data,
@@ -455,31 +408,24 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
455
408
  results["errors"].append(error_msg)
456
409
 
457
410
  # METRICS: Track deployment failure
458
- self._deployment_metrics["failed_deployments"] += 1
459
- error_type = type(e).__name__
460
- self._deployment_metrics["deployment_errors"][error_type] = (
461
- self._deployment_metrics["deployment_errors"].get(error_type, 0) + 1
462
- )
411
+ self.results_manager.update_deployment_metrics(False, type(e).__name__)
463
412
 
464
413
  # METRICS: Calculate final deployment metrics
465
- deployment_end_time = time.time()
466
- deployment_duration = (deployment_end_time - deployment_start_time) * 1000 # ms
467
-
468
- results["metrics"]["end_time"] = deployment_end_time
469
- results["metrics"]["duration_ms"] = deployment_duration
414
+ self.results_manager.finalize_results(results, deployment_start_time)
470
415
 
471
416
  # METRICS: Update rolling averages and statistics
417
+ deployment_duration = results["metrics"].get("duration_ms", 0)
472
418
  self.metrics_collector.update_deployment_metrics(deployment_duration, results)
473
419
 
474
420
  return results
475
421
 
476
422
  def get_deployment_metrics(self) -> Dict[str, Any]:
477
423
  """Get current deployment metrics."""
478
- return self.metrics_collector.get_deployment_metrics()
424
+ return self.results_manager.get_deployment_metrics()
479
425
 
480
426
  def reset_metrics(self) -> None:
481
427
  """Reset deployment metrics."""
482
- return self.metrics_collector.reset_metrics()
428
+ return self.results_manager.reset_metrics()
483
429
 
484
430
  def set_claude_environment(
485
431
  self, config_dir: Optional[Path] = None
@@ -520,75 +466,15 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
520
466
  - Properly loads base_agent_data before building agent content
521
467
  """
522
468
  try:
523
- # Find the template file
524
- template_file = self.templates_dir / f"{agent_name}.json"
525
- if not template_file.exists():
526
- self.logger.error(f"Agent template not found: {agent_name}")
527
- return False
528
-
529
- # Ensure target directory exists
530
- # target_dir should already be the agents directory
531
- target_dir.mkdir(parents=True, exist_ok=True)
532
-
533
- # Build and deploy the agent
534
- target_file = target_dir / f"{agent_name}.md"
535
-
536
- # Check if update is needed
537
- if not force_rebuild and target_file.exists():
538
- # Load base agent data for version checking
539
- base_agent_data = {}
540
- base_agent_version = (0, 0, 0)
541
- if self.base_agent_path.exists():
542
- try:
543
- import json
544
-
545
- base_agent_data = json.loads(self.base_agent_path.read_text())
546
- base_agent_version = self.version_manager.parse_version(
547
- base_agent_data.get("base_version")
548
- or base_agent_data.get("version", 0)
549
- )
550
- except Exception as e:
551
- self.logger.warning(
552
- f"Could not load base agent for version check: {e}"
553
- )
554
-
555
- needs_update, reason = self.version_manager.check_agent_needs_update(
556
- target_file, template_file, base_agent_version
557
- )
558
- if not needs_update:
559
- self.logger.info(f"Agent {agent_name} is up to date")
560
- return True
561
- else:
562
- self.logger.info(f"Updating agent {agent_name}: {reason}")
563
-
564
- # Load base agent data for building
565
- base_agent_data = {}
566
- if self.base_agent_path.exists():
567
- try:
568
- import json
569
-
570
- base_agent_data = json.loads(self.base_agent_path.read_text())
571
- except Exception as e:
572
- self.logger.warning(f"Could not load base agent: {e}")
573
-
574
- # Build the agent markdown
575
- # For single agent deployment, determine source from template location
576
- source_info = self._determine_agent_source(template_file)
577
- agent_content = self.template_builder.build_agent_markdown(
578
- agent_name, template_file, base_agent_data, source_info
579
- )
580
- if not agent_content:
581
- self.logger.error(f"Failed to build agent content for {agent_name}")
582
- return False
583
-
584
- # Write to target file
585
- target_file.write_text(agent_content)
586
- self.logger.info(
587
- f"Successfully deployed agent: {agent_name} to {target_file}"
469
+ return self.single_agent_deployer.deploy_agent(
470
+ agent_name,
471
+ self.templates_dir,
472
+ target_dir,
473
+ self.base_agent_path,
474
+ force_rebuild,
475
+ self.working_directory,
588
476
  )
589
477
 
590
- return True
591
-
592
478
  except AgentDeploymentError:
593
479
  # Re-raise our custom exceptions
594
480
  raise
@@ -628,25 +514,23 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
628
514
  from .system_instructions_deployer import SystemInstructionsDeployer
629
515
 
630
516
  deployer = SystemInstructionsDeployer(self.logger, self.working_directory)
631
- deployer.deploy_system_instructions(
632
- target_dir, force_rebuild, results
633
- )
517
+ deployer.deploy_system_instructions(target_dir, force_rebuild, results)
634
518
 
635
519
  def deploy_system_instructions_explicit(
636
520
  self, target_dir: Optional[Path] = None, force_rebuild: bool = False
637
521
  ) -> Dict[str, Any]:
638
522
  """
639
523
  Explicitly deploy system instructions when requested by user.
640
-
524
+
641
525
  This method should ONLY be called when the user explicitly requests
642
526
  deployment of system instructions through agent-manager commands.
643
527
  It will deploy INSTRUCTIONS.md, MEMORY.md, and WORKFLOW.md to .claude/
644
528
  directory in the project.
645
-
529
+
646
530
  Args:
647
531
  target_dir: Target directory for deployment (ignored - always uses .claude/)
648
532
  force_rebuild: Force rebuild even if files exist
649
-
533
+
650
534
  Returns:
651
535
  Dict with deployment results
652
536
  """
@@ -656,35 +540,34 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
656
540
  "skipped": [],
657
541
  "errors": [],
658
542
  }
659
-
543
+
660
544
  try:
661
545
  # Always use project's .claude directory
662
546
  target_dir = self.working_directory / ".claude"
663
-
547
+
664
548
  # Ensure directory exists
665
549
  target_dir.mkdir(parents=True, exist_ok=True)
666
-
550
+
667
551
  # Deploy using the deployer (targeting .claude/)
668
552
  from .system_instructions_deployer import SystemInstructionsDeployer
553
+
669
554
  deployer = SystemInstructionsDeployer(self.logger, self.working_directory)
670
-
555
+
671
556
  # Deploy to .claude directory
672
- deployer.deploy_system_instructions(
673
- target_dir, force_rebuild, results
674
- )
675
-
557
+ deployer.deploy_system_instructions(target_dir, force_rebuild, results)
558
+
676
559
  self.logger.info(
677
560
  f"Explicitly deployed system instructions to {target_dir}: "
678
561
  f"deployed={len(results['deployed'])}, "
679
562
  f"updated={len(results['updated'])}, "
680
563
  f"skipped={len(results['skipped'])}"
681
564
  )
682
-
565
+
683
566
  except Exception as e:
684
567
  error_msg = f"Failed to deploy system instructions: {e}"
685
568
  self.logger.error(error_msg)
686
569
  results["errors"].append(error_msg)
687
-
570
+
688
571
  return results
689
572
 
690
573
  def _convert_yaml_to_md(self, target_dir: Path) -> Dict[str, Any]:
@@ -745,11 +628,9 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
745
628
  self.logger.info(f"Async deployment completed in {duration_ms:.1f}ms")
746
629
 
747
630
  # Update internal metrics
748
- self._deployment_metrics["total_deployments"] += 1
749
- if not results.get("errors"):
750
- self._deployment_metrics["successful_deployments"] += 1
751
- else:
752
- self._deployment_metrics["failed_deployments"] += 1
631
+ self.results_manager.update_deployment_metrics(
632
+ not results.get("errors")
633
+ )
753
634
 
754
635
  return results
755
636
 
@@ -774,44 +655,6 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
774
655
  resolver = AgentsDirectoryResolver(self.working_directory)
775
656
  return resolver.determine_agents_directory(target_dir)
776
657
 
777
-
778
- def _initialize_deployment_results(
779
- self, agents_dir: Path, deployment_start_time: float
780
- ) -> Dict[str, Any]:
781
- """
782
- Initialize the deployment results dictionary.
783
-
784
- WHY: Consistent result structure ensures all deployment
785
- operations return the same format for easier processing.
786
-
787
- Args:
788
- agents_dir: Target agents directory
789
- deployment_start_time: Start time for metrics
790
-
791
- Returns:
792
- Initialized results dictionary
793
- """
794
- return {
795
- "target_dir": str(agents_dir),
796
- "deployed": [],
797
- "errors": [],
798
- "skipped": [],
799
- "updated": [],
800
- "migrated": [], # Track agents migrated from old format
801
- "converted": [], # Track YAML to MD conversions
802
- "repaired": [], # Track agents with repaired frontmatter
803
- "total": 0,
804
- # METRICS: Add detailed timing and performance data to results
805
- "metrics": {
806
- "start_time": deployment_start_time,
807
- "end_time": None,
808
- "duration_ms": None,
809
- "agent_timings": {}, # Track individual agent deployment times
810
- "validation_times": {}, # Track template validation times
811
- "resource_usage": {}, # Could track memory/CPU if needed
812
- },
813
- }
814
-
815
658
  def _repair_existing_agents(
816
659
  self, agents_dir: Path, results: Dict[str, Any]
817
660
  ) -> None:
@@ -834,12 +677,6 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
834
677
  for agent_name in repair_results["repaired"]:
835
678
  self.logger.debug(f" - Repaired: {agent_name}")
836
679
 
837
- def _determine_source_tier(self) -> str:
838
- """Determine the source tier for logging."""
839
- from .deployment_type_detector import DeploymentTypeDetector
840
-
841
- return DeploymentTypeDetector.determine_source_tier(self.templates_dir)
842
-
843
680
  def _load_base_agent(self) -> tuple:
844
681
  """Load base agent content and version."""
845
682
  return self.configuration_manager.load_base_agent()
@@ -848,279 +685,51 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
848
685
  """Get and filter template files based on exclusion rules."""
849
686
  return self.discovery_service.get_filtered_templates(excluded_agents, config)
850
687
 
851
- def _deploy_single_agent(
852
- self,
853
- template_file: Path,
854
- agents_dir: Path,
855
- base_agent_data: dict,
856
- base_agent_version: tuple,
857
- force_rebuild: bool,
858
- deployment_mode: str,
859
- results: Dict[str, Any],
860
- source_info: str = "unknown",
861
- ) -> None:
862
- """
863
- Deploy a single agent template.
864
-
865
- WHY: Extracting single agent deployment logic reduces complexity
866
- and makes the main deployment loop more readable.
867
-
868
- Args:
869
- template_file: Agent template file
870
- agents_dir: Target agents directory
871
- base_agent_data: Base agent data
872
- base_agent_version: Base agent version
873
- force_rebuild: Whether to force rebuild
874
- deployment_mode: Deployment mode (update/project)
875
- results: Results dictionary to update
876
- source_info: Source of the agent (system/project/user)
877
- """
878
- try:
879
- # METRICS: Track individual agent deployment time
880
- agent_start_time = time.time()
881
-
882
- agent_name = template_file.stem
883
- target_file = agents_dir / f"{agent_name}.md"
884
-
885
- # Check if agent needs update
886
- needs_update, is_migration, reason = self._check_update_status(
887
- target_file,
888
- template_file,
889
- base_agent_version,
890
- force_rebuild,
891
- deployment_mode,
892
- )
893
-
894
- # Skip if exists and doesn't need update (only in update mode)
895
- if (
896
- target_file.exists()
897
- and not needs_update
898
- and deployment_mode != "project"
899
- ):
900
- results["skipped"].append(agent_name)
901
- self.logger.debug(f"Skipped up-to-date agent: {agent_name}")
902
- return
903
-
904
- # Build the agent file as markdown with YAML frontmatter
905
- agent_content = self.template_builder.build_agent_markdown(
906
- agent_name, template_file, base_agent_data, source_info
907
- )
908
-
909
- # Write the agent file
910
- is_update = target_file.exists()
911
- target_file.write_text(agent_content)
912
-
913
- # Record metrics and update results
914
- self._record_agent_deployment(
915
- agent_name,
916
- template_file,
917
- target_file,
918
- is_update,
919
- is_migration,
920
- reason,
921
- agent_start_time,
922
- results,
923
- )
924
-
925
- except AgentDeploymentError as e:
926
- # Re-raise our custom exceptions
927
- self.logger.error(str(e))
928
- results["errors"].append(str(e))
929
- except Exception as e:
930
- # Wrap generic exceptions with context
931
- error_msg = f"Failed to build {template_file.name}: {e}"
932
- self.logger.error(error_msg)
933
- results["errors"].append(error_msg)
934
-
935
- def _check_update_status(
936
- self,
937
- target_file: Path,
938
- template_file: Path,
939
- base_agent_version: tuple,
940
- force_rebuild: bool,
941
- deployment_mode: str,
942
- ) -> tuple:
943
- """
944
- Check if agent needs update and determine status.
945
-
946
- WHY: Centralized update checking logic ensures consistent
947
- version comparison and migration detection.
948
-
949
- Args:
950
- target_file: Target agent file
951
- template_file: Template file
952
- base_agent_version: Base agent version
953
- force_rebuild: Whether to force rebuild
954
- deployment_mode: Deployment mode
955
-
956
- Returns:
957
- Tuple of (needs_update, is_migration, reason)
958
- """
959
- needs_update = force_rebuild
960
- is_migration = False
961
- reason = ""
962
-
963
- # In project deployment mode, always deploy regardless of version
964
- if deployment_mode == "project":
965
- if target_file.exists():
966
- needs_update = True
967
- self.logger.debug(
968
- f"Project deployment mode: will deploy {template_file.stem}"
969
- )
970
- else:
971
- needs_update = True
972
- elif not needs_update and target_file.exists():
973
- # In update mode, check version compatibility
974
- needs_update, reason = self.version_manager.check_agent_needs_update(
975
- target_file, template_file, base_agent_version
976
- )
977
- if needs_update:
978
- # Check if this is a migration from old format
979
- if "migration needed" in reason:
980
- is_migration = True
981
- self.logger.info(f"Migrating agent {template_file.stem}: {reason}")
982
- else:
983
- self.logger.info(
984
- f"Agent {template_file.stem} needs update: {reason}"
985
- )
986
-
987
- return needs_update, is_migration, reason
988
-
989
- def _record_agent_deployment(
990
- self,
991
- agent_name: str,
992
- template_file: Path,
993
- target_file: Path,
994
- is_update: bool,
995
- is_migration: bool,
996
- reason: str,
997
- agent_start_time: float,
998
- results: Dict[str, Any],
999
- ) -> None:
1000
- """
1001
- Record deployment metrics and update results.
1002
-
1003
- WHY: Centralized metrics recording ensures consistent tracking
1004
- of deployment performance and statistics.
1005
-
1006
- Args:
1007
- agent_name: Name of the agent
1008
- template_file: Template file
1009
- target_file: Target file
1010
- is_update: Whether this is an update
1011
- is_migration: Whether this is a migration
1012
- reason: Update/migration reason
1013
- agent_start_time: Start time for this agent
1014
- results: Results dictionary to update
1015
- """
1016
- # METRICS: Record deployment time for this agent
1017
- agent_deployment_time = (time.time() - agent_start_time) * 1000 # Convert to ms
1018
- results["metrics"]["agent_timings"][agent_name] = agent_deployment_time
1019
-
1020
- # METRICS: Update agent type deployment counts
1021
- self._deployment_metrics["agent_type_counts"][agent_name] = (
1022
- self._deployment_metrics["agent_type_counts"].get(agent_name, 0) + 1
1023
- )
1024
-
1025
- deployment_info = {
1026
- "name": agent_name,
1027
- "template": str(template_file),
1028
- "target": str(target_file),
1029
- "deployment_time_ms": agent_deployment_time,
1030
- }
1031
-
1032
- if is_migration:
1033
- deployment_info["reason"] = reason
1034
- results["migrated"].append(deployment_info)
1035
- self.logger.info(
1036
- f"Successfully migrated agent: {agent_name} to semantic versioning"
1037
- )
1038
-
1039
- # METRICS: Track migration statistics
1040
- self._deployment_metrics["migrations_performed"] += 1
1041
- self._deployment_metrics["version_migration_count"] += 1
1042
-
1043
- elif is_update:
1044
- results["updated"].append(deployment_info)
1045
- self.logger.debug(f"Updated agent: {agent_name}")
1046
- else:
1047
- results["deployed"].append(deployment_info)
1048
- self.logger.debug(f"Built and deployed agent: {agent_name}")
1049
-
1050
688
  def _validate_and_repair_existing_agents(self, agents_dir: Path) -> Dict[str, Any]:
1051
689
  """Validate and repair broken frontmatter in existing agent files."""
1052
690
  from .agent_frontmatter_validator import AgentFrontmatterValidator
1053
691
 
1054
692
  validator = AgentFrontmatterValidator(self.logger)
1055
693
  return validator.validate_and_repair_existing_agents(agents_dir)
1056
-
1057
- def _determine_agent_source(self, template_path: Path) -> str:
1058
- """Determine the source of an agent from its template path.
1059
-
1060
- WHY: When deploying single agents, we need to track their source
1061
- for proper version management and debugging.
1062
-
1063
- Args:
1064
- template_path: Path to the agent template
1065
-
1066
- Returns:
1067
- Source string (system/project/user/unknown)
1068
- """
1069
- template_str = str(template_path.resolve())
1070
-
1071
- # Check if it's a system template
1072
- if "/claude_mpm/agents/templates/" in template_str or "/src/claude_mpm/agents/templates/" in template_str:
1073
- return "system"
1074
-
1075
- # Check if it's a project agent
1076
- if "/.claude-mpm/agents/" in template_str:
1077
- # Check if it's in the current working directory
1078
- if str(self.working_directory) in template_str:
1079
- return "project"
1080
- # Check if it's in user home
1081
- elif str(Path.home()) in template_str:
1082
- return "user"
1083
-
1084
- return "unknown"
1085
-
694
+
1086
695
  def _should_use_multi_source_deployment(self, deployment_mode: str) -> bool:
1087
696
  """Determine if multi-source deployment should be used.
1088
-
697
+
1089
698
  WHY: Multi-source deployment ensures the highest version wins,
1090
699
  but we may want to preserve backward compatibility in some modes.
1091
-
700
+
1092
701
  Args:
1093
702
  deployment_mode: Current deployment mode
1094
-
703
+
1095
704
  Returns:
1096
705
  True if multi-source deployment should be used
1097
706
  """
1098
707
  # Always use multi-source for update mode to get highest versions
1099
708
  if deployment_mode == "update":
1100
709
  return True
1101
-
710
+
1102
711
  # For project mode, also use multi-source to ensure highest version wins
1103
712
  # This is the key change - project mode should also compare versions
1104
- if deployment_mode == "project":
1105
- return True
1106
-
1107
- return False
1108
-
713
+ return deployment_mode == "project"
714
+
1109
715
  def _get_multi_source_templates(
1110
- self, excluded_agents: List[str], config: Config, agents_dir: Path,
1111
- force_rebuild: bool = False
716
+ self,
717
+ excluded_agents: List[str],
718
+ config: Config,
719
+ agents_dir: Path,
720
+ force_rebuild: bool = False,
1112
721
  ) -> Tuple[List[Path], Dict[str, str], Dict[str, Any]]:
1113
722
  """Get agent templates from multiple sources with version comparison.
1114
-
723
+
1115
724
  WHY: This method uses the multi-source service to discover agents
1116
725
  from all available sources and select the highest version of each.
1117
-
726
+
1118
727
  Args:
1119
728
  excluded_agents: List of agents to exclude
1120
729
  config: Configuration object
1121
730
  agents_dir: Target deployment directory
1122
731
  force_rebuild: Whether to force rebuild
1123
-
732
+
1124
733
  Returns:
1125
734
  Tuple of (template_files, agent_sources, cleanup_results)
1126
735
  """
@@ -1128,70 +737,79 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
1128
737
  system_templates_dir = self.templates_dir
1129
738
  project_agents_dir = None
1130
739
  user_agents_dir = None
1131
-
740
+
1132
741
  # Check for project agents
1133
742
  if self.working_directory:
1134
743
  potential_project_dir = self.working_directory / ".claude-mpm" / "agents"
1135
744
  if potential_project_dir.exists():
1136
745
  project_agents_dir = potential_project_dir
1137
746
  self.logger.info(f"Found project agents at: {project_agents_dir}")
1138
-
747
+
1139
748
  # Check for user agents
1140
749
  user_home = Path.home()
1141
750
  potential_user_dir = user_home / ".claude-mpm" / "agents"
1142
751
  if potential_user_dir.exists():
1143
752
  user_agents_dir = potential_user_dir
1144
753
  self.logger.info(f"Found user agents at: {user_agents_dir}")
1145
-
754
+
1146
755
  # Get agents with version comparison and cleanup
1147
- agents_to_deploy, agent_sources, cleanup_results = self.multi_source_service.get_agents_for_deployment(
1148
- system_templates_dir=system_templates_dir,
1149
- project_agents_dir=project_agents_dir,
1150
- user_agents_dir=user_agents_dir,
1151
- working_directory=self.working_directory,
1152
- excluded_agents=excluded_agents,
1153
- config=config,
1154
- cleanup_outdated=True # Enable cleanup by default
756
+ agents_to_deploy, agent_sources, cleanup_results = (
757
+ self.multi_source_service.get_agents_for_deployment(
758
+ system_templates_dir=system_templates_dir,
759
+ project_agents_dir=project_agents_dir,
760
+ user_agents_dir=user_agents_dir,
761
+ working_directory=self.working_directory,
762
+ excluded_agents=excluded_agents,
763
+ config=config,
764
+ cleanup_outdated=True, # Enable cleanup by default
765
+ )
1155
766
  )
1156
-
767
+
1157
768
  # Compare with deployed versions if agents directory exists
1158
769
  if agents_dir.exists():
1159
770
  comparison_results = self.multi_source_service.compare_deployed_versions(
1160
771
  deployed_agents_dir=agents_dir,
1161
772
  agents_to_deploy=agents_to_deploy,
1162
- agent_sources=agent_sources
773
+ agent_sources=agent_sources,
1163
774
  )
1164
-
775
+
1165
776
  # Log version upgrades and source changes
1166
777
  if comparison_results.get("version_upgrades"):
1167
- self.logger.info(f"Version upgrades available for {len(comparison_results['version_upgrades'])} agents")
778
+ self.logger.info(
779
+ f"Version upgrades available for {len(comparison_results['version_upgrades'])} agents"
780
+ )
1168
781
  if comparison_results.get("source_changes"):
1169
- self.logger.info(f"Source changes for {len(comparison_results['source_changes'])} agents")
1170
-
782
+ self.logger.info(
783
+ f"Source changes for {len(comparison_results['source_changes'])} agents"
784
+ )
785
+
1171
786
  # Filter agents based on comparison results (unless force_rebuild is set)
1172
787
  if not force_rebuild:
1173
788
  # Only deploy agents that need updates or are new
1174
789
  agents_needing_update = set(comparison_results.get("needs_update", []))
1175
-
790
+
1176
791
  # Extract agent names from new_agents list (which contains dicts)
1177
792
  new_agent_names = [
1178
793
  agent["name"] if isinstance(agent, dict) else agent
1179
794
  for agent in comparison_results.get("new_agents", [])
1180
795
  ]
1181
796
  agents_needing_update.update(new_agent_names)
1182
-
797
+
1183
798
  # Filter agents_to_deploy to only include those needing updates
1184
799
  filtered_agents = {
1185
- name: path for name, path in agents_to_deploy.items()
800
+ name: path
801
+ for name, path in agents_to_deploy.items()
1186
802
  if name in agents_needing_update
1187
803
  }
1188
804
  agents_to_deploy = filtered_agents
1189
-
1190
- self.logger.info(f"Filtered to {len(agents_to_deploy)} agents needing deployment")
1191
-
805
+
806
+ self.logger.info(
807
+ f"Filtered to {len(agents_to_deploy)} agents needing deployment"
808
+ )
809
+
1192
810
  # Convert to list of Path objects
1193
811
  template_files = list(agents_to_deploy.values())
1194
-
812
+
1195
813
  return template_files, agent_sources, cleanup_results
1196
814
 
1197
815
  # ================================================================================
@@ -1243,7 +861,7 @@ class AgentDeploymentService(ConfigServiceBase, AgentDeploymentInterface):
1243
861
  return len(errors) == 0, errors
1244
862
 
1245
863
  except Exception as e:
1246
- return False, [f"Validation error: {str(e)}"]
864
+ return False, [f"Validation error: {e!s}"]
1247
865
 
1248
866
  def get_deployment_status(self) -> Dict[str, Any]:
1249
867
  """Get current deployment status and metrics."""